summaryrefslogtreecommitdiff
path: root/Kernel
diff options
context:
space:
mode:
Diffstat (limited to 'Kernel')
-rw-r--r--Kernel/CMakeLists.txt3
-rw-r--r--Kernel/FileSystem/DevFS.cpp5
-rw-r--r--Kernel/Storage/Partition/DiskPartition.cpp21
-rw-r--r--Kernel/Storage/Partition/DiskPartition.h8
-rw-r--r--Kernel/Storage/Partition/DiskPartitionMetadata.cpp6
-rw-r--r--Kernel/Storage/Partition/DiskPartitionMetadata.h4
-rw-r--r--Kernel/Storage/Partition/EBRPartitionTable.cpp199
-rw-r--r--Kernel/Storage/Partition/EBRPartitionTable.h39
-rw-r--r--Kernel/Storage/Partition/GPTPartitionTable.cpp109
-rw-r--r--Kernel/Storage/Partition/GUIDPartitionTable.cpp153
-rw-r--r--Kernel/Storage/Partition/GUIDPartitionTable.h (renamed from Kernel/Storage/Partition/GPTPartitionTable.h)66
-rw-r--r--Kernel/Storage/Partition/MBRPartitionTable.cpp126
-rw-r--r--Kernel/Storage/Partition/MBRPartitionTable.h87
-rw-r--r--Kernel/Storage/Partition/PartitionTable.cpp42
-rw-r--r--Kernel/Storage/Partition/PartitionTable.h67
-rw-r--r--Kernel/Storage/StorageDevice.h3
-rw-r--r--Kernel/Storage/StorageManagement.cpp134
-rw-r--r--Kernel/Storage/StorageManagement.h18
-rw-r--r--Kernel/init.cpp72
19 files changed, 620 insertions, 542 deletions
diff --git a/Kernel/CMakeLists.txt b/Kernel/CMakeLists.txt
index 373d0ebfb2..46e55fe30d 100644
--- a/Kernel/CMakeLists.txt
+++ b/Kernel/CMakeLists.txt
@@ -38,8 +38,9 @@ set(KERNEL_SOURCES
Storage/Partition/DiskPartition.cpp
Storage/Partition/DiskPartitionMetadata.cpp
Storage/Partition/EBRPartitionTable.cpp
- Storage/Partition/GPTPartitionTable.cpp
+ Storage/Partition/GUIDPartitionTable.cpp
Storage/Partition/MBRPartitionTable.cpp
+ Storage/Partition/PartitionTable.cpp
Storage/StorageDevice.cpp
Storage/IDEController.cpp
Storage/IDEChannel.cpp
diff --git a/Kernel/FileSystem/DevFS.cpp b/Kernel/FileSystem/DevFS.cpp
index f86fda89e9..127a67de90 100644
--- a/Kernel/FileSystem/DevFS.cpp
+++ b/Kernel/FileSystem/DevFS.cpp
@@ -411,7 +411,10 @@ String DevFSDeviceInode::determine_name() const
}
case 100:
- return "hda1";
+ // FIXME: Try to not hardcode a maximum of 16 partitions per drive!
+ size_t drive_index = (u8)'a' + (m_attached_device->minor() / 16);
+ char drive_letter = (u8)drive_index;
+ return String::format("hd%c%d", drive_letter, m_attached_device->minor() + 1);
}
}
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> DiskPartition::create(BlockDevice& device, unsigned block_offset, unsigned block_limit)
+NonnullRefPtr<DiskPartition> 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<AsyncBlockDeviceRequest>(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<size_t> 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<size_t> 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<size_t> 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<size_t> 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 <AK/RefPtr.h>
#include <Kernel/Devices/BlockDevice.h>
+#include <Kernel/Storage/Partition/DiskPartitionMetadata.h>
namespace Kernel {
class DiskPartition final : public BlockDevice {
public:
- static NonnullRefPtr<DiskPartition> create(BlockDevice&, unsigned block_offset, unsigned block_limit);
+ static NonnullRefPtr<DiskPartition> 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<BlockDevice> 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<u64> special_attributes() const;
Optional<String> name() const;
Optional<ByteBuffer> 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<BlockDevice> device)
- : m_device(move(device))
+Result<NonnullOwnPtr<EBRPartitionTable>, PartitionTable::Error> EBRPartitionTable::try_to_initialize(const StorageDevice& device)
{
+ auto table = make<EBRPartitionTable>(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<const MBRPartitionHeader*>(m_cached_mbr_header);
-}
+ if (!is_header_valid())
+ return;
+ m_valid = true;
-const EBRPartitionExtension& EBRPartitionTable::ebr_extension() const
-{
- return *reinterpret_cast<const EBRPartitionExtension*>(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>(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<DiskPartition> 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<DiskPartition> 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<DiskPartition> 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 <AK/NonnullOwnPtr.h>
#include <AK/RefPtr.h>
+#include <AK/Result.h>
#include <AK/Vector.h>
#include <Kernel/Storage/Partition/DiskPartition.h>
#include <Kernel/Storage/Partition/MBRPartitionTable.h>
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<BlockDevice>);
~EBRPartitionTable();
- bool initialize();
- RefPtr<DiskPartition> partition(unsigned index);
+ static Result<NonnullOwnPtr<EBRPartitionTable>, 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<BlockDevice> 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<DiskPartition> get_extended_partition(unsigned index);
- RefPtr<DiskPartition> 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 <kling@serenityos.org>
- * 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 <AK/ByteBuffer.h>
-#include <Kernel/Storage/Partition/GPTPartitionTable.h>
-
-#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<const GPTPartitionHeader*>(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<DiskPartition> 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/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. <liavalb@hotmail.co.il>
+ * 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 <AK/ByteBuffer.h>
+#include <Kernel/Storage/Partition/GUIDPartitionTable.h>
+
+#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<NonnullOwnPtr<GUIDPartitionTable>, PartitionTable::Error> GUIDPartitionTable::try_to_initialize(const StorageDevice& device)
+{
+ auto table = make<GUIDPartitionTable>(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/GPTPartitionTable.h b/Kernel/Storage/Partition/GUIDPartitionTable.h
index b73d0ff005..ecdfd43bc9 100644
--- a/Kernel/Storage/Partition/GPTPartitionTable.h
+++ b/Kernel/Storage/Partition/GUIDPartitionTable.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * Copyright (c) 2020, Liav A. <liavalb@hotmail.co.il>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -27,65 +27,31 @@
#pragma once
#include <AK/RefPtr.h>
+#include <AK/Result.h>
#include <AK/Types.h>
#include <AK/Vector.h>
-#include <Kernel/Storage/Partition/DiskPartition.h>
+#include <Kernel/Storage/Partition/MBRPartitionTable.h>
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 {
-
+struct GUIDPartitionHeader;
+class GUIDPartitionTable final : public MBRPartitionTable {
public:
- explicit GPTPartitionTable(BlockDevice&);
- ~GPTPartitionTable();
+ virtual ~GUIDPartitionTable() {};
- bool initialize();
- RefPtr<DiskPartition> partition(unsigned index);
+ static Result<NonnullOwnPtr<GUIDPartitionTable>, PartitionTable::Error> try_to_initialize(const StorageDevice&);
+ explicit GUIDPartitionTable(const StorageDevice&);
-private:
- NonnullRefPtr<BlockDevice> m_device;
+ virtual Type type() const override { return Type::GPT; };
+ virtual bool is_valid() const override { return m_valid; };
- const GPTPartitionHeader& header() const;
+private:
+ bool is_unused_entry(ByteBuffer) const;
+ const GUIDPartitionHeader& header() const;
+ bool initialize();
- u8 m_cached_header[512];
+ 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 <kling@serenityos.org>
+ * Copyright (c) 2020, Liav A. <liavalb@hotmail.co.il>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -33,38 +33,105 @@
namespace Kernel {
-MBRPartitionTable::MBRPartitionTable(NonnullRefPtr<BlockDevice> device)
- : m_device(move(device))
+#define MBR_SIGNATURE 0xaa55
+#define MBR_PROTECTIVE 0xEE
+#define EBR_CHS_CONTAINER 0x05
+#define EBR_LBA_CONTAINER 0x0F
+
+Result<NonnullOwnPtr<MBRPartitionTable>, PartitionTable::Error> MBRPartitionTable::try_to_initialize(const StorageDevice& device)
{
+ auto table = make<MBRPartitionTable>(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> MBRPartitionTable::try_to_initialize(const StorageDevice& device, u32 start_lba)
{
+ auto table = make<MBRPartitionTable>(device, start_lba);
+ if (!table->is_valid())
+ return nullptr;
+ return table;
}
-const MBRPartitionHeader& MBRPartitionTable::header() const
+bool MBRPartitionTable::read_boot_record()
{
- return *reinterpret_cast<const MBRPartitionHeader*>(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<DiskPartition> 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 <kling@serenityos.org>
+ * Copyright (c) 2020, Liav A. <liavalb@hotmail.co.il>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -26,57 +26,64 @@
#pragma once
+#include <AK/ByteBuffer.h>
#include <AK/RefPtr.h>
+#include <AK/Result.h>
#include <AK/Vector.h>
-#include <Kernel/Storage/Partition/DiskPartition.h>
+#include <Kernel/Storage/Partition/PartitionTable.h>
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<BlockDevice>);
~MBRPartitionTable();
- bool initialize();
+ static Result<NonnullOwnPtr<MBRPartitionTable>, PartitionTable::Error> try_to_initialize(const StorageDevice&);
+ static OwnPtr<MBRPartitionTable> 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<DiskPartition> partition(unsigned index);
-
-private:
- NonnullRefPtr<BlockDevice> 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. <liavalb@hotmail.co.il>
+ * 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 <Kernel/Storage/Partition/PartitionTable.h>
+
+namespace Kernel {
+PartitionTable::PartitionTable(const StorageDevice& device)
+ : m_device(device)
+{
+}
+
+Optional<DiskPartitionMetadata> 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. <liavalb@hotmail.co.il>
+ * 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 <AK/RefPtr.h>
+#include <AK/Vector.h>
+#include <Kernel/Storage/Partition/DiskPartition.h>
+#include <Kernel/Storage/Partition/DiskPartitionMetadata.h>
+#include <Kernel/Storage/StorageDevice.h>
+
+namespace Kernel {
+
+class PartitionTable {
+public:
+ enum class Type {
+ MBR,
+ EBR,
+ GPT,
+ BSD
+ };
+ enum class Error {
+ Invalid,
+ MBRProtective,
+ ConatinsEBR,
+ };
+
+public:
+ Optional<DiskPartitionMetadata> 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<DiskPartitionMetadata> partitions() const { return m_partitions; }
+
+protected:
+ explicit PartitionTable(const StorageDevice&);
+
+ NonnullRefPtr<StorageDevice> m_device;
+ Vector<DiskPartitionMetadata> m_partitions;
+};
+
+}
diff --git a/Kernel/Storage/StorageDevice.h b/Kernel/Storage/StorageDevice.h
index 21840b4d92..1fe30c0bd2 100644
--- a/Kernel/Storage/StorageDevice.h
+++ b/Kernel/Storage/StorageDevice.h
@@ -29,11 +29,13 @@
#include <Kernel/Devices/BlockDevice.h>
#include <Kernel/Interrupts/IRQHandler.h>
#include <Kernel/Lock.h>
+#include <Kernel/Storage/Partition/DiskPartition.h>
#include <Kernel/Storage/StorageController.h>
namespace Kernel {
class StorageDevice : public BlockDevice {
+ friend class StorageManagement;
AK_MAKE_ETERNAL
public:
enum class Type : u8 {
@@ -63,6 +65,7 @@ protected:
private:
NonnullRefPtr<StorageController> m_storage_controller;
+ NonnullRefPtrVector<DiskPartition> m_partitions;
size_t m_max_addressable_block;
};
diff --git a/Kernel/Storage/StorageManagement.cpp b/Kernel/Storage/StorageManagement.cpp
index 78ae8974d0..4f3acf4fe0 100644
--- a/Kernel/Storage/StorageManagement.cpp
+++ b/Kernel/Storage/StorageManagement.cpp
@@ -25,8 +25,12 @@
*/
#include <Kernel/Devices/BlockDevice.h>
+#include <Kernel/FileSystem/Ext2FileSystem.h>
#include <Kernel/PCI/Access.h>
#include <Kernel/Storage/IDEController.h>
+#include <Kernel/Storage/Partition/EBRPartitionTable.h>
+#include <Kernel/Storage/Partition/GUIDPartitionTable.h>
+#include <Kernel/Storage/Partition/MBRPartitionTable.h>
#include <Kernel/Storage/StorageManagement.h>
namespace Kernel {
@@ -35,10 +39,82 @@ static StorageManagement* s_the;
StorageManagement::StorageManagement(String root_device, bool force_pio)
: 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))
{
}
+NonnullRefPtrVector<StorageController> StorageManagement::enumerate_controllers(bool force_pio) const
+{
+ NonnullRefPtrVector<StorageController> controllers;
+ PCI::enumerate([&](const PCI::Address& address, PCI::ID) {
+ if (PCI::get_class(address) == 0x1 && PCI::get_subclass(address) == 0x1) {
+ controllers.append(IDEController::initialize(address, force_pio));
+ }
+ });
+ return controllers;
+}
+
+NonnullRefPtrVector<StorageDevice> StorageManagement::enumerate_storage_devices() const
+{
+ ASSERT(!m_controllers.is_empty());
+ NonnullRefPtrVector<StorageDevice> devices;
+ for (auto& controller : m_controllers) {
+ for (size_t device_index = 0; device_index < controller.devices_count(); device_index++) {
+ auto device = controller.device(device_index);
+ if (device.is_null())
+ continue;
+ devices.append(device.release_nonnull());
+ }
+ }
+ return devices;
+}
+
+OwnPtr<PartitionTable> StorageManagement::try_to_initialize_partition_table(const StorageDevice& device) const
+{
+ auto mbr_table_or_result = MBRPartitionTable::try_to_initialize(device);
+ if (!mbr_table_or_result.is_error())
+ return move(mbr_table_or_result.value());
+ if (mbr_table_or_result.error() == PartitionTable::Error::MBRProtective) {
+ auto gpt_table_or_result = GUIDPartitionTable::try_to_initialize(device);
+ if (gpt_table_or_result.is_error())
+ return nullptr;
+ return move(gpt_table_or_result.value());
+ }
+ if (mbr_table_or_result.error() == PartitionTable::Error::ConatinsEBR) {
+ auto ebr_table_or_result = EBRPartitionTable::try_to_initialize(device);
+ if (ebr_table_or_result.is_error())
+ return nullptr;
+ return move(ebr_table_or_result.value());
+ }
+ return nullptr;
+}
+
+NonnullRefPtrVector<DiskPartition> StorageManagement::enumerate_disk_partitions() const
+{
+ ASSERT(!m_storage_devices.is_empty());
+ NonnullRefPtrVector<DiskPartition> partitions;
+ size_t device_index = 0;
+ for (auto& device : m_storage_devices) {
+ auto partition_table = try_to_initialize_partition_table(device);
+ if (!partition_table)
+ continue;
+ for (size_t partition_index = 0; partition_index < partition_table->partitions_count(); partition_index++) {
+ auto partition_metadata = partition_table->partition(partition_index);
+ if (!partition_metadata.has_value())
+ continue;
+ // FIXME: Try to not hardcode a maximum of 16 partitions per drive!
+ auto disk_partition = DiskPartition::create(const_cast<StorageDevice&>(device), (partition_index + (16 * device_index)), partition_metadata.value());
+ partitions.append(disk_partition);
+ const_cast<StorageDevice&>(device).m_partitions.append(disk_partition);
+ }
+ device_index++;
+ }
+ return partitions;
+}
+
NonnullRefPtr<StorageDevice> StorageManagement::determine_boot_device(String root_device) const
{
ASSERT(!m_controllers.is_empty());
@@ -54,37 +130,48 @@ NonnullRefPtr<StorageDevice> StorageManagement::determine_boot_device(String roo
}
size_t drive_index = (u8)drive_letter - (u8)'a';
- auto devices = storage_devices();
- if (drive_index >= devices.size()) {
+ if (drive_index >= m_storage_devices.size()) {
klog() << "init_stage2: invalid selection of hard drive.";
Processor::halt();
}
- return devices[drive_index];
+ return m_storage_devices[drive_index];
}
-NonnullRefPtrVector<StorageController> StorageManagement::enumerate_controllers(bool force_pio) const
+NonnullRefPtr<BlockDevice> StorageManagement::determine_boot_block_device(String root_device) const
{
- NonnullRefPtrVector<StorageController> controllers;
- PCI::enumerate([&](const PCI::Address& address, PCI::ID) {
- if (PCI::get_class(address) == 0x1 && PCI::get_subclass(address) == 0x1) {
- controllers.append(IDEController::initialize(address, force_pio));
- }
- });
- return controllers;
+ 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 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()) {
+ klog() << "init_stage2: invalid partition number!";
+ Processor::halt();
+ }
+
+ return m_boot_device->m_partitions[partition_number.value() - 1];
}
-NonnullRefPtrVector<StorageDevice> StorageManagement::storage_devices() const
+NonnullRefPtr<BlockDevice> StorageManagement::boot_block_device() const
{
- NonnullRefPtrVector<StorageDevice> devices;
- for (auto& controller : m_controllers) {
- for (size_t index = 0; index < controller.devices_count(); index++) {
- auto device = controller.device(index);
- if (device.is_null())
- continue;
- devices.append(device.release_nonnull());
- }
+ return m_boot_block_device;
+}
+
+NonnullRefPtr<FS> StorageManagement::root_filesystem() const
+{
+ auto e2fs = Ext2FS::create(*FileDescription::create(boot_block_device()));
+ if (!e2fs->initialize()) {
+ klog() << "init_stage2: couldn't open root filesystem";
+ Processor::halt();
}
- return devices;
+ return e2fs;
}
bool StorageManagement::initialized()
@@ -103,10 +190,6 @@ StorageManagement& StorageManagement::the()
return *s_the;
}
-NonnullRefPtr<StorageDevice> StorageManagement::boot_device() const
-{
- return m_boot_device;
-}
NonnullRefPtrVector<StorageController> StorageManagement::ide_controllers() const
{
NonnullRefPtrVector<StorageController> ide_controllers;
@@ -116,5 +199,4 @@ NonnullRefPtrVector<StorageController> StorageManagement::ide_controllers() cons
}
return ide_controllers;
}
-
}
diff --git a/Kernel/Storage/StorageManagement.h b/Kernel/Storage/StorageManagement.h
index c20b2fc698..9cf624d2b6 100644
--- a/Kernel/Storage/StorageManagement.h
+++ b/Kernel/Storage/StorageManagement.h
@@ -29,11 +29,14 @@
#include <AK/NonnullRefPtr.h>
#include <AK/NonnullRefPtrVector.h>
#include <AK/Types.h>
+#include <Kernel/FileSystem/FileSystem.h>
+#include <Kernel/Storage/Partition/DiskPartition.h>
#include <Kernel/Storage/StorageController.h>
#include <Kernel/Storage/StorageDevice.h>
namespace Kernel {
+class PartitionTable;
class StorageManagement {
AK_MAKE_ETERNAL;
@@ -43,16 +46,27 @@ public:
static void initialize(String root_device, bool force_pio);
static StorageManagement& the();
- NonnullRefPtr<StorageDevice> boot_device() const;
+ NonnullRefPtr<FS> root_filesystem() const;
+
NonnullRefPtrVector<StorageController> ide_controllers() const;
- NonnullRefPtrVector<StorageDevice> storage_devices() const;
private:
+ NonnullRefPtr<BlockDevice> boot_block_device() const;
+
NonnullRefPtrVector<StorageController> enumerate_controllers(bool force_pio) const;
+ NonnullRefPtrVector<StorageDevice> enumerate_storage_devices() const;
+ NonnullRefPtrVector<DiskPartition> enumerate_disk_partitions() const;
+
NonnullRefPtr<StorageDevice> determine_boot_device(String root_device) const;
+ NonnullRefPtr<BlockDevice> determine_boot_block_device(String root_device) const;
+
+ OwnPtr<PartitionTable> try_to_initialize_partition_table(const StorageDevice&) const;
NonnullRefPtrVector<StorageController> m_controllers;
+ NonnullRefPtrVector<StorageDevice> m_storage_devices;
+ NonnullRefPtrVector<DiskPartition> m_disk_partitions;
NonnullRefPtr<StorageDevice> m_boot_device;
+ NonnullRefPtr<BlockDevice> m_boot_block_device;
};
}
diff --git a/Kernel/init.cpp b/Kernel/init.cpp
index e124e1ddb2..f261bbd575 100644
--- a/Kernel/init.cpp
+++ b/Kernel/init.cpp
@@ -61,10 +61,6 @@
#include <Kernel/RTC.h>
#include <Kernel/Random.h>
#include <Kernel/Scheduler.h>
-#include <Kernel/Storage/Partition/DiskPartition.h>
-#include <Kernel/Storage/Partition/EBRPartitionTable.h>
-#include <Kernel/Storage/Partition/GPTPartitionTable.h>
-#include <Kernel/Storage/Partition/MBRPartitionTable.h>
#include <Kernel/Storage/StorageManagement.h>
#include <Kernel/TTY/PTYMultiplexer.h>
#include <Kernel/TTY/VirtualConsole.h>
@@ -271,73 +267,7 @@ void init_stage2(void*)
auto root = kernel_command_line().lookup("root").value_or("/dev/hda");
StorageManagement::initialize(root, force_pio);
- NonnullRefPtr<BlockDevice> root_dev = StorageManagement::the().boot_device();
-
- root = root.substring(strlen("/dev/hda"), root.length() - strlen("/dev/hda"));
-
- if (root.length()) {
- auto partition_number = root.to_uint();
-
- if (!partition_number.has_value()) {
- klog() << "init_stage2: couldn't parse partition number from root kernel parameter";
- Processor::halt();
- }
-
- MBRPartitionTable mbr(root_dev);
-
- if (!mbr.initialize()) {
- klog() << "init_stage2: couldn't read MBR from disk";
- Processor::halt();
- }
-
- if (mbr.is_protective_mbr()) {
- dbg() << "GPT Partitioned Storage Detected!";
- GPTPartitionTable gpt(root_dev);
- if (!gpt.initialize()) {
- klog() << "init_stage2: couldn't read GPT from disk";
- Processor::halt();
- }
- auto partition = gpt.partition(partition_number.value());
- if (!partition) {
- klog() << "init_stage2: couldn't get partition " << partition_number.value();
- Processor::halt();
- }
- root_dev = *partition;
- } else {
- dbg() << "MBR Partitioned Storage Detected!";
- if (mbr.contains_ebr()) {
- EBRPartitionTable ebr(root_dev);
- if (!ebr.initialize()) {
- klog() << "init_stage2: couldn't read EBR from disk";
- Processor::halt();
- }
- auto partition = ebr.partition(partition_number.value());
- if (!partition) {
- klog() << "init_stage2: couldn't get partition " << partition_number.value();
- Processor::halt();
- }
- root_dev = *partition;
- } else {
- if (partition_number.value() < 1 || partition_number.value() > 4) {
- klog() << "init_stage2: invalid partition number " << partition_number.value() << "; expected 1 to 4";
- Processor::halt();
- }
- auto partition = mbr.partition(partition_number.value());
- if (!partition) {
- klog() << "init_stage2: couldn't get partition " << partition_number.value();
- Processor::halt();
- }
- root_dev = *partition;
- }
- }
- }
- auto e2fs = Ext2FS::create(*FileDescription::create(root_dev));
- if (!e2fs->initialize()) {
- klog() << "init_stage2: couldn't open root filesystem";
- Processor::halt();
- }
-
- if (!VFS::the().mount_root(e2fs)) {
+ if (!VFS::the().mount_root(StorageManagement::the().root_filesystem())) {
klog() << "VFS::mount_root failed";
Processor::halt();
}