From d1ff7bcc91886626dc9060ec5fb67ee102ab7c1d Mon Sep 17 00:00:00 2001 From: Jon Santmyer Date: Mon, 11 Mar 2024 21:30:31 -0400 Subject: usermode capable kernel with logging syscall --- arch/x86_64/paging.c | 202 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 202 insertions(+) create mode 100644 arch/x86_64/paging.c (limited to 'arch/x86_64/paging.c') diff --git a/arch/x86_64/paging.c b/arch/x86_64/paging.c new file mode 100644 index 0000000..76b5735 --- /dev/null +++ b/arch/x86_64/paging.c @@ -0,0 +1,202 @@ +#include "paging.h" +#include +#include "lib/jove.h" +#include "io/log.h" +#include "lib/string.h" +#include "boot/boot.h" + +extern void *_kernel_end; + +PAGEALIGN static uint64_t s_kernel_initial_pml4[512]; +PAGEALIGN static uint64_t s_kernel_initial_pml3[2][512]; +PAGEALIGN static uint64_t s_kernel_initial_pml2[2][512]; +PAGEALIGN static uint64_t s_kernel_initial_pml1[2][512]; +static struct PageDirectory s_kernel_initial_pd; + +struct PageDirectory *mem_current_pd; + +physptr_t +mem_linear_tophys_koffset(uintptr_t virt) +{ + return (virt - boot_kernel_virtual_base) + boot_kernel_physical_address; +} + +uintptr_t +mem_phys_tolinear(physptr_t phys) +{ + return (uintptr_t)(phys + 0xFFFF800000000000ULL); +} + +static size_t +s_paging_pmle(size_t l, uintptr_t addr) +{ + size_t shift = (12 + (9 * l)); + return (addr & (0x1FFULL << shift)) >> shift; +} + +static union PageEntry* +s_paging_fetch_table(union PageEntry *pt, size_t l, uintptr_t virt) +{ + size_t pmle = s_paging_pmle(l, virt); + union PageEntry entry = pt[pmle]; + bool entry_new = false; + if(!entry.p) { + entry_new = true; + entry.value = mem_phys_take4k(); + entry.p = 1; + entry.rw = 1; + entry.us = 1; + pt[pmle] = entry; + } + union PageEntry *table = (union PageEntry*)(mem_phys_tolinear(entry.paddr << 12)); + if(entry_new) memset(table, 0, PAGESIZE); + return table; +} + +static union PageEntry* +s_paging_get_table(union PageEntry *pt, size_t l, uintptr_t virt) +{ + if(pt == NULL) return NULL; + size_t pmle = s_paging_pmle(l, virt); + union PageEntry entry = pt[pmle]; + if(!entry.p) return NULL; + return (union PageEntry*)(mem_phys_tolinear(entry.paddr << 12)); +} + +physptr_t +mem_linear_tophys(uintptr_t virt) +{ + struct PageDirectory *pd = mem_current_pd; + union PageEntry *pml3 = s_paging_get_table(pd->pml4_vaddr, 3, virt); + union PageEntry *pml2 = s_paging_get_table(pd->pml4_vaddr, 3, virt); + union PageEntry *pml1 = s_paging_get_table(pd->pml4_vaddr, 3, virt); + if(pml1 == NULL) return 0; + + size_t pml1i = s_paging_pmle(0, virt); + + if(!pml1[pml1i].p) return 0; + return pml1[pml1i].paddr << 12; +} + +bool +mem_check_ptr(const void *ptr) +{ + if(ptr == NULL) return false; + return mem_linear_tophys((uintptr_t)ptr) != 0; +} + +void +mem_paging_map4k(struct PageDirectory *pd, physptr_t phys, uintptr_t virt, uint8_t flg) +{ + union PageEntry *pml3 = s_paging_fetch_table(pd->pml4_vaddr, 3, virt); + union PageEntry *pml2 = s_paging_fetch_table(pml3, 2, virt); + union PageEntry *pml1 = s_paging_fetch_table(pml2, 1, virt); + size_t pml1e = s_paging_pmle(0, virt); + + pml1[pml1e] = (union PageEntry) { + .p = (flg & 1) > 0, + .rw = (flg & 2) > 0, + .us = (flg & 4) > 0, + .paddr = phys >> 12 + }; +} + +union PageEntry +mem_paging_fetch4k(struct PageDirectory *pd, uintptr_t virt) +{ + union PageEntry *pml3 = s_paging_fetch_table(pd->pml4_vaddr, 3, virt); + union PageEntry *pml2 = s_paging_fetch_table(pml3, 2, virt); + union PageEntry *pml1 = s_paging_fetch_table(pml2, 1, virt); + return pml1[s_paging_pmle(0, virt)]; +} + +void +mem_pd_ensure_4k(struct PageDirectory *pd, uintptr_t virt, uint8_t flg) +{ + union PageEntry pml1e = mem_paging_fetch4k(pd, virt); + if(!pml1e.p) { + uintptr_t phys = mem_phys_take4k(); + mem_paging_map4k(pd, phys, virt, flg); + } +} + +void +mem_pd_ensure_range(struct PageDirectory *pd, uintptr_t from, uintptr_t to, uint8_t flg) +{ + from &= ~0xFFF; + for(; from < to; from += PAGESIZE) + mem_pd_ensure_4k(pd, from, flg); +} + +void +mem_ensure_range(uintptr_t from, uintptr_t to, bool rw, bool user) +{ + mem_pd_ensure_range(mem_current_pd, from, to, 1 | (rw << 1) | (user << 2)); +} + +void mem_pd_new(struct PageDirectory *pd) +{ + physptr_t pml4p = mem_phys_take4k(); + union PageEntry *pml4 = (union PageEntry*)mem_phys_tolinear(pml4p); + memset(pml4, 0, PAGESIZE); + memcpy(&pml4[256], &pd->pml4_vaddr[256], PAGESIZE / 2); + + *pd = (struct PageDirectory){ + .pml4_vaddr = pml4, + .pml4_paddr = pml4p, + .references = 1 + }; +} + +void mem_pd_clone(struct PageDirectory *pd, struct PageDirectory *parent) +{ + mem_pd_new(pd); + for(size_t i = 0; i < 256; i++) { + + } +} + +void +mem_paging_setup(void) +{ + memset(s_kernel_initial_pml4, 0, PAGESIZE); + memset(s_kernel_initial_pml3, 0, 2 * PAGESIZE); + memset(s_kernel_initial_pml2, 0, 2 * PAGESIZE); + memset(s_kernel_initial_pml1, 0, PAGESIZE); + s_kernel_initial_pd = (struct PageDirectory){ + .pml4_vaddr = (union PageEntry*)&s_kernel_initial_pml4, + .pml4_paddr = mem_linear_tophys_koffset((uintptr_t)&s_kernel_initial_pml4), + .references = 1 + }; + mem_current_pd = &s_kernel_initial_pd; + + /* Map first few GiBs */ + s_kernel_initial_pml4[256] = + mem_linear_tophys_koffset((uintptr_t)&s_kernel_initial_pml3[0]) + | 3; + s_kernel_initial_pml3[0][0] = + mem_linear_tophys_koffset((uintptr_t)&s_kernel_initial_pml2[0]) + | 3; + for(int i = 0; i < 512; i++) { + s_kernel_initial_pml2[0][i] = (i * (PAGESIZE * 512)) | 0x80 | 3; + } + + size_t kernel_pml4e = (boot_kernel_virtual_base >> (39)); + size_t kernel_pml3e = (boot_kernel_virtual_base >> (30)) % 512; + size_t kernel_pml2e = (boot_kernel_virtual_base >> (21)) % 512; + size_t kernel_npages = ((((uintptr_t)&_kernel_end) - boot_kernel_virtual_base) >> 12) + 1; + klogf("Kernel has %i pages\n", kernel_npages); + + /* Map kernel pages */ + s_kernel_initial_pml4[511] = + mem_linear_tophys_koffset((uintptr_t)&s_kernel_initial_pml3[1]) | 3; + s_kernel_initial_pml3[1][kernel_pml3e] = + mem_linear_tophys_koffset((uintptr_t)&s_kernel_initial_pml2[1]) | 3; + s_kernel_initial_pml2[1][kernel_pml2e] = + mem_linear_tophys_koffset((uintptr_t)&s_kernel_initial_pml1[0]) | 3; + for(int i = 0; i < kernel_npages; i++) { + s_kernel_initial_pml1[0][i] = (i * PAGESIZE) + boot_kernel_physical_address | 3; + } + + __asm__ volatile("mov %0, %%cr3":: "r"(s_kernel_initial_pd.pml4_paddr)); +} -- cgit v1.2.1