diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/boot.S | 16 | ||||
-rw-r--r-- | src/kernel.cc | 18 | ||||
-rw-r--r-- | src/vmm.cc | 65 | ||||
-rw-r--r-- | src/vmm.h | 57 |
4 files changed, 89 insertions, 67 deletions
@@ -51,9 +51,10 @@ kernel_ptable0: bootloader will jump to this position once the kernel has been loaded. */ .section .multiboot.text, "ax" +.global VADDR_OFFSET .set VADDR_OFFSET, 0xc0000000 - 0x400000 .global _start -.type _start, @function + .type _start, @function _start: cli @@ -62,12 +63,12 @@ _start: # Only map the kernel. mov $_kernel_start - VADDR_OFFSET, %esi - # Map 1023 pages. The 1024th will be the VGA text buffer. - movl $1023, %ecx + # Map 1024 pages + movl $1024, %ecx l_page_init: - cmpl $(_kernel_end - VADDR_OFFSET), %esi - jge map_vga + cmpl $(_kernel_end - VADDR_OFFSET), %esi + jge map_table /* TODO: Map physical address as "present, writable". Note that this maps .text and .rodata as writable. Mind security and map them as non-writable. */ @@ -82,10 +83,7 @@ l_page_init: # Loop to the next entry if we haven't finished. loop l_page_init -map_vga: - # Map VGA video memory to 0xC03FF000 as "present, writable". - movl $(0x000B8000 | 0x003), kernel_ptable0 - VADDR_OFFSET + 1023 * 4 - +map_table: /* Enabling paging does not change the next instruction, which continues to be physical. Therefore, map the kernel to both its physical address and to the higher half. diff --git a/src/kernel.cc b/src/kernel.cc index 0915365..0d8874c 100644 --- a/src/kernel.cc +++ b/src/kernel.cc @@ -18,6 +18,8 @@ #include "serial.h" #include "vmm.h" +/* hardware */ +vmm kvmm; #include "hardware.h" extern "C" { @@ -25,13 +27,17 @@ void dump_multiboot(uint32_t mb_magic, uint32_t mb_addr); void dump_gdt(); void kernel_main([[maybe_unused]] uint32_t mb_magic, [[maybe_unused]] uint32_t mb_addr) { + #ifdef HAS_SERIAL0 if constexpr (serial0_console) if (serial0.self_check()) Console::set(&serial0); #endif #ifdef HAS_VIDEO0 - if constexpr (video0_console) Console::set(&video0); + if (const auto cga_buffer_r = kvmm.map(0xb8000, 0xc03f3000)) { + video0.set_buffer(cga_buffer_r.value()); + if constexpr (video0_console) Console::set(&video0); + } #endif printk("Hello, kernel World!\n"); @@ -40,12 +46,10 @@ void kernel_main([[maybe_unused]] uint32_t mb_magic, [[maybe_unused]] uint32_t m // dump_gdt(); // - vmm kvmm; - mb_addr = kvmm.map(mb_addr, 0xc03fe000); - - dump_multiboot(mb_magic, mb_addr); - // - // + if (const auto mb_addr_r = kvmm.map(mb_addr, 0xc03fe000)) { + mb_addr = mb_addr_r.value(); + // dump_multiboot(mb_magic, mb_addr); + } GDT gdt; IDT idt{gdt.descriptor(GDT::kcode)}; @@ -1,5 +1,4 @@ #include "vmm.h" -#include <stdlib.h> typedef void (*constructor)(); @@ -49,51 +48,41 @@ void dump_address() { } } // extern "C" -/* boot.S page directory and kernel page table */ +/* boot.S externs */ extern uint32_t kernel_pagedir; extern uint32_t kernel_ptable0; +extern uint32_t VADDR_OFFSET; -constexpr uint32_t to_vma(uint32_t page_dir_address) { - page_dir_address &= 0xfffff000; - page_dir_address += 0xc0000000; - page_dir_address -= 0x00400000; - return page_dir_address; -} - -vmm::vmm(uint32_t* addr) : directory{(addr == nullptr) ? &kernel_pagedir : addr} { - printk("page directory is at ", uhex{reinterpret_cast<uint32_t>(directory)}, '\n'); - printk("page table 768 ", uhex{reinterpret_cast<uint32_t>(directory[768])}, '\n'); - printk("page table 768 vma ", uhex{to_vma(reinterpret_cast<uint32_t>(directory[768]))}, '\n'); - printk("kernel_ptable0 is at ", uhex{reinterpret_cast<uint32_t>(&kernel_ptable0)}, '\n'); - - uint32_t* page = reinterpret_cast<uint32_t*>(&kernel_ptable0); - for (size_t i = 0; i < 32; ++i) { - printk(uhex{page[i] & 0xfffff000}, ' '); - if (i % 4 == 3) printk('\n'); - } -} +/* vmm */ +static_assert(sizeof(vmm::address) == 4); +static_assert(vmm::address(0xc03ff000) == 0xc03ff000); +static_assert(vmm::address(0xc03ff000).table_idx == 768); +static_assert(vmm::address(0xc03ff000).page_idx == 1023); +static_assert(vmm::address(0xc03ff000).offset == 0); -uint32_t vmm::map(uint32_t phys_addr, uint32_t dest) { - const auto phys_offset = phys_addr % 4096; - const auto phys_page = phys_addr - phys_offset; +vmm::vmm(uint32_t* addr) : directory{(addr == nullptr) ? &kernel_pagedir : addr} {} - const auto table = table_id(dest); - const auto page = page_id(dest - table * 4 * 1024 * 1024); +Result<uint32_t, vmm::Error> vmm::map(uint32_t addr, const vmm::address dest) { + const auto phys_offset = addr % 4096; + const auto phys_paddr = addr & 0xfffff000; - printk("phys_addr page: ", uhex{phys_page}, '\n'); - printk(" offset: ", uhex{phys_offset}, '\n'); - printk(" table: ", table, '\n'); - printk(" page: ", page, '\n'); + // TODO allocate page table + if (directory[dest.table_idx] == 0) return Result<uint32_t, vmm::Error>{vmm::TableNotAllocated}; - if (directory[table] == 0) return 0; + page_table table{directory[dest.table_idx]}; - uint32_t* page_table = reinterpret_cast<uint32_t*>(to_vma(reinterpret_cast<uint32_t>(directory[table]))); - if (page_table[page] != 0) return 0; - page_table[page] = phys_page | 0x003; + if (table.set(dest.page_idx, phys_paddr)) { + vmm::reload(); + return Result<uint32_t, vmm::Error>{dest + phys_offset}; + } else + return Result<uint32_t, vmm::Error>{vmm::AddressAlreadyMapped}; +} - uint32_t cr0; - asm volatile("mov %%cr0, %0" : "=r"(cr0)); - asm volatile("mov %0, %%cr0" : : "r"(cr0)); +vmm::page_table::page_table(uint32_t from) { + // TODO get flags + // convert physical address to a virtual address so we can read it + from &= 0xfffff000; // discard flags + from += reinterpret_cast<uint32_t>(&VADDR_OFFSET); - return table * 4 * 1024 * 1024 + page * 4 * 1024 + phys_offset; + pages = reinterpret_cast<uint32_t*>(from); } @@ -1,31 +1,62 @@ -#include <stdlib.h> - #pragma once +#include <result.h> +#include <stdlib.h> extern "C" void dump_address(); -struct page_table { - uint32_t* addr; -}; - class vmm { public: + enum Error { NoError, TableNotAllocated, AddressAlreadyMapped }; + + struct address { + size_t offset : 12 = 0; + size_t page_idx : 10 = 0; + size_t table_idx : 10 = 0; + + constexpr address(uint32_t addr) + : offset{static_cast<size_t>(addr & 0x3ff)}, + page_idx{static_cast<size_t>((addr >> 12) & 0x3ff)}, + table_idx{static_cast<size_t>(addr >> 22)} {} + + constexpr address(size_t table, size_t page) : page_idx{page}, table_idx{table} {} + + constexpr operator uint32_t() const { + return static_cast<uint32_t>(table_idx << 22) | static_cast<uint32_t>(page_idx << 12) | + static_cast<uint32_t>(offset); + } + } __attribute__((packed)); + vmm(uint32_t* addr = nullptr); - constexpr static size_t table_id(uint32_t offset) { + [[deprecated]] constexpr static size_t table_id(uint32_t offset) { offset &= 0xfff00000; offset /= (4 * 1024 * 1024); return static_cast<size_t>(offset); } - constexpr static size_t page_id(uint32_t offset) { return static_cast<size_t>(offset / 4096); } + [[deprecated]] constexpr static size_t page_id(uint32_t offset) { return static_cast<size_t>(offset / 4096); } - uint32_t map(uint32_t phys_addr, uint32_t offset); + static void reload() { + uint32_t cr0; + asm volatile("mov %%cr0, %0" : "=r"(cr0)); + asm volatile("mov %0, %%cr0" : : "r"(cr0)); + } + + [[nodiscard]] Result<uint32_t, Error> map(uint32_t phys_addr, const address dest); private: + class page_table { + public: + page_table(uint32_t); + bool set(size_t idx, uint32_t a) { + if (pages[idx] != 0) return false; + pages[idx] = a | 0x003; + return true; + } + + private: + uint32_t* pages; + }; + uint32_t* directory; }; -static_assert(vmm::table_id(0x00001234) == 0); -static_assert(vmm::table_id(0x00400000) == 1); -static_assert(vmm::table_id(0xc0000000) == 768); -static_assert(vmm::table_id(0xc03ff000) == 768); |