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 -