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.
This commit is contained in:
Liav A 2020-12-26 16:53:30 +02:00 committed by Andreas Kling
parent bc18712adf
commit 72b1998f0d
Notes: sideshowbarker 2024-07-19 00:31:24 +09:00
20 changed files with 639 additions and 561 deletions

View file

@ -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

View file

@ -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);
}
}

View file

@ -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;

View file

@ -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;
};
}

View file

@ -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;

View file

@ -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;
};

View file

@ -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;
}
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));
}
EBRPartitionTable::EBRPartitionTable(const StorageDevice& device)
: MBRPartitionTable(device)
{
if (!is_header_valid())
return;
m_valid = true;
ASSERT(partitions_count() == 0);
auto& header = this->header();
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;
}
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 }));
}
}
EBRPartitionTable::~EBRPartitionTable()
{
}
const MBRPartitionHeader& EBRPartitionTable::header() const
{
return *reinterpret_cast<const MBRPartitionHeader*>(m_cached_mbr_header);
}
const EBRPartitionExtension& EBRPartitionTable::ebr_extension() const
{
return *reinterpret_cast<const EBRPartitionExtension*>(m_cached_ebr_header);
}
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;
}
}
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;
}
}
#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)
{
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);
}
}

View file

@ -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 };
};
}

View file

@ -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]);
}
}

View file

@ -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;
}
}

View file

@ -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&);
virtual Type type() const override { return Type::GPT; };
virtual bool is_valid() const override { return m_valid; };
private:
NonnullRefPtr<BlockDevice> m_device;
bool is_unused_entry(ByteBuffer) const;
const GUIDPartitionHeader& header() const;
bool initialize();
const GPTPartitionHeader& header() const;
u8 m_cached_header[512];
bool m_valid { true };
ByteBuffer m_cached_header;
};
}

View file

@ -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;
}
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;
}
bool MBRPartitionTable::read_boot_record()
{
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;
}
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()))
{
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 MBRPartitionHeader& MBRPartitionTable::header() const
const MBRPartitionTable::Header& MBRPartitionTable::header() const
{
return *reinterpret_cast<const MBRPartitionHeader*>(m_cached_header);
return *(const MBRPartitionTable::Header*)m_cached_header.data();
}
bool MBRPartitionTable::initialize()
{
auto header_buffer = UserOrKernelBuffer::for_kernel_buffer(m_cached_header);
if (!m_device->read_block(0, header_buffer)) {
return false;
}
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));
}
}

View file

@ -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);
virtual Type type() const override { return Type::MBR; };
virtual bool is_valid() const override { return m_valid; };
protected:
const Header& header() const;
bool is_header_valid() const { return m_header_valid; };
private:
NonnullRefPtr<BlockDevice> m_device;
const MBRPartitionHeader& header() const;
u8 m_cached_header[512];
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 };
};
}

View file

@ -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];
}
}

View file

@ -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;
};
}

View file

@ -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;
};

View file

@ -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;
NonnullRefPtrVector<StorageDevice> StorageManagement::storage_devices() 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());
}
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();
}
return devices;
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];
}
NonnullRefPtr<BlockDevice> StorageManagement::boot_block_device() const
{
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 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;
}
}

View file

@ -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;
};
}

View file

@ -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();
}

View file

@ -2,21 +2,21 @@ timeout=1
menuentry 'SerenityOS (normal)' {
root=hd0,5
multiboot /boot/Kernel root=/dev/hda5
multiboot /boot/Kernel root=/dev/hda4
}
menuentry 'SerenityOS (text mode)' {
root=hd0,5
multiboot /boot/Kernel boot_mode=text root=/dev/hda5
multiboot /boot/Kernel boot_mode=text root=/dev/hda4
}
menuentry 'SerenityOS (No ACPI)' {
root=hd0,5
multiboot /boot/Kernel root=/dev/hda5 acpi=off
multiboot /boot/Kernel root=/dev/hda4 acpi=off
}
menuentry 'SerenityOS (with serial debug)' {
root=hd0,5
multiboot /boot/Kernel serial_debug root=/dev/hda5
multiboot /boot/Kernel serial_debug root=/dev/hda4
}