Ver código fonte

Kernel: Implement MBR partition loader (#168)

This implements a basic MBR partition loader, which removes the reliance
on a hard-coded filesystem offset in the stage2 init.
Conrad Pankoff 6 anos atrás
pai
commit
c02b8b715d

+ 61 - 0
Kernel/Devices/MBRPartitionTable.cpp

@@ -0,0 +1,61 @@
+#include <AK/ByteBuffer.h>
+#include <Kernel/Devices/MBRPartitionTable.h>
+
+#define MBR_DEBUG
+
+MBRPartitionTable::MBRPartitionTable(Retained<DiskDevice>&& device)
+    : m_device(move(device))
+{
+}
+
+MBRPartitionTable::~MBRPartitionTable()
+{
+}
+
+const MBRPartitionHeader& MBRPartitionTable::header() const
+{
+    return *reinterpret_cast<const MBRPartitionHeader*>(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<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) {
+        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);
+}

+ 47 - 0
Kernel/Devices/MBRPartitionTable.h

@@ -0,0 +1,47 @@
+#pragma once
+
+#include <AK/RetainPtr.h>
+#include <AK/Vector.h>
+#include <Kernel/Devices/DiskDevice.h>
+#include <Kernel/Devices/DiskPartition.h>
+
+#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<DiskDevice>&& device);
+    ~MBRPartitionTable();
+
+    bool initialize();
+    RetainPtr<DiskPartition> partition(unsigned index);
+
+private:
+    Retained<DiskDevice> m_device;
+
+    ByteBuffer read_header() const;
+    const MBRPartitionHeader& header() const;
+
+    byte m_cached_header[512];
+};

+ 1 - 0
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 \

+ 24 - 9
Kernel/init.cpp

@@ -6,6 +6,7 @@
 #include "Process.h"
 #include "PIC.h"
 #include <Kernel/Devices/IDEDiskDevice.h>
+#include <Kernel/Devices/MBRPartitionTable.h>
 #include <Kernel/Devices/DiskPartition.h>
 #include "KSyms.h"
 #include <Kernel/Devices/NullDevice.h>
@@ -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<FullDevice>();
     auto dev_random = make<RandomDevice>();
     auto dev_ptmx = make<PTYMultiplexer>();
+
+    // 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);