From 5670b0a8e4fe8e5504b2e57a958e1590f6024406 Mon Sep 17 00:00:00 2001 From: Alex Smith Date: Mon, 9 Jul 2012 19:18:09 +0100 Subject: [PATCH] Moved the 32-bit page fault handler to arch_int.cpp, use it for x86_64. A proper page fault handler was required for areas that were not locked into the kernel address space. This enables the boot process to get up to the point of trying to find the boot volume. --- headers/private/kernel/arch/x86/arch_cpu.h | 8 ++- src/system/kernel/arch/x86/32/int.cpp | 83 +--------------------- src/system/kernel/arch/x86/64/int.cpp | 12 +--- src/system/kernel/arch/x86/arch_cpu.cpp | 4 +- src/system/kernel/arch/x86/arch_int.cpp | 83 ++++++++++++++++++++++ 5 files changed, 91 insertions(+), 99 deletions(-) diff --git a/headers/private/kernel/arch/x86/arch_cpu.h b/headers/private/kernel/arch/x86/arch_cpu.h index 32f0129c31..a9100c77c5 100644 --- a/headers/private/kernel/arch/x86/arch_cpu.h +++ b/headers/private/kernel/arch/x86/arch_cpu.h @@ -405,8 +405,9 @@ void x86_set_mtrrs(uint8 defaultType, const x86_mtrr_info* infos, void x86_init_fpu(); bool x86_check_feature(uint32 feature, enum x86_feature_type type); void* x86_get_double_fault_stack(int32 cpu, size_t* _size); -void x86_double_fault_exception(struct iframe* frame); -void x86_page_fault_exception_double_fault(struct iframe* frame); +int32 x86_double_fault_get_cpu(void); + +void x86_page_fault_exception(struct iframe* iframe); #ifndef __x86_64__ @@ -414,7 +415,8 @@ void x86_fnsave(void* fpuState); void x86_frstor(const void* fpuState); void x86_fnsave_swap(void* oldFpuState, const void* newFpuState); void x86_set_task_gate(int32 cpu, int32 n, int32 segment); -int32 x86_double_fault_get_cpu(void); +void x86_double_fault_exception(struct iframe* frame); +void x86_page_fault_exception_double_fault(struct iframe* frame); #endif diff --git a/src/system/kernel/arch/x86/32/int.cpp b/src/system/kernel/arch/x86/32/int.cpp index acfc11778b..c49ec88d0a 100644 --- a/src/system/kernel/arch/x86/32/int.cpp +++ b/src/system/kernel/arch/x86/32/int.cpp @@ -346,87 +346,6 @@ x86_page_fault_exception_double_fault(struct iframe* frame) } -static void -page_fault_exception(struct iframe* frame) -{ - Thread *thread = thread_get_current_thread(); - addr_t cr2 = x86_read_cr2(); - addr_t newip; - - if (debug_debugger_running()) { - // If this CPU or this thread has a fault handler, we're allowed to be - // here. - if (thread != NULL) { - cpu_ent* cpu = &gCPU[smp_get_current_cpu()]; - if (cpu->fault_handler != 0) { - debug_set_page_fault_info(cr2, frame->ip, - (frame->error_code & 0x2) != 0 - ? DEBUG_PAGE_FAULT_WRITE : 0); - frame->ip = cpu->fault_handler; - frame->bp = cpu->fault_handler_stack_pointer; - return; - } - - if (thread->fault_handler != 0) { - kprintf("ERROR: thread::fault_handler used in kernel " - "debugger!\n"); - debug_set_page_fault_info(cr2, frame->ip, - (frame->error_code & 0x2) != 0 - ? DEBUG_PAGE_FAULT_WRITE : 0); - frame->ip = thread->fault_handler; - return; - } - } - - // otherwise, not really - panic("page fault in debugger without fault handler! Touching " - "address %p from eip %p\n", (void *)cr2, (void *)frame->ip); - return; - } else if ((frame->flags & 0x200) == 0) { - // interrupts disabled - - // If a page fault handler is installed, we're allowed to be here. - // TODO: Now we are generally allowing user_memcpy() with interrupts - // disabled, which in most cases is a bug. We should add some thread - // flag allowing to explicitly indicate that this handling is desired. - if (thread && thread->fault_handler != 0) { - if (frame->ip != thread->fault_handler) { - frame->ip = thread->fault_handler; - return; - } - - // The fault happened at the fault handler address. This is a - // certain infinite loop. - panic("page fault, interrupts disabled, fault handler loop. " - "Touching address %p from eip %p\n", (void*)cr2, - (void*)frame->ip); - } - - // If we are not running the kernel startup the page fault was not - // allowed to happen and we must panic. - panic("page fault, but interrupts were disabled. Touching address " - "%p from eip %p\n", (void *)cr2, (void *)frame->ip); - return; - } else if (thread != NULL && thread->page_faults_allowed < 1) { - panic("page fault not allowed at this place. Touching address " - "%p from eip %p\n", (void *)cr2, (void *)frame->ip); - return; - } - - enable_interrupts(); - - vm_page_fault(cr2, frame->ip, - (frame->error_code & 0x2) != 0, // write access - (frame->error_code & 0x4) != 0, // userland - &newip); - if (newip != 0) { - // the page fault handler wants us to modify the iframe to set the - // IP the cpu will return to to be this ip - frame->ip = newip; - } -} - - status_t arch_int_init(struct kernel_args *args) { @@ -720,7 +639,7 @@ arch_int_init(struct kernel_args *args) table[11] = fatal_exception; // Segment Not Present (#NP) table[12] = fatal_exception; // Stack Fault Exception (#SS) table[13] = unexpected_exception; // General Protection Exception (#GP) - table[14] = page_fault_exception; // Page-Fault Exception (#PF) + table[14] = x86_page_fault_exception; // Page-Fault Exception (#PF) table[16] = unexpected_exception; // x87 FPU Floating-Point Error (#MF) table[17] = unexpected_exception; // Alignment Check Exception (#AC) table[18] = fatal_exception; // Machine-Check Exception (#MC) diff --git a/src/system/kernel/arch/x86/64/int.cpp b/src/system/kernel/arch/x86/64/int.cpp index 6117171e30..f0cfb800e6 100644 --- a/src/system/kernel/arch/x86/64/int.cpp +++ b/src/system/kernel/arch/x86/64/int.cpp @@ -96,16 +96,6 @@ unexpected_exception(iframe* frame) } -static void -page_fault_exception(iframe* frame) -{ - addr_t cr2 = x86_read_cr2(); - - panic("page fault exception at ip %#lx on %#lx, error code %#lx\n", - frame->ip, cr2, frame->error_code); -} - - /*! Returns the virtual IDT address for CPU \a cpu. */ void* x86_get_idt(int32 cpu) @@ -164,7 +154,7 @@ arch_int_init(kernel_args* args) table[11] = fatal_exception; // Segment Not Present (#NP) table[12] = fatal_exception; // Stack Fault Exception (#SS) table[13] = unexpected_exception; // General Protection Exception (#GP) - table[14] = page_fault_exception; // Page-Fault Exception (#PF) + table[14] = x86_page_fault_exception; // Page-Fault Exception (#PF) table[16] = unexpected_exception; // x87 FPU Floating-Point Error (#MF) table[17] = unexpected_exception; // Alignment Check Exception (#AC) table[18] = fatal_exception; // Machine-Check Exception (#MC) diff --git a/src/system/kernel/arch/x86/arch_cpu.cpp b/src/system/kernel/arch/x86/arch_cpu.cpp index 3640773097..10c94f6de2 100644 --- a/src/system/kernel/arch/x86/arch_cpu.cpp +++ b/src/system/kernel/arch/x86/arch_cpu.cpp @@ -697,7 +697,6 @@ x86_get_double_fault_stack(int32 cpu, size_t* _size) } -#ifndef __x86_64__ /*! Returns the index of the current CPU. Can only be called from the double fault handler. */ @@ -705,9 +704,8 @@ int32 x86_double_fault_get_cpu(void) { uint32 stack = x86_get_stack_frame(); - return (stack - (uint32)sDoubleFaultStacks) / kDoubleFaultStackSize; + return (stack - (addr_t)sDoubleFaultStacks) / kDoubleFaultStackSize; } -#endif // #pragma mark - diff --git a/src/system/kernel/arch/x86/arch_int.cpp b/src/system/kernel/arch/x86/arch_int.cpp index a7ecd656b1..21dedb3a67 100644 --- a/src/system/kernel/arch/x86/arch_int.cpp +++ b/src/system/kernel/arch/x86/arch_int.cpp @@ -16,6 +16,8 @@ #include #include #include +#include +#include #include #include @@ -90,6 +92,87 @@ hardware_interrupt(struct iframe* frame) } +void +x86_page_fault_exception(struct iframe* frame) +{ + Thread* thread = thread_get_current_thread(); + addr_t cr2 = x86_read_cr2(); + addr_t newip; + + if (debug_debugger_running()) { + // If this CPU or this thread has a fault handler, we're allowed to be + // here. + if (thread != NULL) { + cpu_ent* cpu = &gCPU[smp_get_current_cpu()]; + if (cpu->fault_handler != 0) { + debug_set_page_fault_info(cr2, frame->ip, + (frame->error_code & 0x2) != 0 + ? DEBUG_PAGE_FAULT_WRITE : 0); + frame->ip = cpu->fault_handler; + frame->bp = cpu->fault_handler_stack_pointer; + return; + } + + if (thread->fault_handler != 0) { + kprintf("ERROR: thread::fault_handler used in kernel " + "debugger!\n"); + debug_set_page_fault_info(cr2, frame->ip, + (frame->error_code & 0x2) != 0 + ? DEBUG_PAGE_FAULT_WRITE : 0); + frame->ip = thread->fault_handler; + return; + } + } + + // otherwise, not really + panic("page fault in debugger without fault handler! Touching " + "address %p from ip %p\n", (void*)cr2, (void*)frame->ip); + return; + } else if ((frame->flags & 0x200) == 0) { + // interrupts disabled + + // If a page fault handler is installed, we're allowed to be here. + // TODO: Now we are generally allowing user_memcpy() with interrupts + // disabled, which in most cases is a bug. We should add some thread + // flag allowing to explicitly indicate that this handling is desired. + if (thread && thread->fault_handler != 0) { + if (frame->ip != thread->fault_handler) { + frame->ip = thread->fault_handler; + return; + } + + // The fault happened at the fault handler address. This is a + // certain infinite loop. + panic("page fault, interrupts disabled, fault handler loop. " + "Touching address %p from ip %p\n", (void*)cr2, + (void*)frame->ip); + } + + // If we are not running the kernel startup the page fault was not + // allowed to happen and we must panic. + panic("page fault, but interrupts were disabled. Touching address " + "%p from ip %p\n", (void*)cr2, (void*)frame->ip); + return; + } else if (thread != NULL && thread->page_faults_allowed < 1) { + panic("page fault not allowed at this place. Touching address " + "%p from ip %p\n", (void*)cr2, (void*)frame->ip); + return; + } + + enable_interrupts(); + + vm_page_fault(cr2, frame->ip, + (frame->error_code & 0x2) != 0, // write access + (frame->error_code & 0x4) != 0, // userland + &newip); + if (newip != 0) { + // the page fault handler wants us to modify the iframe to set the + // IP the cpu will return to this ip + frame->ip = newip; + } +} + + // #pragma mark -