vkernel - Fix FP corruption from preemptive thread switch
authorMatthew Dillon <dillon@apollo.backplane.com>
Fri, 2 Oct 2009 22:53:17 +0000 (15:53 -0700)
committerMatthew Dillon <dillon@apollo.backplane.com>
Fri, 2 Oct 2009 22:53:17 +0000 (15:53 -0700)
* Recent work on the vkernel enabled preemptive interrupt thread switching.
  This introduced a race where the floating point state could change
  out from under the vkernel's go_user() function, causing the FP state
  in the virtual user process to become corrupt.

* Fixed by introducing a critical section which essentially defers any
  preemptive thread switches inside go_user().

Reported-by: YONETANI Tomokazu <qhwt+dfly@les.ath.cx>
Test-cases-by: YONETANI Tomokazu <qhwt+dfly@les.ath.cx>
sys/platform/vkernel/i386/trap.c

index e90fedc..edbb75a 100644 (file)
@@ -1425,7 +1425,12 @@ go_user(struct intrframe *frame)
                /*
                 * Tell the real kernel whether it is ok to use the FP
                 * unit or not.
+                *
+                * The critical section is required to prevent an interrupt
+                * from causing a preemptive task switch and changing
+                * the FP state.
                 */
+               crit_enter();
                if (mdcpu->gd_npxthread == curthread) {
                        tf->tf_xflags &= ~PGEX_FPFAULT;
                } else {
@@ -1441,6 +1446,7 @@ go_user(struct intrframe *frame)
                 */
                r = vmspace_ctl(&curproc->p_vmspace->vm_pmap, VMSPACE_CTL_RUN,
                                tf, &curthread->td_savevext);
+               crit_exit();
                frame->if_xflags |= PGEX_U;
 #if 0
                kprintf("GO USER %d trap %d EVA %08x EIP %08x ESP %08x XFLAGS %02x/%02x\n",