summaryrefslogtreecommitdiff
path: root/Userland/Libraries/LibPartition
diff options
context:
space:
mode:
authorSamuel Bowman <sam@sambowman.tech>2022-03-01 20:21:35 -0500
committerLinus Groh <mail@linusgroh.de>2022-07-21 20:13:44 +0100
commit25de9de7dcb8d63302946e7351fcd4dedee0736a (patch)
treeffed30f7ee0baa866fa5dc80fe19fb51fc4d92db /Userland/Libraries/LibPartition
parent9053d86b82dcd4a833b1f64e0dcdf77ac148fb86 (diff)
downloadserenity-25de9de7dcb8d63302946e7351fcd4dedee0736a.zip
Kernel+LibPartition: Move GUIDPartitionTable into LibPartition
Diffstat (limited to 'Userland/Libraries/LibPartition')
-rw-r--r--Userland/Libraries/LibPartition/CMakeLists.txt1
-rw-r--r--Userland/Libraries/LibPartition/GUIDPartitionTable.cpp126
-rw-r--r--Userland/Libraries/LibPartition/GUIDPartitionTable.h32
3 files changed, 159 insertions, 0 deletions
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. <liavalb@hotmail.co.il>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <AK/Debug.h>
+#include <LibPartition/GUIDPartitionTable.h>
+
+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<NonnullOwnPtr<GUIDPartitionTable>> 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<u8, 16> 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<u8, 16> 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<u8, 16> 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. <liavalb@hotmail.co.il>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+#include <LibPartition/MBRPartitionTable.h>
+
+namespace Partition {
+
+struct GUIDPartitionHeader;
+class GUIDPartitionTable final : public MBRPartitionTable {
+public:
+ virtual ~GUIDPartitionTable() = default;
+
+ static ErrorOr<NonnullOwnPtr<GUIDPartitionTable>> 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<u8, 16>) const;
+ GUIDPartitionHeader const& header() const;
+ bool initialize();
+
+ bool m_valid { true };
+ ByteBuffer m_cached_header;
+};
+
+}