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

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