From 75a1e4532166e7aeb2c0c3109851d4dd48c25183 Mon Sep 17 00:00:00 2001 From: Richard Braun Date: Sat, 15 Jun 2013 10:18:07 +0200 Subject: x86 page fault handling --- arch/x86/machine/trap.c | 57 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 56 insertions(+), 1 deletion(-) (limited to 'arch/x86/machine/trap.c') diff --git a/arch/x86/machine/trap.c b/arch/x86/machine/trap.c index 36585c25..9ef26a27 100644 --- a/arch/x86/machine/trap.c +++ b/arch/x86/machine/trap.c @@ -23,7 +23,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -31,6 +33,18 @@ #include #include #include +#include +#include +#include + +/* + * Page fault error codes. + */ +#define TRAP_ERROR_PF_PROT 0x01 /* Protection violation */ +#define TRAP_ERROR_PF_WRITE 0x02 /* Write access */ +#define TRAP_ERROR_PF_USER 0x04 /* User mode access */ +#define TRAP_ERROR_PF_RESERVED 0x08 /* Invalid PTE (reserved bit set) */ +#define TRAP_ERROR_PF_EXEC 0x10 /* Instruction fetch */ /* * Type for interrupt service routines and trap handler functions. @@ -157,6 +171,47 @@ trap_install_double_fault(void) cpu_idt_set_double_fault(trap_isr_double_fault); } +static void +trap_page_fault(struct trap_frame *frame) +{ + struct thread *thread; + struct vm_map *map; + unsigned long addr; + int error, access; + + /* + * TODO Page faults can currently only be handled when they are accesses + * from kernel space to valid mapped objects. Complete according to the + * VM system capabilities. + */ + assert(!(frame->error & TRAP_ERROR_PF_PROT)); + assert(!(frame->error & TRAP_ERROR_PF_USER)); + assert(!(frame->error & TRAP_ERROR_PF_RESERVED)); + assert(!(frame->error & TRAP_ERROR_PF_EXEC)); + + /* + * Reading CR2 is safe because interrupts are disabled and kernel code + * can't cause another page fault while handling a page fault. + */ + addr = cpu_get_cr2(); + access = (frame->error & TRAP_ERROR_PF_WRITE) + ? VM_PROT_WRITE + : VM_PROT_READ; + thread = thread_self(); + map = (addr >= VM_MIN_KERNEL_ADDRESS) ? kernel_map : thread->task->map; + + error = vm_map_fault(map, addr, access); + + if (error) { + cpu_halt_broadcast(); + printk("trap: page fault error: %d, code %#lx at %#lx in task %s\n", + error, frame->error, addr, thread->task->name); + trap_frame_show(frame); + trap_stack_show(frame); + cpu_halt(); + } +} + static void trap_default(struct trap_frame *frame) { @@ -189,7 +244,7 @@ trap_setup(void) trap_install(TRAP_NP, 0, trap_isr_segment_not_present, trap_default); trap_install(TRAP_SS, 0, trap_isr_stack_segment_fault, trap_default); trap_install(TRAP_GP, 0, trap_isr_general_protection, trap_default); - trap_install(TRAP_PF, 0, trap_isr_page_fault, trap_default); + trap_install(TRAP_PF, 0, trap_isr_page_fault, trap_page_fault); trap_install(TRAP_MF, 0, trap_isr_math_fault, trap_default); trap_install(TRAP_AC, 0, trap_isr_alignment_check, trap_default); trap_install(TRAP_MC, TRAP_HF_NOPREEMPT, -- cgit v1.2.3