From 72b1998f0d228f63cd5b095b282ee534f285bcb2 Mon Sep 17 00:00:00 2001 From: Liav A Date: Sat, 26 Dec 2020 16:53:30 +0200 Subject: Kernel: Introduce a new partitioning subsystem The partitioning code was very outdated, and required a full refactor. The new subsystem removes duplicated code and uses more AK containers. The most important change is that all implementations of the PartitionTable class conform to one interface, which made it possible to remove unnecessary code in the EBRPartitionTable class. Finding partitions is now done in the StorageManagement singleton, instead of doing so in init.cpp. Also, now we don't try to find partitions on demand - the kernel will try to detect if a StorageDevice is partitioned, and if so, will check what is the partition table, which could be MBR, GUID or EBR. Then, it will create DiskPartitionMetadata object for each partition that is available in the partition table. This object will be used by the partition enumeration code to create a DiskPartition with the correct minor number. --- Kernel/Storage/Partition/DiskPartition.cpp | 21 ++- Kernel/Storage/Partition/DiskPartition.h | 8 +- Kernel/Storage/Partition/DiskPartitionMetadata.cpp | 6 + Kernel/Storage/Partition/DiskPartitionMetadata.h | 4 +- Kernel/Storage/Partition/EBRPartitionTable.cpp | 199 +++++---------------- Kernel/Storage/Partition/EBRPartitionTable.h | 39 ++-- Kernel/Storage/Partition/GPTPartitionTable.cpp | 109 ----------- Kernel/Storage/Partition/GPTPartitionTable.h | 91 ---------- Kernel/Storage/Partition/GUIDPartitionTable.cpp | 153 ++++++++++++++++ Kernel/Storage/Partition/GUIDPartitionTable.h | 57 ++++++ Kernel/Storage/Partition/MBRPartitionTable.cpp | 126 ++++++++----- Kernel/Storage/Partition/MBRPartitionTable.h | 87 ++++----- Kernel/Storage/Partition/PartitionTable.cpp | 42 +++++ Kernel/Storage/Partition/PartitionTable.h | 67 +++++++ 14 files changed, 527 insertions(+), 482 deletions(-) delete mode 100644 Kernel/Storage/Partition/GPTPartitionTable.cpp delete mode 100644 Kernel/Storage/Partition/GPTPartitionTable.h create mode 100644 Kernel/Storage/Partition/GUIDPartitionTable.cpp create mode 100644 Kernel/Storage/Partition/GUIDPartitionTable.h create mode 100644 Kernel/Storage/Partition/PartitionTable.cpp create mode 100644 Kernel/Storage/Partition/PartitionTable.h (limited to 'Kernel/Storage/Partition') diff --git a/Kernel/Storage/Partition/DiskPartition.cpp b/Kernel/Storage/Partition/DiskPartition.cpp index 64126c0b58..50b97c276d 100644 --- a/Kernel/Storage/Partition/DiskPartition.cpp +++ b/Kernel/Storage/Partition/DiskPartition.cpp @@ -31,16 +31,15 @@ namespace Kernel { -NonnullRefPtr DiskPartition::create(BlockDevice& device, unsigned block_offset, unsigned block_limit) +NonnullRefPtr DiskPartition::create(BlockDevice& device, unsigned minor_number, DiskPartitionMetadata metadata) { - return adopt(*new DiskPartition(device, block_offset, block_limit)); + return adopt(*new DiskPartition(device, minor_number, metadata)); } -DiskPartition::DiskPartition(BlockDevice& device, unsigned block_offset, unsigned block_limit) - : BlockDevice(100, 0, device.block_size()) +DiskPartition::DiskPartition(BlockDevice& device, unsigned minor_number, DiskPartitionMetadata metadata) + : BlockDevice(100, minor_number, device.block_size()) , m_device(device) - , m_block_offset(block_offset) - , m_block_limit(block_limit) + , m_metadata(metadata) { } @@ -51,12 +50,12 @@ DiskPartition::~DiskPartition() void DiskPartition::start_request(AsyncBlockDeviceRequest& request) { request.add_sub_request(m_device->make_request(request.request_type(), - request.block_index() + m_block_offset, request.block_count(), request.buffer(), request.buffer_size())); + request.block_index() + m_metadata.start_block(), request.block_count(), request.buffer(), request.buffer_size())); } KResultOr DiskPartition::read(FileDescription& fd, size_t offset, UserOrKernelBuffer& outbuf, size_t len) { - unsigned adjust = m_block_offset * block_size(); + unsigned adjust = m_metadata.start_block() * block_size(); #ifdef OFFD_DEBUG klog() << "DiskPartition::read offset=" << fd.offset() << " adjust=" << adjust << " len=" << len; @@ -67,7 +66,7 @@ KResultOr DiskPartition::read(FileDescription& fd, size_t offset, UserOr bool DiskPartition::can_read(const FileDescription& fd, size_t offset) const { - unsigned adjust = m_block_offset * block_size(); + unsigned adjust = m_metadata.start_block() * block_size(); #ifdef OFFD_DEBUG klog() << "DiskPartition::can_read offset=" << offset << " adjust=" << adjust; @@ -78,7 +77,7 @@ bool DiskPartition::can_read(const FileDescription& fd, size_t offset) const KResultOr DiskPartition::write(FileDescription& fd, size_t offset, const UserOrKernelBuffer& inbuf, size_t len) { - unsigned adjust = m_block_offset * block_size(); + unsigned adjust = m_metadata.start_block() * block_size(); #ifdef OFFD_DEBUG klog() << "DiskPartition::write offset=" << offset << " adjust=" << adjust << " len=" << len; @@ -89,7 +88,7 @@ KResultOr DiskPartition::write(FileDescription& fd, size_t offset, const bool DiskPartition::can_write(const FileDescription& fd, size_t offset) const { - unsigned adjust = m_block_offset * block_size(); + unsigned adjust = m_metadata.start_block() * block_size(); #ifdef OFFD_DEBUG klog() << "DiskPartition::can_write offset=" << offset << " adjust=" << adjust; diff --git a/Kernel/Storage/Partition/DiskPartition.h b/Kernel/Storage/Partition/DiskPartition.h index acd9547c9a..87409a3e26 100644 --- a/Kernel/Storage/Partition/DiskPartition.h +++ b/Kernel/Storage/Partition/DiskPartition.h @@ -28,12 +28,13 @@ #include #include +#include namespace Kernel { class DiskPartition final : public BlockDevice { public: - static NonnullRefPtr create(BlockDevice&, unsigned block_offset, unsigned block_limit); + static NonnullRefPtr create(BlockDevice&, unsigned, DiskPartitionMetadata); virtual ~DiskPartition(); virtual void start_request(AsyncBlockDeviceRequest&) override; @@ -50,11 +51,10 @@ public: private: virtual const char* class_name() const override; - DiskPartition(BlockDevice&, unsigned block_offset, unsigned block_limit); + DiskPartition(BlockDevice&, unsigned, DiskPartitionMetadata); NonnullRefPtr m_device; - unsigned m_block_offset; - unsigned m_block_limit; + DiskPartitionMetadata m_metadata; }; } diff --git a/Kernel/Storage/Partition/DiskPartitionMetadata.cpp b/Kernel/Storage/Partition/DiskPartitionMetadata.cpp index 99c5a17d21..82ded057e9 100644 --- a/Kernel/Storage/Partition/DiskPartitionMetadata.cpp +++ b/Kernel/Storage/Partition/DiskPartitionMetadata.cpp @@ -45,6 +45,12 @@ DiskPartitionMetadata::DiskPartitionMetadata(u64 start_block, u64 end_block, Byt ASSERT(!m_partition_type.is_empty()); ASSERT(!m_unique_guid.is_empty()); } + +DiskPartitionMetadata DiskPartitionMetadata::offset(u64 blocks_count) const +{ + return DiskPartitionMetadata({ blocks_count + m_start_block, blocks_count + m_end_block, m_partition_type }); +} + u64 DiskPartitionMetadata::start_block() const { return m_start_block; diff --git a/Kernel/Storage/Partition/DiskPartitionMetadata.h b/Kernel/Storage/Partition/DiskPartitionMetadata.h index b1c551ced9..5c1eae70e5 100644 --- a/Kernel/Storage/Partition/DiskPartitionMetadata.h +++ b/Kernel/Storage/Partition/DiskPartitionMetadata.h @@ -38,6 +38,8 @@ public: u64 start_block() const; u64 end_block() const; + DiskPartitionMetadata offset(u64 blocks_count) const; + Optional special_attributes() const; Optional name() const; Optional partition_type() const; @@ -48,7 +50,7 @@ private: u64 m_end_block; ByteBuffer m_partition_type; ByteBuffer m_unique_guid; - u64 m_attributes; + u64 m_attributes { 0 }; String m_name; }; diff --git a/Kernel/Storage/Partition/EBRPartitionTable.cpp b/Kernel/Storage/Partition/EBRPartitionTable.cpp index e026ea3576..e99e90f3bc 100644 --- a/Kernel/Storage/Partition/EBRPartitionTable.cpp +++ b/Kernel/Storage/Partition/EBRPartitionTable.cpp @@ -33,176 +33,69 @@ namespace Kernel { -EBRPartitionTable::EBRPartitionTable(NonnullRefPtr device) - : m_device(move(device)) +Result, PartitionTable::Error> EBRPartitionTable::try_to_initialize(const StorageDevice& device) { + auto table = make(device); + if (table->is_protective_mbr()) + return { PartitionTable::Error::MBRProtective }; + if (!table->is_valid()) + return { PartitionTable::Error::Invalid }; + return table; } -EBRPartitionTable::~EBRPartitionTable() +void EBRPartitionTable::search_extended_partition(const StorageDevice& device, MBRPartitionTable& checked_ebr, u64 current_block_offset, size_t limit) { + if (limit == 0) + return; + // EBRs should not carry more than 2 partitions (because they need to form a linked list) + ASSERT(checked_ebr.partitions_count() <= 2); + auto checked_logical_partition = checked_ebr.partition(0); + + // If we are pointed to an invalid logical partition, something is seriously wrong. + ASSERT(checked_logical_partition.has_value()); + m_partitions.append(checked_logical_partition.value().offset(current_block_offset)); + if (!checked_ebr.contains_ebr()) + return; + current_block_offset += checked_ebr.partition(1).value().start_block(); + auto next_ebr = MBRPartitionTable::try_to_initialize(device, current_block_offset); + if (!next_ebr) + return; + search_extended_partition(device, *next_ebr, current_block_offset, (limit - 1)); } -const MBRPartitionHeader& EBRPartitionTable::header() const +EBRPartitionTable::EBRPartitionTable(const StorageDevice& device) + : MBRPartitionTable(device) { - return *reinterpret_cast(m_cached_mbr_header); -} + if (!is_header_valid()) + return; + m_valid = true; -const EBRPartitionExtension& EBRPartitionTable::ebr_extension() const -{ - return *reinterpret_cast(m_cached_ebr_header); -} + ASSERT(partitions_count() == 0); -int EBRPartitionTable::index_of_ebr_container() const -{ - for (int i = 0; i < 4; i++) { - if (header().entry[i].type == EBR_CHS_CONTAINER || header().entry[i].type == EBR_LBA_CONTAINER) - return i; - } - ASSERT_NOT_REACHED(); -} - -bool EBRPartitionTable::initialize() -{ - auto mbr_header_request = m_device->make_request(AsyncBlockDeviceRequest::Read, - 0, 1, UserOrKernelBuffer::for_kernel_buffer(m_cached_mbr_header), sizeof(m_cached_mbr_header)); - - auto mbr_header_buffer = UserOrKernelBuffer::for_kernel_buffer(m_cached_mbr_header); - if (!m_device->read_block(0, mbr_header_buffer)) { - return false; - } auto& header = this->header(); - - m_ebr_container_id = index_of_ebr_container() + 1; - -#ifdef EBR_DEBUG - klog() << "EBRPartitionTable::initialize: MBR_signature=0x" << String::format("%x", header.mbr_signature); -#endif - - if (header.mbr_signature != MBR_SIGNATURE) { - klog() << "EBRPartitionTable::initialize: bad MBR signature 0x" << String::format("%x", header.mbr_signature); - return false; - } - - auto& ebr_entry = header.entry[m_ebr_container_id - 1]; - auto ebr_header_buffer = UserOrKernelBuffer::for_kernel_buffer(m_cached_ebr_header); - if (!m_device->read_block(ebr_entry.offset, ebr_header_buffer)) { - return false; - } - size_t index = 1; - while (index < 128) { // Unlikely to encounter a disk with 128 partitions in this configuration... - if (ebr_extension().next_chained_ebr_extension.offset == 0 && ebr_extension().next_chained_ebr_extension.type == 0) { - break; - } - index++; - if (!m_device->read_block(ebr_extension().next_chained_ebr_extension.offset, ebr_header_buffer)) { - return false; + for (size_t index = 0; index < 4; index++) { + auto& entry = header.entry[index]; + // Start enumerating all logical partitions + if (entry.type == 0xf) { + auto checked_ebr = MBRPartitionTable::try_to_initialize(device, entry.offset); + if (!checked_ebr) + continue; + // It's quite unlikely to see that amount of partitions, so stop at 128 partitions. + search_extended_partition(device, *checked_ebr, entry.offset, 128); + continue; } - } - - m_ebr_chained_extensions_count = index; - - klog() << "EBRPartitionTable::initialize: Extended partitions count - " << m_ebr_chained_extensions_count; - - return true; -} - -RefPtr EBRPartitionTable::get_non_extended_partition(unsigned index) -{ - auto& header = this->header(); - auto& entry = header.entry[index - 1]; - -#ifdef EBR_DEBUG - klog() << "EBRPartitionTable::partition: status=0x" << String::format("%x", entry.status) << " offset=0x" << String::format("%x", entry.offset); -#endif - - if (entry.offset == 0x00) { -#ifdef EBR_DEBUG - klog() << "EBRPartitionTable::partition: missing partition requested index=" << index; -#endif - - return nullptr; - } -#ifdef EBR_DEBUG - klog() << "EBRPartitionTable::partition: found partition index=" << index << " type=" << String::format("%x", entry.type); -#endif - - return DiskPartition::create(m_device, entry.offset, (entry.offset + entry.length)); -} - -RefPtr EBRPartitionTable::get_extended_partition(unsigned index) -{ - - unsigned relative_index = index - m_ebr_container_id; - auto& header = this->header(); - -#ifdef EBR_DEBUG - klog() << "EBRPartitionTable::partition: relative index " << relative_index; -#endif - - auto& ebr_entry = header.entry[m_ebr_container_id - 1]; -#ifdef EBR_DEBUG - klog() << "EBRPartitionTable::partition: Extended partition, offset 0x" << String::format("%x", ebr_entry.offset) << ", type " << String::format("%x", ebr_entry.type); -#endif - - auto ebr_header_buffer = UserOrKernelBuffer::for_kernel_buffer(m_cached_ebr_header); - if (!m_device->read_block(ebr_entry.offset, ebr_header_buffer)) { - return nullptr; - } - size_t i = 0; - while (i < relative_index) { -#ifdef EBR_DEBUG - klog() << "EBRPartitionTable::partition: logical partition, relative offset 0x" << String::format("%x", ebr_extension().entry.offset) << ", type " << String::format("%x", ebr_extension().entry.type); - klog() << "EBRPartitionTable::partition: next logical partition, relative offset 0x" << String::format("%x", ebr_extension().next_chained_ebr_extension.offset) << ", type " << String::format("%x", ebr_extension().next_chained_ebr_extension.type); -#endif - if (ebr_extension().next_chained_ebr_extension.offset == 0 && ebr_extension().next_chained_ebr_extension.type == 0) { - break; - } - - i++; - if (!m_device->read_block(ebr_extension().next_chained_ebr_extension.offset, ebr_header_buffer)) { - return nullptr; + if (entry.offset == 0x00) { + continue; } + auto partition_type = ByteBuffer::create_zeroed(sizeof(u8)); + partition_type.data()[0] = entry.type; + m_partitions.append(DiskPartitionMetadata({ entry.offset, (entry.offset + entry.length), partition_type })); } - -#ifdef EBR_DEBUG - klog() << "EBRPartitionTable::partition: status=" << String::format("%x", ebr_extension().entry.status) << " offset=" << String::format("%x", ebr_extension().entry.offset + ebr_entry.offset); -#endif - - if (ebr_extension().entry.offset == 0x00) { -#ifdef EBR_DEBUG - klog() << "EBRPartitionTable::partition: missing partition requested index=" << index; -#endif - - return nullptr; - } - -#ifdef EBR_DEBUG - klog() << "EBRPartitionTable::partition: found partition index=" << index << " type=" << String::format("%x", ebr_extension().entry.type); -#endif - - return DiskPartition::create(m_device, ebr_extension().entry.offset + ebr_entry.offset, (ebr_extension().entry.offset + ebr_entry.offset + ebr_extension().entry.length)); -} - -bool EBRPartitionTable::index_is_extended_partition(unsigned index) const -{ - return !(m_ebr_container_id > index || index > (m_ebr_container_id + m_ebr_chained_extensions_count)); } -RefPtr EBRPartitionTable::partition(unsigned index) +EBRPartitionTable::~EBRPartitionTable() { - ASSERT(index >= 1 && index <= m_ebr_chained_extensions_count + 4); - - auto& header = this->header(); - if (header.mbr_signature != MBR_SIGNATURE) { - klog() << "EBRPartitionTable::initialize: bad MBR signature - not initialized? 0x" << String::format("%x", header.mbr_signature); - return nullptr; - } - if (index_is_extended_partition(index)) - return get_extended_partition(index); - if (index > 4) - return get_non_extended_partition(index - m_ebr_chained_extensions_count); - return get_non_extended_partition(index); } } diff --git a/Kernel/Storage/Partition/EBRPartitionTable.h b/Kernel/Storage/Partition/EBRPartitionTable.h index a5dab9660a..b9784706d4 100644 --- a/Kernel/Storage/Partition/EBRPartitionTable.h +++ b/Kernel/Storage/Partition/EBRPartitionTable.h @@ -26,46 +26,29 @@ #pragma once +#include #include +#include #include #include #include namespace Kernel { -struct [[gnu::packed]] EBRPartitionExtension -{ - u8 unused_area[446]; - MBRPartitionEntry entry; - MBRPartitionEntry next_chained_ebr_extension; - MBRPartitionEntry unused[2]; - u16 mbr_signature; -}; - -class EBRPartitionTable { - +struct EBRPartitionHeader; +class EBRPartitionTable : public MBRPartitionTable { public: - explicit EBRPartitionTable(NonnullRefPtr); ~EBRPartitionTable(); - bool initialize(); - RefPtr partition(unsigned index); + static Result, PartitionTable::Error> try_to_initialize(const StorageDevice&); + explicit EBRPartitionTable(const StorageDevice&); + virtual bool is_valid() const override { return m_valid; }; + virtual Type type() const override { return Type::EBR; }; private: - int index_of_ebr_container() const; - NonnullRefPtr m_device; + void search_extended_partition(const StorageDevice&, MBRPartitionTable&, u64, size_t limit); - const MBRPartitionHeader& header() const; - const EBRPartitionExtension& ebr_extension() const; - - bool index_is_extended_partition(unsigned index) const; - - RefPtr get_extended_partition(unsigned index); - RefPtr get_non_extended_partition(unsigned index); - u8 m_ebr_container_id { 0 }; - size_t m_ebr_chained_extensions_count { 0 }; - u8 m_cached_mbr_header[512]; - u8 m_cached_ebr_header[512]; + bool m_valid { false }; + size_t m_partitions_count { 0 }; }; - } diff --git a/Kernel/Storage/Partition/GPTPartitionTable.cpp b/Kernel/Storage/Partition/GPTPartitionTable.cpp deleted file mode 100644 index af81a1ae4e..0000000000 --- a/Kernel/Storage/Partition/GPTPartitionTable.cpp +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright (c) 2018-2020, Andreas Kling - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include -#include - -#ifndef GPT_DEBUG -# define GPT_DEBUG -#endif - -namespace Kernel { - -GPTPartitionTable::GPTPartitionTable(BlockDevice& device) - : m_device(move(device)) -{ -} - -GPTPartitionTable::~GPTPartitionTable() -{ -} - -const GPTPartitionHeader& GPTPartitionTable::header() const -{ - return *reinterpret_cast(m_cached_header); -} - -bool GPTPartitionTable::initialize() -{ - auto header_buffer = UserOrKernelBuffer::for_kernel_buffer(m_cached_header); - if (!m_device->read_block(1, header_buffer)) { - return false; - } - - auto& header = this->header(); - -#ifdef GPT_DEBUG - klog() << "GPTPartitionTable::initialize: gpt_signature=0x" << String::format("%x", header.sig[1]) << String::format("%x", header.sig[0]); -#endif - - if (header.sig[0] != GPT_SIGNATURE && header.sig[1] != GPT_SIGNATURE2) { - klog() << "GPTPartitionTable::initialize: bad GPT signature 0x" << String::format("%x", header.sig[1]) << String::format("%x", header.sig[0]); - return false; - } - - return true; -} - -RefPtr GPTPartitionTable::partition(unsigned index) -{ - ASSERT(index >= 1 && index <= 4294967294); - - auto& header = this->header(); - unsigned lba = header.partition_array_start_lba + (((index - 1) * header.partition_entry_size) / BytesPerSector); - - if (header.sig[0] != GPT_SIGNATURE) { - klog() << "GPTPartitionTable::initialize: bad gpt signature - not initialized? 0x" << String::format("%x", header.sig); - return nullptr; - } - - u8 entries_per_sector = BytesPerSector / header.partition_entry_size; - - GPTPartitionEntry entries[entries_per_sector]; - auto entries_buffer = UserOrKernelBuffer::for_kernel_buffer((u8*)&entries); - this->m_device->read_block(lba, entries_buffer); - GPTPartitionEntry& entry = entries[((index - 1) % entries_per_sector)]; - -#ifdef GPT_DEBUG - klog() << "GPTPartitionTable::partition " << index; - klog() << "GPTPartitionTable - offset = " << entry.first_lba[1] << entry.first_lba[0]; -#endif - - if (entry.first_lba[0] == 0x00) { -#ifdef GPT_DEBUG - klog() << "GPTPartitionTable::partition: missing partition requested index=" << index; -#endif - - return nullptr; - } - -#ifdef GPT_DEBUG - klog() << "GPTPartitionTable::partition: found partition index=" << index << " type=" << String::format("%x", entry.partition_guid[3]) << "-" << String::format("%x", entry.partition_guid[2]) << "-" << String::format("%x", entry.partition_guid[1]) << "-" << String::format("%x", entry.partition_guid[0]); -#endif - return DiskPartition::create(m_device, entry.first_lba[0], entry.last_lba[0]); -} - -} diff --git a/Kernel/Storage/Partition/GPTPartitionTable.h b/Kernel/Storage/Partition/GPTPartitionTable.h deleted file mode 100644 index b73d0ff005..0000000000 --- a/Kernel/Storage/Partition/GPTPartitionTable.h +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (c) 2018-2020, Andreas Kling - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#pragma once - -#include -#include -#include -#include - -namespace Kernel { - -#define GPT_SIGNATURE2 0x54524150 -#define GPT_SIGNATURE 0x20494645 -#define BytesPerSector 512 - -struct [[gnu::packed]] GPTPartitionEntry -{ - u32 partition_guid[4]; - u32 unique_guid[4]; - - u32 first_lba[2]; - u32 last_lba[2]; - - u64 attributes; - u8 partition_name[72]; -}; - -struct [[gnu::packed]] GPTPartitionHeader -{ - 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; -}; - -class GPTPartitionTable { - -public: - explicit GPTPartitionTable(BlockDevice&); - ~GPTPartitionTable(); - - bool initialize(); - RefPtr partition(unsigned index); - -private: - NonnullRefPtr m_device; - - const GPTPartitionHeader& header() const; - - u8 m_cached_header[512]; -}; - -} diff --git a/Kernel/Storage/Partition/GUIDPartitionTable.cpp b/Kernel/Storage/Partition/GUIDPartitionTable.cpp new file mode 100644 index 0000000000..f6064ff23a --- /dev/null +++ b/Kernel/Storage/Partition/GUIDPartitionTable.cpp @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2020, Liav A. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include + +#ifndef GPT_DEBUG +# define GPT_DEBUG +#endif + +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; +}; + +Result, PartitionTable::Error> GUIDPartitionTable::try_to_initialize(const StorageDevice& device) +{ + auto table = make(device); + if (!table->is_valid()) + return { PartitionTable::Error::Invalid }; + return table; +} + +GUIDPartitionTable::GUIDPartitionTable(const StorageDevice& device) + : MBRPartitionTable(device) +{ + m_cached_header = ByteBuffer::create_zeroed(m_device->block_size()); + ASSERT(partitions_count() == 0); + if (!initialize()) + m_valid = false; +} + +const GUIDPartitionHeader& GUIDPartitionTable::header() const +{ + return *(const GUIDPartitionHeader*)m_cached_header.data(); +} + +bool GUIDPartitionTable::initialize() +{ + ASSERT(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; + } + +#ifdef GPT_DEBUG + klog() << "GUIDPartitionTable: signature - 0x" << String::format("%x", header().sig[1]) << String::format("%x", header().sig[0]); +#endif + + if (header().sig[0] != GPT_SIGNATURE && header().sig[1] != GPT_SIGNATURE2) { + klog() << "GUIDPartitionTable: bad signature 0x" << String::format("%x", header().sig[1]) << String::format("%x", header().sig[0]); + return false; + } + + auto entries_buffer = ByteBuffer::create_zeroed(m_device->block_size()); + 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 = (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); + + if (is_unused_entry(partition_type)) { + raw_byte_index += header().partition_entry_size; + continue; + } + + ByteBuffer unique_guid = ByteBuffer::copy(entry.unique_guid, 16); + 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 })); + raw_byte_index += header().partition_entry_size; + } + + return true; +} + +bool GUIDPartitionTable::is_unused_entry(ByteBuffer 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; +} + +} diff --git a/Kernel/Storage/Partition/GUIDPartitionTable.h b/Kernel/Storage/Partition/GUIDPartitionTable.h new file mode 100644 index 0000000000..ecdfd43bc9 --- /dev/null +++ b/Kernel/Storage/Partition/GUIDPartitionTable.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2020, Liav A. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include +#include +#include +#include +#include + +namespace Kernel { + +struct GUIDPartitionHeader; +class GUIDPartitionTable final : public MBRPartitionTable { +public: + virtual ~GUIDPartitionTable() {}; + + static Result, PartitionTable::Error> try_to_initialize(const StorageDevice&); + explicit GUIDPartitionTable(const StorageDevice&); + + virtual Type type() const override { return Type::GPT; }; + virtual bool is_valid() const override { return m_valid; }; + +private: + bool is_unused_entry(ByteBuffer) const; + const GUIDPartitionHeader& header() const; + bool initialize(); + + bool m_valid { true }; + ByteBuffer m_cached_header; +}; + +} diff --git a/Kernel/Storage/Partition/MBRPartitionTable.cpp b/Kernel/Storage/Partition/MBRPartitionTable.cpp index e2538ad87c..931081c628 100644 --- a/Kernel/Storage/Partition/MBRPartitionTable.cpp +++ b/Kernel/Storage/Partition/MBRPartitionTable.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018-2020, Andreas Kling + * Copyright (c) 2020, Liav A. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -33,38 +33,105 @@ namespace Kernel { -MBRPartitionTable::MBRPartitionTable(NonnullRefPtr device) - : m_device(move(device)) +#define MBR_SIGNATURE 0xaa55 +#define MBR_PROTECTIVE 0xEE +#define EBR_CHS_CONTAINER 0x05 +#define EBR_LBA_CONTAINER 0x0F + +Result, PartitionTable::Error> MBRPartitionTable::try_to_initialize(const StorageDevice& device) { + auto table = make(device); + if (table->contains_ebr()) + return { PartitionTable::Error::ConatinsEBR }; + if (table->is_protective_mbr()) + return { PartitionTable::Error::MBRProtective }; + if (!table->is_valid()) + return { PartitionTable::Error::Invalid }; + return table; } -MBRPartitionTable::~MBRPartitionTable() +OwnPtr MBRPartitionTable::try_to_initialize(const StorageDevice& device, u32 start_lba) { + auto table = make(device, start_lba); + if (!table->is_valid()) + return nullptr; + return table; } -const MBRPartitionHeader& MBRPartitionTable::header() const +bool MBRPartitionTable::read_boot_record() { - return *reinterpret_cast(m_cached_header); + auto buffer = UserOrKernelBuffer::for_kernel_buffer(m_cached_header.data()); + if (!m_device->read_block(m_start_lba, buffer)) + return false; + m_header_valid = true; + return m_header_valid; } -bool MBRPartitionTable::initialize() +MBRPartitionTable::MBRPartitionTable(const StorageDevice& device, u32 start_lba) + : PartitionTable(device) + , m_start_lba(start_lba) + , m_cached_header(ByteBuffer::create_zeroed(m_device->block_size())) { - auto header_buffer = UserOrKernelBuffer::for_kernel_buffer(m_cached_header); - if (!m_device->read_block(0, header_buffer)) { - return false; + if (!read_boot_record() || !initialize()) + return; + + m_header_valid = true; + + auto& header = this->header(); + for (size_t index = 0; index < 4; index++) { + auto& entry = header.entry[index]; + if (entry.offset == 0x00) { + continue; + } + auto partition_type = ByteBuffer::create_zeroed(sizeof(u8)); + partition_type.data()[0] = entry.type; + m_partitions.append(DiskPartitionMetadata({ entry.offset, (entry.offset + entry.length), partition_type })); } + m_valid = true; +} + +MBRPartitionTable::MBRPartitionTable(const StorageDevice& device) + : PartitionTable(device) + , m_start_lba(0) + , m_cached_header(ByteBuffer::create_zeroed(m_device->block_size())) +{ + if (!read_boot_record() || contains_ebr() || is_protective_mbr() || !initialize()) + return; auto& header = this->header(); + for (size_t index = 0; index < 4; index++) { + auto& entry = header.entry[index]; + if (entry.offset == 0x00) { + continue; + } + auto partition_type = ByteBuffer::create_zeroed(sizeof(u8)); + partition_type.data()[0] = entry.type; + m_partitions.append(DiskPartitionMetadata({ entry.offset, (entry.offset + entry.length), partition_type })); + } + m_valid = true; +} + +MBRPartitionTable::~MBRPartitionTable() +{ +} + +const MBRPartitionTable::Header& MBRPartitionTable::header() const +{ + return *(const MBRPartitionTable::Header*)m_cached_header.data(); +} +bool MBRPartitionTable::initialize() +{ + auto& header = this->header(); #ifdef MBR_DEBUG - klog() << "MBRPartitionTable::initialize: mbr_signature=0x" << String::format("%x", header.mbr_signature); -#endif + klog() << "Master Boot Record: mbr_signature=0x" << String::format("%x", header.mbr_signature); + +#endif if (header.mbr_signature != MBR_SIGNATURE) { - klog() << "MBRPartitionTable::initialize: bad mbr signature 0x" << String::format("%x", header.mbr_signature); + klog() << "Master Boot Record: invalid signature"; return false; } - return true; } @@ -82,35 +149,4 @@ bool MBRPartitionTable::is_protective_mbr() const return header().entry[0].type == MBR_PROTECTIVE; } -RefPtr MBRPartitionTable::partition(unsigned index) -{ - ASSERT(index >= 1 && index <= 4); - - auto& header = this->header(); - auto& entry = header.entry[index - 1]; - - if (header.mbr_signature != MBR_SIGNATURE) { - klog() << "MBRPartitionTable::initialize: bad mbr signature - not initialized? 0x" << String::format("%x", header.mbr_signature); - return nullptr; - } - -#ifdef MBR_DEBUG - klog() << "MBRPartitionTable::partition: status=0x" << String::format("%x", entry.status) << " offset=0x" << String::format("%x", entry.offset); -#endif - - if (entry.offset == 0x00) { -#ifdef MBR_DEBUG - klog() << "MBRPartitionTable::partition: missing partition requested index=" << index; -#endif - - return nullptr; - } - -#ifdef MBR_DEBUG - klog() << "MBRPartitionTable::partition: found partition index=" << index << " type=" << String::format("%x", entry.type); -#endif - - return DiskPartition::create(m_device, entry.offset, (entry.offset + entry.length)); -} - } diff --git a/Kernel/Storage/Partition/MBRPartitionTable.h b/Kernel/Storage/Partition/MBRPartitionTable.h index 74b7d06b83..93f134ad43 100644 --- a/Kernel/Storage/Partition/MBRPartitionTable.h +++ b/Kernel/Storage/Partition/MBRPartitionTable.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018-2020, Andreas Kling + * Copyright (c) 2020, Liav A. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -26,57 +26,64 @@ #pragma once +#include #include +#include #include -#include +#include namespace Kernel { -#define MBR_SIGNATURE 0xaa55 -#define MBR_PROTECTIVE 0xEE -#define EBR_CHS_CONTAINER 0x05 -#define EBR_LBA_CONTAINER 0x0F - -struct [[gnu::packed]] MBRPartitionEntry -{ - u8 status; - u8 chs1[3]; - u8 type; - u8 chs2[3]; - u32 offset; - u32 length; -}; - -struct [[gnu::packed]] MBRPartitionHeader -{ - u8 code1[218]; - u16 ts_zero; - u8 ts_drive, ts_seconds, ts_minutes, ts_hours; - u8 code2[216]; - u32 disk_signature; - u16 disk_signature_zero; - MBRPartitionEntry entry[4]; - u16 mbr_signature; -}; - -class MBRPartitionTable { - AK_MAKE_ETERNAL +class MBRPartitionTable : public PartitionTable { +public: + struct [[gnu::packed]] Entry + { + u8 status; + u8 chs1[3]; + u8 type; + u8 chs2[3]; + u32 offset; + u32 length; + }; + struct [[gnu::packed]] Header + { + u8 code1[218]; + u16 ts_zero; + u8 ts_drive; + u8 ts_seconds; + u8 ts_minutes; + u8 ts_hours; + u8 code2[216]; + u32 disk_signature; + u16 disk_signature_zero; + Entry entry[4]; + u16 mbr_signature; + }; public: - explicit MBRPartitionTable(NonnullRefPtr); ~MBRPartitionTable(); - bool initialize(); + static Result, PartitionTable::Error> try_to_initialize(const StorageDevice&); + static OwnPtr try_to_initialize(const StorageDevice&, u32 start_lba); + explicit MBRPartitionTable(const StorageDevice&); + MBRPartitionTable(const StorageDevice&, u32 start_lba); + bool is_protective_mbr() const; bool contains_ebr() const; - RefPtr partition(unsigned index); - -private: - NonnullRefPtr m_device; + virtual Type type() const override { return Type::MBR; }; + virtual bool is_valid() const override { return m_valid; }; - const MBRPartitionHeader& header() const; +protected: + const Header& header() const; + bool is_header_valid() const { return m_header_valid; }; - u8 m_cached_header[512]; +private: + bool read_boot_record(); + bool initialize(); + bool m_valid { false }; + bool m_header_valid { false }; + const u32 m_start_lba; + ByteBuffer m_cached_header; + size_t m_partitions_count { 0 }; }; - } diff --git a/Kernel/Storage/Partition/PartitionTable.cpp b/Kernel/Storage/Partition/PartitionTable.cpp new file mode 100644 index 0000000000..4f719f872a --- /dev/null +++ b/Kernel/Storage/Partition/PartitionTable.cpp @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2020, Liav A. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +namespace Kernel { +PartitionTable::PartitionTable(const StorageDevice& device) + : m_device(device) +{ +} + +Optional PartitionTable::partition(unsigned index) +{ + if (index > partitions_count()) + return {}; + return m_partitions[index]; +} + +} diff --git a/Kernel/Storage/Partition/PartitionTable.h b/Kernel/Storage/Partition/PartitionTable.h new file mode 100644 index 0000000000..324284492e --- /dev/null +++ b/Kernel/Storage/Partition/PartitionTable.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2020, Liav A. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include +#include +#include +#include +#include + +namespace Kernel { + +class PartitionTable { +public: + enum class Type { + MBR, + EBR, + GPT, + BSD + }; + enum class Error { + Invalid, + MBRProtective, + ConatinsEBR, + }; + +public: + Optional partition(unsigned index); + size_t partitions_count() const { return m_partitions.size(); } + virtual Type type() const = 0; + virtual ~PartitionTable() { } + virtual bool is_valid() const = 0; + + Vector partitions() const { return m_partitions; } + +protected: + explicit PartitionTable(const StorageDevice&); + + NonnullRefPtr m_device; + Vector m_partitions; +}; + +} -- cgit v1.2.3