mirror of
https://github.com/justinian/jsix.git
synced 2025-12-10 00:14:32 -08:00
Add GPT partition handling as virtual block devices
This commit is contained in:
@@ -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
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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); }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
114
src/kernel/fs/gpt.cpp
Normal 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
37
src/kernel/fs/gpt.h
Normal 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
|
||||||
@@ -15,6 +15,7 @@ static const char *areas[] = {
|
|||||||
"apic",
|
"apic",
|
||||||
"dev ",
|
"dev ",
|
||||||
"driv",
|
"driv",
|
||||||
|
"file",
|
||||||
|
|
||||||
nullptr
|
nullptr
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ enum class logs
|
|||||||
apic,
|
apic,
|
||||||
device,
|
device,
|
||||||
driver,
|
driver,
|
||||||
|
fs,
|
||||||
|
|
||||||
max
|
max
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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,19 +96,21 @@ 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) {
|
||||||
uint8_t buf[512];
|
for (int i=0; i<1; ++i) {
|
||||||
kutil::memset(buf, 0, 512);
|
uint8_t buf[512];
|
||||||
|
kutil::memset(buf, 0, 512);
|
||||||
|
|
||||||
kassert(disk->read(0x200, sizeof(buf), buf),
|
kassert(disk->read(0x200, sizeof(buf), buf),
|
||||||
"Disk read returned 0");
|
"Disk read returned 0");
|
||||||
|
|
||||||
console *cons = console::get();
|
console *cons = console::get();
|
||||||
uint8_t *p = &buf[0];
|
uint8_t *p = &buf[0];
|
||||||
for (int i = 0; i < 8; ++i) {
|
for (int i = 0; i < 8; ++i) {
|
||||||
for (int j = 0; j < 16; ++j) {
|
for (int j = 0; j < 16; ++j) {
|
||||||
cons->printf(" %02x", *p++);
|
cons->printf(" %02x", *p++);
|
||||||
|
}
|
||||||
|
cons->putc('\n');
|
||||||
}
|
}
|
||||||
cons->putc('\n');
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
log::warn(logs::boot, "No block devices present.");
|
log::warn(logs::boot, "No block devices present.");
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user