diff options
-rw-r--r-- | kernel/CMakeLists.txt | 1 | ||||
-rw-r--r-- | kernel/include/common.h | 11 | ||||
-rw-r--r-- | kernel/include/mm/virtual_mm.h | 45 | ||||
-rw-r--r-- | kernel/kernel/kernel.c | 4 | ||||
-rw-r--r-- | kernel/mm/virtual_mm/virtual_mm.c | 104 |
5 files changed, 146 insertions, 19 deletions
diff --git a/kernel/CMakeLists.txt b/kernel/CMakeLists.txt index 204295d..72365fb 100644 --- a/kernel/CMakeLists.txt +++ b/kernel/CMakeLists.txt @@ -38,6 +38,7 @@ set(C_COMPILE_OPTIONS -Wall -Wextra -pedantic + -Werror -g ) diff --git a/kernel/include/common.h b/kernel/include/common.h index 9fa2011..2e1faa3 100644 --- a/kernel/include/common.h +++ b/kernel/include/common.h @@ -26,7 +26,14 @@ #define MiB (KiB * KiB) #define ASSERT_NOT_REACHED() \ - printk("ASSERTION FAILED", "[%s] SHOULD NOT BE REACHED.", __func__); \ - halt(); + { \ + printk("ASSERTION FAILED", \ + "[%s]:%lu SHOULD NOT BE REACHED.", \ + __func__, \ + __LINE__); \ + /* TODO: We should probably remove this exit() eventually */ \ + exit(); \ + halt(); \ + } #endif diff --git a/kernel/include/mm/virtual_mm.h b/kernel/include/mm/virtual_mm.h index 3f938d2..ad2b961 100644 --- a/kernel/include/mm/virtual_mm.h +++ b/kernel/include/mm/virtual_mm.h @@ -29,20 +29,22 @@ #define PAGE_DIRECTORY_INDEX(virtual_address) ((virtual_address >> 22) & 0x3ff) #define PAGE_TABLE_INDEX(virtual_address) ((virtual_address >> 12) & 0x3ff) -#define PDE_PRESENT 1 -#define PDE_WRITABLE (1 << 1) -#define PDE_USER (1 << 2) -#define PDE_WRITETHROUGH (1 << 3) -#define PDE_CACHE_DISABLE (1 << 4) -#define PDE_ACCESSED (1 << 5) +#define SET_PDE_PRESENT(x) x +#define SET_PDE_WRITABLE(x) (x << 1) +#define SET_PDE_USER(x) (x << 2) +#define SET_PDE_WRITETHROUGH(x) (x << 3) +#define SET_PDE_CACHE_DISABLE(x) (x << 4) +#define SET_PDE_ACCESSED(x) (x << 5) /* Never set (reserved by Intel) */ -#define PDE_RESERVED (0 << 6) -#define PDE_PAGE_SIZE (1 << 7) -#define PDE_GLOBAL (1 << 8) +#define SET_PDE_RESERVED(x) (x << 6) +#define SET_PDE_PAGE_SIZE(x) (x << 7) +#define SET_PDE_GLOBAL(x) (x << 8) /* NOTE: Unused by the CPU, free to be used by us! */ -#define PDE_UNUSED(x) (x << 9) +#define SET_PDE_UNUSED(x) (x << 9) /* Page table address */ -#define PDE_FRAME(x) (x << 11) +#define SET_PDE_FRAME(x) (x << 11) + +#define GET_PDE_FRAME(x) (*x >> 11) #define SET_PTE_PRESENT(x) x #define SET_PTE_WRITABLE(x) (x << 1) @@ -58,6 +60,7 @@ /* MAX: 0xFFFFF000 */ #define SET_PTE_FRAME(x) (x << 11) +#define PTE_IS_PRESENT(x) (x & 1) #define GET_PTE_FRAME(x) (*x >> 11) #define ADD_ATTRIB(entry, attribute) (*entry |= (attribute)) @@ -92,4 +95,24 @@ uint32_t *virtual_mm_lookup_directory(uint32_t *page_directory, */ void virtual_mm_load_page_directory(uint32_t *page_directory); +/* + * Switches the current page directory to a given page directory + */ +bool virtual_mm_switch_page_directory(uint32_t *page_directory); + +/* + * Flushes the given TLB entry + */ +void virtual_mm_flush_tlb_entry(uint32_t *virtual_addr); + +/* + * Map a given physical address to a virtual address + */ +bool virtual_mm_map_page(uint32_t *physical_addr, uint32_t *virtual_addr); + +/* + * Initialize the virtual memory manager + */ +void virtual_mm_initialize(void); + #endif diff --git a/kernel/kernel/kernel.c b/kernel/kernel/kernel.c index fe75d7d..0ebaf64 100644 --- a/kernel/kernel/kernel.c +++ b/kernel/kernel/kernel.c @@ -44,12 +44,10 @@ kernel_main(uint32_t magic, multiboot_info_t *multiboot_info) GDT_load(); memory_map_load(multiboot_info); physical_mm_init(); + virtual_mm_initialize(); printk("\nKernel", "Started."); - uint32_t x = 0; - virtual_mm_allocate_page(&x); - exit(); halt(); /* If exit() fails (on real hardware) */ } diff --git a/kernel/mm/virtual_mm/virtual_mm.c b/kernel/mm/virtual_mm/virtual_mm.c index 6350c11..0f55950 100644 --- a/kernel/mm/virtual_mm/virtual_mm.c +++ b/kernel/mm/virtual_mm/virtual_mm.c @@ -18,6 +18,8 @@ #include <stdint.h> +#include <kernel/halt.h> + #include <libk/stdio.h> #include <mm/physical_mm.h> @@ -26,8 +28,7 @@ extern uint32_t kernel_start; extern uint32_t kernel_end; -uint32_t initial_page_directory[PAGE_DIRECTORY_SIZE]; -uint32_t initial_page_table[PAGE_TABLE_SIZE]; +uint32_t *current_page_directory = 0; bool virtual_mm_allocate_page(uint32_t *pt_entry) @@ -75,5 +76,102 @@ virtual_mm_lookup_directory(uint32_t *page_directory, uint32_t virtual_addr) ALWAYS_INLINE void virtual_mm_load_page_directory(uint32_t *page_directory) { - __asm__("movl %0, %%cr0" ::"r"(page_directory)); + __asm__("movl %0, %%eax" ::"r"(page_directory) : "%eax"); + /* For some reason, that colon is required; else the assembler thinks that + * %eax doesn't exist :^) */ + __asm__("movl %%eax, %%cr3" ::: "%eax"); +} + +bool +virtual_mm_switch_page_directory(uint32_t *page_directory) +{ + if (!page_directory) + return false; + current_page_directory = page_directory; + virtual_mm_load_page_directory(page_directory); + + return true; +} + +/* TODO: I have absolutely _no_ idea if this works */ +void +virtual_mm_flush_tlb_entry(uint32_t *virtual_addr) +{ + __asm__("cli;" + "invlpg (%0);" + "sti" ::"r"(virtual_addr)); +} + +bool +virtual_mm_map_page(uint32_t *physical_addr, uint32_t *virtual_addr) +{ + uint32_t *pd_entry + = ¤t_page_directory[PAGE_DIRECTORY_INDEX((uint32_t) virtual_addr)]; + + /* If the page directory entry isn't present */ + if (!PTE_IS_PRESENT(*pd_entry)) { + uint32_t *page_table = physical_mm_allocate_block(); + if (!page_table) + return false; + + *pd_entry = 0; + ADD_ATTRIB(pd_entry, SET_PDE_PRESENT(1)); + ADD_ATTRIB(pd_entry, SET_PDE_WRITABLE(1)); + ADD_ATTRIB(pd_entry, SET_PDE_FRAME((uint32_t) page_table)); + } + + uint32_t *page_table = (uint32_t *) GET_PDE_FRAME(pd_entry); + uint32_t *pt_entry = &page_table[PAGE_TABLE_INDEX((uint32_t) virtual_addr)]; + *pt_entry = 0; + + ADD_ATTRIB(pt_entry, SET_PTE_PRESENT(1)); + ADD_ATTRIB(pt_entry, SET_PTE_FRAME((uint32_t) physical_addr)); + + return true; +} + +ALWAYS_INLINE static void +virtual_mm_enable_paging(void) +{ + __asm__("movl %%cr0, %%eax;" + "orl $0x80000000, %%eax;" + "movl %%eax, %%cr0" :: + : "eax"); +} + +void +virtual_mm_initialize(void) +{ + uint32_t *table = physical_mm_allocate_block(); + if (!table) + ASSERT_NOT_REACHED(); + + for (uint32_t i = 0; i < 1024; i++) + table[i] = 0; + + /* Identity map the first 4MiB (maps 4KiB 1024 times) */ + for (uint32_t i = 0, physical_addr = 0, virtual_addr = 0; i < 1024; + i++, physical_addr += 4096, virtual_addr += 4096) { + uint32_t page = 0; + ADD_ATTRIB(&page, SET_PTE_PRESENT(1)); + ADD_ATTRIB(&page, SET_PTE_FRAME(physical_addr)); + + table[PAGE_TABLE_INDEX(virtual_addr)] = page; + } + + uint32_t *page_directory = physical_mm_allocate_block(); + if (!page_directory) + ASSERT_NOT_REACHED(); + + for (uint32_t i = 0; i < 1024; i++) + page_directory[i] = 0; + + uint32_t *pd_entry = &page_directory[PAGE_DIRECTORY_INDEX(0)]; + ADD_ATTRIB(pd_entry, SET_PDE_PRESENT(1)); + ADD_ATTRIB(pd_entry, SET_PDE_WRITABLE(1)); + ADD_ATTRIB(pd_entry, SET_PDE_FRAME((uint32_t) table)); + + current_page_directory = page_directory; + virtual_mm_switch_page_directory(current_page_directory); + virtual_mm_enable_paging(); } |