diff --git a/src/kernel/core/arch/x86/Jamfile b/src/kernel/core/arch/x86/Jamfile index 5365a297a3..2c793d8801 100644 --- a/src/kernel/core/arch/x86/Jamfile +++ b/src/kernel/core/arch/x86/Jamfile @@ -7,7 +7,7 @@ KernelStaticLibrary libx86 : <$(SOURCE_GRIST)>arch_elf.c <$(SOURCE_GRIST)>arch_faults.c <$(SOURCE_GRIST)>arch_int.c - <$(SOURCE_GRIST)>arch_selector.c +# <$(SOURCE_GRIST)>arch_selector.c <$(SOURCE_GRIST)>arch_smp.c <$(SOURCE_GRIST)>arch_thread.c <$(SOURCE_GRIST)>arch_timer.c diff --git a/src/kernel/core/arch/x86/arch_cpu.c b/src/kernel/core/arch/x86/arch_cpu.c index 3749217c90..c1db89580f 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 @@ -21,7 +22,7 @@ static struct tss **tss; static int *tss_loaded; -static unsigned int *gdt = 0; +segment_descriptor *gGDT = NULL; int @@ -44,16 +45,19 @@ arch_cpu_init(kernel_args *ka) int arch_cpu_init2(kernel_args *ka) { - region_id rid; - struct tss_descriptor *tss_d; unsigned int i; // account for the segment descriptors - gdt = (unsigned int *)ka->arch_args.vir_gdt; - vm_create_anonymous_region(vm_get_kernel_aspace_id(), "gdt", (void **)&gdt, + + gGDT = (segment_descriptor *)ka->arch_args.vir_gdt; + vm_create_anonymous_region(vm_get_kernel_aspace_id(), "gdt", (void **)&gGDT, REGION_ADDR_EXACT_ADDRESS, PAGE_SIZE, REGION_WIRING_WIRED_ALREADY, LOCK_RW|LOCK_KERNEL); - i386_selector_init(gdt); // pass the new gdt + // currently taken out of the build, because it's not yet used (and assumes + // (a fixed number of used GDT entries) + //i386_selector_init(gGDT); // pass the new gdt + + // setup task-state segments tss = malloc(sizeof(struct tss *) * ka->num_cpus); if (tss == NULL) { @@ -69,7 +73,9 @@ arch_cpu_init2(kernel_args *ka) memset(tss_loaded, 0, sizeof(int) * ka->num_cpus); for (i = 0; i < ka->num_cpus; i++) { + struct segment_descriptor *tss_d; char tss_name[16]; + region_id rid; sprintf(tss_name, "tss%d", i); rid = vm_create_anonymous_region(vm_get_kernel_aspace_id(), tss_name, (void **)&tss[i], @@ -79,25 +85,21 @@ arch_cpu_init2(kernel_args *ka) return ENOMEM; } + // initialize TSS memset(tss[i], 0, sizeof(struct tss)); tss[i]->ss0 = KERNEL_DATA_SEG; // add TSS descriptor for this new TSS - tss_d = (struct tss_descriptor *)&gdt[10 + i*2]; - tss_d->limit_00_15 = sizeof(struct tss) & 0xffff; - tss_d->limit_19_16 = 0; // not this long - tss_d->base_00_15 = (addr)tss[i] & 0xffff; - tss_d->base_23_16 = ((addr)tss[i] >> 16) & 0xff; - tss_d->base_31_24 = (addr)tss[i] >> 24; - tss_d->type = 0x9; - tss_d->zero = 0; - tss_d->dpl = 0; - tss_d->present = 1; - tss_d->avail = 0; - tss_d->zero1 = 0; - tss_d->zero2 = 1; - tss_d->granularity = 1; + set_tss_descriptor(&gGDT[TSS_BASE_SEGMENT + i], (addr)tss[i], sizeof(struct tss)); } + + // setup TLS descriptors (one for every CPU) + + for (i = 0; i < ka->num_cpus; i++) { + set_segment_descriptor(&gGDT[TLS_BASE_SEGMENT + i], 0, TLS_MAX_KEYS * sizeof(void *), + DT_DATA_WRITEABLE, DPL_USER); + } + return 0; } diff --git a/src/kernel/core/arch/x86/arch_int.c b/src/kernel/core/arch/x86/arch_int.c index c9d6037084..4c5d55e773 100755 --- a/src/kernel/core/arch/x86/arch_int.c +++ b/src/kernel/core/arch/x86/arch_int.c @@ -24,6 +24,7 @@ #include #include +#include #include @@ -31,15 +32,18 @@ #define MAX_ARGS 16 +typedef struct { + uint32 a, b; +} desc_table; static desc_table *idt = NULL; static void interrupt_ack(int n) { - if(n >= 0x20 && n < 0x30) { + if (n >= 0x20 && n < 0x30) { // 8239 controlled interrupt - if(n > 0x27) + if (n > 0x27) out8(0x20, 0xa0); // EOI to pic 2 out8(0x20, 0x20); // EOI to pic 1 } @@ -47,7 +51,7 @@ interrupt_ack(int n) static void -_set_gate(desc_table *gate_addr, unsigned int addr, int type, int dpl) +set_gate(desc_table *gate_addr, unsigned int addr, int type, int dpl) { unsigned int gate1; // first byte of gate desc unsigned int gate2; // second byte of gate desc @@ -60,6 +64,29 @@ _set_gate(desc_table *gate_addr, unsigned int addr, int type, int dpl) } +static void +set_intr_gate(int n, void *addr) +{ + set_gate(&idt[n], (unsigned int)addr, 14, DPL_KERNEL); +} + + +/* XXX - currently unused and static... +static void +set_trap_gate(int n, void *addr) +{ + set_gate(&idt[n], (unsigned int)addr, 15, DPL_KERNEL); +} +*/ + + +static void +set_system_gate(int n, void *addr) +{ + set_gate(&idt[n], (unsigned int)addr, 15, DPL_USER); +} + + void arch_int_enable_io_interrupt(int irq) { @@ -89,29 +116,6 @@ arch_int_disable_io_interrupt(int irq) } -static void -set_intr_gate(int n, void *addr) -{ - _set_gate(&idt[n], (unsigned int)addr, 14, 0); -} - - -/* XXX - currently unused and static... -static void -set_trap_gate(int n, void *addr) -{ - _set_gate(&idt[n], (unsigned int)addr, 15, 0); -} -*/ - - -static void -set_system_gate(int n, void *addr) -{ - _set_gate(&idt[n], (unsigned int)addr, 15, 3); -} - - void arch_int_enable_interrupts(void) { @@ -136,8 +140,7 @@ arch_int_restore_interrupts(int oldstate) { int flags = oldstate ? 0x200 : 0; - asm ( - "pushfl;\n" + asm("pushfl;\n" "popl %1;\n" "andl $0xfffffdff,%1;\n" "orl %0,%1;\n" @@ -174,14 +177,16 @@ i386_handle_trap(struct iframe frame) // if(frame.vector != 0x20) // dprintf("i386_handle_trap: vector 0x%x, ip 0x%x, cpu %d\n", frame.vector, frame.eip, smp_get_current_cpu()); - switch(frame.vector) { - case 8: + + switch (frame.vector) { + case 8: // double fault ret = i386_double_fault(frame.error_code); break; - case 13: + case 13: // general protection fault ret = i386_general_protection_fault(frame.error_code); break; - case 14: { + case 14: // page fault + { unsigned int cr2; addr newip; @@ -207,7 +212,8 @@ i386_handle_trap(struct iframe frame) } break; } - case 99: { + case 99: // syscall + { uint64 retcode; unsigned int args[MAX_ARGS]; int rc; @@ -279,6 +285,7 @@ i386_handle_trap(struct iframe frame) int arch_int_init(kernel_args *ka) { + // set the global idt variable idt = (desc_table *)ka->arch_args.vir_idt; // setup the interrupt controller diff --git a/src/kernel/core/arch/x86/arch_interrupts.S b/src/kernel/core/arch/x86/arch_interrupts.S index de6cd0c778..1e8d05a01d 100755 --- a/src/kernel/core/arch/x86/arch_interrupts.S +++ b/src/kernel/core/arch/x86/arch_interrupts.S @@ -145,8 +145,8 @@ FUNCTION(i386_stack_switch): pushl %ss cmpl $KERNEL_DATA_SEG,(%esp) je kernel_stack2 - popl %eax - jmp switch + popl %eax + jmp switch kernel_stack2: popl 4(%eax) movl %esp,(%eax) diff --git a/src/kernel/core/arch/x86/arch_smp.c b/src/kernel/core/arch/x86/arch_smp.c index a2e78dd042..71164e2a07 100755 --- a/src/kernel/core/arch/x86/arch_smp.c +++ b/src/kernel/core/arch/x86/arch_smp.c @@ -23,13 +23,13 @@ #include #include -static int num_cpus = 1; -static unsigned int *apic = NULL; -static unsigned int cpu_apic_id[SMP_MAX_CPUS] = { 0, 0}; -static unsigned int cpu_os_id[SMP_MAX_CPUS] = { 0, 0}; -static unsigned int cpu_apic_version[SMP_MAX_CPUS] = { 0, 0}; -static unsigned int *ioapic = NULL; -static unsigned int apic_timer_tics_per_sec = 0; + +static uint32 *apic = NULL; +static uint32 cpu_apic_id[SMP_MAX_CPUS] = { 0, 0}; +static uint32 cpu_os_id[SMP_MAX_CPUS] = { 0, 0}; +static uint32 cpu_apic_version[SMP_MAX_CPUS] = { 0, 0}; +static uint32 *ioapic = NULL; +static uint32 apic_timer_tics_per_sec = 0; static int32 @@ -58,6 +58,7 @@ i386_spurious_interrupt(void *data) // spurious interrupt // dprintf("spurious interrupt on cpu %d\n", arch_smp_get_current_cpu()); arch_smp_ack_interrupt(); + return B_HANDLED_INTERRUPT; } @@ -68,6 +69,7 @@ i386_smp_error_interrupt(void *data) // smp error interrupt // dprintf("smp error interrupt on cpu %d\n", arch_smp_get_current_cpu()); arch_smp_ack_interrupt(); + return B_HANDLED_INTERRUPT; } @@ -91,11 +93,10 @@ arch_smp_init(kernel_args *ka) { dprintf("arch_smp_init: entry\n"); - if(ka->num_cpus > 1) { + if (ka->num_cpus > 1) { // setup some globals - num_cpus = ka->num_cpus; - apic = ka->arch_args.apic; - ioapic = ka->arch_args.ioapic; + apic = (uint32 *)ka->arch_args.apic; + ioapic = (uint32 *)ka->arch_args.ioapic; memcpy(cpu_apic_id, ka->arch_args.cpu_apic_id, sizeof(ka->arch_args.cpu_apic_id)); memcpy(cpu_os_id, ka->arch_args.cpu_os_id, sizeof(ka->arch_args.cpu_os_id)); memcpy(cpu_apic_version, ka->arch_args.cpu_apic_version, sizeof(ka->arch_args.cpu_apic_version)); @@ -111,8 +112,6 @@ arch_smp_init(kernel_args *ka) install_interrupt_handler(0xfd, &i386_ici_interrupt, NULL); install_interrupt_handler(0xfe, &i386_smp_error_interrupt, NULL); install_interrupt_handler(0xff, &i386_spurious_interrupt, NULL); - } else { - num_cpus = 1; } return 0; } diff --git a/src/kernel/core/arch/x86/arch_thread.c b/src/kernel/core/arch/x86/arch_thread.c index 3a49bd4475..62b66e6b04 100755 --- a/src/kernel/core/arch/x86/arch_thread.c +++ b/src/kernel/core/arch/x86/arch_thread.c @@ -18,7 +18,7 @@ // from arch_interrupts.S -extern void i386_stack_init( struct farcall *interrupt_stack_offset ); +extern void i386_stack_init(struct farcall *interrupt_stack_offset); void @@ -37,6 +37,13 @@ i386_pop_iframe(struct thread *thread) } +static void +i386_set_fs_register(uint32 segment) +{ + asm("movl %0,%%fs" :: "r" (segment)); +} + + int arch_team_init_team_struct(struct team *p, bool kernel) { @@ -52,7 +59,7 @@ arch_thread_init_thread_struct(struct thread *t) // let the asm function know the offset to the interrupt stack within struct thread // I know no better ( = static) way to tell the asm function the offset - i386_stack_init( &((struct thread*)0)->arch_info.interrupt_stack ); + i386_stack_init(&((struct thread *)0)->arch_info.interrupt_stack); return 0; } @@ -89,7 +96,7 @@ arch_thread_initialize_kthread_stack(struct thread *t, int (*start_func)(void), // *kstack_top = 0x00; // interrupts still disabled after the switch // simulate initial popad - for(i=0; i<8; i++) { + for (i = 0; i < 8; i++) { kstack_top--; *kstack_top = 0; } @@ -123,7 +130,7 @@ arch_thread_context_switch(struct thread *t_from, struct thread *t_to) t_to->arch_info.current_stack.ss, t_to->arch_info.current_stack.esp); #endif #if 0 - for(i=0; i<11; i++) + for (i = 0; i < 11; i++) dprintf("*esp[%d] (0x%x) = 0x%x\n", i, ((unsigned int *)new_at->esp + i), *((unsigned int *)new_at->esp + i)); #endif i386_set_kstack(t_to->kernel_stack_base + KSTACK_SIZE); @@ -134,19 +141,19 @@ arch_thread_context_switch(struct thread *t_from, struct thread *t_to) } #endif - if(t_from->team->_aspace_id >= 0 && t_to->team->_aspace_id >= 0) { + if (t_from->team->_aspace_id >= 0 && t_to->team->_aspace_id >= 0) { // they are both uspace threads - if(t_from->team->_aspace_id == t_to->team->_aspace_id) { + if (t_from->team->_aspace_id == t_to->team->_aspace_id) { // dont change the pgdir, same address space new_pgdir = NULL; } else { // switching to a new address space new_pgdir = vm_translation_map_get_pgdir(&t_to->team->aspace->translation_map); } - } else if(t_from->team->_aspace_id < 0 && t_to->team->_aspace_id < 0) { + } else if (t_from->team->_aspace_id < 0 && t_to->team->_aspace_id < 0) { // they must both be kspace threads new_pgdir = NULL; - } else if(t_to->team->_aspace_id < 0) { + } else if (t_to->team->_aspace_id < 0) { // the one we're switching to is kspace new_pgdir = vm_translation_map_get_pgdir(&t_to->team->kaspace->translation_map); } else { @@ -162,11 +169,26 @@ arch_thread_context_switch(struct thread *t_from, struct thread *t_to) } #endif - if((new_pgdir % PAGE_SIZE) != 0) + if ((new_pgdir % PAGE_SIZE) != 0) panic("arch_thread_context_switch: bad pgdir 0x%lx\n", new_pgdir); i386_fsave_swap(t_from->arch_info.fpu_state, t_to->arch_info.fpu_state); i386_context_switch(&t_from->arch_info, &t_to->arch_info, new_pgdir); + + // set TLS GDT entry to the current thread - since this action is + // dependent on the current CPU, we have to do it here + { + int entry = smp_get_current_cpu() + TLS_BASE_SEGMENT; + + // ToDo: the TLS storage is currently located simply at the bottom of the user stack + // perhaps we want to put it somewhere else, in a safe place? + // very strange: the user_stack_base pointer seg faults, (+ PAGE_SIZE) improves + // the situation, but the main thread still don't work correctly... + // Also have a look at the stack addresses: the main thread is located at + // 0x7ffd600, the ones of the others are at 0x0062b000 and following + set_segment_descriptor_base(&gGDT[entry], t_to->user_stack_base + PAGE_SIZE); + i386_set_fs_register((entry << 3) | DPL_USER); + } } @@ -184,7 +206,7 @@ arch_thread_dump_info(void *info) void arch_thread_enter_uspace(addr entry, void *args, addr ustack_top) { - dprintf("arch_thread_entry_uspace: entry 0x%lx, args %p, ustack_top 0x%lx\n", + dprintf("arch_thread_enter_uspace: entry 0x%lx, args %p, ustack_top 0x%lx\n", entry, args, ustack_top); // make sure the fpu is in a good state diff --git a/src/kernel/core/arch/x86/arch_x86.S b/src/kernel/core/arch/x86/arch_x86.S index b109978292..233d33a234 100755 --- a/src/kernel/core/arch/x86/arch_x86.S +++ b/src/kernel/core/arch/x86/arch_x86.S @@ -144,7 +144,7 @@ FUNCTION(i386_fxsave_swap): /* void i386_context_switch(struct arch_thread *old_state, struct arch_thread *new_state, addr new_pgdir); */ FUNCTION(i386_context_switch): pusha /* pushes 8 words onto the stack */ - movl 36(%esp),%eax /* save current_stack */ + movl 36(%esp),%eax /* save old_state->current_stack */ movl %esp,(%eax) pushl %ss popl %edx @@ -152,9 +152,9 @@ FUNCTION(i386_context_switch): movl 44(%esp),%eax /* get possible new pgdir */ orl %eax,%eax /* is it null? */ je skip_pgdir_swap - movl %eax,%cr3 + movl %eax,%cr3 skip_pgdir_swap: - movl 40(%esp),%eax /* get new current_stack */ + movl 40(%esp),%eax /* get new new_state->current_stack */ lss (%eax),%esp popa ret @@ -185,7 +185,7 @@ FUNCTION(i386_enter_uspace): movw $0x23,%cx movw %cx,%ds movw %cx,%es - movw %cx,%fs + //movw %cx,%fs // fs points to the TLS storage (CPU dependent segment) movw %cx,%gs // copy exit stub to stack @@ -198,7 +198,6 @@ _copy_more: cmp $i386_uspace_exit_stub, %esi jg _copy_more - // push the args onto the user stack movl %edx,-4(%ebx) // args movl %ebx,-8(%ebx) // fake return address to copied exit stub