aboutsummaryrefslogtreecommitdiff
path: root/src/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'src/kernel')
-rw-r--r--src/kernel/core/paging.c103
-rw-r--r--src/kernel/core/region.c4
-rw-r--r--src/kernel/core/thread.c17
-rw-r--r--src/kernel/include/paging.h8
-rw-r--r--src/kernel/include/region.h6
-rw-r--r--src/kernel/include/thread.h6
6 files changed, 94 insertions, 50 deletions
diff --git a/src/kernel/core/paging.c b/src/kernel/core/paging.c
index 44e00fe..3bc36ea 100644
--- a/src/kernel/core/paging.c
+++ b/src/kernel/core/paging.c
@@ -53,48 +53,73 @@ void page_fault_handler(registers_t *regs) {
void* vaddr;
asm volatile("movl %%cr2, %0":"=r"(vaddr));
- if ((size_t)vaddr >= K_HIGHHALF_ADDR) {
- uint32_t pt = PT_OF_ADDR(vaddr);
+ bool is_user = ((regs->err_code & PF_USER_BIT) != 0);
- if (current_pd != &kernel_pd && current_pd->page[pt] != kernel_pd.page[pt]) {
- current_pd->page[pt] = kernel_pd.page[pt];
- invlpg(&current_pt[pt]);
- return;
- }
- if (regs->eflags & EFLAGS_IF) asm volatile("sti"); // from now on we are preemptible
-
- if (vaddr >= (void*)&kernel_stack_protector && vaddr < (void*)&kernel_stack_protector + PAGE_SIZE) {
- dbg_printf("Kernel stack overflow at 0x%p\n", vaddr);
- PANIC("Kernel stack overflow.");
- }
+ if (is_user) {
+ if (regs->eflags & EFLAGS_IF) asm volatile("sti");
+ // remark : sti should always be executed, it is stupid to run user code with interrupts disabled
- if ((size_t)vaddr >= PD_MIRROR_ADDR) {
- dbg_printf("Fault on access to mirrorred PD at 0x%p\n", vaddr);
- dbg_print_region_info();
- PANIC("Unhandled kernel space page fault");
- }
-
- region_info_t *i = find_region(vaddr);
- if (i == 0) {
- dbg_printf("Kernel pagefault in non-existing region at 0x%p\n", vaddr);
- dbg_dump_registers(regs);
- PANIC("Unhandled kernel space page fault");
+ if ((size_t)vaddr >= K_HIGHHALF_ADDR) {
+ ASSERT(current_thread->kmem_violation_handler != 0);
+ current_thread->kmem_violation_handler(regs);
+ } else {
+ ASSERT(current_thread->usermem_pf_handler != 0);
+ current_thread->usermem_pf_handler(get_current_pagedir(), regs, vaddr);
}
- if (i->pf == 0) {
- dbg_printf("Kernel pagefault in region with no handler at 0x%p\n", vaddr);
+ } else {
+ //TODO: instead of panicing, we should try to recover from the exception (?)
+ if ((size_t)vaddr < PAGE_SIZE) {
+ dbg_printf("Null pointer dereference in kernel code (0x%p)\n", vaddr);
dbg_dump_registers(regs);
- dbg_print_region_info();
- PANIC("Unhandled kernel space page fault");
+ PANIC("Null pointer dereference in kernel code.");
+ } else if ((size_t)vaddr < K_HIGHHALF_ADDR) {
+ if (current_thread->usermem_pf_handler == 0) {
+ dbg_printf("Userspace page fault at 0x%p, no handler declared\n", vaddr);
+ dbg_dump_registers(regs);
+ PANIC("Unhandled userspace page fault");
+ }
+
+ // userspace PF handlers should always be preemptible
+ if (regs->eflags & EFLAGS_IF) asm volatile("sti");
+ current_thread->usermem_pf_handler(get_current_pagedir(), regs, vaddr);
+ } else {
+ uint32_t pt = PT_OF_ADDR(vaddr);
+
+ if (current_pd != &kernel_pd && current_pd->page[pt] != kernel_pd.page[pt]) {
+ current_pd->page[pt] = kernel_pd.page[pt];
+ invlpg(&current_pt[pt]);
+ return;
+ }
+
+ // from now on we are preemptible
+ if (regs->eflags & EFLAGS_IF) asm volatile("sti");
+
+ if (vaddr >= (void*)&kernel_stack_protector && vaddr < (void*)&kernel_stack_protector + PAGE_SIZE) {
+ dbg_printf("Kernel stack overflow at 0x%p\n", vaddr);
+ dbg_dump_registers(regs);
+ PANIC("Kernel stack overflow.");
+ }
+
+ if ((size_t)vaddr >= PD_MIRROR_ADDR) {
+ dbg_printf("Fault on access to mirrorred PD at 0x%p\n", vaddr);
+ dbg_print_region_info();
+ PANIC("Unhandled kernel space page fault");
+ }
+
+ region_info_t *i = find_region(vaddr);
+ if (i == 0) {
+ dbg_printf("Kernel pagefault in non-existing region at 0x%p\n", vaddr);
+ dbg_dump_registers(regs);
+ PANIC("Unhandled kernel space page fault");
+ }
+ if (i->pf == 0) {
+ dbg_printf("Kernel pagefault in region with no handler at 0x%p\n", vaddr);
+ dbg_dump_registers(regs);
+ dbg_print_region_info();
+ PANIC("Unhandled kernel space page fault");
+ }
+ i->pf(get_current_pagedir(), i, vaddr);
}
- i->pf(get_current_pagedir(), i, vaddr);
- } else {
- if (regs->eflags & EFLAGS_IF) asm volatile("sti"); // userspace PF handlers should always be preemptible
-
- dbg_printf("Userspace page fault at 0x%p\n", vaddr);
- dbg_dump_registers(regs);
- PANIC("Unhandled userspace page fault");
- // not handled yet
- // TODO
}
}
@@ -237,7 +262,7 @@ pagedir_t *create_pagedir() {
pd = (pagedir_t*)malloc(sizeof(pagedir_t));
if (pd == 0) goto error;
- temp = region_alloc(PAGE_SIZE, 0, 0);
+ temp = region_alloc(PAGE_SIZE, "Temporary pagedir mapping", 0);
if (temp == 0) goto error;
bool map_ok = pd_map_page(temp, pd_phys, true);
@@ -262,7 +287,7 @@ pagedir_t *create_pagedir() {
return pd;
- error:
+error:
if (pd_phys != 0) frame_free(pd_phys, 1);
if (pd != 0) free(pd);
if (temp != 0) region_free(temp);
diff --git a/src/kernel/core/region.c b/src/kernel/core/region.c
index c14f129..c2c00a9 100644
--- a/src/kernel/core/region.c
+++ b/src/kernel/core/region.c
@@ -238,7 +238,7 @@ void region_free(void* addr) {
mutex_unlock(&ra_mutex);
}
-static void* region_alloc_inner(size_t size, char* type, page_fault_handler_t pf, bool use_reserve) {
+static void* region_alloc_inner(size_t size, char* type, kernel_pf_handler_t pf, bool use_reserve) {
size = PAGE_ALIGN_UP(size);
for (descriptor_t *i = first_free_region_by_size; i != 0; i = i->free.first_bigger) {
@@ -282,7 +282,7 @@ static void* region_alloc_inner(size_t size, char* type, page_fault_handler_t pf
return 0; //No big enough block found
}
-void* region_alloc(size_t size, char* type, page_fault_handler_t pf) {
+void* region_alloc(size_t size, char* type, kernel_pf_handler_t pf) {
void* result = 0;
mutex_lock(&ra_mutex);
diff --git a/src/kernel/core/thread.c b/src/kernel/core/thread.c
index 3f25add..9d11da2 100644
--- a/src/kernel/core/thread.c
+++ b/src/kernel/core/thread.c
@@ -107,10 +107,7 @@ static void run_thread(void (*entry)(void*), void* data) {
asm volatile("sti");
entry(data);
- current_thread->state = T_STATE_FINISHED;
- // TODO : add job for deleting the thread, or whatever
- yield(); // expected never to return!
- ASSERT(false);
+ exit();
}
thread_t *new_thread(entry_t entry, void* data) {
thread_t *t = (thread_t*)malloc(sizeof(thread_t));
@@ -147,7 +144,10 @@ thread_t *new_thread(entry_t entry, void* data) {
t->current_pd_d = get_kernel_pagedir();
- t->proc = 0; // used by L1 functions
+ // used by user processes
+ t->proc = 0;
+ t->usermem_pf_handler = 0;
+ t->kmem_violation_handler = 0;
return t;
}
@@ -196,6 +196,13 @@ void pause() {
resume_interrupts(st);
}
+void exit() {
+ current_thread->state = T_STATE_FINISHED;
+ // TODO : add job for deleting the thread, or whatever
+ yield(); // expected never to return!
+ ASSERT(false);
+}
+
void resume_thread(thread_t *thread, bool run_at_once) {
bool st = disable_interrupts();
diff --git a/src/kernel/include/paging.h b/src/kernel/include/paging.h
index d42ec52..56fa7fa 100644
--- a/src/kernel/include/paging.h
+++ b/src/kernel/include/paging.h
@@ -3,10 +3,16 @@
#include <sys.h>
#include <stdbool.h>
+// Bits in the error code for page fault
+#define PF_PRESENT_BIT (1<<0)
+#define PF_WRITE_BIT (1<<1)
+#define PF_USER_BIT (1<<2)
+#define PF_RSVD_WRITE_BIT (1<<3)
+#define PF_OPFETCH_BIT (1<<4)
+
struct page_directory;
typedef struct page_directory pagedir_t;
-
void paging_setup(void* kernel_data_end);
pagedir_t *get_current_pagedir();
diff --git a/src/kernel/include/region.h b/src/kernel/include/region.h
index 1fef582..a390e06 100644
--- a/src/kernel/include/region.h
+++ b/src/kernel/include/region.h
@@ -8,18 +8,18 @@
#include <paging.h>
struct region_info;
-typedef void (*page_fault_handler_t)(pagedir_t *pd, struct region_info *r, void* addr);
+typedef void (*kernel_pf_handler_t)(pagedir_t *pd, struct region_info *r, void* addr);
typedef struct region_info {
void* addr;
size_t size;
char* type;
- page_fault_handler_t pf;
+ kernel_pf_handler_t pf;
} region_info_t;
void region_allocator_init(void* kernel_data_end);
-void* region_alloc(size_t size, char* type, page_fault_handler_t pf); // returns 0 on error
+void* region_alloc(size_t size, char* type, kernel_pf_handler_t pf); // returns 0 on error
region_info_t *find_region(void* addr);
void region_free(void* addr);
diff --git a/src/kernel/include/thread.h b/src/kernel/include/thread.h
index b5fa50d..011067f 100644
--- a/src/kernel/include/thread.h
+++ b/src/kernel/include/thread.h
@@ -3,6 +3,7 @@
#include <sys.h>
#include <paging.h>
#include <region.h>
+#include <idt.h>
#define T_STATE_RUNNING 1
#define T_STATE_PAUSED 2
@@ -12,6 +13,8 @@
#define TASK_SWITCH_FREQUENCY 50 // in herz
+typedef void (*user_pf_handler_t)(pagedir_t *pd, registers_t *regs, void* addr);
+
typedef struct saved_context {
uint32_t *esp;
void (*eip)();
@@ -27,6 +30,8 @@ typedef struct thread {
region_info_t *stack_region;
struct process *proc; // process : L1 data structure
+ user_pf_handler_t usermem_pf_handler; // page fault in user memory
+ isr_handler_t kmem_violation_handler; // page fault in kernel memory accessed by user code (violation)
struct thread *next_in_queue;
} thread_t;
@@ -40,6 +45,7 @@ extern thread_t *current_thread;
void yield();
void pause();
+void exit();
void resume_thread(thread_t *thread, bool run_at_once);