summaryrefslogtreecommitdiff
path: root/arch
diff options
context:
space:
mode:
authorDanny Holman <dholman@gymli.org>2024-05-29 00:26:59 -0500
committerDanny Holman <dholman@gymli.org>2024-05-29 00:26:59 -0500
commitffc782f8740027d21793c37c6094ebed06d1dfd2 (patch)
treefadd5544ed493d9935d6c4052a442f70c17030fd /arch
parent5fb0ba537ab15f9c83afd9a939cf57c84d443856 (diff)
arch: i386: fix several bugs in paging subsystem
Fix several triple-faulting bugs in the paging initialization routines. These include causing a page fault during physical memory manager initialization, causing a page fault during paging initialization and other double-faulting and triple-faulting bugs. Signed-off-by: Danny Holman <dholman@gymli.org>
Diffstat (limited to 'arch')
-rw-r--r--arch/i386/include/kernel/paging.h14
-rw-r--r--arch/i386/kernel/kmalloc.c3
-rw-r--r--arch/i386/kernel/multiboot.c19
-rw-r--r--arch/i386/kernel/paging.c192
-rw-r--r--arch/i386/kernel/pmem.c2
5 files changed, 108 insertions, 122 deletions
diff --git a/arch/i386/include/kernel/paging.h b/arch/i386/include/kernel/paging.h
index e949e32..5999986 100644
--- a/arch/i386/include/kernel/paging.h
+++ b/arch/i386/include/kernel/paging.h
@@ -3,7 +3,6 @@
#include <kernel/asm.h>
#include <kernel/multiboot.h>
-#include <kernel/data/list.h>
#include <stdint.h>
#define PD_PRES 0x0001
@@ -26,15 +25,18 @@
#define PGROUNDUP(size) (((size)+PAGE_SIZE-1) & ~(PAGE_SIZE-1))
#define PGROUNDDN(size) (((size)) & ~(PAGE_SIZE-1))
-int init_page_directory(uintptr_t *pd, int user);
-void enable_paging(uintptr_t pd_addr);
+#define GET_PADDR(x) (((uint32_t)(x)) - 0xC0000000)
+#define GET_VADDR(x) (((uint32_t)(x)) + 0xC0000000)
-void paging_init(void);
-void page_fault_handler(struct regs *regs);
+#define GET_PDX(x) (((uintptr_t)(x) >> 22) & 0x3FF)
+#define GET_PTX(x) (((uintptr_t)(x) >> 12) & 0x3FF)
-uint32_t get_vaddr(uintptr_t paddr);
+uintptr_t* init_page_table(void);
+void paging_init(void);
void map_page(uint32_t *pd, uintptr_t paddr, uintptr_t vaddr, uint32_t flags);
void unmap_page(uint32_t *pd, uintptr_t vaddr);
+void page_fault_handler(struct isr_frame *frame);
+
#endif
diff --git a/arch/i386/kernel/kmalloc.c b/arch/i386/kernel/kmalloc.c
index 183545a..8118ecd 100644
--- a/arch/i386/kernel/kmalloc.c
+++ b/arch/i386/kernel/kmalloc.c
@@ -1,8 +1,7 @@
-#include <kernel/kmalloc.h>
+#include <libk/kmalloc.h>
#include <kernel/paging.h>
#include <kernel/pmem.h>
#include <kernel/asm.h>
-#include <kernel/errno.h>
#include <kernel/panic.h>
#include <stdint.h>
diff --git a/arch/i386/kernel/multiboot.c b/arch/i386/kernel/multiboot.c
index 87b5e32..f56910a 100644
--- a/arch/i386/kernel/multiboot.c
+++ b/arch/i386/kernel/multiboot.c
@@ -10,6 +10,7 @@
#include <kernel/video/framebuffer.h>
#include <libk/io.h>
#include <libk/string.h>
+#include <libk/kmalloc.h>
extern void kernel_main(char *cmdline);
extern uintptr_t *kpgdir;
@@ -19,22 +20,20 @@ void i386_entry(uint32_t mboot_magic, struct mboot_info *header, uintptr_t *entr
fb_init();
if (mboot_magic != MBOOT_LOADER_MAGIC) {
- kprintf("NOT BOOTED WITH MULTIBOOT BOOTLOADER\n");
- kprintf("RESET PC!\n");
disable_ints();
- while (1);
+ panic("Not booted with multiboot bootloader");
}
- map_page(NULL, (uintptr_t)header, (uintptr_t)GET_VADDR(header), PD_PRES);
+ map_page(NULL, (uintptr_t)header, (uintptr_t)header, PD_PRES);
if (!(header->flags >> 6 & 0x1)) {
- kprintf("NO MEMORY MAP FROM BOOTLOADER\n");
- kprintf("RESET PC!\n");
disable_ints();
- while (1);
+ panic("Physical memory map not provided by bootloader");
}
struct mboot_info hcopy;
+ char cmdcopy[1024];
memcpy(&hcopy, header, sizeof(struct mboot_info));
- unmap_page(NULL, (uintptr_t)header);
+ map_page(NULL, (uintptr_t)header->cmdline, (uintptr_t)header->cmdline, PD_PRES);
+ strcpy(cmdcopy, header->cmdline);
pfa_init(&hcopy);
paging_init();
@@ -44,8 +43,8 @@ void i386_entry(uint32_t mboot_magic, struct mboot_info *header, uintptr_t *entr
pic_remap();
timer_init();
- //enable_ints();
- kernel_main((char*)header->cmdline);
+ enable_ints();
+ kernel_main(cmdcopy);
while (1);
}
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;
+ }
}
diff --git a/arch/i386/kernel/pmem.c b/arch/i386/kernel/pmem.c
index e59c80b..0e53507 100644
--- a/arch/i386/kernel/pmem.c
+++ b/arch/i386/kernel/pmem.c
@@ -25,7 +25,7 @@ uintptr_t pfa_alloc(void) {
if (ret == NULL)
return PFA_ALLOC_ERR;
- struct pfa_page *temp_map = (struct pfa_page*)0x1000;
+ struct pfa_page *temp_map = (struct pfa_page*)0xD0000000;
map_page(NULL, (uintptr_t)ret, (uintptr_t)temp_map, PD_PRES | PD_RW);
memset((char*)temp_map, 0, PAGE_SIZE);
unmap_page(NULL, (uintptr_t)temp_map);