Correct a bug in the last FPU optimized bcopy commit. The user FPU state
authorMatthew Dillon <dillon@dragonflybsd.org>
Fri, 30 Apr 2004 00:59:55 +0000 (00:59 +0000)
committerMatthew Dillon <dillon@dragonflybsd.org>
Fri, 30 Apr 2004 00:59:55 +0000 (00:59 +0000)
was being corrupted by interrupts.

Fix the bug by implementing a feature described as a missif in the original
FreeBSD comments... add a pointer to the FP saved state in the thread
structure so routines which 'borrow' the FP unit can simply revector the
pointer temporarily to avoid corruption of the original user FP state.

The MMX_*_BLOCK macros in bcopy.s have also been simplified somewhat.  We
can simplify them even more (in the future) by reserving FPU save space in
the per-cpu structure instead of on the stack.

23 files changed:
sys/i386/gnu/fpemul/fpu_system.h
sys/i386/i386/bcopy.s
sys/i386/i386/genassym.c
sys/i386/i386/math_emu.h
sys/i386/i386/pmap.c
sys/i386/i386/swtch.s
sys/i386/i386/vm86bios.s
sys/i386/i386/vm_machdep.c
sys/i386/include/pcb.h
sys/i386/include/thread.h
sys/i386/isa/npx.c
sys/platform/pc32/gnu/fpemul/fpu_system.h
sys/platform/pc32/i386/bcopy.s
sys/platform/pc32/i386/genassym.c
sys/platform/pc32/i386/math_emu.h
sys/platform/pc32/i386/pmap.c
sys/platform/pc32/i386/swtch.s
sys/platform/pc32/i386/vm86bios.s
sys/platform/pc32/i386/vm_machdep.c
sys/platform/pc32/include/pcb.h
sys/platform/pc32/include/thread.h
sys/platform/pc32/isa/npx.c
sys/platform/vkernel/i386/genassym.c

index 1e62fe8..e3712bd 100644 (file)
@@ -55,7 +55,7 @@
  *
  *
  * $FreeBSD: src/sys/gnu/i386/fpemul/fpu_system.h,v 1.7.2.1 2001/08/15 01:23:49 peter Exp $
- * $DragonFly: src/sys/i386/gnu/fpemul/Attic/fpu_system.h,v 1.2 2003/06/17 04:28:34 dillon Exp $
+ * $DragonFly: src/sys/i386/gnu/fpemul/Attic/fpu_system.h,v 1.3 2004/04/30 00:59:48 dillon Exp $
  *
  */
 
@@ -70,7 +70,7 @@
 #include <linux/kernel.h>
 */
 
-#define I387 (*(union i387_union *)&(((struct pcb *)curproc->p_addr)->pcb_save.sv_87))
+#define I387   (*(union i387_union *)(&curthread->td_savefpu->sv_87))
 #define FPU_info               (I387.soft.frame)
 
 #define FPU_CS                 (*(unsigned short *) &(FPU_info->tf_cs))
index 99c2c10..ae354f9 100644 (file)
@@ -23,7 +23,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $DragonFly: src/sys/i386/i386/Attic/bcopy.s,v 1.1 2004/04/29 17:24:58 dillon Exp $
+ * $DragonFly: src/sys/i386/i386/Attic/bcopy.s,v 1.2 2004/04/30 00:59:52 dillon Exp $
  */
 /*
  * bcopy(source:%esi, target:%edi, count:%ecx)
@@ -164,35 +164,31 @@ ENTRY(asm_generic_bcopy)
         * In order for the kernel to be able to use the FPU:
         *
         *      (1) The kernel may not already be using the fpu
+        *
         *      (2) If the fpu is owned by the application, we must save
-        *          and restore its state.
-        *      (3) Our thread begins using the FPU, we clts (clear CR0_TS)
-        *          to prevent an FP fault, fninit, and set our thread as
-        *          the npxthread.
+        *          its state.  If the fpu is not owned by the application
+        *          the application's saved fp state may already exist
+        *          in TD_SAVEFPU.
         *
+        *      (3) We cannot allow the kernel overwrite the application's
+        *          FPU state with our own, so we allocate space on the
+        *          stack and create a new TD_SAVEFPU, saving the old
+        *          pointer.
+        *          
         *      (4) While we are using the FP unit, an interrupt may come
         *          along and preempt us, causing our FP state to be saved.
-        *          We will fault/restore upon resumption.
-        *
-        *      (5) To cleanup we have to restore the original application's
-        *          FP state, which means restoring any saved state, CR0_TS,
-        *          and npxthread settings as appropriate.
+        *          We will fault/restore upon resumption.  Our FP state
+        *          will be saved on the stack.
         *
-        *          However, as an optimization we can instead copy the
-        *          saved state to the PCB, clear npxthread, and set CR0_TS,
-        *          which will allow additional bcopy's to use the FP unit
-        *          at virtually no cost and cause the application to trap
-        *          when it tries to use the FP unit again.
+        *      (5) To clean up we throw away our FP state and, zero out
+        *          npxthread to indicate that the application's FP state
+        *          is stored in TD_SAVEFPU, and we then restore the original
+        *          TD_SAVEFPU.
         *
-        *          So, why choose one over another?  Well, having to save
-        *          and restore the FP state eats a lot of cycles.  Many 
-        *          kernel operations actually wind up looping on a bcopy
-        *          (e.g. the PIPE/SFBUF case), or looping in userland without
-        *          any intervening FP ops.  Our minimum copy size check
-        *          (2048) avoids the use of FP for the smaller copies that
-        *          are more likely to be intermingled with user FP ops, so
-        *          it is my belief that saving the user FP state to the PCB
-        *          is a better solution then restoring it.
+        *          We do not attempt to restore the application's FP state.
+        *          We set the TS bit to guarentee that the application will
+        *          fault when it next tries to access the FP (to restore its
+        *          state).
         *
         *  NOTE: fxsave requires a 16-byte aligned address
         *
@@ -205,22 +201,20 @@ ENTRY(asm_generic_bcopy)
        jb      missfunc ;                      \
        btsl    $1,PCPU(kernel_fpu_lock) ;      \
        jc      missfunc ;                      \
+       pushl   %ebx ;                          \
        pushl   %ebp ;                          \
        movl    %esp, %ebp ;                    \
-       smsw    %ax ;                           \
-       movl    PCPU(npxthread),%edx ;          \
-       testl   %edx,%edx ;                     \
-       jz      100f ;                          \
-       clts ;                                  \
+       movl    PCPU(curthread),%edx ;          \
+       movl    TD_SAVEFPU(%edx),%ebx ;         \
        subl    $512,%esp ;                     \
        andl    $0xfffffff0,%esp ;              \
-       fxsave  0(%esp) ;                       \
+       movl    %esp,TD_SAVEFPU(%edx) ;         \
+       cmpl    %edx,PCPU(npxthread) ;          \
+       jne     100f ;                          \
+       fxsave  0(%ebx) ;                       \
 100: ;                                         \
-       pushl   %eax ;                          \
-       pushl   %edx ;                          \
-       movl    PCPU(curthread),%edx ;          \
-       movl    %edx,PCPU(npxthread) ;          \
        clts ;                                  \
+       movl    %edx,PCPU(npxthread) ;          \
        fninit ;                                \
        pushl   $mmx_onfault
 
@@ -230,24 +224,15 @@ ENTRY(asm_generic_bcopy)
        MMX_RESTORE_BLOCK2
 
 #define MMX_RESTORE_BLOCK2                     \
-       popl    %edx ;                          \
-       popl    %eax ;                          \
-       testl   %edx,%edx ;                     \
-       jz      100f ;                          \
-       movl    %esp,%esi ;                     \
-       movl    PCPU(curthread),%edi ;          \
-       movl    TD_PCB(%edi),%edi ;             \
-       addl    $PCB_SAVEFPU,%edi ;             \
-       movl    $512>>2,%ecx ;                  \
-       cld ;                                   \
-       rep ;                                   \
-       movsl ;                                 \
-       orb     $CR0_TS,%al ;                   \
-100: ;                                         \
+       movl    PCPU(curthread),%edx ;          \
+       movl    $0,PCPU(npxthread) ;            \
+       movl    %ebx,TD_SAVEFPU(%edx) ;         \
+       smsw    %ax ;                           \
        movl    %ebp,%esp ;                     \
+       orb     $CR0_TS,%al ;                   \
        popl    %ebp ;                          \
-       movl    $0,PCPU(npxthread) ;            \
        lmsw    %ax ;                           \
+       popl    %ebx ;                          \
        movl    $0,PCPU(kernel_fpu_lock)
 
        /*
index 2ea2e79..f743dd6 100644 (file)
@@ -35,7 +35,7 @@
  *
  *     from: @(#)genassym.c    5.11 (Berkeley) 5/10/91
  * $FreeBSD: src/sys/i386/i386/genassym.c,v 1.86.2.3 2002/03/03 05:42:49 nyan Exp $
- * $DragonFly: src/sys/i386/i386/Attic/genassym.c,v 1.37 2004/04/29 17:24:58 dillon Exp $
+ * $DragonFly: src/sys/i386/i386/Attic/genassym.c,v 1.38 2004/04/30 00:59:52 dillon Exp $
  */
 
 #include <sys/param.h>
@@ -97,6 +97,7 @@ ASSYM(MP_FREE_LOCK, MP_FREE_LOCK);
 ASSYM(RW_OWNER, offsetof(struct lwkt_rwlock, rw_owner));
 
 ASSYM(TD_CPL, offsetof(struct thread, td_mach) + offsetof(struct md_thread, mtd_cpl));
+ASSYM(TD_SAVEFPU, offsetof(struct thread, td_mach) + offsetof(struct md_thread, mtd_savefpu));
 
 ASSYM(TDPRI_CRIT, TDPRI_CRIT);
 ASSYM(TDPRI_INT_SUPPORT, TDPRI_INT_SUPPORT);
index bedf201..4a9dcce 100644 (file)
@@ -4,7 +4,7 @@
  * (C) 1991 Linus Torvalds
  *
  * $FreeBSD: src/sys/i386/i386/math_emu.h,v 1.7.2.1 2001/08/15 01:23:50 peter Exp $
- * $DragonFly: src/sys/i386/i386/Attic/math_emu.h,v 1.4 2003/06/18 18:29:55 dillon Exp $
+ * $DragonFly: src/sys/i386/i386/Attic/math_emu.h,v 1.5 2004/04/30 00:59:52 dillon Exp $
  */
 #ifndef _LINUX_MATH_EMU_H
 #define _LINUX_MATH_EMU_H
@@ -70,7 +70,7 @@ struct i387_struct {
        int32_t st_space[20];   /* 8*10 bytes for each FP-reg = 80 bytes */
 };
 
-#define I387 (*(struct i387_struct *)&((curthread->td_pcb)->pcb_save.sv_87))
+#define I387 (*(struct i387_struct *)(&curthread->td_savefpu->sv_87))
 #define SWD (*(struct swd *) &I387.swd)
 #define ROUNDING ((I387.cwd >> 10) & 3)
 #define PRECISION ((I387.cwd >> 8) & 3)
index 17267f6..39fe0c7 100644 (file)
@@ -40,7 +40,7 @@
  *
  *     from:   @(#)pmap.c      7.7 (Berkeley)  5/12/91
  * $FreeBSD: src/sys/i386/i386/pmap.c,v 1.250.2.18 2002/03/06 22:48:53 silby Exp $
- * $DragonFly: src/sys/i386/i386/Attic/pmap.c,v 1.34 2004/04/26 20:26:57 dillon Exp $
+ * $DragonFly: src/sys/i386/i386/Attic/pmap.c,v 1.35 2004/04/30 00:59:52 dillon Exp $
  */
 
 /*
@@ -848,6 +848,7 @@ void
 pmap_init_thread(thread_t td)
 {
        td->td_pcb = (struct pcb *)(td->td_kstack + UPAGES * PAGE_SIZE) - 1;
+       td->td_savefpu = &td->td_pcb->pcb_save;
        td->td_sp = (char *)td->td_pcb - 16;
 }
 
index c112315..d283311 100644 (file)
@@ -35,7 +35,7 @@
  * SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/i386/i386/swtch.s,v 1.89.2.10 2003/01/23 03:36:24 ps Exp $
- * $DragonFly: src/sys/i386/i386/Attic/swtch.s,v 1.32 2004/04/29 17:24:58 dillon Exp $
+ * $DragonFly: src/sys/i386/i386/Attic/swtch.s,v 1.33 2004/04/30 00:59:52 dillon Exp $
  */
 
 #include "use_npx.h"
@@ -143,8 +143,7 @@ ENTRY(cpu_heavy_switch)
         */
        cmpl    %ebx,PCPU(npxthread)
        jne     1f
-       addl    $PCB_SAVEFPU,%edx
-       pushl   %edx
+       pushl   TD_SAVEFPU(%ebx)
        call    npxsave                 /* do it in a big C function */
        addl    $4,%esp                 /* EAX, ECX, EDX trashed */
 1:
@@ -399,6 +398,7 @@ sw0_2:      .asciz  "cpu_switch: not SRUN"
 
 /*
  * savectx(pcb)
+ *
  * Update pcb, saving current processor state.
  */
 ENTRY(savectx)
@@ -437,8 +437,7 @@ ENTRY(savectx)
        je      1f
 
        pushl   %ecx
-       movl    TD_PCB(%eax),%eax
-       leal    PCB_SAVEFPU(%eax),%eax
+       movl    TD_SAVEFPU(%eax),%eax
        pushl   %eax
        pushl   %eax
        call    npxsave
@@ -447,7 +446,7 @@ ENTRY(savectx)
        popl    %ecx
 
        pushl   $PCB_SAVEFPU_SIZE
-       leal    PCB_SAVEFPU(%ecx),%ecx
+       leal    PCB_SAVEFPU(%ecx),%ecx
        pushl   %ecx
        pushl   %eax
        call    bcopy
@@ -550,9 +549,7 @@ ENTRY(cpu_lwkt_switch)
         */
        cmpl    %ebx,PCPU(npxthread)
        jne     1f
-       movl    TD_PCB(%ebx),%edx               /* EDX = PCB */
-       addl    $PCB_SAVEFPU,%edx
-       pushl   %edx
+       pushl   TD_SAVEFPU(%ebx)
        call    npxsave                 /* do it in a big C function */
        addl    $4,%esp                 /* EAX, ECX, EDX trashed */
 1:
index 6cd9537..b5f7d95 100644 (file)
@@ -24,7 +24,7 @@
  * SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/i386/i386/vm86bios.s,v 1.15.2.1 2000/05/16 06:58:07 dillon Exp $
- * $DragonFly: src/sys/i386/i386/Attic/vm86bios.s,v 1.11 2003/08/25 19:50:28 dillon Exp $
+ * $DragonFly: src/sys/i386/i386/Attic/vm86bios.s,v 1.12 2004/04/30 00:59:52 dillon Exp $
  */
 
 #include <machine/asmacros.h>          /* miscellaneous asm macros */
@@ -70,11 +70,9 @@ ENTRY(vm86_bioscall)
        testl   %ecx,%ecx
        je      1f                      /* no curthread/npxthread */
        pushl   %edx
-       movl    TD_PCB(%ecx),%ecx
-       addl    $PCB_SAVEFPU,%ecx
-       pushl   %ecx
+       pushl   TD_SAVEFPU(%ecx)
        call    npxsave
-       popl    %ecx
+       popl    %ecx                    /* pop argument (now garabge) */
        popl    %edx                    /* recover our pcb */
 #endif
 
@@ -95,7 +93,10 @@ ENTRY(vm86_bioscall)
        movl    PCPU(curthread),%ebx
        movl    TD_PCB(%ebx),%eax       /* save curpcb */
        pushl   %eax                    /* save curpcb */
+       pushl   TD_SAVEFPU(%ebx)        /* save fpu pointer */
        movl    %edx,TD_PCB(%ebx)       /* set curpcb to vm86pcb */
+       leal    PCB_SAVEFPU(%edx),%eax  /* new savefpu pointer */
+       movl    %eax,TD_SAVEFPU(%ebx)
 
        movl    PCPU(tss_gdt),%ebx      /* entry in GDT */
        movl    0(%ebx),%eax
@@ -173,6 +174,7 @@ ENTRY(vm86_biosret)
        ltr     %si
 
        movl    PCPU(curthread),%eax
+       popl    TD_SAVEFPU(%eax)        /* restore savefpu pointer */
        popl    TD_PCB(%eax)            /* restore curpcb */
        movl    SCR_ARGFRAME(%edx),%edx /* original stack frame */
        movl    TF_TRAPNO(%edx),%eax    /* return (trapno) */
index e80a7dc..4d860b5 100644 (file)
@@ -39,7 +39,7 @@
  *     from: @(#)vm_machdep.c  7.3 (Berkeley) 5/13/91
  *     Utah $Hdr: vm_machdep.c 1.16.1.1 89/06/23$
  * $FreeBSD: src/sys/i386/i386/vm_machdep.c,v 1.132.2.9 2003/01/25 19:02:23 dillon Exp $
- * $DragonFly: src/sys/i386/i386/Attic/vm_machdep.c,v 1.29 2004/04/10 20:55:20 dillon Exp $
+ * $DragonFly: src/sys/i386/i386/Attic/vm_machdep.c,v 1.30 2004/04/30 00:59:52 dillon Exp $
  */
 
 #include "use_npx.h"
@@ -129,7 +129,7 @@ cpu_fork(p1, p2, flags)
 #if NNPX > 0
        /* Ensure that p1's pcb is up to date. */
        if (mdcpu->gd_npxthread == p1->p_thread)
-               npxsave(&p1->p_thread->td_pcb->pcb_save);
+               npxsave(p1->p_thread->td_savefpu);
 #endif
 
        /* Copy p1's pcb. */
index a51f4f8..7609563 100644 (file)
@@ -35,7 +35,7 @@
  *
  *     from: @(#)pcb.h 5.10 (Berkeley) 5/12/91
  * $FreeBSD: src/sys/i386/include/pcb.h,v 1.32.2.1 2001/08/15 01:23:52 peter Exp $
- * $DragonFly: src/sys/i386/include/Attic/pcb.h,v 1.8 2003/12/20 05:52:27 dillon Exp $
+ * $DragonFly: src/sys/i386/include/Attic/pcb.h,v 1.9 2004/04/30 00:59:54 dillon Exp $
  */
 
 #ifndef _I386_PCB_H_
@@ -68,13 +68,6 @@ struct pcb {
 #define        FP_SOFTFP       0x01    /* process using software fltng pnt emulator */
 #define        PCB_DBREGS      0x02    /* process using debug registers */
        caddr_t pcb_onfault;    /* copyin/out fault recovery */
-#if 0
-#ifdef SMP
-       u_long  pcb_mpnest;
-#else
-       u_long  pcb_mpnest_dontuse;
-#endif
-#endif
        int     pcb_gs;
        struct  pcb_ext *pcb_ext;       /* optional pcb extension */
        u_long  __pcb_spare[3]; /* adjust to avoid core dump size changes */
index 205fb6a..46300c1 100644 (file)
  *
  *     Machine independant code should not directly include this file.
  *
- * $DragonFly: src/sys/i386/include/Attic/thread.h,v 1.5 2003/07/10 04:47:53 dillon Exp $
+ * $DragonFly: src/sys/i386/include/Attic/thread.h,v 1.6 2004/04/30 00:59:54 dillon Exp $
  */
 
 #ifndef        _MACHINE_THREAD_H_
 #define        _MACHINE_THREAD_H_
 
+union savefpu;
+
 struct md_thread {
     unsigned int       mtd_cpl;
+    union savefpu      *mtd_savefpu;
 };
 
 #ifdef _KERNEL
 
-#define td_cpl td_mach.mtd_cpl
+#define td_cpl         td_mach.mtd_cpl
+#define td_savefpu     td_mach.mtd_savefpu
 
 /*
  * mycpu() retrieves the base of the current cpu's globaldata structure.
index 070f557..0c8611c 100644 (file)
@@ -33,7 +33,7 @@
  *
  *     from: @(#)npx.c 7.2 (Berkeley) 5/12/91
  * $FreeBSD: src/sys/i386/isa/npx.c,v 1.80.2.3 2001/10/20 19:04:38 tegge Exp $
- * $DragonFly: src/sys/i386/isa/Attic/npx.c,v 1.14 2004/04/29 17:25:02 dillon Exp $
+ * $DragonFly: src/sys/i386/isa/Attic/npx.c,v 1.15 2004/04/30 00:59:55 dillon Exp $
  */
 
 #include "opt_cpu.h"
@@ -128,13 +128,13 @@ void      stop_emulating  (void);
 #endif /* __GNUC__ */
 
 #ifndef CPU_DISABLE_SSE
-#define GET_FPU_EXSW_PTR(pcb) \
+#define GET_FPU_EXSW_PTR(td) \
        (cpu_fxsr ? \
-               &(pcb)->pcb_save.sv_xmm.sv_ex_sw : \
-               &(pcb)->pcb_save.sv_87.sv_ex_sw)
+               &(td)->td_savefpu->sv_xmm.sv_ex_sw : \
+               &(td)->td_savefpu->sv_87.sv_ex_sw)
 #else /* CPU_DISABLE_SSE */
-#define GET_FPU_EXSW_PTR(pcb) \
-       (&(pcb)->pcb_save.sv_87.sv_ex_sw)
+#define GET_FPU_EXSW_PTR(td) \
+       (&(td)->td_savefpu->sv_87.sv_ex_sw)
 #endif /* CPU_DISABLE_SSE */
 
 typedef u_char bool_t;
@@ -545,7 +545,7 @@ npxinit(control)
                fninit();
 #endif
        fldcw(&control);
-       fpusave(&curthread->td_pcb->pcb_save);
+       fpusave(curthread->td_savefpu);
        start_emulating();
 }
 
@@ -557,14 +557,14 @@ npxexit(struct proc *p)
 {
 
        if (p->p_thread == mdcpu->gd_npxthread)
-               npxsave(&curthread->td_pcb->pcb_save);
+               npxsave(curthread->td_savefpu);
 #ifdef NPX_DEBUG
        if (npx_exists) {
                u_int   masked_exceptions;
 
                masked_exceptions = 
-                   curthread->td_pcb->pcb_save.sv_87.sv_env.en_cw
-                   & curthread->td_pcb->pcb_save.sv_87.sv_env.en_sw & 0x7f;
+                   curthread->td_savefpu->sv_87.sv_env.en_cw
+                   & curthread->td_savefpu->sv_87.sv_env.en_sw & 0x7f;
                /*
                 * Log exceptions that would have trapped with the old
                 * control word (overflow, divide by 0, and invalid operand).
@@ -790,7 +790,7 @@ npx_intr(dummy)
                panic("npxintr from non-current process");
        }
 
-       exstat = GET_FPU_EXSW_PTR(curthread->td_pcb);
+       exstat = GET_FPU_EXSW_PTR(curthread);
        outb(0xf0, 0);
        fnstsw(exstat);
        fnstcw(&control);
@@ -866,7 +866,7 @@ npxdna()
         * Record new context early in case frstor causes an IRQ13.
         */
        mdcpu->gd_npxthread = curthread;
-       exstat = GET_FPU_EXSW_PTR(curthread->td_pcb);
+       exstat = GET_FPU_EXSW_PTR(curthread);
        *exstat = 0;
        /*
         * The following frstor may cause an IRQ13 when the state being
@@ -880,7 +880,7 @@ npxdna()
         * fnsave are broken, so our treatment breaks fnclex if it is the
         * first FPU instruction after a context switch.
         */
-       fpurstor(&curthread->td_pcb->pcb_save);
+       fpurstor(curthread->td_savefpu);
 
        return (1);
 }
index b25bc5e..65f38e8 100644 (file)
@@ -55,7 +55,7 @@
  *
  *
  * $FreeBSD: src/sys/gnu/i386/fpemul/fpu_system.h,v 1.7.2.1 2001/08/15 01:23:49 peter Exp $
- * $DragonFly: src/sys/platform/pc32/gnu/fpemul/Attic/fpu_system.h,v 1.2 2003/06/17 04:28:34 dillon Exp $
+ * $DragonFly: src/sys/platform/pc32/gnu/fpemul/Attic/fpu_system.h,v 1.3 2004/04/30 00:59:48 dillon Exp $
  *
  */
 
@@ -70,7 +70,7 @@
 #include <linux/kernel.h>
 */
 
-#define I387 (*(union i387_union *)&(((struct pcb *)curproc->p_addr)->pcb_save.sv_87))
+#define I387   (*(union i387_union *)(&curthread->td_savefpu->sv_87))
 #define FPU_info               (I387.soft.frame)
 
 #define FPU_CS                 (*(unsigned short *) &(FPU_info->tf_cs))
index a734654..929767e 100644 (file)
@@ -23,7 +23,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $DragonFly: src/sys/platform/pc32/i386/bcopy.s,v 1.1 2004/04/29 17:24:58 dillon Exp $
+ * $DragonFly: src/sys/platform/pc32/i386/bcopy.s,v 1.2 2004/04/30 00:59:52 dillon Exp $
  */
 /*
  * bcopy(source:%esi, target:%edi, count:%ecx)
@@ -164,35 +164,31 @@ ENTRY(asm_generic_bcopy)
         * In order for the kernel to be able to use the FPU:
         *
         *      (1) The kernel may not already be using the fpu
+        *
         *      (2) If the fpu is owned by the application, we must save
-        *          and restore its state.
-        *      (3) Our thread begins using the FPU, we clts (clear CR0_TS)
-        *          to prevent an FP fault, fninit, and set our thread as
-        *          the npxthread.
+        *          its state.  If the fpu is not owned by the application
+        *          the application's saved fp state may already exist
+        *          in TD_SAVEFPU.
         *
+        *      (3) We cannot allow the kernel overwrite the application's
+        *          FPU state with our own, so we allocate space on the
+        *          stack and create a new TD_SAVEFPU, saving the old
+        *          pointer.
+        *          
         *      (4) While we are using the FP unit, an interrupt may come
         *          along and preempt us, causing our FP state to be saved.
-        *          We will fault/restore upon resumption.
-        *
-        *      (5) To cleanup we have to restore the original application's
-        *          FP state, which means restoring any saved state, CR0_TS,
-        *          and npxthread settings as appropriate.
+        *          We will fault/restore upon resumption.  Our FP state
+        *          will be saved on the stack.
         *
-        *          However, as an optimization we can instead copy the
-        *          saved state to the PCB, clear npxthread, and set CR0_TS,
-        *          which will allow additional bcopy's to use the FP unit
-        *          at virtually no cost and cause the application to trap
-        *          when it tries to use the FP unit again.
+        *      (5) To clean up we throw away our FP state and, zero out
+        *          npxthread to indicate that the application's FP state
+        *          is stored in TD_SAVEFPU, and we then restore the original
+        *          TD_SAVEFPU.
         *
-        *          So, why choose one over another?  Well, having to save
-        *          and restore the FP state eats a lot of cycles.  Many 
-        *          kernel operations actually wind up looping on a bcopy
-        *          (e.g. the PIPE/SFBUF case), or looping in userland without
-        *          any intervening FP ops.  Our minimum copy size check
-        *          (2048) avoids the use of FP for the smaller copies that
-        *          are more likely to be intermingled with user FP ops, so
-        *          it is my belief that saving the user FP state to the PCB
-        *          is a better solution then restoring it.
+        *          We do not attempt to restore the application's FP state.
+        *          We set the TS bit to guarentee that the application will
+        *          fault when it next tries to access the FP (to restore its
+        *          state).
         *
         *  NOTE: fxsave requires a 16-byte aligned address
         *
@@ -205,22 +201,20 @@ ENTRY(asm_generic_bcopy)
        jb      missfunc ;                      \
        btsl    $1,PCPU(kernel_fpu_lock) ;      \
        jc      missfunc ;                      \
+       pushl   %ebx ;                          \
        pushl   %ebp ;                          \
        movl    %esp, %ebp ;                    \
-       smsw    %ax ;                           \
-       movl    PCPU(npxthread),%edx ;          \
-       testl   %edx,%edx ;                     \
-       jz      100f ;                          \
-       clts ;                                  \
+       movl    PCPU(curthread),%edx ;          \
+       movl    TD_SAVEFPU(%edx),%ebx ;         \
        subl    $512,%esp ;                     \
        andl    $0xfffffff0,%esp ;              \
-       fxsave  0(%esp) ;                       \
+       movl    %esp,TD_SAVEFPU(%edx) ;         \
+       cmpl    %edx,PCPU(npxthread) ;          \
+       jne     100f ;                          \
+       fxsave  0(%ebx) ;                       \
 100: ;                                         \
-       pushl   %eax ;                          \
-       pushl   %edx ;                          \
-       movl    PCPU(curthread),%edx ;          \
-       movl    %edx,PCPU(npxthread) ;          \
        clts ;                                  \
+       movl    %edx,PCPU(npxthread) ;          \
        fninit ;                                \
        pushl   $mmx_onfault
 
@@ -230,24 +224,15 @@ ENTRY(asm_generic_bcopy)
        MMX_RESTORE_BLOCK2
 
 #define MMX_RESTORE_BLOCK2                     \
-       popl    %edx ;                          \
-       popl    %eax ;                          \
-       testl   %edx,%edx ;                     \
-       jz      100f ;                          \
-       movl    %esp,%esi ;                     \
-       movl    PCPU(curthread),%edi ;          \
-       movl    TD_PCB(%edi),%edi ;             \
-       addl    $PCB_SAVEFPU,%edi ;             \
-       movl    $512>>2,%ecx ;                  \
-       cld ;                                   \
-       rep ;                                   \
-       movsl ;                                 \
-       orb     $CR0_TS,%al ;                   \
-100: ;                                         \
+       movl    PCPU(curthread),%edx ;          \
+       movl    $0,PCPU(npxthread) ;            \
+       movl    %ebx,TD_SAVEFPU(%edx) ;         \
+       smsw    %ax ;                           \
        movl    %ebp,%esp ;                     \
+       orb     $CR0_TS,%al ;                   \
        popl    %ebp ;                          \
-       movl    $0,PCPU(npxthread) ;            \
        lmsw    %ax ;                           \
+       popl    %ebx ;                          \
        movl    $0,PCPU(kernel_fpu_lock)
 
        /*
index c490468..a59426e 100644 (file)
@@ -35,7 +35,7 @@
  *
  *     from: @(#)genassym.c    5.11 (Berkeley) 5/10/91
  * $FreeBSD: src/sys/i386/i386/genassym.c,v 1.86.2.3 2002/03/03 05:42:49 nyan Exp $
- * $DragonFly: src/sys/platform/pc32/i386/genassym.c,v 1.37 2004/04/29 17:24:58 dillon Exp $
+ * $DragonFly: src/sys/platform/pc32/i386/genassym.c,v 1.38 2004/04/30 00:59:52 dillon Exp $
  */
 
 #include <sys/param.h>
@@ -97,6 +97,7 @@ ASSYM(MP_FREE_LOCK, MP_FREE_LOCK);
 ASSYM(RW_OWNER, offsetof(struct lwkt_rwlock, rw_owner));
 
 ASSYM(TD_CPL, offsetof(struct thread, td_mach) + offsetof(struct md_thread, mtd_cpl));
+ASSYM(TD_SAVEFPU, offsetof(struct thread, td_mach) + offsetof(struct md_thread, mtd_savefpu));
 
 ASSYM(TDPRI_CRIT, TDPRI_CRIT);
 ASSYM(TDPRI_INT_SUPPORT, TDPRI_INT_SUPPORT);
index 615d7ac..2186c68 100644 (file)
@@ -4,7 +4,7 @@
  * (C) 1991 Linus Torvalds
  *
  * $FreeBSD: src/sys/i386/i386/math_emu.h,v 1.7.2.1 2001/08/15 01:23:50 peter Exp $
- * $DragonFly: src/sys/platform/pc32/i386/math_emu.h,v 1.4 2003/06/18 18:29:55 dillon Exp $
+ * $DragonFly: src/sys/platform/pc32/i386/math_emu.h,v 1.5 2004/04/30 00:59:52 dillon Exp $
  */
 #ifndef _LINUX_MATH_EMU_H
 #define _LINUX_MATH_EMU_H
@@ -70,7 +70,7 @@ struct i387_struct {
        int32_t st_space[20];   /* 8*10 bytes for each FP-reg = 80 bytes */
 };
 
-#define I387 (*(struct i387_struct *)&((curthread->td_pcb)->pcb_save.sv_87))
+#define I387 (*(struct i387_struct *)(&curthread->td_savefpu->sv_87))
 #define SWD (*(struct swd *) &I387.swd)
 #define ROUNDING ((I387.cwd >> 10) & 3)
 #define PRECISION ((I387.cwd >> 8) & 3)
index 9631086..a609104 100644 (file)
@@ -40,7 +40,7 @@
  *
  *     from:   @(#)pmap.c      7.7 (Berkeley)  5/12/91
  * $FreeBSD: src/sys/i386/i386/pmap.c,v 1.250.2.18 2002/03/06 22:48:53 silby Exp $
- * $DragonFly: src/sys/platform/pc32/i386/pmap.c,v 1.34 2004/04/26 20:26:57 dillon Exp $
+ * $DragonFly: src/sys/platform/pc32/i386/pmap.c,v 1.35 2004/04/30 00:59:52 dillon Exp $
  */
 
 /*
@@ -848,6 +848,7 @@ void
 pmap_init_thread(thread_t td)
 {
        td->td_pcb = (struct pcb *)(td->td_kstack + UPAGES * PAGE_SIZE) - 1;
+       td->td_savefpu = &td->td_pcb->pcb_save;
        td->td_sp = (char *)td->td_pcb - 16;
 }
 
index 8aaafba..91735bb 100644 (file)
@@ -35,7 +35,7 @@
  * SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/i386/i386/swtch.s,v 1.89.2.10 2003/01/23 03:36:24 ps Exp $
- * $DragonFly: src/sys/platform/pc32/i386/swtch.s,v 1.32 2004/04/29 17:24:58 dillon Exp $
+ * $DragonFly: src/sys/platform/pc32/i386/swtch.s,v 1.33 2004/04/30 00:59:52 dillon Exp $
  */
 
 #include "use_npx.h"
@@ -143,8 +143,7 @@ ENTRY(cpu_heavy_switch)
         */
        cmpl    %ebx,PCPU(npxthread)
        jne     1f
-       addl    $PCB_SAVEFPU,%edx
-       pushl   %edx
+       pushl   TD_SAVEFPU(%ebx)
        call    npxsave                 /* do it in a big C function */
        addl    $4,%esp                 /* EAX, ECX, EDX trashed */
 1:
@@ -399,6 +398,7 @@ sw0_2:      .asciz  "cpu_switch: not SRUN"
 
 /*
  * savectx(pcb)
+ *
  * Update pcb, saving current processor state.
  */
 ENTRY(savectx)
@@ -437,8 +437,7 @@ ENTRY(savectx)
        je      1f
 
        pushl   %ecx
-       movl    TD_PCB(%eax),%eax
-       leal    PCB_SAVEFPU(%eax),%eax
+       movl    TD_SAVEFPU(%eax),%eax
        pushl   %eax
        pushl   %eax
        call    npxsave
@@ -447,7 +446,7 @@ ENTRY(savectx)
        popl    %ecx
 
        pushl   $PCB_SAVEFPU_SIZE
-       leal    PCB_SAVEFPU(%ecx),%ecx
+       leal    PCB_SAVEFPU(%ecx),%ecx
        pushl   %ecx
        pushl   %eax
        call    bcopy
@@ -550,9 +549,7 @@ ENTRY(cpu_lwkt_switch)
         */
        cmpl    %ebx,PCPU(npxthread)
        jne     1f
-       movl    TD_PCB(%ebx),%edx               /* EDX = PCB */
-       addl    $PCB_SAVEFPU,%edx
-       pushl   %edx
+       pushl   TD_SAVEFPU(%ebx)
        call    npxsave                 /* do it in a big C function */
        addl    $4,%esp                 /* EAX, ECX, EDX trashed */
 1:
index 6d1159f..2811327 100644 (file)
@@ -24,7 +24,7 @@
  * SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/i386/i386/vm86bios.s,v 1.15.2.1 2000/05/16 06:58:07 dillon Exp $
- * $DragonFly: src/sys/platform/pc32/i386/vm86bios.s,v 1.11 2003/08/25 19:50:28 dillon Exp $
+ * $DragonFly: src/sys/platform/pc32/i386/vm86bios.s,v 1.12 2004/04/30 00:59:52 dillon Exp $
  */
 
 #include <machine/asmacros.h>          /* miscellaneous asm macros */
@@ -70,11 +70,9 @@ ENTRY(vm86_bioscall)
        testl   %ecx,%ecx
        je      1f                      /* no curthread/npxthread */
        pushl   %edx
-       movl    TD_PCB(%ecx),%ecx
-       addl    $PCB_SAVEFPU,%ecx
-       pushl   %ecx
+       pushl   TD_SAVEFPU(%ecx)
        call    npxsave
-       popl    %ecx
+       popl    %ecx                    /* pop argument (now garabge) */
        popl    %edx                    /* recover our pcb */
 #endif
 
@@ -95,7 +93,10 @@ ENTRY(vm86_bioscall)
        movl    PCPU(curthread),%ebx
        movl    TD_PCB(%ebx),%eax       /* save curpcb */
        pushl   %eax                    /* save curpcb */
+       pushl   TD_SAVEFPU(%ebx)        /* save fpu pointer */
        movl    %edx,TD_PCB(%ebx)       /* set curpcb to vm86pcb */
+       leal    PCB_SAVEFPU(%edx),%eax  /* new savefpu pointer */
+       movl    %eax,TD_SAVEFPU(%ebx)
 
        movl    PCPU(tss_gdt),%ebx      /* entry in GDT */
        movl    0(%ebx),%eax
@@ -173,6 +174,7 @@ ENTRY(vm86_biosret)
        ltr     %si
 
        movl    PCPU(curthread),%eax
+       popl    TD_SAVEFPU(%eax)        /* restore savefpu pointer */
        popl    TD_PCB(%eax)            /* restore curpcb */
        movl    SCR_ARGFRAME(%edx),%edx /* original stack frame */
        movl    TF_TRAPNO(%edx),%eax    /* return (trapno) */
index c21ad93..dbf760d 100644 (file)
@@ -39,7 +39,7 @@
  *     from: @(#)vm_machdep.c  7.3 (Berkeley) 5/13/91
  *     Utah $Hdr: vm_machdep.c 1.16.1.1 89/06/23$
  * $FreeBSD: src/sys/i386/i386/vm_machdep.c,v 1.132.2.9 2003/01/25 19:02:23 dillon Exp $
- * $DragonFly: src/sys/platform/pc32/i386/vm_machdep.c,v 1.29 2004/04/10 20:55:20 dillon Exp $
+ * $DragonFly: src/sys/platform/pc32/i386/vm_machdep.c,v 1.30 2004/04/30 00:59:52 dillon Exp $
  */
 
 #include "use_npx.h"
@@ -129,7 +129,7 @@ cpu_fork(p1, p2, flags)
 #if NNPX > 0
        /* Ensure that p1's pcb is up to date. */
        if (mdcpu->gd_npxthread == p1->p_thread)
-               npxsave(&p1->p_thread->td_pcb->pcb_save);
+               npxsave(p1->p_thread->td_savefpu);
 #endif
 
        /* Copy p1's pcb. */
index 7942a6d..b2547e5 100644 (file)
@@ -35,7 +35,7 @@
  *
  *     from: @(#)pcb.h 5.10 (Berkeley) 5/12/91
  * $FreeBSD: src/sys/i386/include/pcb.h,v 1.32.2.1 2001/08/15 01:23:52 peter Exp $
- * $DragonFly: src/sys/platform/pc32/include/pcb.h,v 1.8 2003/12/20 05:52:27 dillon Exp $
+ * $DragonFly: src/sys/platform/pc32/include/pcb.h,v 1.9 2004/04/30 00:59:54 dillon Exp $
  */
 
 #ifndef _I386_PCB_H_
@@ -68,13 +68,6 @@ struct pcb {
 #define        FP_SOFTFP       0x01    /* process using software fltng pnt emulator */
 #define        PCB_DBREGS      0x02    /* process using debug registers */
        caddr_t pcb_onfault;    /* copyin/out fault recovery */
-#if 0
-#ifdef SMP
-       u_long  pcb_mpnest;
-#else
-       u_long  pcb_mpnest_dontuse;
-#endif
-#endif
        int     pcb_gs;
        struct  pcb_ext *pcb_ext;       /* optional pcb extension */
        u_long  __pcb_spare[3]; /* adjust to avoid core dump size changes */
index f126d06..8102b46 100644 (file)
  *
  *     Machine independant code should not directly include this file.
  *
- * $DragonFly: src/sys/platform/pc32/include/thread.h,v 1.5 2003/07/10 04:47:53 dillon Exp $
+ * $DragonFly: src/sys/platform/pc32/include/thread.h,v 1.6 2004/04/30 00:59:54 dillon Exp $
  */
 
 #ifndef        _MACHINE_THREAD_H_
 #define        _MACHINE_THREAD_H_
 
+union savefpu;
+
 struct md_thread {
     unsigned int       mtd_cpl;
+    union savefpu      *mtd_savefpu;
 };
 
 #ifdef _KERNEL
 
-#define td_cpl td_mach.mtd_cpl
+#define td_cpl         td_mach.mtd_cpl
+#define td_savefpu     td_mach.mtd_savefpu
 
 /*
  * mycpu() retrieves the base of the current cpu's globaldata structure.
index c83fe22..4547235 100644 (file)
@@ -33,7 +33,7 @@
  *
  *     from: @(#)npx.c 7.2 (Berkeley) 5/12/91
  * $FreeBSD: src/sys/i386/isa/npx.c,v 1.80.2.3 2001/10/20 19:04:38 tegge Exp $
- * $DragonFly: src/sys/platform/pc32/isa/npx.c,v 1.14 2004/04/29 17:25:02 dillon Exp $
+ * $DragonFly: src/sys/platform/pc32/isa/npx.c,v 1.15 2004/04/30 00:59:55 dillon Exp $
  */
 
 #include "opt_cpu.h"
@@ -128,13 +128,13 @@ void      stop_emulating  (void);
 #endif /* __GNUC__ */
 
 #ifndef CPU_DISABLE_SSE
-#define GET_FPU_EXSW_PTR(pcb) \
+#define GET_FPU_EXSW_PTR(td) \
        (cpu_fxsr ? \
-               &(pcb)->pcb_save.sv_xmm.sv_ex_sw : \
-               &(pcb)->pcb_save.sv_87.sv_ex_sw)
+               &(td)->td_savefpu->sv_xmm.sv_ex_sw : \
+               &(td)->td_savefpu->sv_87.sv_ex_sw)
 #else /* CPU_DISABLE_SSE */
-#define GET_FPU_EXSW_PTR(pcb) \
-       (&(pcb)->pcb_save.sv_87.sv_ex_sw)
+#define GET_FPU_EXSW_PTR(td) \
+       (&(td)->td_savefpu->sv_87.sv_ex_sw)
 #endif /* CPU_DISABLE_SSE */
 
 typedef u_char bool_t;
@@ -545,7 +545,7 @@ npxinit(control)
                fninit();
 #endif
        fldcw(&control);
-       fpusave(&curthread->td_pcb->pcb_save);
+       fpusave(curthread->td_savefpu);
        start_emulating();
 }
 
@@ -557,14 +557,14 @@ npxexit(struct proc *p)
 {
 
        if (p->p_thread == mdcpu->gd_npxthread)
-               npxsave(&curthread->td_pcb->pcb_save);
+               npxsave(curthread->td_savefpu);
 #ifdef NPX_DEBUG
        if (npx_exists) {
                u_int   masked_exceptions;
 
                masked_exceptions = 
-                   curthread->td_pcb->pcb_save.sv_87.sv_env.en_cw
-                   & curthread->td_pcb->pcb_save.sv_87.sv_env.en_sw & 0x7f;
+                   curthread->td_savefpu->sv_87.sv_env.en_cw
+                   & curthread->td_savefpu->sv_87.sv_env.en_sw & 0x7f;
                /*
                 * Log exceptions that would have trapped with the old
                 * control word (overflow, divide by 0, and invalid operand).
@@ -790,7 +790,7 @@ npx_intr(dummy)
                panic("npxintr from non-current process");
        }
 
-       exstat = GET_FPU_EXSW_PTR(curthread->td_pcb);
+       exstat = GET_FPU_EXSW_PTR(curthread);
        outb(0xf0, 0);
        fnstsw(exstat);
        fnstcw(&control);
@@ -866,7 +866,7 @@ npxdna()
         * Record new context early in case frstor causes an IRQ13.
         */
        mdcpu->gd_npxthread = curthread;
-       exstat = GET_FPU_EXSW_PTR(curthread->td_pcb);
+       exstat = GET_FPU_EXSW_PTR(curthread);
        *exstat = 0;
        /*
         * The following frstor may cause an IRQ13 when the state being
@@ -880,7 +880,7 @@ npxdna()
         * fnsave are broken, so our treatment breaks fnclex if it is the
         * first FPU instruction after a context switch.
         */
-       fpurstor(&curthread->td_pcb->pcb_save);
+       fpurstor(curthread->td_savefpu);
 
        return (1);
 }
index 7331a26..e89e80b 100644 (file)
@@ -35,7 +35,7 @@
  *
  *     from: @(#)genassym.c    5.11 (Berkeley) 5/10/91
  * $FreeBSD: src/sys/i386/i386/genassym.c,v 1.86.2.3 2002/03/03 05:42:49 nyan Exp $
- * $DragonFly: src/sys/platform/vkernel/i386/genassym.c,v 1.37 2004/04/29 17:24:58 dillon Exp $
+ * $DragonFly: src/sys/platform/vkernel/i386/genassym.c,v 1.38 2004/04/30 00:59:52 dillon Exp $
  */
 
 #include <sys/param.h>
@@ -97,6 +97,7 @@ ASSYM(MP_FREE_LOCK, MP_FREE_LOCK);
 ASSYM(RW_OWNER, offsetof(struct lwkt_rwlock, rw_owner));
 
 ASSYM(TD_CPL, offsetof(struct thread, td_mach) + offsetof(struct md_thread, mtd_cpl));
+ASSYM(TD_SAVEFPU, offsetof(struct thread, td_mach) + offsetof(struct md_thread, mtd_savefpu));
 
 ASSYM(TDPRI_CRIT, TDPRI_CRIT);
 ASSYM(TDPRI_INT_SUPPORT, TDPRI_INT_SUPPORT);