From eb909686f19073b324dee15366b957802dc095a7 Mon Sep 17 00:00:00 2001 From: Aqua-sama Date: Sun, 14 Mar 2021 23:08:46 +0200 Subject: CGA: map and set buffer address in kernel main --- drivers/cga.cc | 20 +++++++++--------- drivers/cga.h | 5 ++++- src/boot.S | 16 +++++++-------- src/kernel.cc | 18 +++++++++------- src/vmm.cc | 65 ++++++++++++++++++++++++---------------------------------- src/vmm.h | 57 ++++++++++++++++++++++++++++++++++++++------------ 6 files changed, 103 insertions(+), 78 deletions(-) diff --git a/drivers/cga.cc b/drivers/cga.cc index 6589cee..51b7221 100644 --- a/drivers/cga.cc +++ b/drivers/cga.cc @@ -21,31 +21,31 @@ constexpr uint8_t cursor_addr_l = 15; // 0xf * 1 1 | blink fast */ constexpr uint8_t cursor_hide = 0b00100000; -constexpr uint32_t address = 0xc03ff000; -CGA::CGA() { +void CGA::set_buffer(uint32_t address) { buffer = reinterpret_cast(address); + clear(); + enable_cursor(14, 15); + update_cursor(); +} - // clear buffer +void CGA::set_colour(Colour fg, Colour bg) { + colour_fg = fg; + colour_bg = bg; for (size_t y = 0; y < max_rows; y++) { for (size_t x = 0; x < max_columns; x++) { const size_t index = y * max_columns + x; - buffer[index].c = ' '; buffer[index].fg = colour_fg; buffer[index].bg = colour_bg; } } - - enable_cursor(14, 15); - update_cursor(); } -void CGA::set_colour(Colour fg, Colour bg) { - colour_fg = fg; - colour_bg = bg; +void CGA::clear() { for (size_t y = 0; y < max_rows; y++) { for (size_t x = 0; x < max_columns; x++) { const size_t index = y * max_columns + x; + buffer[index].c = ' '; buffer[index].fg = colour_fg; buffer[index].bg = colour_bg; } diff --git a/drivers/cga.h b/drivers/cga.h index f4dfb3c..ec207c4 100644 --- a/drivers/cga.h +++ b/drivers/cga.h @@ -35,10 +35,13 @@ public: CGA_COLOR_WHITE = 15, }; - CGA(); + CGA() = default; ~CGA() = default; + void set_buffer(uint32_t); + void set_colour(Colour fg, Colour bg); + void clear(); void enable_cursor(uint8_t start, uint8_t end); void disable_cursor(); diff --git a/src/boot.S b/src/boot.S index d1c4f9b..e39883e 100644 --- a/src/boot.S +++ b/src/boot.S @@ -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)}; diff --git a/src/vmm.cc b/src/vmm.cc index 483f02f..3c90c48 100644 --- a/src/vmm.cc +++ b/src/vmm.cc @@ -1,5 +1,4 @@ #include "vmm.h" -#include 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(directory)}, '\n'); - printk("page table 768 ", uhex{reinterpret_cast(directory[768])}, '\n'); - printk("page table 768 vma ", uhex{to_vma(reinterpret_cast(directory[768]))}, '\n'); - printk("kernel_ptable0 is at ", uhex{reinterpret_cast(&kernel_ptable0)}, '\n'); - - uint32_t* page = reinterpret_cast(&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 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{vmm::TableNotAllocated}; - if (directory[table] == 0) return 0; + page_table table{directory[dest.table_idx]}; - uint32_t* page_table = reinterpret_cast(to_vma(reinterpret_cast(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{dest + phys_offset}; + } else + return Result{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(&VADDR_OFFSET); - return table * 4 * 1024 * 1024 + page * 4 * 1024 + phys_offset; + pages = reinterpret_cast(from); } diff --git a/src/vmm.h b/src/vmm.h index 9de487b..252e5bb 100644 --- a/src/vmm.h +++ b/src/vmm.h @@ -1,31 +1,62 @@ -#include - #pragma once +#include +#include 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(addr & 0x3ff)}, + page_idx{static_cast((addr >> 12) & 0x3ff)}, + table_idx{static_cast(addr >> 22)} {} + + constexpr address(size_t table, size_t page) : page_idx{page}, table_idx{table} {} + + constexpr operator uint32_t() const { + return static_cast(table_idx << 22) | static_cast(page_idx << 12) | + static_cast(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(offset); } - constexpr static size_t page_id(uint32_t offset) { return static_cast(offset / 4096); } + [[deprecated]] constexpr static size_t page_id(uint32_t offset) { return static_cast(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 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); -- cgit v1.2.1