diff --git a/headers/private/kernel/arch/x86/arch_thread.h b/headers/private/kernel/arch/x86/arch_thread.h index ff1f42a3cc..f0513717c9 100644 --- a/headers/private/kernel/arch/x86/arch_thread.h +++ b/headers/private/kernel/arch/x86/arch_thread.h @@ -22,7 +22,9 @@ struct iframe *i386_get_thread_user_iframe(Thread *thread); uint32 x86_next_page_directory(Thread *from, Thread *to); -void x86_restart_syscall(struct iframe* frame); +void x86_restart_syscall(struct iframe *frame); + +void x86_set_tls_context(Thread *thread); // override empty macro #undef arch_syscall_64_bit_return_value diff --git a/src/system/kernel/arch/x86/arch_interrupts.S b/src/system/kernel/arch/x86/arch_interrupts.S index 558b132372..aa4dfe16ac 100644 --- a/src/system/kernel/arch/x86/arch_interrupts.S +++ b/src/system/kernel/arch/x86/arch_interrupts.S @@ -601,13 +601,15 @@ STATIC_FUNCTION(int_bottom_vm86): movl IFRAME_vector(%ebp), %eax call *gInterruptHandlerTable(, %eax, 4) + cli // disable interrupts + // update the thread's kernel time and return - cli UPDATE_THREAD_KERNEL_TIME() - lea 20(%ebp), %esp; - popa; - addl $16,%esp; - iret + + // the above will reset the in_kernel flag to 0, but we actually stay + movb $1, THREAD_in_kernel(%edi); + + POP_IFRAME_AND_RETURN() FUNCTION_END(int_bottom_vm86) @@ -869,7 +871,7 @@ FUNCTION(x86_vm86_enter): // get pointers movl 32(%esp), %esi // vm86 iframe - push %esi // ... store iframe addr for x86_vm86_return + pushl %esi // ... store iframe addr for x86_vm86_return movl %dr3, %edi // Thread* // make sure eflags are in right shape @@ -913,13 +915,16 @@ FUNCTION(x86_vm86_return): // adjust kernel_stack_top and tss.esp0 movl %dr3, %edi movl %eax, THREAD_kernel_stack_top(%edi) - push %eax + pushl %eax call i386_set_tss_and_kstack addl $4, %esp // restore registers movl %ebx, %eax - pop %fs + + // we skip %fs, as this contains the CPU dependent TLS segment + addl $4, %esp; + pop %gs popl %ebx popl %ebp diff --git a/src/system/kernel/arch/x86/arch_thread.cpp b/src/system/kernel/arch/x86/arch_thread.cpp index 59ad054453..69ca734eb4 100644 --- a/src/system/kernel/arch/x86/arch_thread.cpp +++ b/src/system/kernel/arch/x86/arch_thread.cpp @@ -144,16 +144,6 @@ set_fs_register(uint32 segment) } -static void -set_tls_context(Thread *thread) -{ - int entry = smp_get_current_cpu() + TLS_BASE_SEGMENT; - - set_segment_descriptor_base(&gGDT[entry], thread->user_local_storage); - set_fs_register((entry << 3) | DPL_USER); -} - - /*! Returns to the userland environment given by \a frame for a thread not having been userland before. @@ -171,7 +161,7 @@ initial_return_to_userland(Thread* thread, iframe* frame) disable_interrupts(); i386_set_tss_and_kstack(thread->kernel_stack_top); - set_tls_context(thread); + x86_set_tls_context(thread); x86_set_syscall_stack(thread->kernel_stack_top); // return to userland @@ -268,6 +258,16 @@ x86_restart_syscall(struct iframe* frame) } +void +x86_set_tls_context(Thread *thread) +{ + int entry = smp_get_current_cpu() + TLS_BASE_SEGMENT; + + set_segment_descriptor_base(&gGDT[entry], thread->user_local_storage); + set_fs_register((entry << 3) | DPL_USER); +} + + static uint8* get_signal_stack(Thread* thread, struct iframe* frame, struct sigaction* action) { @@ -373,7 +373,7 @@ arch_thread_context_switch(Thread *from, Thread *to) // set TLS GDT entry to the current thread - since this action is // dependent on the current CPU, we have to do it here if (to->user_local_storage != 0) - set_tls_context(to); + x86_set_tls_context(to); struct cpu_ent* cpuData = to->cpu; X86PagingStructures* activePagingStructures @@ -453,7 +453,7 @@ arch_thread_enter_userspace(Thread* thread, addr_t entry, void* args1, iframe frame = {}; frame.type = IFRAME_TYPE_SYSCALL; frame.gs = USER_DATA_SEG; - // frame.fs not used -- we call set_tls_context() below + // frame.fs not used, we call x86_set_tls_context() on context switch frame.es = USER_DATA_SEG; frame.ds = USER_DATA_SEG; frame.eip = entry; diff --git a/src/system/kernel/arch/x86/vm86.cpp b/src/system/kernel/arch/x86/vm86.cpp index 993fb24fb0..ebfce515af 100644 --- a/src/system/kernel/arch/x86/vm86.cpp +++ b/src/system/kernel/arch/x86/vm86.cpp @@ -657,6 +657,12 @@ vm86_do_int(struct vm86_state *state, uint8 vec) } while (emuState == 0); thread->fault_callback = NULL; + // We might have clobbered %fs, so we need to restore the CPU dependent + // TLS context that we may have overwritten. Note that we can't simply + // restore %fs to its previous value as we might not run on the same CPU + // anymore. + x86_set_tls_context(thread); + return emuState < 0 ? B_BAD_DATA : ret; }