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.
This commit is contained in:
Alex Smith
2012-07-09 19:18:09 +01:00
parent c8049a88a3
commit 5670b0a8e4
5 changed files with 91 additions and 99 deletions
+5 -3
View File
@@ -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
+1 -82
View File
@@ -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)
+1 -11
View File
@@ -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)
+1 -3
View File
@@ -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 -
+83
View File
@@ -16,6 +16,8 @@
#include <team.h>
#include <thread.h>
#include <util/AutoLock.h>
#include <vm/vm.h>
#include <vm/vm_priv.h>
#include <arch/cpu.h>
#include <arch/int.h>
@@ -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 -