diff --git a/Base/usr/share/man/man7/boot_device_addressing.md b/Base/usr/share/man/man7/boot_device_addressing.md new file mode 100644 index 0000000000..021ace43ad --- /dev/null +++ b/Base/usr/share/man/man7/boot_device_addressing.md @@ -0,0 +1,62 @@ +## Name + +Boot Device Addressing - addressing the correct boot device to use. + +## Synopsis + +Serenity's kernel can select the boot device at boot time, based on the `root` boot parameter. +This functionality is used to control which boot device is selected to be used for all further boot process operations. + +## Description + +The kernel `root` boot parameter takes the form of **`root={value}`**, where the **`={value}`** +trailer can be set to specific prefixes to indicate the boot device preference. + +### Addressing options + +The user can choose to use addressing based on synthetic unix concepts: + +``` +block0:0 +``` + +This is especially useful in static hardware setups, so the user can choose to use +either a raw `StorageDevice` or partition block device. The `0,0` selection is the `MAJOR,MINOR` +numbers of the device. + +However, when there's knowledge of the hardware arrangement of raw `StorageDevice`s, +it could be valuable to use addressing based on hardware-relative interface-specific "location" +to address raw `StorageDevice`s: + +``` +ata0:0:0 [First ATA controller, ATA first primary channel, master device] +nvme0:0 [First NVMe Controller, First NVMe Namespace] +ramdisk0 [First Ramdisk] +``` + +When the logical arrangement is known, using (absolute) LUNs is the easiest option as it doesn't rely on +using unix device numbers or hardware-relative location: + +``` +lun0:0:0 - first device on the first channel of the first controller to be enumerated +``` + +### Note on selecting partitions from raw `StorageDevice`s + +All the addressing options above support selecting a partition device, given that +the selected device is a `StorageDevice` and not a `DiskPartition` device: + +``` +nvme0;part0 +lun0:0:0;part0 +``` + +The only exception to this is when choosing a `BlockDevice`. As such, +trying to specify `block0:0;part0`, for example, will lead to a kernel panic, +as an invalid boot device parameter. + +### Selecting a specific partition based on known GUID + +For GPT partitions, passing `PARTUUID:` and the GUID of the partition can be used +to select a GPT partition. Although it could be slower to find the corresponding +partition, it is the safest option available for persistent storage. diff --git a/Kernel/CMakeLists.txt b/Kernel/CMakeLists.txt index 790bcc9b77..872b994ff7 100644 --- a/Kernel/CMakeLists.txt +++ b/Kernel/CMakeLists.txt @@ -100,6 +100,7 @@ set(KERNEL_SOURCES Storage/ATA/GenericIDE/Channel.cpp Storage/ATA/GenericIDE/ISAController.cpp Storage/ATA/GenericIDE/PCIController.cpp + Storage/ATA/ATAController.cpp Storage/ATA/ATADevice.cpp Storage/ATA/ATADiskDevice.cpp Storage/ATA/ATAPort.cpp diff --git a/Kernel/CommandLine.cpp b/Kernel/CommandLine.cpp index 675896bd93..e55a3f5d68 100644 --- a/Kernel/CommandLine.cpp +++ b/Kernel/CommandLine.cpp @@ -183,7 +183,7 @@ UNMAP_AFTER_INIT bool CommandLine::is_force_pio() const UNMAP_AFTER_INIT StringView CommandLine::root_device() const { - return lookup("root"sv).value_or("/dev/hda"sv); + return lookup("root"sv).value_or("lun0:0:0"sv); } bool CommandLine::is_nvme_polling_enabled() const diff --git a/Kernel/Storage/ATA/ATAController.cpp b/Kernel/Storage/ATA/ATAController.cpp new file mode 100644 index 0000000000..042bb16fde --- /dev/null +++ b/Kernel/Storage/ATA/ATAController.cpp @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2022, Liav A. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include + +namespace Kernel { + +ATAController::ATAController() + : StorageController(StorageManagement::generate_relative_ata_controller_id({})) +{ +} + +} diff --git a/Kernel/Storage/ATA/ATAController.h b/Kernel/Storage/ATA/ATAController.h index 7a314ef087..d86f840cad 100644 --- a/Kernel/Storage/ATA/ATAController.h +++ b/Kernel/Storage/ATA/ATAController.h @@ -24,6 +24,6 @@ public: virtual void start_request(ATADevice const&, AsyncBlockDeviceRequest&) = 0; protected: - ATAController() = default; + ATAController(); }; } diff --git a/Kernel/Storage/ATA/ATADevice.cpp b/Kernel/Storage/ATA/ATADevice.cpp index 53fbf18bb8..f78bed2286 100644 --- a/Kernel/Storage/ATA/ATADevice.cpp +++ b/Kernel/Storage/ATA/ATADevice.cpp @@ -16,8 +16,8 @@ static StorageDevice::LUNAddress convert_ata_address_to_lun_address(ATAControlle return StorageDevice::LUNAddress { controller.controller_id(), ata_address.port, ata_address.subport }; } -ATADevice::ATADevice(ATAController const& controller, ATADevice::Address ata_address, MinorNumber minor_number, u16 capabilities, u16 logical_sector_size, u64 max_addressable_block, NonnullOwnPtr early_storage_name) - : StorageDevice(convert_ata_address_to_lun_address(controller, ata_address), StorageManagement::storage_type_major_number(), minor_number, logical_sector_size, max_addressable_block, move(early_storage_name)) +ATADevice::ATADevice(ATAController const& controller, ATADevice::Address ata_address, u16 capabilities, u16 logical_sector_size, u64 max_addressable_block) + : StorageDevice(convert_ata_address_to_lun_address(controller, ata_address), controller.hardware_relative_controller_id(), logical_sector_size, max_addressable_block) , m_controller(controller) , m_ata_address(ata_address) , m_capabilities(capabilities) diff --git a/Kernel/Storage/ATA/ATADevice.h b/Kernel/Storage/ATA/ATADevice.h index debd0acc2a..18d95df5f3 100644 --- a/Kernel/Storage/ATA/ATADevice.h +++ b/Kernel/Storage/ATA/ATADevice.h @@ -36,7 +36,7 @@ public: Address const& ata_address() const { return m_ata_address; } protected: - ATADevice(ATAController const&, Address, MinorNumber, u16, u16, u64, NonnullOwnPtr); + ATADevice(ATAController const&, Address, u16, u16, u64); LockWeakPtr m_controller; const Address m_ata_address; diff --git a/Kernel/Storage/ATA/ATADiskDevice.cpp b/Kernel/Storage/ATA/ATADiskDevice.cpp index 7fd895eb1b..7944687566 100644 --- a/Kernel/Storage/ATA/ATADiskDevice.cpp +++ b/Kernel/Storage/ATA/ATADiskDevice.cpp @@ -14,18 +14,14 @@ namespace Kernel { NonnullLockRefPtr ATADiskDevice::create(ATAController const& controller, ATADevice::Address ata_address, u16 capabilities, u16 logical_sector_size, u64 max_addressable_block) { - auto minor_device_number = StorageManagement::generate_storage_minor_number(); - - auto device_name = MUST(KString::formatted("hd{:c}", 'a' + minor_device_number.value())); - - auto disk_device_or_error = DeviceManagement::try_create_device(controller, ata_address, minor_device_number, capabilities, logical_sector_size, max_addressable_block, move(device_name)); + auto disk_device_or_error = DeviceManagement::try_create_device(controller, ata_address, capabilities, logical_sector_size, max_addressable_block); // FIXME: Find a way to propagate errors VERIFY(!disk_device_or_error.is_error()); return disk_device_or_error.release_value(); } -ATADiskDevice::ATADiskDevice(ATAController const& controller, ATADevice::Address ata_address, MinorNumber minor_number, u16 capabilities, u16 logical_sector_size, u64 max_addressable_block, NonnullOwnPtr early_storage_name) - : ATADevice(controller, ata_address, minor_number, capabilities, logical_sector_size, max_addressable_block, move(early_storage_name)) +ATADiskDevice::ATADiskDevice(ATAController const& controller, ATADevice::Address ata_address, u16 capabilities, u16 logical_sector_size, u64 max_addressable_block) + : ATADevice(controller, ata_address, capabilities, logical_sector_size, max_addressable_block) { } diff --git a/Kernel/Storage/ATA/ATADiskDevice.h b/Kernel/Storage/ATA/ATADiskDevice.h index 33f8c7b307..d1b0ac2f5a 100644 --- a/Kernel/Storage/ATA/ATADiskDevice.h +++ b/Kernel/Storage/ATA/ATADiskDevice.h @@ -25,7 +25,7 @@ public: virtual CommandSet command_set() const override { return CommandSet::ATA; } private: - ATADiskDevice(ATAController const&, Address, MinorNumber, u16, u16, u64, NonnullOwnPtr); + ATADiskDevice(ATAController const&, Address, u16, u16, u64); // ^DiskDevice virtual StringView class_name() const override; diff --git a/Kernel/Storage/NVMe/NVMeController.cpp b/Kernel/Storage/NVMe/NVMeController.cpp index 3bd8fd53cf..2871c22695 100644 --- a/Kernel/Storage/NVMe/NVMeController.cpp +++ b/Kernel/Storage/NVMe/NVMeController.cpp @@ -17,20 +17,20 @@ #include #include #include +#include namespace Kernel { -Atomic NVMeController::s_controller_id {}; UNMAP_AFTER_INIT ErrorOr> NVMeController::try_initialize(Kernel::PCI::DeviceIdentifier const& device_identifier, bool is_queue_polled) { - auto controller = TRY(adopt_nonnull_lock_ref_or_enomem(new NVMeController(device_identifier))); + auto controller = TRY(adopt_nonnull_lock_ref_or_enomem(new NVMeController(device_identifier, StorageManagement::generate_relative_nvme_controller_id({})))); TRY(controller->initialize(is_queue_polled)); - NVMeController::s_controller_id++; return controller; } -UNMAP_AFTER_INIT NVMeController::NVMeController(const PCI::DeviceIdentifier& device_identifier) +UNMAP_AFTER_INIT NVMeController::NVMeController(const PCI::DeviceIdentifier& device_identifier, u32 hardware_relative_controller_id) : PCI::Device(device_identifier.address()) + , StorageController(hardware_relative_controller_id) , m_pci_device_id(device_identifier) { } @@ -207,7 +207,7 @@ UNMAP_AFTER_INIT ErrorOr NVMeController::identify_and_init_namespaces() dbgln_if(NVME_DEBUG, "NVMe: Block count is {} and Block size is {}", block_counts, block_size); - m_namespaces.append(TRY(NVMeNameSpace::try_create(*this, m_queues, s_controller_id.load(), nsid, block_counts, block_size))); + m_namespaces.append(TRY(NVMeNameSpace::try_create(*this, m_queues, nsid, block_counts, block_size))); m_device_count++; dbgln_if(NVME_DEBUG, "NVMe: Initialized namespace with NSID: {}", nsid); } diff --git a/Kernel/Storage/NVMe/NVMeController.h b/Kernel/Storage/NVMe/NVMeController.h index 4210fc5ea9..d260c72572 100644 --- a/Kernel/Storage/NVMe/NVMeController.h +++ b/Kernel/Storage/NVMe/NVMeController.h @@ -28,7 +28,6 @@ class NVMeController : public PCI::Device public: static ErrorOr> try_initialize(PCI::DeviceIdentifier const&, bool is_queue_polled); ErrorOr initialize(bool is_queue_polled); - explicit NVMeController(PCI::DeviceIdentifier const&); LockRefPtr device(u32 index) const override; size_t devices_count() const override; @@ -56,6 +55,8 @@ public: void set_admin_queue_ready_flag() { m_admin_queue_ready = true; }; private: + NVMeController(PCI::DeviceIdentifier const&, u32 hardware_relative_controller_id); + ErrorOr identify_and_init_namespaces(); Tuple get_ns_features(IdentifyNamespace& identify_data_struct); ErrorOr create_admin_queue(Optional irq); diff --git a/Kernel/Storage/NVMe/NVMeNameSpace.cpp b/Kernel/Storage/NVMe/NVMeNameSpace.cpp index f91d157434..a54cddfcd1 100644 --- a/Kernel/Storage/NVMe/NVMeNameSpace.cpp +++ b/Kernel/Storage/NVMe/NVMeNameSpace.cpp @@ -12,17 +12,14 @@ namespace Kernel { -UNMAP_AFTER_INIT ErrorOr> NVMeNameSpace::try_create(NVMeController const& controller, NonnullLockRefPtrVector queues, u8 controller_id, u16 nsid, size_t storage_size, size_t lba_size) +UNMAP_AFTER_INIT ErrorOr> NVMeNameSpace::try_create(NVMeController const& controller, NonnullLockRefPtrVector queues, u16 nsid, size_t storage_size, size_t lba_size) { - auto minor_number = StorageManagement::generate_storage_minor_number(); - auto major_number = StorageManagement::storage_type_major_number(); - auto device_name_kstring = TRY(KString::formatted("nvme{:d}n{:d}", controller_id, nsid)); - auto device = TRY(DeviceManagement::try_create_device(StorageDevice::LUNAddress { controller.controller_id(), nsid, 0 }, move(queues), storage_size, lba_size, major_number.value(), minor_number.value(), nsid, move(device_name_kstring))); + auto device = TRY(DeviceManagement::try_create_device(StorageDevice::LUNAddress { controller.controller_id(), nsid, 0 }, controller.hardware_relative_controller_id(), move(queues), storage_size, lba_size, nsid)); return device; } -UNMAP_AFTER_INIT NVMeNameSpace::NVMeNameSpace(LUNAddress logical_unit_number_address, NonnullLockRefPtrVector queues, size_t max_addresable_block, size_t lba_size, size_t major_number, size_t minor_number, u16 nsid, NonnullOwnPtr dev_name) - : StorageDevice(logical_unit_number_address, major_number, minor_number, lba_size, max_addresable_block, move(dev_name)) +UNMAP_AFTER_INIT NVMeNameSpace::NVMeNameSpace(LUNAddress logical_unit_number_address, u32 hardware_relative_controller_id, NonnullLockRefPtrVector queues, size_t max_addresable_block, size_t lba_size, u16 nsid) + : StorageDevice(logical_unit_number_address, hardware_relative_controller_id, lba_size, max_addresable_block) , m_nsid(nsid) , m_queues(move(queues)) { diff --git a/Kernel/Storage/NVMe/NVMeNameSpace.h b/Kernel/Storage/NVMe/NVMeNameSpace.h index 150f94172e..4a1ed072c9 100644 --- a/Kernel/Storage/NVMe/NVMeNameSpace.h +++ b/Kernel/Storage/NVMe/NVMeNameSpace.h @@ -24,13 +24,13 @@ class NVMeNameSpace : public StorageDevice { friend class DeviceManagement; public: - static ErrorOr> try_create(NVMeController const&, NonnullLockRefPtrVector queues, u8 controller_id, u16 nsid, size_t storage_size, size_t lba_size); + static ErrorOr> try_create(NVMeController const&, NonnullLockRefPtrVector queues, u16 nsid, size_t storage_size, size_t lba_size); CommandSet command_set() const override { return CommandSet::NVMe; }; void start_request(AsyncBlockDeviceRequest& request) override; private: - NVMeNameSpace(LUNAddress, NonnullLockRefPtrVector queues, size_t storage_size, size_t lba_size, size_t major_number, size_t minor_number, u16 nsid, NonnullOwnPtr early_device_name); + NVMeNameSpace(LUNAddress, u32 hardware_relative_controller_id, NonnullLockRefPtrVector queues, size_t storage_size, size_t lba_size, u16 nsid); u16 m_nsid; NonnullLockRefPtrVector m_queues; diff --git a/Kernel/Storage/Ramdisk/Controller.cpp b/Kernel/Storage/Ramdisk/Controller.cpp index ad6f011441..495c070836 100644 --- a/Kernel/Storage/Ramdisk/Controller.cpp +++ b/Kernel/Storage/Ramdisk/Controller.cpp @@ -37,7 +37,7 @@ void RamdiskController::complete_current_request(AsyncDeviceRequest::RequestResu } RamdiskController::RamdiskController() - : StorageController() + : StorageController(0) { // Populate ramdisk controllers from Multiboot boot modules, if any. size_t count = 0; diff --git a/Kernel/Storage/Ramdisk/Device.cpp b/Kernel/Storage/Ramdisk/Device.cpp index b1ae1a7d1a..08033bb0a1 100644 --- a/Kernel/Storage/Ramdisk/Device.cpp +++ b/Kernel/Storage/Ramdisk/Device.cpp @@ -15,16 +15,14 @@ namespace Kernel { NonnullLockRefPtr RamdiskDevice::create(RamdiskController const& controller, NonnullOwnPtr&& region, int major, int minor) { - auto device_name = MUST(KString::formatted("ramdisk{}", minor)); - - auto device_or_error = DeviceManagement::try_create_device(controller, move(region), major, minor, move(device_name)); + auto device_or_error = DeviceManagement::try_create_device(controller, move(region), major, minor); // FIXME: Find a way to propagate errors VERIFY(!device_or_error.is_error()); return device_or_error.release_value(); } -RamdiskDevice::RamdiskDevice(RamdiskController const& controller, NonnullOwnPtr&& region, int major, int minor, NonnullOwnPtr device_name) - : StorageDevice(LUNAddress { controller.controller_id(), 0, 0 }, major, minor, 512, region->size() / 512, move(device_name)) +RamdiskDevice::RamdiskDevice(RamdiskController const& controller, NonnullOwnPtr&& region, int major, int minor) + : StorageDevice({}, LUNAddress { controller.controller_id(), 0, 0 }, 0, major, minor, 512, region->size() / 512) , m_region(move(region)) { dmesgln("Ramdisk: Device #{} @ {}, Capacity={}", minor, m_region->vaddr(), max_addressable_block() * 512); diff --git a/Kernel/Storage/Ramdisk/Device.h b/Kernel/Storage/Ramdisk/Device.h index c99ecba111..28759bbc9a 100644 --- a/Kernel/Storage/Ramdisk/Device.h +++ b/Kernel/Storage/Ramdisk/Device.h @@ -25,7 +25,7 @@ public: virtual StringView class_name() const override; private: - RamdiskDevice(RamdiskController const&, NonnullOwnPtr&&, int major, int minor, NonnullOwnPtr device_name); + RamdiskDevice(RamdiskController const&, NonnullOwnPtr&&, int major, int minor); // ^BlockDevice virtual void start_request(AsyncBlockDeviceRequest&) override; diff --git a/Kernel/Storage/StorageController.cpp b/Kernel/Storage/StorageController.cpp index 739c1ec1ae..6aec6ecd98 100644 --- a/Kernel/Storage/StorageController.cpp +++ b/Kernel/Storage/StorageController.cpp @@ -9,8 +9,9 @@ namespace Kernel { -StorageController::StorageController() +StorageController::StorageController(u32 hardware_relative_controller_id) : m_controller_id(StorageManagement::generate_controller_id()) + , m_hardware_relative_controller_id(hardware_relative_controller_id) { } diff --git a/Kernel/Storage/StorageController.h b/Kernel/Storage/StorageController.h index dd7d73102c..bcd4465517 100644 --- a/Kernel/Storage/StorageController.h +++ b/Kernel/Storage/StorageController.h @@ -30,6 +30,7 @@ public: virtual size_t devices_count() const = 0; u32 controller_id() const { return m_controller_id; } + u32 hardware_relative_controller_id() const { return m_hardware_relative_controller_id; } protected: virtual bool reset() = 0; @@ -37,9 +38,11 @@ protected: virtual void complete_current_request(AsyncDeviceRequest::RequestResult) = 0; - StorageController(); + explicit StorageController(u32 hardware_relative_controller_id); private: u32 const m_controller_id { 0 }; + + u32 const m_hardware_relative_controller_id { 0 }; }; } diff --git a/Kernel/Storage/StorageDevice.cpp b/Kernel/Storage/StorageDevice.cpp index 5407a939f6..267319632e 100644 --- a/Kernel/Storage/StorageDevice.cpp +++ b/Kernel/Storage/StorageDevice.cpp @@ -19,10 +19,19 @@ namespace Kernel { -StorageDevice::StorageDevice(LUNAddress logical_unit_number_address, MajorNumber major, MinorNumber minor, size_t sector_size, u64 max_addressable_block, NonnullOwnPtr device_name) - : BlockDevice(major, minor, sector_size) - , m_early_storage_device_name(move(device_name)) +StorageDevice::StorageDevice(LUNAddress logical_unit_number_address, u32 hardware_relative_controller_id, size_t sector_size, u64 max_addressable_block) + : BlockDevice(StorageManagement::storage_type_major_number(), StorageManagement::generate_storage_minor_number(), sector_size) , m_logical_unit_number_address(logical_unit_number_address) + , m_hardware_relative_controller_id(hardware_relative_controller_id) + , m_max_addressable_block(max_addressable_block) + , m_blocks_per_page(PAGE_SIZE / block_size()) +{ +} + +StorageDevice::StorageDevice(Badge, LUNAddress logical_unit_number_address, u32 hardware_relative_controller_id, MajorNumber major, MinorNumber minor, size_t sector_size, u64 max_addressable_block) + : BlockDevice(major, minor, sector_size) + , m_logical_unit_number_address(logical_unit_number_address) + , m_hardware_relative_controller_id(hardware_relative_controller_id) , m_max_addressable_block(max_addressable_block) , m_blocks_per_page(PAGE_SIZE / block_size()) { @@ -227,11 +236,6 @@ ErrorOr StorageDevice::write(OpenFileDescription&, u64 offset, UserOrKer return pos + remaining; } -StringView StorageDevice::early_storage_name() const -{ - return m_early_storage_device_name->view(); -} - bool StorageDevice::can_write(OpenFileDescription const&, u64 offset) const { return offset < (max_addressable_block() * block_size()); diff --git a/Kernel/Storage/StorageDevice.h b/Kernel/Storage/StorageDevice.h index feac7f4a06..0ac12c97ad 100644 --- a/Kernel/Storage/StorageDevice.h +++ b/Kernel/Storage/StorageDevice.h @@ -15,6 +15,7 @@ namespace Kernel { +class RamdiskDevice; class StorageDevice : public BlockDevice { friend class StorageManagement; friend class DeviceManagement; @@ -46,7 +47,6 @@ public: // to the Primary channel as a slave device, which translates to LUN 1:0:1. // On NVMe, for example, connecting a second PCIe NVMe storage device as a sole NVMe namespace translates // to LUN 1:0:0. - // TODO: LUNs are also useful also when specifying the boot drive on boot. Consider doing that. struct LUNAddress { u32 controller_id; u32 target_id; @@ -63,15 +63,14 @@ public: virtual bool can_write(OpenFileDescription const&, u64) const override; virtual void prepare_for_unplug() { m_partitions.clear(); } - // FIXME: Remove this method after figuring out another scheme for naming. - StringView early_storage_name() const; - NonnullLockRefPtrVector const& partitions() const { return m_partitions; } void add_partition(NonnullLockRefPtr disk_partition) { MUST(m_partitions.try_append(disk_partition)); } LUNAddress const& logical_unit_number_address() const { return m_logical_unit_number_address; } + u32 parent_controller_hardware_relative_id() const { return m_hardware_relative_controller_id; } + virtual CommandSet command_set() const = 0; StringView command_set_to_string_view() const; @@ -80,7 +79,12 @@ public: virtual ErrorOr ioctl(OpenFileDescription&, unsigned request, Userspace arg) final; protected: - StorageDevice(LUNAddress, MajorNumber, MinorNumber, size_t, u64, NonnullOwnPtr); + StorageDevice(LUNAddress, u32 hardware_relative_controller_id, size_t sector_size, u64); + + // Note: We want to be able to put distinction between Storage devices and Ramdisk-based devices. + // We do this because it will make selecting ramdisk devices much more easier in boot time in the kernel commandline. + StorageDevice(Badge, LUNAddress, u32 hardware_relative_controller_id, MajorNumber, MinorNumber, size_t sector_size, u64); + // ^DiskDevice virtual StringView class_name() const override; @@ -91,9 +95,15 @@ private: mutable IntrusiveListNode> m_list_node; NonnullLockRefPtrVector m_partitions; - // FIXME: Remove this method after figuring out another scheme for naming. - NonnullOwnPtr m_early_storage_device_name; LUNAddress const m_logical_unit_number_address; + + // Note: This data member should be used with LUNAddress target_id and disk_id. + // LUNs are agnostic system-wide addresses, so they are assigned without caring about the specific hardware interfaces. + // This class member on the other side, is meant to be assigned *per hardware type*, + // which means in constrast to the LUNAddress controller_id struct member, we take the index of the hardware + // controller among its fellow controllers of the same hardware type in the system. + u32 const m_hardware_relative_controller_id { 0 }; + u64 m_max_addressable_block { 0 }; size_t m_blocks_per_page { 0 }; }; diff --git a/Kernel/Storage/StorageManagement.cpp b/Kernel/Storage/StorageManagement.cpp index 50fefd7bbc..d0ac325625 100644 --- a/Kernel/Storage/StorageManagement.cpp +++ b/Kernel/Storage/StorageManagement.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -34,22 +35,41 @@ static Atomic s_storage_device_minor_number; static Atomic s_partition_device_minor_number; static Atomic s_controller_id; +static Atomic s_relative_ata_controller_id; +static Atomic s_relative_nvme_controller_id; + static constexpr StringView partition_uuid_prefix = "PARTUUID:"sv; +static constexpr StringView partition_number_prefix = "part"sv; +static constexpr StringView block_device_prefix = "block"sv; + +static constexpr StringView ata_device_prefix = "ata"sv; +static constexpr StringView nvme_device_prefix = "nvme"sv; +static constexpr StringView ramdisk_device_prefix = "ramdisk"sv; +static constexpr StringView logical_unit_number_device_prefix = "lun"sv; + UNMAP_AFTER_INIT StorageManagement::StorageManagement() { } +u32 StorageManagement::generate_relative_nvme_controller_id(Badge) +{ + auto controller_id = s_relative_nvme_controller_id.load(); + s_relative_nvme_controller_id++; + return controller_id; +} +u32 StorageManagement::generate_relative_ata_controller_id(Badge) +{ + auto controller_id = s_relative_ata_controller_id.load(); + s_relative_ata_controller_id++; + return controller_id; +} + void StorageManagement::remove_device(StorageDevice& device) { m_storage_devices.remove(device); } -bool StorageManagement::boot_argument_contains_partition_uuid() -{ - return m_boot_argument.starts_with(partition_uuid_prefix); -} - UNMAP_AFTER_INIT void StorageManagement::enumerate_pci_controllers(bool force_pio, bool nvme_poll) { VERIFY(m_controllers.is_empty()); @@ -120,12 +140,12 @@ UNMAP_AFTER_INIT void StorageManagement::dump_storage_devices_and_partitions() c for (auto const& storage_device : m_storage_devices) { auto const& partitions = storage_device.partitions(); if (partitions.is_empty()) { - dbgln(" Device: {} (no partitions)", storage_device.early_storage_name()); + dbgln(" Device: block{}:{} (no partitions)", storage_device.major(), storage_device.minor()); } else { - dbgln(" Device: {} ({} partitions)", storage_device.early_storage_name(), partitions.size()); + dbgln(" Device: block{}:{} ({} partitions)", storage_device.major(), storage_device.minor(), partitions.size()); unsigned partition_number = 1; for (auto const& partition : partitions) { - dbgln(" Partition: {} (UUID {})", partition_number, partition.metadata().unique_guid().to_string()); + dbgln(" Partition: {}, block{}:{} (UUID {})", partition_number, partition.major(), partition.minor(), partition.metadata().unique_guid().to_string()); partition_number++; } } @@ -164,51 +184,184 @@ UNMAP_AFTER_INIT void StorageManagement::enumerate_disk_partitions() } } -UNMAP_AFTER_INIT void StorageManagement::determine_boot_device() +UNMAP_AFTER_INIT Optional StorageManagement::extract_boot_device_partition_number_parameter(StringView device_prefix) { - VERIFY(!m_controllers.is_empty()); - if (m_boot_argument.starts_with("/dev/"sv)) { - StringView storage_name = m_boot_argument.substring_view(5); - for (auto& storage_device : m_storage_devices) { - if (storage_device.early_storage_name() == storage_name) { - m_boot_block_device = storage_device; - break; - } + VERIFY(m_boot_argument.starts_with(device_prefix)); + VERIFY(!m_boot_argument.starts_with(partition_uuid_prefix)); + auto storage_device_relative_address_view = m_boot_argument.substring_view(device_prefix.length()); + auto parameter_view = storage_device_relative_address_view.find_last_split_view(';'); + if (parameter_view == storage_device_relative_address_view) + return {}; + if (!parameter_view.starts_with(partition_number_prefix)) { + PANIC("StorageManagement: Invalid root boot parameter."); + } - // If the early storage name's last character is a digit (e.g. in the case of NVMe where the last - // number in the device name indicates the node, e.g. /dev/nvme0n1 we need to append a "p" character - // so that we can properly distinguish the partition index from the device itself - char storage_name_last_char = *(storage_device.early_storage_name().end() - 1); - OwnPtr normalized_name; - StringView early_storage_name; - if (storage_name_last_char >= '0' && storage_name_last_char <= '9') { - normalized_name = MUST(KString::formatted("{}p", storage_device.early_storage_name())); - early_storage_name = normalized_name->view(); - } else { - early_storage_name = storage_device.early_storage_name(); - } + auto parameter_number = parameter_view.substring_view(partition_number_prefix.length()).to_uint(); + if (!parameter_number.has_value()) { + PANIC("StorageManagement: Invalid root boot parameter."); + } - auto start_storage_name = storage_name.substring_view(0, min(early_storage_name.length(), storage_name.length())); + return parameter_number.value(); +} - if (early_storage_name.starts_with(start_storage_name)) { - StringView partition_sign = storage_name.substring_view(start_storage_name.length()); - auto possible_partition_number = partition_sign.to_uint(); - if (!possible_partition_number.has_value()) - break; - if (possible_partition_number.value() == 0) - break; - if (storage_device.partitions().size() < possible_partition_number.value()) - break; - m_boot_block_device = storage_device.partitions()[possible_partition_number.value() - 1]; - break; - } +UNMAP_AFTER_INIT Array StorageManagement::extract_boot_device_address_parameters(StringView device_prefix) +{ + VERIFY(!m_boot_argument.starts_with(partition_uuid_prefix)); + Array address_parameters; + auto parameters_view = m_boot_argument.substring_view(device_prefix.length()).find_first_split_view(';'); + size_t parts_count = 0; + bool parse_failure = false; + parameters_view.for_each_split_view(':', false, [&](StringView parameter_view) { + if (parse_failure) + return; + if (parts_count > 2) + return; + auto parameter_number = parameter_view.to_uint(); + if (!parameter_number.has_value()) { + parse_failure = true; + return; + } + address_parameters[parts_count] = parameter_number.value(); + parts_count++; + }); + + if (parts_count > 3) { + dbgln("StorageManagement: Detected {} parts in boot device parameter.", parts_count); + PANIC("StorageManagement: Invalid root boot parameter."); + } + if (parse_failure) { + PANIC("StorageManagement: Invalid root boot parameter."); + } + + return address_parameters; +} + +UNMAP_AFTER_INIT void StorageManagement::resolve_partition_from_boot_device_parameter(StorageDevice const& chosen_storage_device, StringView boot_device_prefix) +{ + auto possible_partition_number = extract_boot_device_partition_number_parameter(boot_device_prefix); + if (!possible_partition_number.has_value()) + return; + + auto partition_number = possible_partition_number.value(); + if (chosen_storage_device.partitions().size() <= partition_number) + PANIC("StorageManagement: Invalid partition number parameter."); + m_boot_block_device = chosen_storage_device.partitions()[partition_number]; +} + +UNMAP_AFTER_INIT void StorageManagement::determine_hardware_relative_boot_device(StringView relative_hardware_prefix, Function filter_device_callback) +{ + VERIFY(m_boot_argument.starts_with(relative_hardware_prefix)); + auto address_parameters = extract_boot_device_address_parameters(relative_hardware_prefix); + + RefPtr chosen_storage_device; + + for (auto& storage_device : m_storage_devices) { + if (!filter_device_callback(storage_device)) + continue; + auto storage_device_lun = storage_device.logical_unit_number_address(); + if (storage_device.parent_controller_hardware_relative_id() == address_parameters[0] + && storage_device_lun.target_id == address_parameters[1] + && storage_device_lun.disk_id == address_parameters[2]) { + m_boot_block_device = storage_device; + chosen_storage_device = storage_device; + break; } } - if (m_boot_block_device.is_null()) { - dump_storage_devices_and_partitions(); - PANIC("StorageManagement: boot device {} not found", m_boot_argument); + if (chosen_storage_device) + resolve_partition_from_boot_device_parameter(*chosen_storage_device, relative_hardware_prefix); +} + +UNMAP_AFTER_INIT void StorageManagement::determine_ata_boot_device() +{ + determine_hardware_relative_boot_device(ata_device_prefix, [](StorageDevice const& device) -> bool { + return device.command_set() == StorageDevice::CommandSet::ATA; + }); +} + +UNMAP_AFTER_INIT void StorageManagement::determine_nvme_boot_device() +{ + determine_hardware_relative_boot_device(nvme_device_prefix, [](StorageDevice const& device) -> bool { + return device.command_set() == StorageDevice::CommandSet::NVMe; + }); +} + +UNMAP_AFTER_INIT void StorageManagement::determine_ramdisk_boot_device() +{ + determine_hardware_relative_boot_device(ramdisk_device_prefix, [](StorageDevice const& device) -> bool { + return device.command_set() == StorageDevice::CommandSet::PlainMemory; + }); +} + +UNMAP_AFTER_INIT void StorageManagement::determine_block_boot_device() +{ + VERIFY(m_boot_argument.starts_with(block_device_prefix)); + auto parameters_view = extract_boot_device_address_parameters(block_device_prefix); + + // Note: We simply fetch the corresponding BlockDevice with the major and minor parameters. + // We don't try to accept and resolve a partition number as it will make this code much more + // complicated. This rule is also explained in the boot_device_addressing(7) manual page. + LockRefPtr device = DeviceManagement::the().get_device(parameters_view[0], parameters_view[1]); + if (device && device->is_block_device()) + m_boot_block_device = static_ptr_cast(device); +} + +UNMAP_AFTER_INIT void StorageManagement::determine_boot_device_with_logical_unit_number() +{ + VERIFY(m_boot_argument.starts_with(logical_unit_number_device_prefix)); + auto address_parameters = extract_boot_device_address_parameters(logical_unit_number_device_prefix); + + RefPtr chosen_storage_device; + + for (auto& storage_device : m_storage_devices) { + auto storage_device_lun = storage_device.logical_unit_number_address(); + if (storage_device_lun.controller_id == address_parameters[0] + && storage_device_lun.target_id == address_parameters[1] + && storage_device_lun.disk_id == address_parameters[2]) { + m_boot_block_device = storage_device; + chosen_storage_device = storage_device; + break; + } } + + if (chosen_storage_device) + resolve_partition_from_boot_device_parameter(*chosen_storage_device, logical_unit_number_device_prefix); +} + +UNMAP_AFTER_INIT void StorageManagement::determine_boot_device() +{ + VERIFY(!m_controllers.is_empty()); + + if (m_boot_argument.starts_with(block_device_prefix)) { + determine_block_boot_device(); + return; + } + + if (m_boot_argument.starts_with(partition_uuid_prefix)) { + determine_boot_device_with_partition_uuid(); + return; + } + + if (m_boot_argument.starts_with(logical_unit_number_device_prefix)) { + determine_boot_device_with_logical_unit_number(); + return; + } + + if (m_boot_argument.starts_with(ata_device_prefix)) { + determine_ata_boot_device(); + return; + } + + if (m_boot_argument.starts_with(ramdisk_device_prefix)) { + determine_ramdisk_boot_device(); + return; + } + + if (m_boot_argument.starts_with(nvme_device_prefix)) { + determine_nvme_boot_device(); + return; + } + PANIC("StorageManagement: Invalid root boot parameter."); } UNMAP_AFTER_INIT void StorageManagement::determine_boot_device_with_partition_uuid() @@ -289,11 +442,12 @@ UNMAP_AFTER_INIT void StorageManagement::initialize(StringView root_device, bool m_controllers.append(RamdiskController::initialize()); enumerate_storage_devices(); enumerate_disk_partitions(); - if (!boot_argument_contains_partition_uuid()) { - determine_boot_device(); - return; + + determine_boot_device(); + if (m_boot_block_device.is_null()) { + dump_storage_devices_and_partitions(); + PANIC("StorageManagement: boot device {} not found", m_boot_argument); } - determine_boot_device_with_partition_uuid(); } StorageManagement& StorageManagement::the() diff --git a/Kernel/Storage/StorageManagement.h b/Kernel/Storage/StorageManagement.h index 238dfe9055..81ae90ccca 100644 --- a/Kernel/Storage/StorageManagement.h +++ b/Kernel/Storage/StorageManagement.h @@ -18,6 +18,8 @@ namespace Kernel { +class ATAController; +class NVMeController; class StorageManagement { public: @@ -35,6 +37,9 @@ public: static u32 generate_controller_id(); + static u32 generate_relative_nvme_controller_id(Badge); + static u32 generate_relative_ata_controller_id(Badge); + void remove_device(StorageDevice&); private: @@ -47,6 +52,16 @@ private: void determine_boot_device(); void determine_boot_device_with_partition_uuid(); + void resolve_partition_from_boot_device_parameter(StorageDevice const& chosen_storage_device, StringView boot_device_prefix); + void determine_boot_device_with_logical_unit_number(); + void determine_block_boot_device(); + void determine_ramdisk_boot_device(); + void determine_nvme_boot_device(); + void determine_ata_boot_device(); + void determine_hardware_relative_boot_device(StringView relative_hardware_prefix, Function filter_device_callback); + Array extract_boot_device_address_parameters(StringView device_prefix); + Optional extract_boot_device_partition_number_parameter(StringView device_prefix); + void dump_storage_devices_and_partitions() const; ErrorOr> try_to_initialize_partition_table(StorageDevice const&) const;