diff --git a/Kernel/Devices/MBRPartitionTable.cpp b/Kernel/Devices/MBRPartitionTable.cpp new file mode 100644 index 0000000000..369be452e1 --- /dev/null +++ b/Kernel/Devices/MBRPartitionTable.cpp @@ -0,0 +1,61 @@ +#include +#include + +#define MBR_DEBUG + +MBRPartitionTable::MBRPartitionTable(Retained&& device) + : m_device(move(device)) +{ +} + +MBRPartitionTable::~MBRPartitionTable() +{ +} + +const MBRPartitionHeader& MBRPartitionTable::header() const +{ + return *reinterpret_cast(m_cached_header); +} + +bool MBRPartitionTable::initialize() +{ + if (!m_device->read_block(0, m_cached_header)) { + return false; + } + + auto& header = this->header(); + +#ifdef MBR_DEBUG + kprintf("MBRPartitionTable::initialize: mbr_signature=%#x\n", header.mbr_signature); +#endif + + if (header.mbr_signature != MBR_SIGNATURE) { + kprintf("MBRPartitionTable::initialize: bad mbr signature %#x\n", header.mbr_signature); + return false; + } + + return true; +} + +RetainPtr 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) { + kprintf("MBRPartitionTable::initialize: bad mbr signature - not initalized? %#x\n", header.mbr_signature); + return nullptr; + } + +#ifdef MBR_DEBUG + kprintf("MBRPartitionTable::partition: status=%#x offset=%#x\n", entry.status, entry.offset); +#endif + + if (entry.status == 0x00) { + return nullptr; + } + + return DiskPartition::create(m_device.copy_ref(), entry.offset); +} diff --git a/Kernel/Devices/MBRPartitionTable.h b/Kernel/Devices/MBRPartitionTable.h new file mode 100644 index 0000000000..a3ad937b2c --- /dev/null +++ b/Kernel/Devices/MBRPartitionTable.h @@ -0,0 +1,47 @@ +#pragma once + +#include +#include +#include +#include + +#define MBR_SIGNATURE 0xaa55 + +struct MBRPartitionEntry { + byte status; + byte chs1[3]; + byte type; + byte chs2[3]; + dword offset; + dword length; +} __attribute__((packed)); + +struct MBRPartitionHeader { + byte code1[218]; + word ts_zero; + byte ts_drive, ts_seconds, ts_minutes, ts_hours; + byte code2[216]; + dword disk_signature; + word disk_signature_zero; + MBRPartitionEntry entry[4]; + word mbr_signature; +} __attribute__((packed)); + +class MBRPartitionTable { + AK_MAKE_ETERNAL + +public: + MBRPartitionTable(Retained&& device); + ~MBRPartitionTable(); + + bool initialize(); + RetainPtr partition(unsigned index); + +private: + Retained m_device; + + ByteBuffer read_header() const; + const MBRPartitionHeader& header() const; + + byte m_cached_header[512]; +}; diff --git a/Kernel/Makefile b/Kernel/Makefile index 4da36b2020..ac124001d7 100644 --- a/Kernel/Makefile +++ b/Kernel/Makefile @@ -66,6 +66,7 @@ VFS_OBJS = \ Devices/RandomDevice.o \ Devices/DebugLogDevice.o \ Devices/DiskPartition.o \ + Devices/MBRPartitionTable.o \ FileSystem/FileSystem.o \ FileSystem/DiskBackedFileSystem.o \ FileSystem/Ext2FileSystem.o \ diff --git a/Kernel/init.cpp b/Kernel/init.cpp index e3992f7f1e..098e81c9d1 100644 --- a/Kernel/init.cpp +++ b/Kernel/init.cpp @@ -6,6 +6,7 @@ #include "Process.h" #include "PIC.h" #include +#include #include #include "KSyms.h" #include @@ -58,11 +59,6 @@ VFS* vfs; } #endif -// TODO: delete this magic number. this block offset corresponds to a -// partition that starts at 32k into an MBR disk. this value is also specified -// in sync.sh, but should ideally be read from the MBR header at startup. -#define PARTITION_OFFSET 62 - [[noreturn]] static void init_stage2() { Syscall::initialize(); @@ -71,10 +67,29 @@ VFS* vfs; auto dev_full = make(); auto dev_random = make(); auto dev_ptmx = make(); + + // TODO: decide what drive/partition to use based on cmdline from + // bootloader. currently hardcoded to the equivalent of hd0,1. + auto dev_hd0 = IDEDiskDevice::create(); - auto dev_hd0p1 = DiskPartition::create(dev_hd0.copy_ref(), PARTITION_OFFSET); - auto e2fs = Ext2FS::create(dev_hd0p1.copy_ref()); - e2fs->initialize(); + + MBRPartitionTable dev_hd0pt(dev_hd0.copy_ref()); + if (!dev_hd0pt.initialize()) { + kprintf("init_stage2: couldn't read MBR from disk"); + hang(); + } + + auto dev_hd0p1 = dev_hd0pt.partition(1); + if (!dev_hd0p1) { + kprintf("init_stage2: couldn't get first partition"); + hang(); + } + + auto e2fs = Ext2FS::create(*dev_hd0p1.copy_ref()); + if (!e2fs->initialize()) { + kprintf("init_stage2: couldn't open root filesystem"); + hang(); + } vfs->mount_root(e2fs.copy_ref()); @@ -89,7 +104,7 @@ VFS* vfs; auto* system_server_process = Process::create_user_process("/bin/SystemServer", (uid_t)100, (gid_t)100, (pid_t)0, error, { }, { }, tty0); if (error != 0) { - dbgprintf("error spawning SystemServer: %d\n", error); + dbgprintf("init_stage2: error spawning SystemServer: %d\n", error); hang(); } system_server_process->set_priority(Process::HighPriority);