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.c116
1 files changed, 77 insertions, 39 deletions
diff --git a/arch/i386/kernel/paging.c b/arch/i386/kernel/paging.c
index b2a1392..64afcf7 100644
--- a/arch/i386/kernel/paging.c
+++ b/arch/i386/kernel/paging.c
@@ -1,46 +1,80 @@
#include <kernel/paging.h>
+#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>
-extern uintptr_t _kernel_start;
-extern uintptr_t _kernel_end;
-static uintptr_t kstart = (uintptr_t)&_kernel_start;
-static uintptr_t kend = (uintptr_t)&_kernel_end - 0xC0000000;
-
static uintptr_t page_directory[1024] __attribute__((aligned(PAGE_SIZE)));
static uintptr_t first_page_table[1024] __attribute__((aligned(PAGE_SIZE)));
-static uintptr_t second_page_table[1024] __attribute__((aligned(PAGE_SIZE)));
static int paging_enabled = 0;
-uint32_t* init_page_table(uint32_t flags) {
- uint32_t *ret = kmalloc(sizeof(uint32_t)*1024);
- for (int i = 0; i < 1024; i++)
- ret[i] = flags;
+int init_page_table(uintptr_t *pd, int index, int user) {
+ if (pd == NULL)
+ return 0;
+
+ uintptr_t paddr = pfa_alloc();
+ if (paddr == PFA_ALLOC_ERR)
+ return -ENOMEM;
+
+ map_page(NULL, paddr, paddr, PD_PRES | PD_RW);
+ if (user)
+ pd[index] = paddr | PD_USR;
+ else
+ pd[index] = paddr;
+}
+
+int init_page_directory(uintptr_t *pd, int user) {
+ uintptr_t paddr = pfa_alloc();
+ if (paddr == PFA_ALLOC_ERR)
+ return -ENOMEM;
+
+ 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;
}
-uint32_t* init_page_dir(uint32_t flags) {
- uint32_t *ret = init_page_table(flags);
- ret[0] = ((uintptr_t)&first_page_table - 0xC0000000) | 3;
- ret[768] = ((uintptr_t)&second_page_table - 0xC0000000) | 3;
+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);
}
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;
- second_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)&second_page_table - 0xC0000000) | 3;
- for (uintptr_t i = kstart; i < kend; i += PAGE_SIZE)
- map_page(page_directory, i, i + 0xC0000000, 0x003);
+ page_directory[768] = ((uintptr_t)&first_page_table - 0xC0000000) | 3;
+ for (uintptr_t i = KSTART; i < KEND; i += PAGE_SIZE)
+ map_page(page_directory, i, i + 0xC0000000, PD_PRES);
enable_paging(((uintptr_t)&page_directory) - 0xC0000000);
paging_enabled = 1;
+
+ for (int i = 0; i < 1023; i++) {
+ if (i == 0 || i == 768)
+ continue;
+ init_page_table(page_directory, i, 0);
+ }
return;
}
@@ -55,17 +89,21 @@ void page_fault_handler(struct regs *regs) {
int reserved = errno & ERR_RESERVED;
int ifetch = errno & ERR_INST;
- uintptr_t first_free;
- if (!present)
- map_page(regs->cr3, fault_addr, fault_addr, PD_PRES | PD_RW | PD_USR);
- if (user)
- panic("Usermode attempted to read supervisor page");
+ 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)
- panic("Task wrote to read only page");
- if (reserved)
- panic("Task overwrote reserved page bits");
- if (ifetch)
- panic("Task paging instruction fetch failure");
+ _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) {
@@ -73,11 +111,11 @@ uintptr_t get_paddr(uintptr_t vaddr) {
uint32_t ptindex = (uint32_t)vaddr >> 12 & 0x03FF;
uint32_t *pd = (uint32_t*)0xFFFFF000;
- if (*pd & PD_PRES != 1)
- return NULL;
+ if ((*pd & PD_PRES) != 1)
+ return 0;
uint32_t *pt = ((uint32_t*)0xFFC00000) + (0x400 * pdindex);
- if (*pt & PD_PRES != 1)
- return NULL;
+ if ((*pt & PD_PRES) != 1)
+ return 0;
return (uintptr_t)((pt[ptindex] & ~0xFFF) + ((uint32_t)vaddr & 0xFFF));
}
@@ -85,15 +123,15 @@ void map_page(uint32_t *pd, uintptr_t paddr, uintptr_t vaddr, uint32_t flags) {
if (pd == NULL)
pd = page_directory;
- uintptr_t paddr_aligned = paddr & 0xFFFFF000;
- uintptr_t vaddr_aligned = vaddr & 0xFFFFF000;
+ paddr = PGROUNDDN(paddr);
+ vaddr = PGROUNDDN(vaddr);
- uintptr_t pdindex = vaddr_aligned >> 22;
- uintptr_t ptindex = vaddr_aligned >> 12 & 0x03FF;
+ uintptr_t pdindex = vaddr >> 22;
+ uintptr_t ptindex = vaddr >> 12 & 0x03FF;
- uintptr_t *pt = (pd[pdindex] + 0xC0000000 & 0xFFFFF000);
+ uintptr_t *pt = (uintptr_t*)((pd[pdindex] + 0xC0000000) & 0xFFFFF000);
uintptr_t *pte = (uintptr_t*)(&pt[ptindex]);
- *pte |= paddr_aligned | (flags & 0xFFF) | 0x01;
+ *pte |= paddr | (flags & 0xFFF) | 0x01;
}
void unmap_page(uint32_t *pd, uintptr_t vaddr) {
@@ -103,7 +141,7 @@ void unmap_page(uint32_t *pd, uintptr_t vaddr) {
uintptr_t pdindex = vaddr >> 22;
uintptr_t ptindex = vaddr >> 12 & 0x03FF;
- uintptr_t *pt = (pd[pdindex] + 0xC0000000 & 0xFFFFF000);
+ uintptr_t *pt = (uintptr_t*)((pd[pdindex] + 0xC0000000) & 0xFFFFF000);
uintptr_t *pte = (uintptr_t*)(&pt[ptindex]);
*pte &= 0;
}