[haiku-commits] haiku: hrev43321 - src/system/kernel/arch/x86 headers/private/kernel/arch/x86

  • From: mmlr@xxxxxxxx
  • To: haiku-commits@xxxxxxxxxxxxx
  • Date: Fri, 25 Nov 2011 16:12:03 +0100 (CET)

hrev43321 adds 1 changeset to branch 'master'
old head: 653ce5db53af26a3cc568b2b5ab7749f1e18534f
new head: 79f005600225dcd5d1cdb4539a2f0d31dff8ee73

----------------------------------------------------------------------------

4 files changed, 35 insertions(+), 22 deletions(-)
headers/private/kernel/arch/x86/arch_thread.h |    4 ++-
src/system/kernel/arch/x86/arch_interrupts.S  |   21 ++++++++++------
src/system/kernel/arch/x86/arch_thread.cpp    |   26 ++++++++++----------
src/system/kernel/arch/x86/vm86.cpp           |    6 +++++

############################################################################

Revision:    hrev43321
Commit:      79f005600225dcd5d1cdb4539a2f0d31dff8ee73
URL:         http://cgit.haiku-os.org/haiku/commit/?id=79f0056
Author:      Michael Lotz <mmlr@xxxxxxxx>
Date:        Fri Nov 25 14:51:13 2011 UTC

Ticket:      https://dev.haiku-os.org/ticket/8068

Fix virtual 8086 mode to properly account for TLS.

* The vm86 code or the code running in virtual 8086 mode may clobber the
  %fs register that we use for the CPU dependent thread local storage
  (TLS). Previously the vm86 code would simply restore %fs on exit, but
  this doesn't always work. If the thread got unscheduled while running
  in virtual 8086 mode and was then rescheduled on a different CPU, the
  vm86 exit code would restore the %fs register with the TLS value of
  the old CPU, causing anything using TLS in userland to crash later on.
  Instead we skip the %fs register restore on exit (as do the other
  interrupt return functions) and explicitly update the potentially
  clobbered %fs by calling x86_set_tls_context(). This will repopulate
  the %fs register with the TLS value for the right CPU. Fixes #8068.

* Made the static set_tls_context() into x86_set_tls_context() and made
  it available to others to faciliate the above.

* Sync the vm86 specific interrupt code with the changes from hrev23370,
  using the iframe pop macro to properly return. Previously what was
  pushed in int_bottom wasn't poped on return.

* Account for the time update macro resetting the in_kernel flag and
  reset it to 1, as we aren't actually returning to userland. This
  didn't cause any harm though as only the time tracking is using that
  flag so far.

* Some minor cleanup.

----------------------------------------------------------------------------

diff --git a/headers/private/kernel/arch/x86/arch_thread.h 
b/headers/private/kernel/arch/x86/arch_thread.h
index ff1f42a..f051371 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 558b132..aa4dfe1 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 59ad054..69ca734 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 993fb24..ebfce51 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;
 }
 


Other related posts:

  • » [haiku-commits] haiku: hrev43321 - src/system/kernel/arch/x86 headers/private/kernel/arch/x86 - mmlr