aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAqua-sama <aqua@iserlohn-fortress.net>2021-03-14 23:08:46 +0200
committerAqua-sama <aqua@iserlohn-fortress.net>2021-03-14 23:08:46 +0200
commiteb909686f19073b324dee15366b957802dc095a7 (patch)
tree4adf50f94a19f8d2ed76fe9d181bafd8e1fb16fd
parentAdd GPL3 license (diff)
downloadkernel.cpp-eb909686f19073b324dee15366b957802dc095a7.tar.xz
CGA: map and set buffer address in kernel main
-rw-r--r--drivers/cga.cc20
-rw-r--r--drivers/cga.h5
-rw-r--r--src/boot.S16
-rw-r--r--src/kernel.cc18
-rw-r--r--src/vmm.cc65
-rw-r--r--src/vmm.h57
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<Entry*>(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 <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);
}
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 <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);