From 25de9de7dcb8d63302946e7351fcd4dedee0736a Mon Sep 17 00:00:00 2001 From: Samuel Bowman Date: Tue, 1 Mar 2022 20:21:35 -0500 Subject: Kernel+LibPartition: Move GUIDPartitionTable into LibPartition --- AK/Debug.h.in | 4 + Kernel/CMakeLists.txt | 2 +- Kernel/Debug.h.in | 4 - Kernel/Storage/Partition/GUIDPartitionTable.cpp | 129 --------------------- Kernel/Storage/Partition/GUIDPartitionTable.h | 38 ------ Kernel/Storage/StorageManagement.cpp | 4 +- Userland/Libraries/LibPartition/CMakeLists.txt | 1 + .../Libraries/LibPartition/GUIDPartitionTable.cpp | 126 ++++++++++++++++++++ .../Libraries/LibPartition/GUIDPartitionTable.h | 32 +++++ 9 files changed, 166 insertions(+), 174 deletions(-) delete mode 100644 Kernel/Storage/Partition/GUIDPartitionTable.cpp delete mode 100644 Kernel/Storage/Partition/GUIDPartitionTable.h create mode 100644 Userland/Libraries/LibPartition/GUIDPartitionTable.cpp create mode 100644 Userland/Libraries/LibPartition/GUIDPartitionTable.h diff --git a/AK/Debug.h.in b/AK/Debug.h.in index dfaaf8a234..df89896591 100644 --- a/AK/Debug.h.in +++ b/AK/Debug.h.in @@ -174,6 +174,10 @@ #cmakedefine01 GLOBAL_DTORS_DEBUG #endif +#ifndef GPT_DEBUG +#cmakedefine01 GPT_DEBUG +#endif + #ifndef GZIP_DEBUG #cmakedefine01 GZIP_DEBUG #endif diff --git a/Kernel/CMakeLists.txt b/Kernel/CMakeLists.txt index 59deda8990..4cdbdaf0ee 100644 --- a/Kernel/CMakeLists.txt +++ b/Kernel/CMakeLists.txt @@ -104,7 +104,6 @@ set(KERNEL_SOURCES Storage/ATA/ATAPIDiscDevice.cpp Storage/ATA/ATAPort.cpp Storage/Partition/DiskPartition.cpp - Storage/Partition/GUIDPartitionTable.cpp Storage/NVMe/NVMeController.cpp Storage/NVMe/NVMeNameSpace.cpp Storage/NVMe/NVMeInterruptQueue.cpp @@ -404,6 +403,7 @@ set(CRYPTO_SOURCES set(PARTITION_SOURCES ../Userland/Libraries/LibPartition/DiskPartitionMetadata.cpp ../Userland/Libraries/LibPartition/EBRPartitionTable.cpp + ../Userland/Libraries/LibPartition/GUIDPartitionTable.cpp ../Userland/Libraries/LibPartition/MBRPartitionTable.cpp ../Userland/Libraries/LibPartition/PartitionTable.cpp ) diff --git a/Kernel/Debug.h.in b/Kernel/Debug.h.in index d5d6d9fc09..6ae13d54aa 100644 --- a/Kernel/Debug.h.in +++ b/Kernel/Debug.h.in @@ -107,10 +107,6 @@ #cmakedefine01 FUTEXQUEUE_DEBUG #endif -#ifndef GPT_DEBUG -#cmakedefine01 GPT_DEBUG -#endif - #ifndef HPET_COMPARATOR_DEBUG #cmakedefine01 HPET_COMPARATOR_DEBUG #endif diff --git a/Kernel/Storage/Partition/GUIDPartitionTable.cpp b/Kernel/Storage/Partition/GUIDPartitionTable.cpp deleted file mode 100644 index ff71737ea4..0000000000 --- a/Kernel/Storage/Partition/GUIDPartitionTable.cpp +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Copyright (c) 2020-2022, Liav A. - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include -#include -#include -#include - -namespace Kernel { - -#define GPT_SIGNATURE2 0x54524150 -#define GPT_SIGNATURE 0x20494645 -#define BytesPerSector 512 - -struct [[gnu::packed]] GPTPartitionEntry { - u8 partition_guid[16]; - u8 unique_guid[16]; - - u64 first_lba; - u64 last_lba; - - u64 attributes; - char partition_name[72]; -}; - -struct [[gnu::packed]] GUIDPartitionHeader { - u32 sig[2]; - u32 revision; - u32 header_size; - u32 crc32_header; - u32 reserved; - u64 current_lba; - u64 backup_lba; - - u64 first_usable_lba; - u64 last_usable_lba; - - u64 disk_guid1[2]; - - u64 partition_array_start_lba; - - u32 entries_count; - u32 partition_entry_size; - u32 crc32_entries_array; -}; - -ErrorOr> GUIDPartitionTable::try_to_initialize(StorageDevice const& device) -{ - auto table = TRY(adopt_nonnull_own_or_enomem(new (nothrow) GUIDPartitionTable(device))); - if (!table->is_valid()) - return Error::from_errno(EINVAL); - return table; -} - -GUIDPartitionTable::GUIDPartitionTable(StorageDevice const& device) - : MBRPartitionTable(device) -{ - // FIXME: Handle OOM failure here. - m_cached_header = ByteBuffer::create_zeroed(m_device->block_size()).release_value_but_fixme_should_propagate_errors(); - VERIFY(partitions_count() == 0); - if (!initialize()) - m_valid = false; -} - -GUIDPartitionHeader const& GUIDPartitionTable::header() const -{ - return *(GUIDPartitionHeader const*)m_cached_header.data(); -} - -bool GUIDPartitionTable::initialize() -{ - VERIFY(m_cached_header.data() != nullptr); - - auto first_gpt_block = (m_device->block_size() == 512) ? 1 : 0; - - auto buffer = UserOrKernelBuffer::for_kernel_buffer(m_cached_header.data()); - if (!m_device->read_block(first_gpt_block, buffer)) { - return false; - } - - dbgln_if(GPT_DEBUG, "GUIDPartitionTable: signature - {:#08x} {:#08x}", header().sig[1], header().sig[0]); - - if (header().sig[0] != GPT_SIGNATURE && header().sig[1] != GPT_SIGNATURE2) { - dbgln("GUIDPartitionTable: bad signature {:#08x} {:#08x}", header().sig[1], header().sig[0]); - return false; - } - - auto entries_buffer_result = ByteBuffer::create_zeroed(m_device->block_size()); - if (entries_buffer_result.is_error()) { - dbgln("GUIPartitionTable: not enough memory for entries buffer"); - return false; - } - auto entries_buffer = entries_buffer_result.release_value(); - auto raw_entries_buffer = UserOrKernelBuffer::for_kernel_buffer(entries_buffer.data()); - size_t raw_byte_index = header().partition_array_start_lba * m_device->block_size(); - for (size_t entry_index = 0; entry_index < header().entries_count; entry_index++) { - - if (!m_device->read_block((raw_byte_index / m_device->block_size()), raw_entries_buffer)) { - return false; - } - auto* entries = (GPTPartitionEntry const*)entries_buffer.data(); - auto& entry = entries[entry_index % (m_device->block_size() / (size_t)header().partition_entry_size)]; - 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; - } - - Array unique_guid {}; - unique_guid.span().overwrite(0, entry.unique_guid, unique_guid.size()); - dbgln("Detected GPT partition (entry={}), offset={}, limit={}", entry_index, entry.first_lba, entry.last_lba); - 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(Array partition_type) const -{ - return all_of(partition_type, [](auto const octet) { return octet == 0; }); -} - -} diff --git a/Kernel/Storage/Partition/GUIDPartitionTable.h b/Kernel/Storage/Partition/GUIDPartitionTable.h deleted file mode 100644 index 163e75fb61..0000000000 --- a/Kernel/Storage/Partition/GUIDPartitionTable.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2020-2022, Liav A. - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include -#include -#include -#include -#include - -namespace Kernel { - -struct GUIDPartitionHeader; -class GUIDPartitionTable final : public Partition::MBRPartitionTable { -public: - virtual ~GUIDPartitionTable() = default; - ; - - static ErrorOr> try_to_initialize(StorageDevice const&); - explicit GUIDPartitionTable(StorageDevice const&); - - virtual bool is_valid() const override { return m_valid; }; - -private: - bool is_unused_entry(Array) const; - GUIDPartitionHeader const& header() const; - bool initialize(); - - bool m_valid { true }; - ByteBuffer m_cached_header; -}; - -} diff --git a/Kernel/Storage/StorageManagement.cpp b/Kernel/Storage/StorageManagement.cpp index ce7c41e5c3..335d80f782 100644 --- a/Kernel/Storage/StorageManagement.cpp +++ b/Kernel/Storage/StorageManagement.cpp @@ -21,10 +21,10 @@ #include #include #include -#include #include #include #include +#include #include namespace Kernel { @@ -140,7 +140,7 @@ UNMAP_AFTER_INIT ErrorOr> StorageManage if (!ebr_table_or_error.is_error()) { return ebr_table_or_error.release_value(); } - return TRY(GUIDPartitionTable::try_to_initialize(device)); + return TRY(Partition::GUIDPartitionTable::try_to_initialize(device)); } UNMAP_AFTER_INIT void StorageManagement::enumerate_disk_partitions() diff --git a/Userland/Libraries/LibPartition/CMakeLists.txt b/Userland/Libraries/LibPartition/CMakeLists.txt index adae3e4c98..08682886dc 100644 --- a/Userland/Libraries/LibPartition/CMakeLists.txt +++ b/Userland/Libraries/LibPartition/CMakeLists.txt @@ -1,6 +1,7 @@ set(SOURCES DiskPartitionMetadata.cpp EBRPartitionTable.cpp + GUIDPartitionTable.cpp MBRPartitionTable.cpp PartitionTable.cpp ) diff --git a/Userland/Libraries/LibPartition/GUIDPartitionTable.cpp b/Userland/Libraries/LibPartition/GUIDPartitionTable.cpp new file mode 100644 index 0000000000..45028102ff --- /dev/null +++ b/Userland/Libraries/LibPartition/GUIDPartitionTable.cpp @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2020-2022, Liav A. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include + +namespace Partition { + +#define GPT_SIGNATURE2 0x54524150 +#define GPT_SIGNATURE 0x20494645 + +struct [[gnu::packed]] GPTPartitionEntry { + u8 partition_guid[16]; + u8 unique_guid[16]; + + u64 first_lba; + u64 last_lba; + + u64 attributes; + char partition_name[72]; +}; + +struct [[gnu::packed]] GUIDPartitionHeader { + u32 sig[2]; + u32 revision; + u32 header_size; + u32 crc32_header; + u32 reserved; + u64 current_lba; + u64 backup_lba; + + u64 first_usable_lba; + u64 last_usable_lba; + + u64 disk_guid1[2]; + + u64 partition_array_start_lba; + + u32 entries_count; + u32 partition_entry_size; + u32 crc32_entries_array; +}; + +ErrorOr> GUIDPartitionTable::try_to_initialize(Kernel::StorageDevice const& device) +{ + auto table = TRY(adopt_nonnull_own_or_enomem(new (nothrow) GUIDPartitionTable(device))); + if (!table->is_valid()) + return Error::from_errno(EINVAL); + return table; +} + +GUIDPartitionTable::GUIDPartitionTable(Kernel::StorageDevice const& device) + : MBRPartitionTable(device) +{ + // FIXME: Handle OOM failure here. + m_cached_header = ByteBuffer::create_zeroed(m_device->block_size()).release_value_but_fixme_should_propagate_errors(); + VERIFY(partitions_count() == 0); + if (!initialize()) + m_valid = false; +} + +GUIDPartitionHeader const& GUIDPartitionTable::header() const +{ + return *(GUIDPartitionHeader const*)m_cached_header.data(); +} + +bool GUIDPartitionTable::initialize() +{ + VERIFY(m_cached_header.data() != nullptr); + + auto first_gpt_block = (m_device->block_size() == 512) ? 1 : 0; + + auto buffer = UserOrKernelBuffer::for_kernel_buffer(m_cached_header.data()); + if (!m_device->read_block(first_gpt_block, buffer)) { + return false; + } + + dbgln_if(GPT_DEBUG, "GUIDPartitionTable: signature - {:#08x} {:#08x}", header().sig[1], header().sig[0]); + + if (header().sig[0] != GPT_SIGNATURE && header().sig[1] != GPT_SIGNATURE2) { + dbgln("GUIDPartitionTable: bad signature {:#08x} {:#08x}", header().sig[1], header().sig[0]); + return false; + } + + auto entries_buffer_result = ByteBuffer::create_zeroed(m_device->block_size()); + if (entries_buffer_result.is_error()) { + dbgln("GUIPartitionTable: not enough memory for entries buffer"); + return false; + } + auto entries_buffer = entries_buffer_result.release_value(); + auto raw_entries_buffer = UserOrKernelBuffer::for_kernel_buffer(entries_buffer.data()); + size_t raw_byte_index = header().partition_array_start_lba * m_device->block_size(); + for (size_t entry_index = 0; entry_index < header().entries_count; entry_index++) { + + if (!m_device->read_block((raw_byte_index / m_device->block_size()), raw_entries_buffer)) { + return false; + } + auto* entries = (GPTPartitionEntry const*)entries_buffer.data(); + auto& entry = entries[entry_index % (m_device->block_size() / (size_t)header().partition_entry_size)]; + 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; + } + + Array unique_guid {}; + unique_guid.span().overwrite(0, entry.unique_guid, unique_guid.size()); + dbgln("Detected GPT partition (entry={}), offset={}, limit={}", entry_index, entry.first_lba, entry.last_lba); + 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(Array partition_type) const +{ + return all_of(partition_type, [](auto const octet) { return octet == 0; }); +} + +} diff --git a/Userland/Libraries/LibPartition/GUIDPartitionTable.h b/Userland/Libraries/LibPartition/GUIDPartitionTable.h new file mode 100644 index 0000000000..eda6473933 --- /dev/null +++ b/Userland/Libraries/LibPartition/GUIDPartitionTable.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2020-2022, Liav A. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include + +namespace Partition { + +struct GUIDPartitionHeader; +class GUIDPartitionTable final : public MBRPartitionTable { +public: + virtual ~GUIDPartitionTable() = default; + + static ErrorOr> try_to_initialize(Kernel::StorageDevice const&); + explicit GUIDPartitionTable(Kernel::StorageDevice const&); + + virtual bool is_valid() const override { return m_valid; }; + +private: + bool is_unused_entry(Array) const; + GUIDPartitionHeader const& header() const; + bool initialize(); + + bool m_valid { true }; + ByteBuffer m_cached_header; +}; + +} -- cgit v1.2.3