diff --git a/Kernel/CMakeLists.txt b/Kernel/CMakeLists.txt index cb8368c663..882568c6fe 100644 --- a/Kernel/CMakeLists.txt +++ b/Kernel/CMakeLists.txt @@ -212,8 +212,10 @@ set(KERNEL_SOURCES ) set(AK_SOURCES + ../AK/ByteBuffer.cpp ../AK/FlyString.cpp ../AK/GenericLexer.cpp + ../AK/Hex.cpp ../AK/JsonParser.cpp ../AK/JsonValue.cpp ../AK/LexicalPath.cpp @@ -225,6 +227,7 @@ set(AK_SOURCES ../AK/StringView.cpp ../AK/Time.cpp ../AK/Format.cpp + ../AK/UUID.cpp ) set(ELF_SOURCES diff --git a/Kernel/Storage/Partition/DiskPartition.cpp b/Kernel/Storage/Partition/DiskPartition.cpp index 50b97c276d..e1600834ca 100644 --- a/Kernel/Storage/Partition/DiskPartition.cpp +++ b/Kernel/Storage/Partition/DiskPartition.cpp @@ -47,6 +47,11 @@ DiskPartition::~DiskPartition() { } +const DiskPartitionMetadata& DiskPartition::metadata() const +{ + return m_metadata; +} + void DiskPartition::start_request(AsyncBlockDeviceRequest& request) { request.add_sub_request(m_device->make_request(request.request_type(), diff --git a/Kernel/Storage/Partition/DiskPartition.h b/Kernel/Storage/Partition/DiskPartition.h index 87409a3e26..e2d244c3b4 100644 --- a/Kernel/Storage/Partition/DiskPartition.h +++ b/Kernel/Storage/Partition/DiskPartition.h @@ -48,6 +48,8 @@ public: // ^Device virtual mode_t required_mode() const override { return 0600; } + const DiskPartitionMetadata& metadata() const; + private: virtual const char* class_name() const override; diff --git a/Kernel/Storage/Partition/DiskPartitionMetadata.cpp b/Kernel/Storage/Partition/DiskPartitionMetadata.cpp index 82ded057e9..aa2dbd6fb0 100644 --- a/Kernel/Storage/Partition/DiskPartitionMetadata.cpp +++ b/Kernel/Storage/Partition/DiskPartitionMetadata.cpp @@ -24,31 +24,72 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include #include namespace Kernel { -DiskPartitionMetadata::DiskPartitionMetadata(u64 start_block, u64 end_block, ByteBuffer partition_type) - : m_start_block(start_block) - , m_end_block(end_block) - , m_partition_type(partition_type) + +DiskPartitionMetadata::PartitionType::PartitionType(u8 partition_type) { - ASSERT(!m_partition_type.is_empty()); + m_partition_type[0] = partition_type; } -DiskPartitionMetadata::DiskPartitionMetadata(u64 start_block, u64 end_block, ByteBuffer partition_guid, ByteBuffer unique_guid, u64 special_attributes, String name) +DiskPartitionMetadata::PartitionType::PartitionType(Array partition_type) + : m_partition_type_is_uuid(true) +{ + m_partition_type.span().overwrite(0, partition_type.data(), partition_type.size()); +} +UUID DiskPartitionMetadata::PartitionType::to_uuid() const +{ + ASSERT(is_uuid()); + return m_partition_type; +} +u8 DiskPartitionMetadata::PartitionType::to_byte_indicator() const +{ + ASSERT(!is_uuid()); + return m_partition_type[0]; +} +bool DiskPartitionMetadata::PartitionType::is_uuid() const +{ + return m_partition_type_is_uuid; +} +bool DiskPartitionMetadata::PartitionType::is_valid() const +{ + return !all_of(m_partition_type.begin(), m_partition_type.end(), [](const auto octet) { return octet == 0; }); +} + +DiskPartitionMetadata::DiskPartitionMetadata(u64 start_block, u64 end_block, u8 partition_type) : m_start_block(start_block) , m_end_block(end_block) - , m_partition_type(partition_guid) + , m_type(partition_type) +{ + + ASSERT(m_type.is_valid()); +} + +DiskPartitionMetadata::DiskPartitionMetadata(u64 start_block, u64 end_block, Array partition_type) + : m_start_block(start_block) + , m_end_block(end_block) + , m_type(partition_type) +{ + + ASSERT(m_type.is_valid()); +} + +DiskPartitionMetadata::DiskPartitionMetadata(u64 start_block, u64 end_block, Array partition_type, UUID unique_guid, u64 special_attributes, String name) + : m_start_block(start_block) + , m_end_block(end_block) + , m_type(partition_type) , m_unique_guid(unique_guid) , m_attributes(special_attributes) , m_name(name) { - ASSERT(!m_partition_type.is_empty()); - ASSERT(!m_unique_guid.is_empty()); + ASSERT(m_type.is_valid()); + ASSERT(!m_unique_guid.is_zero()); } DiskPartitionMetadata DiskPartitionMetadata::offset(u64 blocks_count) const { - return DiskPartitionMetadata({ blocks_count + m_start_block, blocks_count + m_end_block, m_partition_type }); + return { blocks_count + m_start_block, blocks_count + m_end_block, m_type.m_partition_type }; } u64 DiskPartitionMetadata::start_block() const @@ -71,16 +112,12 @@ Optional DiskPartitionMetadata::name() const return {}; return m_name; } -Optional DiskPartitionMetadata::partition_type() const +const DiskPartitionMetadata::PartitionType& DiskPartitionMetadata::type() const { - if (m_partition_type.is_null() || m_partition_type.is_empty()) - return {}; - return m_partition_type; + return m_type; } -Optional DiskPartitionMetadata::unique_guid() const +const UUID& DiskPartitionMetadata::unique_guid() const { - if (m_unique_guid.is_null() || m_unique_guid.is_empty()) - return {}; return m_unique_guid; } diff --git a/Kernel/Storage/Partition/DiskPartitionMetadata.h b/Kernel/Storage/Partition/DiskPartitionMetadata.h index 5c1eae70e5..0a343a6548 100644 --- a/Kernel/Storage/Partition/DiskPartitionMetadata.h +++ b/Kernel/Storage/Partition/DiskPartitionMetadata.h @@ -27,14 +27,33 @@ #pragma once #include +#include #include namespace Kernel { class DiskPartitionMetadata { +private: + class PartitionType { + friend class DiskPartitionMetadata; + + public: + explicit PartitionType(u8 partition_type); + explicit PartitionType(Array partition_type); + UUID to_uuid() const; + u8 to_byte_indicator() const; + bool is_uuid() const; + bool is_valid() const; + + private: + Array m_partition_type {}; + bool m_partition_type_is_uuid { false }; + }; + public: - DiskPartitionMetadata(u64 block_offset, u64 block_limit, ByteBuffer partition_type); - DiskPartitionMetadata(u64 block_offset, u64 block_limit, ByteBuffer partition_type, ByteBuffer unique_guid, u64 special_attributes, String name); + DiskPartitionMetadata(u64 block_offset, u64 block_limit, u8 partition_type); + DiskPartitionMetadata(u64 start_block, u64 end_block, Array partition_type); + DiskPartitionMetadata(u64 block_offset, u64 block_limit, Array partition_type, UUID unique_guid, u64 special_attributes, String name); u64 start_block() const; u64 end_block() const; @@ -42,14 +61,14 @@ public: Optional special_attributes() const; Optional name() const; - Optional partition_type() const; - Optional unique_guid() const; + const PartitionType& type() const; + const UUID& unique_guid() const; private: u64 m_start_block; u64 m_end_block; - ByteBuffer m_partition_type; - ByteBuffer m_unique_guid; + PartitionType m_type; + UUID m_unique_guid {}; u64 m_attributes { 0 }; String m_name; }; diff --git a/Kernel/Storage/Partition/GUIDPartitionTable.cpp b/Kernel/Storage/Partition/GUIDPartitionTable.cpp index 296415ed3f..f7d3f7d843 100644 --- a/Kernel/Storage/Partition/GUIDPartitionTable.cpp +++ b/Kernel/Storage/Partition/GUIDPartitionTable.cpp @@ -24,7 +24,8 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include +#include +#include #include #ifndef GPT_DEBUG @@ -121,31 +122,28 @@ bool GUIDPartitionTable::initialize() } auto* entries = (const GPTPartitionEntry*)entries_buffer.data(); auto& entry = entries[entry_index % (m_device->block_size() / (size_t)header().partition_entry_size)]; - ByteBuffer partition_type = ByteBuffer::copy(entry.partition_guid, 16); + Array partition_type {}; + partition_type.span().overwrite(0, entry.partition_guid, partition_type.size()); if (is_unused_entry(partition_type)) { raw_byte_index += header().partition_entry_size; continue; } - ByteBuffer unique_guid = ByteBuffer::copy(entry.unique_guid, 16); + Array unique_guid {}; + unique_guid.span().overwrite(0, entry.unique_guid, unique_guid.size()); String name = entry.partition_name; dbg() << "Detected GPT partition (entry " << entry_index << ") , offset " << entry.first_lba << " , limit " << entry.last_lba; - m_partitions.append(DiskPartitionMetadata({ entry.first_lba, entry.last_lba, partition_type })); + m_partitions.append({ entry.first_lba, entry.last_lba, partition_type, unique_guid, entry.attributes, "" }); raw_byte_index += header().partition_entry_size; } return true; } -bool GUIDPartitionTable::is_unused_entry(ByteBuffer partition_type) const +bool GUIDPartitionTable::is_unused_entry(Array partition_type) const { - ASSERT(partition_type.size() == 16); - for (size_t byte_index = 0; byte_index < 16; byte_index++) { - if (partition_type[byte_index] != 0) - return false; - } - return true; + return all_of(partition_type.begin(), partition_type.end(), [](const auto octet) { return octet == 0; }); } } diff --git a/Kernel/Storage/Partition/GUIDPartitionTable.h b/Kernel/Storage/Partition/GUIDPartitionTable.h index ecdfd43bc9..3988324e04 100644 --- a/Kernel/Storage/Partition/GUIDPartitionTable.h +++ b/Kernel/Storage/Partition/GUIDPartitionTable.h @@ -46,7 +46,7 @@ public: virtual bool is_valid() const override { return m_valid; }; private: - bool is_unused_entry(ByteBuffer) const; + bool is_unused_entry(Array) const; const GUIDPartitionHeader& header() const; bool initialize(); diff --git a/Kernel/Storage/StorageManagement.cpp b/Kernel/Storage/StorageManagement.cpp index 4f3acf4fe0..30152ba3aa 100644 --- a/Kernel/Storage/StorageManagement.cpp +++ b/Kernel/Storage/StorageManagement.cpp @@ -24,6 +24,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include #include #include #include @@ -37,13 +38,22 @@ namespace Kernel { static StorageManagement* s_the; -StorageManagement::StorageManagement(String root_device, bool force_pio) - : m_controllers(enumerate_controllers(force_pio)) +StorageManagement::StorageManagement(String boot_argument, bool force_pio) + : m_boot_argument(boot_argument) + , m_controllers(enumerate_controllers(force_pio)) , m_storage_devices(enumerate_storage_devices()) , m_disk_partitions(enumerate_disk_partitions()) - , m_boot_device(determine_boot_device(root_device)) - , m_boot_block_device(determine_boot_block_device(root_device)) { + if (!boot_argument_contains_partition_uuid()) { + determine_boot_device(); + return; + } + determine_boot_device_with_partition_uuid(); +} + +bool StorageManagement::boot_argument_contains_partition_uuid() +{ + return m_boot_argument.starts_with("PARTUUID="); } NonnullRefPtrVector StorageManagement::enumerate_controllers(bool force_pio) const @@ -115,14 +125,15 @@ NonnullRefPtrVector StorageManagement::enumerate_disk_partitions( return partitions; } -NonnullRefPtr StorageManagement::determine_boot_device(String root_device) const +void StorageManagement::determine_boot_device() { ASSERT(!m_controllers.is_empty()); - if (!root_device.starts_with("/dev/hd")) { + if (!m_boot_argument.starts_with("/dev/hd")) { klog() << "init_stage2: root filesystem must be on an hard drive"; Processor::halt(); } - auto drive_letter = root_device.substring(strlen("/dev/hd"), root_device.length() - strlen("/dev/hd"))[0]; + + auto drive_letter = m_boot_argument.substring(strlen("/dev/hd"), m_boot_argument.length() - strlen("/dev/hd"))[0]; if (drive_letter < 'a' || drive_letter > 'z') { klog() << "init_stage2: root filesystem must be on an hard drive name"; @@ -134,39 +145,62 @@ NonnullRefPtr StorageManagement::determine_boot_device(String roo klog() << "init_stage2: invalid selection of hard drive."; Processor::halt(); } - return m_storage_devices[drive_index]; -} -NonnullRefPtr StorageManagement::determine_boot_block_device(String root_device) const -{ - auto determined_boot_device = m_boot_device; - root_device = root_device.substring(strlen("/dev/hda"), root_device.length() - strlen("/dev/hda")); - if (!root_device.length()) - return determined_boot_device; + auto& determined_boot_device = m_storage_devices[drive_index]; + auto root_device = m_boot_argument.substring(strlen("/dev/hda"), m_boot_argument.length() - strlen("/dev/hda")); + if (!root_device.length()) { + m_boot_block_device = determined_boot_device; + return; + } auto partition_number = root_device.to_uint(); - if (!partition_number.has_value()) { klog() << "init_stage2: couldn't parse partition number from root kernel parameter"; Processor::halt(); } - if (partition_number.value() > m_boot_device->m_partitions.size()) { + if (partition_number.value() > determined_boot_device.m_partitions.size()) { klog() << "init_stage2: invalid partition number!"; Processor::halt(); } - return m_boot_device->m_partitions[partition_number.value() - 1]; + m_boot_block_device = determined_boot_device.m_partitions[partition_number.value() - 1]; } -NonnullRefPtr StorageManagement::boot_block_device() const +void StorageManagement::determine_boot_device_with_partition_uuid() +{ + ASSERT(!m_disk_partitions.is_empty()); + ASSERT(m_boot_argument.starts_with("PARTUUID=")); + + auto partition_uuid = UUID(m_boot_argument.substring_view(strlen("PARTUUID="))); + + if (partition_uuid.to_string().length() != 36) { + klog() << "init_stage2: specified partition UUID is not valid"; + Processor::halt(); + } + + for (auto& partition : m_disk_partitions) { + if (partition.metadata().unique_guid().is_zero()) + continue; + if (partition.metadata().unique_guid() == partition_uuid) { + m_boot_block_device = partition; + break; + } + } +} + +RefPtr StorageManagement::boot_block_device() const { return m_boot_block_device; } NonnullRefPtr StorageManagement::root_filesystem() const { - auto e2fs = Ext2FS::create(*FileDescription::create(boot_block_device())); + if (!boot_block_device()) { + klog() << "init_stage2: couldn't find a suitable device to boot from"; + Processor::halt(); + } + auto e2fs = Ext2FS::create(*FileDescription::create(boot_block_device().release_nonnull())); if (!e2fs->initialize()) { klog() << "init_stage2: couldn't open root filesystem"; Processor::halt(); diff --git a/Kernel/Storage/StorageManagement.h b/Kernel/Storage/StorageManagement.h index 9cf624d2b6..04ff219377 100644 --- a/Kernel/Storage/StorageManagement.h +++ b/Kernel/Storage/StorageManagement.h @@ -41,9 +41,9 @@ class StorageManagement { AK_MAKE_ETERNAL; public: - StorageManagement(String root_device, bool force_pio); + StorageManagement(String boot_argument, bool force_pio); static bool initialized(); - static void initialize(String root_device, bool force_pio); + static void initialize(String boot_argument, bool force_pio); static StorageManagement& the(); NonnullRefPtr root_filesystem() const; @@ -51,22 +51,24 @@ public: NonnullRefPtrVector ide_controllers() const; private: - NonnullRefPtr boot_block_device() const; + bool boot_argument_contains_partition_uuid(); NonnullRefPtrVector enumerate_controllers(bool force_pio) const; NonnullRefPtrVector enumerate_storage_devices() const; NonnullRefPtrVector enumerate_disk_partitions() const; - NonnullRefPtr determine_boot_device(String root_device) const; - NonnullRefPtr determine_boot_block_device(String root_device) const; + void determine_boot_device(); + void determine_boot_device_with_partition_uuid(); OwnPtr try_to_initialize_partition_table(const StorageDevice&) const; + RefPtr boot_block_device() const; + + String m_boot_argument; + RefPtr m_boot_block_device { nullptr }; NonnullRefPtrVector m_controllers; NonnullRefPtrVector m_storage_devices; NonnullRefPtrVector m_disk_partitions; - NonnullRefPtr m_boot_device; - NonnullRefPtr m_boot_block_device; }; }