diff --git a/src/kernel/core/arch/x86/arch_cpu.c b/src/kernel/core/arch/x86/arch_cpu.c index a6c9d238ea..49b441e468 100755 --- a/src/kernel/core/arch/x86/arch_cpu.c +++ b/src/kernel/core/arch/x86/arch_cpu.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -18,14 +19,40 @@ #include #include - -void reboot(void); +extern void reboot(void); + // from arch_x86.S static struct tss **sTSS; static int *sIsTSSLoaded; segment_descriptor *gGDT = NULL; +/* Some specials for the double fault handler */ +static struct tss sDoubleFaultTSS; +static uint32 sDoubleFaultStack[1024]; + + +static void +init_double_fault(void) +{ + /* set up the double fault tss */ + memset(&sDoubleFaultTSS, 0, sizeof(struct tss)); + sDoubleFaultTSS.sp0 = (uint32)sDoubleFaultStack + sizeof(sDoubleFaultStack); + sDoubleFaultTSS.ss0 = KERNEL_DATA_SEG; + read_cr3(sDoubleFaultTSS.cr3); // copy the current cr3 to the double fault cr3 + sDoubleFaultTSS.eip = (uint32)&trap8; + sDoubleFaultTSS.es = KERNEL_DATA_SEG; + sDoubleFaultTSS.cs = KERNEL_CODE_SEG; + sDoubleFaultTSS.ss = KERNEL_DATA_SEG; + sDoubleFaultTSS.ds = KERNEL_DATA_SEG; + sDoubleFaultTSS.fs = KERNEL_DATA_SEG; + sDoubleFaultTSS.gs = KERNEL_DATA_SEG; + sDoubleFaultTSS.ldt_seg_selector = KERNEL_DATA_SEG; + + set_tss_descriptor(&gGDT[DOUBLE_FAULT_TSS_SEGMENT], (addr_t)&sDoubleFaultTSS, sizeof(struct tss)); + x86_set_task_gate(8, DOUBLE_FAULT_TSS_SEGMENT << 3); +} + status_t arch_cpu_preboot_init(kernel_args *args) @@ -101,16 +128,16 @@ arch_cpu_init_post_vm(kernel_args *args) DT_DATA_WRITEABLE, DPL_USER); } - return 0; + init_double_fault(); + return B_OK; } void i386_set_tss_and_kstack(addr_t kstack) { - int currentCPU = smp_get_current_cpu(); + int32 currentCPU = smp_get_current_cpu(); -// dprintf("i386_set_kstack: kstack 0x%x, cpu %d\n", kstack, currentCPU); if (!sIsTSSLoaded[currentCPU]) { short seg = ((TSS_BASE_SEGMENT + currentCPU) << 3) | DPL_KERNEL; asm("movw %0, %%ax;" @@ -119,7 +146,6 @@ i386_set_tss_and_kstack(addr_t kstack) } sTSS[currentCPU]->sp0 = kstack; -// dprintf("done\n"); } diff --git a/src/kernel/core/arch/x86/arch_int.c b/src/kernel/core/arch/x86/arch_int.c index 0f9b7bd11d..01527ec18d 100755 --- a/src/kernel/core/arch/x86/arch_int.c +++ b/src/kernel/core/arch/x86/arch_int.c @@ -105,6 +105,14 @@ set_system_gate(int n, void *addr) } +void +x86_set_task_gate(int32 n, int32 segment) +{ + idt[n].a = (segment << 16); + idt[n].b = 0x8000 | (0 << 13) | (0x5 << 8); // present, dpl 0, type 5 +} + + void arch_int_enable_io_interrupt(int irq) { @@ -324,7 +332,7 @@ arch_int_init(kernel_args *args) set_intr_gate(5, &trap5); set_intr_gate(6, &trap6); set_intr_gate(7, &trap7); - set_intr_gate(8, &trap8); + // trap8 (double fault) is set in arch_cpu.c set_intr_gate(9, &trap9); set_intr_gate(10, &trap10); set_intr_gate(11, &trap11);