diff --git a/src/kernel/ahci/hba.cpp b/src/kernel/ahci/hba.cpp index 9182137..5eb28f4 100644 --- a/src/kernel/ahci/hba.cpp +++ b/src/kernel/ahci/hba.cpp @@ -3,6 +3,7 @@ #include "ahci/hba.h" #include "console.h" #include "device_manager.h" +#include "fs/gpt.h" #include "log.h" #include "page_manager.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); if (p.get_state() == port::state::active) needs_interrupt = true; - - if (p.get_type() == sata_signature::sata_drive) - dm.register_block_device(&p); } if (needs_interrupt) { device_manager::get().allocate_msi("AHCI Device", *device, irq_cb, this); 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 diff --git a/src/kernel/ahci/port.cpp b/src/kernel/ahci/port.cpp index f81030c..52e3eac 100644 --- a/src/kernel/ahci/port.cpp +++ b/src/kernel/ahci/port.cpp @@ -387,6 +387,9 @@ port::finish_read(int slot) static_cast(cmdt.entries[i].data_base_high) << 32; 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); p = kutil::offset_pointer(p, prd_len - offset); count += (prd_len - offset); diff --git a/src/kernel/allocator.cpp b/src/kernel/allocator.cpp index a71650b..c670b70 100644 --- a/src/kernel/allocator.cpp +++ b/src/kernel/allocator.cpp @@ -1,9 +1,18 @@ #include "kutil/memory_manager.h" +#include "log.h" kutil::memory_manager g_kernel_memory_manager; // kutil malloc/free implementation 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); } + } diff --git a/src/kernel/block_device.h b/src/kernel/block_device.h index 3a2ebfb..4e8cd49 100644 --- a/src/kernel/block_device.h +++ b/src/kernel/block_device.h @@ -1,6 +1,7 @@ #pragma once /// \file block_device.h /// Interface definition for block devices +#include /// Interface for block devices class block_device diff --git a/src/kernel/fs/gpt.cpp b/src/kernel/fs/gpt.cpp new file mode 100644 index 0000000..2de0b88 --- /dev/null +++ b/src/kernel/fs/gpt.cpp @@ -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(&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(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 diff --git a/src/kernel/fs/gpt.h b/src/kernel/fs/gpt.h new file mode 100644 index 0000000..45b8274 --- /dev/null +++ b/src/kernel/fs/gpt.h @@ -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 diff --git a/src/kernel/log.cpp b/src/kernel/log.cpp index e0ca21c..04c61c8 100644 --- a/src/kernel/log.cpp +++ b/src/kernel/log.cpp @@ -15,6 +15,7 @@ static const char *areas[] = { "apic", "dev ", "driv", + "file", nullptr }; diff --git a/src/kernel/log.h b/src/kernel/log.h index f175edc..1a2d5c5 100644 --- a/src/kernel/log.h +++ b/src/kernel/log.h @@ -12,6 +12,7 @@ enum class logs apic, device, driver, + fs, max }; diff --git a/src/kernel/main.cpp b/src/kernel/main.cpp index ddb5534..2e87e99 100644 --- a/src/kernel/main.cpp +++ b/src/kernel/main.cpp @@ -54,6 +54,7 @@ init_console(const popcorn_data *header) log::enable(logs::device, log::level::debug); log::enable(logs::driver, 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; } @@ -95,19 +96,21 @@ kernel_main(popcorn_data *header) block_device *disk = devices->get_block_device(0); if (disk) { - uint8_t buf[512]; - kutil::memset(buf, 0, 512); + for (int i=0; i<1; ++i) { + uint8_t buf[512]; + kutil::memset(buf, 0, 512); - kassert(disk->read(0x200, sizeof(buf), buf), - "Disk read returned 0"); + kassert(disk->read(0x200, sizeof(buf), buf), + "Disk read returned 0"); - console *cons = console::get(); - uint8_t *p = &buf[0]; - for (int i = 0; i < 8; ++i) { - for (int j = 0; j < 16; ++j) { - cons->printf(" %02x", *p++); + console *cons = console::get(); + uint8_t *p = &buf[0]; + for (int i = 0; i < 8; ++i) { + for (int j = 0; j < 16; ++j) { + cons->printf(" %02x", *p++); + } + cons->putc('\n'); } - cons->putc('\n'); } } else { log::warn(logs::boot, "No block devices present."); diff --git a/src/kernel/page_manager.cpp b/src/kernel/page_manager.cpp index 275e1b6..ceab902 100644 --- a/src/kernel/page_manager.cpp +++ b/src/kernel/page_manager.cpp @@ -374,7 +374,6 @@ page_manager::map_offset_pages(size_t count) page_block *free = m_free; page_block *prev = nullptr; - log::debug(logs::memory, "Got request to offset map %d pages", count); while (free) { if (free->count < count) { @@ -405,6 +404,7 @@ page_manager::map_offset_pages(size_t count) 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); return reinterpret_cast(used->virtual_address); }