summaryrefslogtreecommitdiff
path: root/kernel/arch/x86/kernel/paging.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/arch/x86/kernel/paging.c')
-rw-r--r--kernel/arch/x86/kernel/paging.c130
1 files changed, 130 insertions, 0 deletions
diff --git a/kernel/arch/x86/kernel/paging.c b/kernel/arch/x86/kernel/paging.c
new file mode 100644
index 0000000..a0bbb92
--- /dev/null
+++ b/kernel/arch/x86/kernel/paging.c
@@ -0,0 +1,130 @@
+#include <kernel/paging.h>
+#include <kernel/asm.h>
+#include <kernel/vmem.h>
+#include <kernel/pmem.h>
+#include <kernel/panic.h>
+#include <kernel/syscall.h>
+#include <libk/io.h>
+#include <libk/string.h>
+
+static int paging_enabled = 0;
+
+void paging_init(void) {
+ if (paging_enabled == 1)
+ return;
+
+ uintptr_t phys_pt = pfa_alloc(1);
+ map_page(phys_pt, PAGE_TMP_MAP, PD_PRES | PD_RW);
+ uintptr_t *pt = (uintptr_t*)PAGE_TMP_MAP;
+ for (uintptr_t i = KSTART; i < KEND; i += PAGE_SIZE)
+ pt[GET_PTX(GET_VADDR(i))] = i | PD_PRES;
+ unmap_page(PAGE_TMP_MAP);
+
+ uintptr_t temp_pt = pfa_alloc(1);
+
+ uintptr_t phys_pd = pfa_alloc(1);
+ map_page(phys_pd, PAGE_TMP_MAP, PD_PRES | PD_RW);
+ uintptr_t *pd = (uintptr_t*)PAGE_TMP_MAP;
+ pd[GET_PDX(GET_VADDR(KSTART))] = phys_pt | PD_PRES | PD_RW;
+ pd[GET_PDX(PAGE_TMP_MAP)] = temp_pt | PD_PRES | PD_RW;
+ pd[1023] = phys_pd | PD_PRES | PD_RW;
+ unmap_page(PAGE_TMP_MAP);
+
+ enable_paging(phys_pd);
+ paging_enabled = 1;
+ return;
+}
+
+void init_page_table(int pdindex, uint32_t flags) {
+ uintptr_t *pd = (uintptr_t*)PAGE_DIR_MAP;
+ if ((pd[pdindex] & PD_PRES) != 0)
+ return;
+
+ uintptr_t paddr = pfa_alloc(1);
+ pd[pdindex] = paddr | PD_PRES | PD_RW | flags;
+
+ uintptr_t *pt = ((uintptr_t*)PAGE_TAB_MAP) + (pdindex << 12);
+ pd[GET_PDX(pt)] = paddr | PD_PRES | PD_RW;
+}
+
+uintptr_t init_page_directory(void) {
+ uintptr_t ret = pfa_alloc(1);
+ map_page(ret, PAGE_TMP_MAP, PD_RW);
+
+ uintptr_t *new_pd = (uintptr_t*)PAGE_TMP_MAP;
+ uintptr_t *cur_pd = (uintptr_t*)PAGE_DIR_MAP;
+ int kernel_pdx = GET_PDX(GET_VADDR(KSTART));
+ new_pd[kernel_pdx] = cur_pd[kernel_pdx];
+
+ unmap_page(PAGE_TMP_MAP);
+ return ret;
+}
+
+void map_page(uintptr_t paddr, uintptr_t vaddr, uint32_t flags) {
+ paddr = PGROUNDDN(paddr);
+ vaddr = PGROUNDDN(vaddr);
+
+ int pdindex = GET_PDX(vaddr);
+ int ptindex = GET_PTX(vaddr);
+
+ uintptr_t *pd = (uintptr_t*)PAGE_DIR_MAP;
+ if ((pd[pdindex] & PD_PRES) == 0)
+ init_page_table(pdindex, 0);
+
+ uintptr_t *pt = (uintptr_t*)(PAGE_TAB_MAP + (pdindex << 12));
+ pt[ptindex] = paddr | PD_PRES | flags;
+ invlpg((void*)vaddr);
+}
+
+void unmap_page(uintptr_t vaddr) {
+ uintptr_t pdindex = GET_PDX(vaddr);
+ uintptr_t ptindex = GET_PTX(vaddr);
+
+ uintptr_t *pd = (uintptr_t*)PAGE_DIR_MAP;
+ if ((pd[pdindex] & PD_PRES) == 0)
+ return;
+
+ uintptr_t *pt = (uintptr_t*)(PAGE_TAB_MAP + (pdindex << 12));
+ pt[ptindex] = 0;
+ invlpg((void*)vaddr);
+}
+
+void page_fault_handler(struct isr_frame *frame) {
+ uintptr_t fault_addr;
+ __asm__ volatile("movl %%cr2, %0" : "=r"(fault_addr));
+
+ kprintf("Faulting address: %x\n", fault_addr);
+ panic("Page fault not operational");
+ switch (frame->isr_err) {
+ case 0:
+ //map_page((uintptr_t*)GET_VADDR(frame->cr3), pfa_alloc(), fault_addr, PD_PRES);
+ break;
+ case 1:
+ panic("Kernel process caused protection fault on read\n");
+ break;
+ case 2:
+ //map_page((uintptr_t*)GET_VADDR(frame->cr3), pfa_alloc(), fault_addr, PD_PRES | PD_RW);
+ break;
+ case 3:
+ panic("Kernel process caused protection fault on write\n");
+ break;
+ case 4:
+ //map_page((uintptr_t*)GET_VADDR(frame->cr3), pfa_alloc(), fault_addr, PD_PRES | PD_USR);
+ break;
+ case 5:
+ // TODO: instead of panicking, kill process
+ panic("User process caused protection fault on read\n");
+ break;
+ case 6:
+ //map_page((uintptr_t*)GET_VADDR(frame->cr3), pfa_alloc(), fault_addr, PD_PRES | PD_RW | PD_USR);
+ break;
+ case 7:
+ // TODO: see case 101
+ panic("USER process caused protection fault on write\n");
+ break;
+ default:
+ kprintf("Unknown paging error occured on address %x\n", fault_addr);
+ panic("Paging error");
+ break;
+ }
+}