summaryrefslogtreecommitdiff
path: root/arch/i386/kernel/paging.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/i386/kernel/paging.c')
-rw-r--r--arch/i386/kernel/paging.c192
1 files changed, 89 insertions, 103 deletions
diff --git a/arch/i386/kernel/paging.c b/arch/i386/kernel/paging.c
index 64afcf7..05cd04c 100644
--- a/arch/i386/kernel/paging.c
+++ b/arch/i386/kernel/paging.c
@@ -2,146 +2,132 @@
#include <kernel/asm.h>
#include <kernel/pmem.h>
#include <kernel/panic.h>
-#include <kernel/errno.h>
-#include <kernel/io.h>
#include <kernel/syscall.h>
-#include <kernel/string.h>
+#include <libk/io.h>
+#include <libk/string.h>
+#include <libk/errno.h>
-static uintptr_t page_directory[1024] __attribute__((aligned(PAGE_SIZE)));
-static uintptr_t first_page_table[1024] __attribute__((aligned(PAGE_SIZE)));
+uintptr_t *kpgdir = NULL;
+static uintptr_t kernel_pd[1024] __attribute__((aligned(PAGE_SIZE)));
+static uintptr_t kernel_pt[1024] __attribute__((aligned(PAGE_SIZE)));
+static uintptr_t accnt_pt[1024] __attribute__((aligned(PAGE_SIZE)));
static int paging_enabled = 0;
-int init_page_table(uintptr_t *pd, int index, int user) {
- if (pd == NULL)
- return 0;
+void _copy_kernel_maps(uintptr_t *new_pd) {
+ int pdx = GET_PDX(GET_VADDR(KSTART));
+ new_pd[pdx] = GET_PADDR(kernel_pt) | PD_PRES | PD_RW;
+ new_pd[832] = GET_PADDR(accnt_pt) | PD_PRES | PD_RW;
+}
- uintptr_t paddr = pfa_alloc();
- if (paddr == PFA_ALLOC_ERR)
- return -ENOMEM;
+uintptr_t* init_page_table(void) {
+ uintptr_t *ret = (uintptr_t*)pfa_alloc();
+ if ((uintptr_t)ret == PFA_ALLOC_ERR)
+ return NULL;
- map_page(NULL, paddr, paddr, PD_PRES | PD_RW);
- if (user)
- pd[index] = paddr | PD_USR;
- else
- pd[index] = paddr;
+ map_page(NULL, (uintptr_t)ret, (uintptr_t)ret+0x20000000, PD_PRES | PD_RW);
+ memset((char*)ret, 0, PAGE_SIZE);
+ unmap_page(NULL, (uintptr_t)ret);
+ return ret;
}
-int init_page_directory(uintptr_t *pd, int user) {
- uintptr_t paddr = pfa_alloc();
- if (paddr == PFA_ALLOC_ERR)
- return -ENOMEM;
+uintptr_t* init_page_directory(void) {
+ uintptr_t *ret = (uintptr_t*)pfa_alloc();
+ if ((uintptr_t)ret == PFA_ALLOC_ERR)
+ return NULL;
- map_page(NULL, paddr, pd, PD_PRES | PD_RW);
- for (int i = 0; i < 1023; i++)
- init_page_table(pd, i, 0);
- pd[1023] = paddr | 3;
- return paddr;
-}
+ map_page(NULL, (uintptr_t)ret, (uintptr_t)ret, PD_PRES | PD_RW);
+ memset(ret, 0, PAGE_SIZE);
+ _copy_kernel_maps(ret);
+ unmap_page(NULL, (uintptr_t)ret);
-static void _alloc_new_page(uint32_t *cr3, uintptr_t vaddr, int user, int rw) {
- uintptr_t paddr = pfa_alloc();
- if (paddr == PFA_ALLOC_ERR)
- panic("Cannot allocate physical page");
-
- uint32_t flags = PD_PRES;
- if (rw == 1)
- flags |= PD_RW;
- if (user == 1)
- flags |= PD_USR;
- map_page(cr3, paddr, vaddr, flags);
+ return ret;
}
void paging_init(void) {
if (paging_enabled == 1)
return;
-
- for (int i = 0; i < 1024; i++) {
- page_directory[i] = PD_RW;
- first_page_table[i] = PD_RW;
- }
-
- page_directory[1023] = ((uintptr_t)&page_directory - 0xC0000000) | 3;
- page_directory[0] = ((uintptr_t)&first_page_table - 0xC0000000) | 3;
- page_directory[768] = ((uintptr_t)&first_page_table - 0xC0000000) | 3;
+
+ _copy_kernel_maps(kernel_pd);
for (uintptr_t i = KSTART; i < KEND; i += PAGE_SIZE)
- map_page(page_directory, i, i + 0xC0000000, PD_PRES);
+ map_page(kernel_pd, i, GET_VADDR(i), PD_PRES);
- enable_paging(((uintptr_t)&page_directory) - 0xC0000000);
+ map_page(kernel_pd, 0xB8000, 0xC03FF000, PD_PRES | PD_RW);
+ kpgdir = kernel_pd;
+ enable_paging(GET_PADDR(kpgdir));
paging_enabled = 1;
-
- for (int i = 0; i < 1023; i++) {
- if (i == 0 || i == 768)
- continue;
- init_page_table(page_directory, i, 0);
- }
return;
}
-void page_fault_handler(struct regs *regs) {
- uintptr_t errno = regs->isr_err;
-
- uintptr_t fault_addr;
- __asm__ volatile("movl %%cr2, %0" : "=r"(fault_addr));
- int present = errno & ERR_PRESENT;
- int rw = errno & ERR_RW;
- int user = errno & ERR_USER;
- int reserved = errno & ERR_RESERVED;
- int ifetch = errno & ERR_INST;
-
- if (reserved || ifetch)
- panic("Unknown error in page fault");
- if (present && user)
- panic("User process generated protection fault"); // TODO: this shouldn't panic
- if (present && !user)
- panic("Kernel process generated protection fault");
-
- if (user && rw)
- _alloc_new_page((uint32_t*)regs->cr3, fault_addr, 1, 1);
- if (user && !rw)
- _alloc_new_page((uint32_t*)regs->cr3, fault_addr, 1, 0);
- if (rw)
- _alloc_new_page((uint32_t*)regs->cr3, fault_addr, 0, 1);
- if (!rw)
- _alloc_new_page((uint32_t*)regs->cr3, fault_addr, 0, 0);
-}
-
-uintptr_t get_paddr(uintptr_t vaddr) {
- uint32_t pdindex = (uint32_t)vaddr >> 22;
- uint32_t ptindex = (uint32_t)vaddr >> 12 & 0x03FF;
-
- uint32_t *pd = (uint32_t*)0xFFFFF000;
- if ((*pd & PD_PRES) != 1)
- return 0;
- uint32_t *pt = ((uint32_t*)0xFFC00000) + (0x400 * pdindex);
- if ((*pt & PD_PRES) != 1)
- return 0;
- return (uintptr_t)((pt[ptindex] & ~0xFFF) + ((uint32_t)vaddr & 0xFFF));
-}
-
void map_page(uint32_t *pd, uintptr_t paddr, uintptr_t vaddr, uint32_t flags) {
if (pd == NULL)
- pd = page_directory;
+ pd = kpgdir;
paddr = PGROUNDDN(paddr);
vaddr = PGROUNDDN(vaddr);
- uintptr_t pdindex = vaddr >> 22;
- uintptr_t ptindex = vaddr >> 12 & 0x03FF;
+ uintptr_t pdindex = GET_PDX(vaddr);
+ uintptr_t ptindex = GET_PTX(vaddr);
+
+ uintptr_t *pt = (uintptr_t*)(GET_VADDR(pd[pdindex]) & 0xFFFFF000);
+ if (pd[pdindex] == 0)
+ pd[pdindex] = (uintptr_t)init_page_table();
- uintptr_t *pt = (uintptr_t*)((pd[pdindex] + 0xC0000000) & 0xFFFFF000);
uintptr_t *pte = (uintptr_t*)(&pt[ptindex]);
*pte |= paddr | (flags & 0xFFF) | 0x01;
+ invlpg((void*)vaddr);
}
void unmap_page(uint32_t *pd, uintptr_t vaddr) {
if (pd == NULL)
- pd = page_directory;
+ pd = kpgdir;
+
+ uintptr_t pdindex = GET_PDX(vaddr);
+ uintptr_t ptindex = GET_PTX(vaddr);
- uintptr_t pdindex = vaddr >> 22;
- uintptr_t ptindex = vaddr >> 12 & 0x03FF;
+ uintptr_t *pt = (uintptr_t*)(GET_VADDR(pd[pdindex]) & 0xFFFFF000);
+ if (pd[pdindex] == 0)
+ return;
- uintptr_t *pt = (uintptr_t*)((pd[pdindex] + 0xC0000000) & 0xFFFFF000);
uintptr_t *pte = (uintptr_t*)(&pt[ptindex]);
*pte &= 0;
+ invlpg((void*)vaddr);
+}
+
+void page_fault_handler(struct isr_frame *frame) {
+ uintptr_t fault_addr;
+ __asm__ volatile("movl %%cr2, %0" : "=r"(fault_addr));
+
+ 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;
+ }
}