StorageManagement.cpp 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. /*
  2. * Copyright (c) 2020, Liav A. <liavalb@hotmail.co.il>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <AK/UUID.h>
  7. #include <Kernel/Bus/PCI/API.h>
  8. #include <Kernel/Bus/PCI/Access.h>
  9. #include <Kernel/CommandLine.h>
  10. #include <Kernel/Devices/BlockDevice.h>
  11. #include <Kernel/FileSystem/Ext2FileSystem.h>
  12. #include <Kernel/Panic.h>
  13. #include <Kernel/Storage/AHCIController.h>
  14. #include <Kernel/Storage/IDEController.h>
  15. #include <Kernel/Storage/Partition/EBRPartitionTable.h>
  16. #include <Kernel/Storage/Partition/GUIDPartitionTable.h>
  17. #include <Kernel/Storage/Partition/MBRPartitionTable.h>
  18. #include <Kernel/Storage/RamdiskController.h>
  19. #include <Kernel/Storage/StorageManagement.h>
  20. namespace Kernel {
  21. static StorageManagement* s_the;
  22. static size_t s_device_minor_number;
  23. UNMAP_AFTER_INIT StorageManagement::StorageManagement(String boot_argument, bool force_pio)
  24. : m_boot_argument(boot_argument)
  25. , m_controllers(enumerate_controllers(force_pio))
  26. , m_storage_devices(enumerate_storage_devices())
  27. , m_disk_partitions(enumerate_disk_partitions())
  28. {
  29. s_device_minor_number = 0;
  30. if (!boot_argument_contains_partition_uuid()) {
  31. determine_boot_device();
  32. return;
  33. }
  34. determine_boot_device_with_partition_uuid();
  35. }
  36. bool StorageManagement::boot_argument_contains_partition_uuid()
  37. {
  38. return m_boot_argument.starts_with("PARTUUID=");
  39. }
  40. UNMAP_AFTER_INIT NonnullRefPtrVector<StorageController> StorageManagement::enumerate_controllers(bool force_pio) const
  41. {
  42. NonnullRefPtrVector<StorageController> controllers;
  43. if (!kernel_command_line().disable_physical_storage()) {
  44. if (kernel_command_line().is_ide_enabled()) {
  45. PCI::enumerate([&](const PCI::Address& address, PCI::ID) {
  46. if (PCI::get_class(address) == PCI_MASS_STORAGE_CLASS_ID && PCI::get_subclass(address) == PCI_IDE_CTRL_SUBCLASS_ID) {
  47. controllers.append(IDEController::initialize(address, force_pio));
  48. }
  49. });
  50. }
  51. PCI::enumerate([&](const PCI::Address& address, PCI::ID) {
  52. if (PCI::get_class(address) == PCI_MASS_STORAGE_CLASS_ID && PCI::get_subclass(address) == PCI_SATA_CTRL_SUBCLASS_ID && PCI::get_programming_interface(address) == PCI_AHCI_IF_PROGIF) {
  53. controllers.append(AHCIController::initialize(address));
  54. }
  55. });
  56. }
  57. controllers.append(RamdiskController::initialize());
  58. return controllers;
  59. }
  60. UNMAP_AFTER_INIT NonnullRefPtrVector<StorageDevice> StorageManagement::enumerate_storage_devices() const
  61. {
  62. VERIFY(!m_controllers.is_empty());
  63. NonnullRefPtrVector<StorageDevice> devices;
  64. for (auto& controller : m_controllers) {
  65. for (size_t device_index = 0; device_index < controller.devices_count(); device_index++) {
  66. auto device = controller.device(device_index);
  67. if (device.is_null())
  68. continue;
  69. devices.append(device.release_nonnull());
  70. }
  71. }
  72. return devices;
  73. }
  74. UNMAP_AFTER_INIT OwnPtr<PartitionTable> StorageManagement::try_to_initialize_partition_table(const StorageDevice& device) const
  75. {
  76. auto mbr_table_or_result = MBRPartitionTable::try_to_initialize(device);
  77. if (!mbr_table_or_result.is_error())
  78. return move(mbr_table_or_result.value());
  79. if (mbr_table_or_result.error() == PartitionTable::Error::MBRProtective) {
  80. auto gpt_table_or_result = GUIDPartitionTable::try_to_initialize(device);
  81. if (gpt_table_or_result.is_error())
  82. return {};
  83. return move(gpt_table_or_result.value());
  84. }
  85. if (mbr_table_or_result.error() == PartitionTable::Error::ConatinsEBR) {
  86. auto ebr_table_or_result = EBRPartitionTable::try_to_initialize(device);
  87. if (ebr_table_or_result.is_error())
  88. return {};
  89. return move(ebr_table_or_result.value());
  90. }
  91. return {};
  92. }
  93. UNMAP_AFTER_INIT NonnullRefPtrVector<DiskPartition> StorageManagement::enumerate_disk_partitions() const
  94. {
  95. VERIFY(!m_storage_devices.is_empty());
  96. NonnullRefPtrVector<DiskPartition> partitions;
  97. size_t device_index = 0;
  98. for (auto& device : m_storage_devices) {
  99. auto partition_table = try_to_initialize_partition_table(device);
  100. if (!partition_table)
  101. continue;
  102. for (size_t partition_index = 0; partition_index < partition_table->partitions_count(); partition_index++) {
  103. auto partition_metadata = partition_table->partition(partition_index);
  104. if (!partition_metadata.has_value())
  105. continue;
  106. // FIXME: Try to not hardcode a maximum of 16 partitions per drive!
  107. auto disk_partition = DiskPartition::create(const_cast<StorageDevice&>(device), (partition_index + (16 * device_index)), partition_metadata.value());
  108. partitions.append(disk_partition);
  109. const_cast<StorageDevice&>(device).m_partitions.append(disk_partition);
  110. }
  111. device_index++;
  112. }
  113. return partitions;
  114. }
  115. UNMAP_AFTER_INIT void StorageManagement::determine_boot_device()
  116. {
  117. VERIFY(!m_controllers.is_empty());
  118. if (m_boot_argument.starts_with("/dev/")) {
  119. StringView device_name = m_boot_argument.substring_view(5);
  120. Device::for_each([&](Device& device) {
  121. if (device.is_block_device()) {
  122. auto& block_device = static_cast<BlockDevice&>(device);
  123. if (device.device_name() == device_name) {
  124. m_boot_block_device = block_device;
  125. }
  126. }
  127. });
  128. }
  129. if (m_boot_block_device.is_null()) {
  130. PANIC("StorageManagement: boot device {} not found", m_boot_argument);
  131. }
  132. }
  133. UNMAP_AFTER_INIT void StorageManagement::determine_boot_device_with_partition_uuid()
  134. {
  135. VERIFY(!m_disk_partitions.is_empty());
  136. VERIFY(m_boot_argument.starts_with("PARTUUID="));
  137. auto partition_uuid = UUID(m_boot_argument.substring_view(strlen("PARTUUID=")));
  138. if (partition_uuid.to_string().length() != 36) {
  139. PANIC("StorageManagement: Specified partition UUID is not valid");
  140. }
  141. for (auto& partition : m_disk_partitions) {
  142. if (partition.metadata().unique_guid().is_zero())
  143. continue;
  144. if (partition.metadata().unique_guid() == partition_uuid) {
  145. m_boot_block_device = partition;
  146. break;
  147. }
  148. }
  149. }
  150. RefPtr<BlockDevice> StorageManagement::boot_block_device() const
  151. {
  152. return m_boot_block_device;
  153. }
  154. int StorageManagement::major_number()
  155. {
  156. return 3;
  157. }
  158. int StorageManagement::minor_number()
  159. {
  160. return s_device_minor_number++;
  161. }
  162. NonnullRefPtr<FileSystem> StorageManagement::root_filesystem() const
  163. {
  164. auto boot_device_description = boot_block_device();
  165. if (!boot_device_description) {
  166. PANIC("StorageManagement: Couldn't find a suitable device to boot from");
  167. }
  168. auto description_or_error = FileDescription::try_create(boot_device_description.release_nonnull());
  169. VERIFY(!description_or_error.is_error());
  170. auto file_system = Ext2FS::try_create(description_or_error.release_value()).release_value();
  171. if (auto result = file_system->initialize(); result.is_error()) {
  172. PANIC("StorageManagement: Couldn't open root filesystem: {}", result);
  173. }
  174. return file_system;
  175. }
  176. bool StorageManagement::initialized()
  177. {
  178. return (s_the != nullptr);
  179. }
  180. UNMAP_AFTER_INIT void StorageManagement::initialize(String root_device, bool force_pio)
  181. {
  182. VERIFY(!StorageManagement::initialized());
  183. s_the = new StorageManagement(root_device, force_pio);
  184. }
  185. StorageManagement& StorageManagement::the()
  186. {
  187. return *s_the;
  188. }
  189. }