mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-22 07:30:19 +00:00
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:
parent
bc18712adf
commit
72b1998f0d
Notes:
sideshowbarker
2024-07-19 00:31:24 +09:00
Author: https://github.com/supercomputer7 Commit: https://github.com/SerenityOS/serenity/commit/72b1998f0d2 Pull-request: https://github.com/SerenityOS/serenity/pull/4527 Reviewed-by: https://github.com/awesomekling Reviewed-by: https://github.com/bugaevc
20 changed files with 639 additions and 561 deletions
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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 };
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -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]);
|
||||
}
|
||||
|
||||
}
|
153
Kernel/Storage/Partition/GUIDPartitionTable.cpp
Normal file
153
Kernel/Storage/Partition/GUIDPartitionTable.cpp
Normal 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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
|
@ -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));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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 };
|
||||
};
|
||||
|
||||
}
|
||||
|
|
42
Kernel/Storage/Partition/PartitionTable.cpp
Normal file
42
Kernel/Storage/Partition/PartitionTable.cpp
Normal 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];
|
||||
}
|
||||
|
||||
}
|
67
Kernel/Storage/Partition/PartitionTable.h
Normal file
67
Kernel/Storage/Partition/PartitionTable.h
Normal 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;
|
||||
};
|
||||
|
||||
}
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue