Serenity Operating System
at master 463 lines 18 kB view raw
1/* 2 * Copyright (c) 2020-2022, Liav A. <liavalb@hotmail.co.il> 3 * Copyright (c) 2022, the SerenityOS developers. 4 * 5 * SPDX-License-Identifier: BSD-2-Clause 6 */ 7 8#include <AK/Platform.h> 9#include <AK/Singleton.h> 10#include <AK/StringView.h> 11#include <AK/UUID.h> 12#if ARCH(X86_64) 13# include <Kernel/Arch/x86_64/ISABus/IDEController.h> 14# include <Kernel/Arch/x86_64/PCI/IDELegacyModeController.h> 15#endif 16#include <Kernel/Bus/PCI/API.h> 17#include <Kernel/Bus/PCI/Access.h> 18#include <Kernel/Bus/PCI/Controller/VolumeManagementDevice.h> 19#include <Kernel/CommandLine.h> 20#include <Kernel/Devices/BlockDevice.h> 21#include <Kernel/Devices/DeviceManagement.h> 22#include <Kernel/FileSystem/Ext2FS/FileSystem.h> 23#include <Kernel/FileSystem/VirtualFileSystem.h> 24#include <Kernel/Panic.h> 25#include <Kernel/Storage/ATA/AHCI/Controller.h> 26#include <Kernel/Storage/ATA/GenericIDE/Controller.h> 27#include <Kernel/Storage/NVMe/NVMeController.h> 28#include <Kernel/Storage/Ramdisk/Controller.h> 29#include <Kernel/Storage/StorageManagement.h> 30#include <LibPartition/EBRPartitionTable.h> 31#include <LibPartition/GUIDPartitionTable.h> 32#include <LibPartition/MBRPartitionTable.h> 33 34namespace Kernel { 35 36static Singleton<StorageManagement> s_the; 37static Atomic<u32> s_storage_device_minor_number; 38static Atomic<u32> s_partition_device_minor_number; 39static Atomic<u32> s_controller_id; 40 41static Atomic<u32> s_relative_ata_controller_id; 42static Atomic<u32> s_relative_nvme_controller_id; 43 44static constexpr StringView partition_uuid_prefix = "PARTUUID:"sv; 45 46static constexpr StringView partition_number_prefix = "part"sv; 47static constexpr StringView block_device_prefix = "block"sv; 48 49static constexpr StringView ata_device_prefix = "ata"sv; 50static constexpr StringView nvme_device_prefix = "nvme"sv; 51static constexpr StringView ramdisk_device_prefix = "ramdisk"sv; 52static constexpr StringView logical_unit_number_device_prefix = "lun"sv; 53 54UNMAP_AFTER_INIT StorageManagement::StorageManagement() 55{ 56} 57 58u32 StorageManagement::generate_relative_nvme_controller_id(Badge<NVMeController>) 59{ 60 auto controller_id = s_relative_nvme_controller_id.load(); 61 s_relative_nvme_controller_id++; 62 return controller_id; 63} 64u32 StorageManagement::generate_relative_ata_controller_id(Badge<ATAController>) 65{ 66 auto controller_id = s_relative_ata_controller_id.load(); 67 s_relative_ata_controller_id++; 68 return controller_id; 69} 70 71void StorageManagement::remove_device(StorageDevice& device) 72{ 73 m_storage_devices.remove(device); 74} 75 76UNMAP_AFTER_INIT void StorageManagement::enumerate_pci_controllers(bool force_pio, bool nvme_poll) 77{ 78 VERIFY(m_controllers.is_empty()); 79 80 using SubclassID = PCI::MassStorage::SubclassID; 81 if (!kernel_command_line().disable_physical_storage()) { 82 // NOTE: Search for VMD devices before actually searching for storage controllers 83 // because the VMD device is only a bridge to such (NVMe) controllers. 84 MUST(PCI::enumerate([&](PCI::DeviceIdentifier const& device_identifier) -> void { 85 constexpr PCI::HardwareID vmd_device = { 0x8086, 0x9a0b }; 86 if (device_identifier.hardware_id() == vmd_device) { 87 auto controller = PCI::VolumeManagementDevice::must_create(device_identifier); 88 MUST(PCI::Access::the().add_host_controller_and_scan_for_devices(move(controller))); 89 } 90 })); 91 92 MUST(PCI::enumerate([&](PCI::DeviceIdentifier const& device_identifier) -> void { 93 if (device_identifier.class_code().value() != to_underlying(PCI::ClassID::MassStorage)) { 94 return; 95 } 96 97 auto subclass_code = static_cast<SubclassID>(device_identifier.subclass_code().value()); 98#if ARCH(X86_64) 99 if (subclass_code == SubclassID::IDEController && kernel_command_line().is_ide_enabled()) { 100 if (auto ide_controller_or_error = PCIIDELegacyModeController::initialize(device_identifier, force_pio); !ide_controller_or_error.is_error()) 101 m_controllers.append(ide_controller_or_error.release_value()); 102 else 103 dmesgln("Unable to initialize IDE controller: {}", ide_controller_or_error.error()); 104 } 105#elif ARCH(AARCH64) 106 (void)force_pio; 107 TODO_AARCH64(); 108#else 109# error Unknown architecture 110#endif 111 112 if (subclass_code == SubclassID::SATAController 113 && device_identifier.prog_if().value() == to_underlying(PCI::MassStorage::SATAProgIF::AHCI)) { 114 m_controllers.append(AHCIController::initialize(device_identifier)); 115 } 116 if (subclass_code == SubclassID::NVMeController) { 117 auto controller = NVMeController::try_initialize(device_identifier, nvme_poll); 118 if (controller.is_error()) { 119 dmesgln("Unable to initialize NVMe controller: {}", controller.error()); 120 } else { 121 m_controllers.append(controller.release_value()); 122 } 123 } 124 })); 125 } 126} 127 128UNMAP_AFTER_INIT void StorageManagement::enumerate_storage_devices() 129{ 130 VERIFY(!m_controllers.is_empty()); 131 for (auto& controller : m_controllers) { 132 for (size_t device_index = 0; device_index < controller->devices_count(); device_index++) { 133 auto device = controller->device(device_index); 134 if (device.is_null()) 135 continue; 136 m_storage_devices.append(device.release_nonnull()); 137 } 138 } 139} 140 141UNMAP_AFTER_INIT void StorageManagement::dump_storage_devices_and_partitions() const 142{ 143 dbgln("StorageManagement: Detected {} storage devices", m_storage_devices.size_slow()); 144 for (auto const& storage_device : m_storage_devices) { 145 auto const& partitions = storage_device.partitions(); 146 if (partitions.is_empty()) { 147 dbgln(" Device: block{}:{} (no partitions)", storage_device.major(), storage_device.minor()); 148 } else { 149 dbgln(" Device: block{}:{} ({} partitions)", storage_device.major(), storage_device.minor(), partitions.size()); 150 unsigned partition_number = 1; 151 for (auto const& partition : partitions) { 152 dbgln(" Partition: {}, block{}:{} (UUID {})", partition_number, partition->major(), partition->minor(), partition->metadata().unique_guid().to_string()); 153 partition_number++; 154 } 155 } 156 } 157} 158 159UNMAP_AFTER_INIT ErrorOr<NonnullOwnPtr<Partition::PartitionTable>> StorageManagement::try_to_initialize_partition_table(StorageDevice& device) const 160{ 161 auto mbr_table_or_error = Partition::MBRPartitionTable::try_to_initialize(device); 162 if (!mbr_table_or_error.is_error()) 163 return mbr_table_or_error.release_value(); 164 auto ebr_table_or_error = Partition::EBRPartitionTable::try_to_initialize(device); 165 if (!ebr_table_or_error.is_error()) { 166 return ebr_table_or_error.release_value(); 167 } 168 return TRY(Partition::GUIDPartitionTable::try_to_initialize(device)); 169} 170 171UNMAP_AFTER_INIT void StorageManagement::enumerate_disk_partitions() 172{ 173 VERIFY(!m_storage_devices.is_empty()); 174 for (auto& device : m_storage_devices) { 175 auto partition_table_or_error = try_to_initialize_partition_table(device); 176 if (partition_table_or_error.is_error()) 177 continue; 178 auto partition_table = partition_table_or_error.release_value(); 179 for (size_t partition_index = 0; partition_index < partition_table->partitions_count(); partition_index++) { 180 auto partition_metadata = partition_table->partition(partition_index); 181 if (!partition_metadata.has_value()) 182 continue; 183 auto disk_partition = DiskPartition::create(device, generate_partition_minor_number(), partition_metadata.value()); 184 device.add_partition(disk_partition); 185 } 186 } 187} 188 189UNMAP_AFTER_INIT Optional<unsigned> StorageManagement::extract_boot_device_partition_number_parameter(StringView device_prefix) 190{ 191 VERIFY(m_boot_argument.starts_with(device_prefix)); 192 VERIFY(!m_boot_argument.starts_with(partition_uuid_prefix)); 193 auto storage_device_relative_address_view = m_boot_argument.substring_view(device_prefix.length()); 194 auto parameter_view = storage_device_relative_address_view.find_last_split_view(';'); 195 if (parameter_view == storage_device_relative_address_view) 196 return {}; 197 if (!parameter_view.starts_with(partition_number_prefix)) { 198 PANIC("StorageManagement: Invalid root boot parameter."); 199 } 200 201 auto parameter_number = parameter_view.substring_view(partition_number_prefix.length()).to_uint<unsigned>(); 202 if (!parameter_number.has_value()) { 203 PANIC("StorageManagement: Invalid root boot parameter."); 204 } 205 206 return parameter_number.value(); 207} 208 209UNMAP_AFTER_INIT Array<unsigned, 3> StorageManagement::extract_boot_device_address_parameters(StringView device_prefix) 210{ 211 VERIFY(!m_boot_argument.starts_with(partition_uuid_prefix)); 212 Array<unsigned, 3> address_parameters; 213 auto parameters_view = m_boot_argument.substring_view(device_prefix.length()).find_first_split_view(';'); 214 size_t parts_count = 0; 215 bool parse_failure = false; 216 parameters_view.for_each_split_view(':', SplitBehavior::Nothing, [&](StringView parameter_view) { 217 if (parse_failure) 218 return; 219 if (parts_count > 2) 220 return; 221 auto parameter_number = parameter_view.to_uint<unsigned>(); 222 if (!parameter_number.has_value()) { 223 parse_failure = true; 224 return; 225 } 226 address_parameters[parts_count] = parameter_number.value(); 227 parts_count++; 228 }); 229 230 if (parts_count > 3) { 231 dbgln("StorageManagement: Detected {} parts in boot device parameter.", parts_count); 232 PANIC("StorageManagement: Invalid root boot parameter."); 233 } 234 if (parse_failure) { 235 PANIC("StorageManagement: Invalid root boot parameter."); 236 } 237 238 return address_parameters; 239} 240 241UNMAP_AFTER_INIT void StorageManagement::resolve_partition_from_boot_device_parameter(StorageDevice const& chosen_storage_device, StringView boot_device_prefix) 242{ 243 auto possible_partition_number = extract_boot_device_partition_number_parameter(boot_device_prefix); 244 if (!possible_partition_number.has_value()) 245 return; 246 247 auto partition_number = possible_partition_number.value(); 248 if (chosen_storage_device.partitions().size() <= partition_number) 249 PANIC("StorageManagement: Invalid partition number parameter."); 250 m_boot_block_device = chosen_storage_device.partitions()[partition_number]; 251} 252 253UNMAP_AFTER_INIT void StorageManagement::determine_hardware_relative_boot_device(StringView relative_hardware_prefix, Function<bool(StorageDevice const&)> filter_device_callback) 254{ 255 VERIFY(m_boot_argument.starts_with(relative_hardware_prefix)); 256 auto address_parameters = extract_boot_device_address_parameters(relative_hardware_prefix); 257 258 RefPtr<StorageDevice> chosen_storage_device; 259 260 for (auto& storage_device : m_storage_devices) { 261 if (!filter_device_callback(storage_device)) 262 continue; 263 auto storage_device_lun = storage_device.logical_unit_number_address(); 264 if (storage_device.parent_controller_hardware_relative_id() == address_parameters[0] 265 && storage_device_lun.target_id == address_parameters[1] 266 && storage_device_lun.disk_id == address_parameters[2]) { 267 m_boot_block_device = storage_device; 268 chosen_storage_device = storage_device; 269 break; 270 } 271 } 272 273 if (chosen_storage_device) 274 resolve_partition_from_boot_device_parameter(*chosen_storage_device, relative_hardware_prefix); 275} 276 277UNMAP_AFTER_INIT void StorageManagement::determine_ata_boot_device() 278{ 279 determine_hardware_relative_boot_device(ata_device_prefix, [](StorageDevice const& device) -> bool { 280 return device.command_set() == StorageDevice::CommandSet::ATA; 281 }); 282} 283 284UNMAP_AFTER_INIT void StorageManagement::determine_nvme_boot_device() 285{ 286 determine_hardware_relative_boot_device(nvme_device_prefix, [](StorageDevice const& device) -> bool { 287 return device.command_set() == StorageDevice::CommandSet::NVMe; 288 }); 289} 290 291UNMAP_AFTER_INIT void StorageManagement::determine_ramdisk_boot_device() 292{ 293 determine_hardware_relative_boot_device(ramdisk_device_prefix, [](StorageDevice const& device) -> bool { 294 return device.command_set() == StorageDevice::CommandSet::PlainMemory; 295 }); 296} 297 298UNMAP_AFTER_INIT void StorageManagement::determine_block_boot_device() 299{ 300 VERIFY(m_boot_argument.starts_with(block_device_prefix)); 301 auto parameters_view = extract_boot_device_address_parameters(block_device_prefix); 302 303 // Note: We simply fetch the corresponding BlockDevice with the major and minor parameters. 304 // We don't try to accept and resolve a partition number as it will make this code much more 305 // complicated. This rule is also explained in the boot_device_addressing(7) manual page. 306 LockRefPtr<Device> device = DeviceManagement::the().get_device(parameters_view[0], parameters_view[1]); 307 if (device && device->is_block_device()) 308 m_boot_block_device = static_ptr_cast<BlockDevice>(device); 309} 310 311UNMAP_AFTER_INIT void StorageManagement::determine_boot_device_with_logical_unit_number() 312{ 313 VERIFY(m_boot_argument.starts_with(logical_unit_number_device_prefix)); 314 auto address_parameters = extract_boot_device_address_parameters(logical_unit_number_device_prefix); 315 316 RefPtr<StorageDevice> chosen_storage_device; 317 318 for (auto& storage_device : m_storage_devices) { 319 auto storage_device_lun = storage_device.logical_unit_number_address(); 320 if (storage_device_lun.controller_id == address_parameters[0] 321 && storage_device_lun.target_id == address_parameters[1] 322 && storage_device_lun.disk_id == address_parameters[2]) { 323 m_boot_block_device = storage_device; 324 chosen_storage_device = storage_device; 325 break; 326 } 327 } 328 329 if (chosen_storage_device) 330 resolve_partition_from_boot_device_parameter(*chosen_storage_device, logical_unit_number_device_prefix); 331} 332 333UNMAP_AFTER_INIT void StorageManagement::determine_boot_device() 334{ 335 VERIFY(!m_controllers.is_empty()); 336 337 if (m_boot_argument.starts_with(block_device_prefix)) { 338 determine_block_boot_device(); 339 return; 340 } 341 342 if (m_boot_argument.starts_with(partition_uuid_prefix)) { 343 determine_boot_device_with_partition_uuid(); 344 return; 345 } 346 347 if (m_boot_argument.starts_with(logical_unit_number_device_prefix)) { 348 determine_boot_device_with_logical_unit_number(); 349 return; 350 } 351 352 if (m_boot_argument.starts_with(ata_device_prefix)) { 353 determine_ata_boot_device(); 354 return; 355 } 356 357 if (m_boot_argument.starts_with(ramdisk_device_prefix)) { 358 determine_ramdisk_boot_device(); 359 return; 360 } 361 362 if (m_boot_argument.starts_with(nvme_device_prefix)) { 363 determine_nvme_boot_device(); 364 return; 365 } 366 PANIC("StorageManagement: Invalid root boot parameter."); 367} 368 369UNMAP_AFTER_INIT void StorageManagement::determine_boot_device_with_partition_uuid() 370{ 371 VERIFY(!m_storage_devices.is_empty()); 372 VERIFY(m_boot_argument.starts_with(partition_uuid_prefix)); 373 374 auto partition_uuid = UUID(m_boot_argument.substring_view(partition_uuid_prefix.length()), UUID::Endianness::Mixed); 375 376 for (auto& storage_device : m_storage_devices) { 377 for (auto& partition : storage_device.partitions()) { 378 if (partition->metadata().unique_guid().is_zero()) 379 continue; 380 if (partition->metadata().unique_guid() == partition_uuid) { 381 m_boot_block_device = partition; 382 break; 383 } 384 } 385 } 386} 387 388LockRefPtr<BlockDevice> StorageManagement::boot_block_device() const 389{ 390 return m_boot_block_device.strong_ref(); 391} 392 393MajorNumber StorageManagement::storage_type_major_number() 394{ 395 return 3; 396} 397MinorNumber StorageManagement::generate_storage_minor_number() 398{ 399 return s_storage_device_minor_number.fetch_add(1); 400} 401 402MinorNumber StorageManagement::generate_partition_minor_number() 403{ 404 return s_partition_device_minor_number.fetch_add(1); 405} 406 407u32 StorageManagement::generate_controller_id() 408{ 409 return s_controller_id.fetch_add(1); 410} 411 412NonnullLockRefPtr<FileSystem> StorageManagement::root_filesystem() const 413{ 414 auto boot_device_description = boot_block_device(); 415 if (!boot_device_description) { 416 dump_storage_devices_and_partitions(); 417 PANIC("StorageManagement: Couldn't find a suitable device to boot from"); 418 } 419 auto description_or_error = OpenFileDescription::try_create(boot_device_description.release_nonnull()); 420 VERIFY(!description_or_error.is_error()); 421 422 auto file_system = Ext2FS::try_create(description_or_error.release_value()).release_value(); 423 424 if (auto result = file_system->initialize(); result.is_error()) { 425 dump_storage_devices_and_partitions(); 426 PANIC("StorageManagement: Couldn't open root filesystem: {}", result.error()); 427 } 428 return file_system; 429} 430 431UNMAP_AFTER_INIT void StorageManagement::initialize(StringView root_device, bool force_pio, bool poll) 432{ 433 VERIFY(s_storage_device_minor_number == 0); 434 m_boot_argument = root_device; 435 if (PCI::Access::is_disabled()) { 436#if ARCH(X86_64) 437 // Note: If PCI is disabled, we assume that at least we have an ISA IDE controller 438 // to probe and use 439 auto isa_ide_controller = MUST(ISAIDEController::initialize()); 440 m_controllers.append(isa_ide_controller); 441#endif 442 } else { 443 enumerate_pci_controllers(force_pio, poll); 444 } 445 // Note: Whether PCI bus is present on the system or not, always try to attach 446 // a given ramdisk. 447 m_controllers.append(RamdiskController::initialize()); 448 enumerate_storage_devices(); 449 enumerate_disk_partitions(); 450 451 determine_boot_device(); 452 if (m_boot_block_device.is_null()) { 453 dump_storage_devices_and_partitions(); 454 PANIC("StorageManagement: boot device {} not found", m_boot_argument); 455 } 456} 457 458StorageManagement& StorageManagement::the() 459{ 460 return *s_the; 461} 462 463}