diff --git a/headers/private/kernel/arch/x86/arch_cpu.h b/headers/private/kernel/arch/x86/arch_cpu.h index ea5ee96966..f8a4acf975 100644 --- a/headers/private/kernel/arch/x86/arch_cpu.h +++ b/headers/private/kernel/arch/x86/arch_cpu.h @@ -75,6 +75,8 @@ void i386_fxrstor(const void *fpu_state); void i386_fsave_swap(void *old_fpu_state, const void *new_fpu_state); void i386_fxsave_swap(void *old_fpu_state, const void *new_fpu_state); void x86_set_task_gate(int32 n, int32 segment); +struct tss *x86_get_main_tss(void); + #define read_ebp(value) \ __asm__("movl %%ebp,%0" : "=r" (value)) diff --git a/headers/private/kernel/arch/x86/descriptors.h b/headers/private/kernel/arch/x86/descriptors.h index 8615027a16..1e4a86f4b8 100644 --- a/headers/private/kernel/arch/x86/descriptors.h +++ b/headers/private/kernel/arch/x86/descriptors.h @@ -17,8 +17,8 @@ // this file can also be included from assembler as well // (and is in arch_interrupts.S) -#define DOUBLE_FAULT_TSS_SEGMENT 5 -#define TSS_BASE_SEGMENT 6 +#define DOUBLE_FAULT_TSS_BASE_SEGMENT 5 +#define TSS_BASE_SEGMENT (DOUBLE_FAULT_TSS_BASE_SEGMENT + smp_get_num_cpus()) #define TLS_BASE_SEGMENT (TSS_BASE_SEGMENT + smp_get_num_cpus()) @@ -125,7 +125,7 @@ set_tss_descriptor(struct segment_descriptor *desc, addr_t base, uint32 limit) desc->privilege_level = DPL_KERNEL; desc->present = 1; - desc->granularity = 1; // 4 GB size (in page size steps) + desc->granularity = 0; // 1 Byte granularity desc->available = 0; // system available bit is currently not used desc->d_b = 0; diff --git a/headers/private/kernel/arch/x86/faults.h b/headers/private/kernel/arch/x86/faults.h index 7998a04f20..b0141c6817 100644 --- a/headers/private/kernel/arch/x86/faults.h +++ b/headers/private/kernel/arch/x86/faults.h @@ -5,8 +5,10 @@ #ifndef _NEWOS_KERNEL_ARCH_I386_FAULTS #define _NEWOS_KERNEL_ARCH_I386_FAULTS +struct iframe; + int i386_general_protection_fault(int errorcode); -int i386_double_fault(int errorcode); +int i386_double_fault(struct iframe *frame); #endif diff --git a/headers/private/kernel/arch/x86/interrupts.h b/headers/private/kernel/arch/x86/interrupts.h index c2901ed898..dcf0d262e7 100644 --- a/headers/private/kernel/arch/x86/interrupts.h +++ b/headers/private/kernel/arch/x86/interrupts.h @@ -6,12 +6,14 @@ #define _NEWOS_KERNEL_ARCH_I386_INTERRUPTS_H void trap0();void trap1();void trap2();void trap3();void trap4();void trap5(); -void trap6();void trap7();void trap8();void trap9();void trap10();void trap11(); +void trap6();void trap7();void trap9();void trap10();void trap11(); void trap12();void trap13();void trap14();void trap16();void trap17();void trap18(); void trap32();void trap33();void trap34();void trap35();void trap36();void trap37(); void trap38();void trap39();void trap40();void trap41();void trap42();void trap43(); void trap44();void trap45();void trap46();void trap47(); +void double_fault(); // int 8 + void trap99(); void trap251();void trap252();void trap253();void trap254();void trap255(); diff --git a/src/kernel/core/arch/x86/arch_cpu.c b/src/kernel/core/arch/x86/arch_cpu.c index 88462b59b3..688ceb54da 100644 --- a/src/kernel/core/arch/x86/arch_cpu.c +++ b/src/kernel/core/arch/x86/arch_cpu.c @@ -23,34 +23,51 @@ extern void reboot(void); // from arch_x86.S static struct tss **sTSS; +//static struct tss **sDoubleFaultTSS; +struct tss **sDoubleFaultTSS; static int *sIsTSSLoaded; segment_descriptor *gGDT = NULL; /* Some specials for the double fault handler */ -static struct tss sDoubleFaultTSS; -static uint32 sDoubleFaultStack[1024]; +//static struct tss sDoubleFaultTSS; +static uint32 sDoubleFaultStack[10240]; + + +struct tss * +x86_get_main_tss(void) +{ + int cpuNum = smp_get_current_cpu(); + + return sTSS[cpuNum]; +} static void -init_double_fault(void) +init_double_fault(int cpuNum) { /* 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; + /* TODO: Axel - fix SMP support */ + struct tss *tss = sDoubleFaultTSS[cpuNum]; + + memset(tss, 0, sizeof(struct tss)); + tss->sp0 = (uint32)sDoubleFaultStack + sizeof(sDoubleFaultStack); + tss->ss0 = KERNEL_DATA_SEG; + read_cr3(tss->cr3); // copy the current cr3 to the double fault cr3 + tss->eip = (uint32)&double_fault; + tss->es = KERNEL_DATA_SEG; + tss->cs = KERNEL_CODE_SEG; + tss->ss = KERNEL_DATA_SEG; + tss->esp = tss->sp0; + tss->ds = KERNEL_DATA_SEG; + tss->fs = KERNEL_DATA_SEG; + tss->gs = KERNEL_DATA_SEG; + tss->ldt_seg_selector = 0; - set_tss_descriptor(&gGDT[DOUBLE_FAULT_TSS_SEGMENT], (addr_t)&sDoubleFaultTSS, sizeof(struct tss)); - x86_set_task_gate(8, DOUBLE_FAULT_TSS_SEGMENT << 3); + // add TSS descriptor for this new TSS + set_tss_descriptor(&gGDT[DOUBLE_FAULT_TSS_BASE_SEGMENT + cpuNum], (addr_t)tss, sizeof(struct tss)); + +// set_tss_descriptor(&gGDT[DOUBLE_FAULT_TSS_SEGMENT + cpuNum], (addr_t)sDoubleFaultTSS[cpuNum], sizeof(struct tss)); } @@ -93,6 +110,12 @@ arch_cpu_init_post_vm(kernel_args *args) panic("arch_cpu_init_post_vm: could not allocate buffer for tss pointers\n"); return B_NO_MEMORY; } + + sDoubleFaultTSS = malloc(sizeof(struct tss *) * args->num_cpus); + if (sDoubleFaultTSS == NULL) { + panic("arch_cpu_init_post_vm: could not allocate buffer for double fault tss pointers\n"); + return B_NO_MEMORY; + } sIsTSSLoaded = malloc(sizeof(int) * args->num_cpus); if (sIsTSSLoaded == NULL) { @@ -102,9 +125,10 @@ arch_cpu_init_post_vm(kernel_args *args) memset(sIsTSSLoaded, 0, sizeof(int) * args->num_cpus); for (i = 0; i < args->num_cpus; i++) { - char tssName[16]; + char tssName[32]; area_id area; + // create standard tasks sprintf(tssName, "tss%lu", i); area = create_area(tssName, (void **)&sTSS[i], B_ANY_KERNEL_ADDRESS, B_PAGE_SIZE, B_FULL_LOCK, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA); @@ -119,7 +143,30 @@ arch_cpu_init_post_vm(kernel_args *args) // add TSS descriptor for this new TSS set_tss_descriptor(&gGDT[TSS_BASE_SEGMENT + i], (addr_t)sTSS[i], sizeof(struct tss)); + + + // create double-fault task + sprintf(tssName, "double_fault_tss%lu", i); + area = create_area(tssName, (void **)&sDoubleFaultTSS[i], B_ANY_KERNEL_ADDRESS, B_PAGE_SIZE, + B_FULL_LOCK, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA); + if (area < 0) { + panic("arch_cpu_init2: unable to create region for tss\n"); + return B_NO_MEMORY; + } + + // initialize TSS + init_double_fault(i); } + + /* TODO: Axel - call on all CPUs */ + { + short seg = ((TSS_BASE_SEGMENT + 0) << 3) | DPL_KERNEL; + asm("movw %0, %%ax;" + "ltr %%ax;" : : "r" (seg) : "eax"); + sIsTSSLoaded[0] = true; + } + + x86_set_task_gate(8, DOUBLE_FAULT_TSS_BASE_SEGMENT << 3); // setup TLS descriptors (one for every CPU) @@ -127,8 +174,7 @@ arch_cpu_init_post_vm(kernel_args *args) set_segment_descriptor(&gGDT[TLS_BASE_SEGMENT + i], 0, TLS_SIZE, DT_DATA_WRITEABLE, DPL_USER); } - - init_double_fault(); + return B_OK; } diff --git a/src/kernel/core/arch/x86/arch_faults.c b/src/kernel/core/arch/x86/arch_faults.c index 05987a8fc2..60e49f8cfa 100644 --- a/src/kernel/core/arch/x86/arch_faults.c +++ b/src/kernel/core/arch/x86/arch_faults.c @@ -8,6 +8,7 @@ #include #include +#include #include // XXX this module is largely outdated. Will probably be removed later. @@ -22,11 +23,17 @@ int i386_general_protection_fault(int errorcode) return general_protection_fault(errorcode); } -int i386_double_fault(int errorcode) +int i386_double_fault(struct iframe *frame) { - kprintf("double fault! errorcode = 0x%x\n", errorcode); - dprintf("double fault! errorcode = 0x%x\n", errorcode); - for(;;); + struct tss *tss = x86_get_main_tss(); + + frame->cs = tss->cs; + frame->eip = tss->eip; + frame->esp = tss->esp; + frame->flags = tss->eflags; + + panic("double fault! errorcode = 0x%x\n", frame->error_code); + return B_HANDLED_INTERRUPT; } diff --git a/src/kernel/core/arch/x86/arch_int.c b/src/kernel/core/arch/x86/arch_int.c index 6459d22bdf..c4f5367901 100644 --- a/src/kernel/core/arch/x86/arch_int.c +++ b/src/kernel/core/arch/x86/arch_int.c @@ -213,7 +213,7 @@ i386_handle_trap(struct iframe frame) ret = i386_handle_breakpoint_exception(&frame); break; case 8: // double fault - ret = i386_double_fault(frame.error_code); + ret = i386_double_fault(&frame); break; case 13: // general protection fault ret = i386_general_protection_fault(frame.error_code); diff --git a/src/kernel/core/arch/x86/arch_interrupts.S b/src/kernel/core/arch/x86/arch_interrupts.S index 03a38de8c0..8e2ca7eded 100644 --- a/src/kernel/core/arch/x86/arch_interrupts.S +++ b/src/kernel/core/arch/x86/arch_interrupts.S @@ -42,7 +42,21 @@ TRAP(trap4, 4) TRAP(trap5, 5) TRAP(trap6, 6) TRAP(trap7, 7) -TRAP_ERRC(trap8, 8) + +.globl double_fault; +.align 8; +double_fault: + pushl $-1; // user-ss + pushl $-1; // user-esp + pushl $-1; // flags + pushl $KERNEL_CODE_SEG; // cs + pushl $-1; // eip + pushl $0; // error-code + pushl $8; + pushl $-1; + pushl $-1; + jmp int_bottom + TRAP(trap9, 9) TRAP_ERRC(trap10, 10) TRAP_ERRC(trap11, 11)