Add GPT partition handling as virtual block devices

This commit is contained in:
Justin C. Miller
2018-05-16 10:14:40 -07:00
parent a5da56d02f
commit 0d75cc999c
10 changed files with 191 additions and 16 deletions

View File

@@ -3,6 +3,7 @@
#include "ahci/hba.h" #include "ahci/hba.h"
#include "console.h" #include "console.h"
#include "device_manager.h" #include "device_manager.h"
#include "fs/gpt.h"
#include "log.h" #include "log.h"
#include "page_manager.h" #include "page_manager.h"
#include "pci.h" #include "pci.h"
@@ -85,15 +86,20 @@ hba::hba(pci_device *device)
port &p = m_ports.emplace(this, i, kutil::offset_pointer(pd, 0x80 * i), impl); port &p = m_ports.emplace(this, i, kutil::offset_pointer(pd, 0x80 * i), impl);
if (p.get_state() == port::state::active) if (p.get_state() == port::state::active)
needs_interrupt = true; needs_interrupt = true;
if (p.get_type() == sata_signature::sata_drive)
dm.register_block_device(&p);
} }
if (needs_interrupt) { if (needs_interrupt) {
device_manager::get().allocate_msi("AHCI Device", *device, irq_cb, this); device_manager::get().allocate_msi("AHCI Device", *device, irq_cb, this);
m_data->host_control |= 0x02; // enable interrupts m_data->host_control |= 0x02; // enable interrupts
} }
for (auto &p : m_ports) {
if (p.get_state() == port::state::active &&
p.get_type() == sata_signature::sata_drive) {
if (fs::partition::load(&p) == 0)
dm.register_block_device(&p);
}
}
} }
void void

View File

@@ -387,6 +387,9 @@ port::finish_read(int slot)
static_cast<addr_t>(cmdt.entries[i].data_base_high) << 32; static_cast<addr_t>(cmdt.entries[i].data_base_high) << 32;
void *mem = kutil::offset_pointer(pm->offset_virt(phys), offset); void *mem = kutil::offset_pointer(pm->offset_virt(phys), offset);
log::debug(logs::driver, "Reading PRD %2d: %016lx->%016lx [%lxb]", i, mem, p, prd_len);
kutil::memcpy(p, mem, prd_len); kutil::memcpy(p, mem, prd_len);
p = kutil::offset_pointer(p, prd_len - offset); p = kutil::offset_pointer(p, prd_len - offset);
count += (prd_len - offset); count += (prd_len - offset);

View File

@@ -1,9 +1,18 @@
#include "kutil/memory_manager.h" #include "kutil/memory_manager.h"
#include "log.h"
kutil::memory_manager g_kernel_memory_manager; kutil::memory_manager g_kernel_memory_manager;
// kutil malloc/free implementation // kutil malloc/free implementation
namespace kutil { namespace kutil {
void * malloc(size_t n) { return g_kernel_memory_manager.allocate(n); }
void free(void *p) { g_kernel_memory_manager.free(p); } void *
malloc(size_t n) {
void *p = g_kernel_memory_manager.allocate(n);
log::debug(logs::memory, "Heap allocated %ld bytes: %016lx", n, p);
return p;
}
void free(void *p) { g_kernel_memory_manager.free(p); }
} }

View File

@@ -1,6 +1,7 @@
#pragma once #pragma once
/// \file block_device.h /// \file block_device.h
/// Interface definition for block devices /// Interface definition for block devices
#include <stddef.h>
/// Interface for block devices /// Interface for block devices
class block_device class block_device

114
src/kernel/fs/gpt.cpp Normal file
View File

@@ -0,0 +1,114 @@
#include "kutil/assert.h"
#include "kutil/guid.h"
#include "kutil/memory.h"
#include "device_manager.h"
#include "fs/gpt.h"
#include "log.h"
namespace fs {
const kutil::guid efi_system_part = kutil::make_guid(0xC12A7328, 0xF81F, 0x11D2, 0xBA4B, 0x00A0C93EC93B);
const kutil::guid efi_unused_part = kutil::make_guid(0, 0, 0, 0, 0);
const uint64_t gpt_signature = 0x5452415020494645; // "EFI PART"
const size_t block_size = 512;
struct gpt_header
{
uint64_t signature;
uint32_t revision;
uint32_t headersize;
uint32_t crc32;
uint32_t reserved;
uint64_t my_lba;
uint64_t alt_lba;
uint64_t first_usable_lba;
uint64_t last_usable_lba;
kutil::guid disk_guid;
uint64_t table_lba;
uint32_t entry_count;
uint32_t entry_length;
uint32_t table_crc32;
} __attribute__ ((packed));
struct gpt_entry
{
kutil::guid type;
kutil::guid part_guid;
uint64_t start_lba;
uint64_t end_lba;
uint64_t attributes;
uint16_t name_wide[36];
} __attribute__ ((packed));
partition::partition(block_device *parent, size_t start, size_t length) :
m_parent(parent),
m_start(start),
m_length(length)
{
}
size_t
partition::read(size_t offset, size_t length, void *buffer)
{
if (offset + length > m_length)
offset = m_length - offset;
return m_parent->read(m_start + offset, length, buffer);
}
unsigned
partition::load(block_device *device)
{
// Read LBA 1
uint8_t block[block_size];
size_t count = device->read(block_size, block_size, &block);
kassert(count == block_size, "Short read for GPT header.");
gpt_header *header = reinterpret_cast<gpt_header *>(&block);
if (header->signature != gpt_signature)
return 0;
size_t arraysize = header->entry_length * header->entry_count;
log::debug(logs::fs, "Found GPT header: %d paritions, size 0x%lx",
header->entry_count, arraysize);
uint8_t *array = new uint8_t[arraysize];
count = device->read(block_size * header->table_lba, arraysize, array);
kassert(count == arraysize, "Short read for GPT entry array.");
auto &dm = device_manager::get();
unsigned found = 0;
gpt_entry *entry0 = reinterpret_cast<gpt_entry *>(array);
for (uint32_t i = 0; i < header->entry_count; ++i) {
gpt_entry *entry = kutil::offset_pointer(entry0, i * header->entry_length);
if (entry->type == efi_unused_part) continue;
// TODO: real UTF16->UTF8
char name[sizeof(gpt_entry::name_wide) / 2];
for (int i = 0; i < sizeof(name); ++i)
name[i] = entry->name_wide[i];
log::debug(logs::fs, "Found partition %02x at %lx-%lx", i, entry->start_lba, entry->end_lba);
if (entry->type == efi_system_part)
log::debug(logs::fs, " type EFI SYSTEM PARTITION");
else
log::debug(logs::fs, " type %G", entry->type);
log::debug(logs::fs, " name %s", name);
log::debug(logs::fs, " attr %016lx", entry->attributes);
found += 1;
partition *part = new partition(
device,
entry->start_lba * block_size,
(entry->end_lba - entry->start_lba) * block_size);
dm.register_block_device(part);
}
return found;
}
} // namespace fs

37
src/kernel/fs/gpt.h Normal file
View File

@@ -0,0 +1,37 @@
#pragma once
/// \file gpt.h
/// Definitions for dealing with GUID Partition Tables
#include "block_device.h"
namespace fs {
class partition :
public block_device
{
public:
/// Constructor.
/// \arg parent The block device this partition is a part of
/// \arg start The starting offset in bytes from the start of the parent
/// \arg lenght The length in bytes of this partition
partition(block_device *parent, size_t start, size_t length);
/// Read bytes from the partition.
/// \arg offset The offset in bytes at which to start reading
/// \arg length The number of bytes to read
/// \arg buffer [out] Data is read into this buffer
/// \returns The number of bytes read
virtual size_t read(size_t offset, size_t length, void *buffer);
/// Find partitions on a block device and add them to the device manager
/// \arg device The device to search for partitions
/// \returns The number of partitions found
static unsigned load(block_device *device);
private:
block_device *m_parent;
size_t m_start;
size_t m_length;
};
} // namespace fs

View File

@@ -15,6 +15,7 @@ static const char *areas[] = {
"apic", "apic",
"dev ", "dev ",
"driv", "driv",
"file",
nullptr nullptr
}; };

View File

@@ -12,6 +12,7 @@ enum class logs
apic, apic,
device, device,
driver, driver,
fs,
max max
}; };

View File

@@ -54,6 +54,7 @@ init_console(const popcorn_data *header)
log::enable(logs::device, log::level::debug); log::enable(logs::device, log::level::debug);
log::enable(logs::driver, log::level::debug); log::enable(logs::driver, log::level::debug);
log::enable(logs::memory, log::level::debug); log::enable(logs::memory, log::level::debug);
log::enable(logs::fs, log::level::debug);
} }
void do_error_3() { volatile int x = 1; volatile int y = 0; volatile int z = x / y; } void do_error_3() { volatile int x = 1; volatile int y = 0; volatile int z = x / y; }
@@ -95,6 +96,7 @@ kernel_main(popcorn_data *header)
block_device *disk = devices->get_block_device(0); block_device *disk = devices->get_block_device(0);
if (disk) { if (disk) {
for (int i=0; i<1; ++i) {
uint8_t buf[512]; uint8_t buf[512];
kutil::memset(buf, 0, 512); kutil::memset(buf, 0, 512);
@@ -109,6 +111,7 @@ kernel_main(popcorn_data *header)
} }
cons->putc('\n'); cons->putc('\n');
} }
}
} else { } else {
log::warn(logs::boot, "No block devices present."); log::warn(logs::boot, "No block devices present.");
} }

View File

@@ -374,7 +374,6 @@ page_manager::map_offset_pages(size_t count)
page_block *free = m_free; page_block *free = m_free;
page_block *prev = nullptr; page_block *prev = nullptr;
log::debug(logs::memory, "Got request to offset map %d pages", count);
while (free) { while (free) {
if (free->count < count) { if (free->count < count) {
@@ -405,6 +404,7 @@ page_manager::map_offset_pages(size_t count)
m_block_cache = free; m_block_cache = free;
} }
log::debug(logs::memory, "Got request for offset map %016lx [%d]", used->virtual_address, count);
page_in(pml4, used->physical_address, used->virtual_address, count); page_in(pml4, used->physical_address, used->virtual_address, count);
return reinterpret_cast<void *>(used->virtual_address); return reinterpret_cast<void *>(used->virtual_address);
} }