Author: jhb
Date: Sat Aug 30 17:48:38 2014
New Revision: 270850
URL: http://svnweb.freebsd.org/changeset/base/270850

Log:
  Save and restore FPU state across suspend and resume.  In earlier revisions
  of this patch, resumectx() called npxresume() directly, but that doesn't
  work because resumectx() runs with a non-standard %cs selector.  Instead,
  all of the FPU suspend/resume handling is done in C.
  
  MFC after:    1 week

Modified:
  head/sys/i386/i386/mp_machdep.c
  head/sys/i386/i386/swtch.s
  head/sys/i386/include/npx.h
  head/sys/i386/include/pcb.h
  head/sys/i386/isa/npx.c
  head/sys/x86/acpica/acpi_wakeup.c

Modified: head/sys/i386/i386/mp_machdep.c
==============================================================================
--- head/sys/i386/i386/mp_machdep.c     Sat Aug 30 17:39:28 2014        
(r270849)
+++ head/sys/i386/i386/mp_machdep.c     Sat Aug 30 17:48:38 2014        
(r270850)
@@ -1522,9 +1522,15 @@ cpususpend_handler(void)
 
        cpu = PCPU_GET(cpuid);
        if (savectx(susppcbs[cpu])) {
+#ifdef DEV_NPX
+               npxsuspend(&suspcbs[cpu]->pcb_fpususpend);
+#endif
                wbinvd();
                CPU_SET_ATOMIC(cpu, &suspended_cpus);
        } else {
+#ifdef DEV_NPX
+               npxresume(&suspcbs[cpu]->pcb_fpususpend);
+#endif
                pmap_init_pat();
                PCPU_SET(switchtime, 0);
                PCPU_SET(switchticks, ticks);

Modified: head/sys/i386/i386/swtch.s
==============================================================================
--- head/sys/i386/i386/swtch.s  Sat Aug 30 17:39:28 2014        (r270849)
+++ head/sys/i386/i386/swtch.s  Sat Aug 30 17:48:38 2014        (r270850)
@@ -416,45 +416,6 @@ ENTRY(savectx)
        sldt    PCB_LDT(%ecx)
        str     PCB_TR(%ecx)
 
-#ifdef DEV_NPX
-       /*
-        * If fpcurthread == NULL, then the npx h/w state is irrelevant and the
-        * state had better already be in the pcb.  This is true for forks
-        * but not for dumps (the old book-keeping with FP flags in the pcb
-        * always lost for dumps because the dump pcb has 0 flags).
-        *
-        * If fpcurthread != NULL, then we have to save the npx h/w state to
-        * fpcurthread's pcb and copy it to the requested pcb, or save to the
-        * requested pcb and reload.  Copying is easier because we would
-        * have to handle h/w bugs for reloading.  We used to lose the
-        * parent's npx state for forks by forgetting to reload.
-        */
-       pushfl
-       CLI
-       movl    PCPU(FPCURTHREAD),%eax
-       testl   %eax,%eax
-       je      1f
-
-       pushl   %ecx
-       movl    TD_PCB(%eax),%eax
-       movl    PCB_SAVEFPU(%eax),%eax
-       pushl   %eax
-       pushl   %eax
-       call    npxsave
-       addl    $4,%esp
-       popl    %eax
-       popl    %ecx
-
-       pushl   $PCB_SAVEFPU_SIZE
-       leal    PCB_USERFPU(%ecx),%ecx
-       pushl   %ecx
-       pushl   %eax
-       call    bcopy
-       addl    $12,%esp
-1:
-       popfl
-#endif /* DEV_NPX */
-
        movl    $1,%eax
        ret
 END(savectx)
@@ -519,10 +480,6 @@ ENTRY(resumectx)
        movl    PCB_DR7(%ecx),%eax
        movl    %eax,%dr7
 
-#ifdef DEV_NPX
-       /* XXX FIX ME */
-#endif
-
        /* Restore other registers */
        movl    PCB_EDI(%ecx),%edi
        movl    PCB_ESI(%ecx),%esi

Modified: head/sys/i386/include/npx.h
==============================================================================
--- head/sys/i386/include/npx.h Sat Aug 30 17:39:28 2014        (r270849)
+++ head/sys/i386/include/npx.h Sat Aug 30 17:48:38 2014        (r270850)
@@ -53,8 +53,10 @@ void npxexit(struct thread *td);
 int    npxformat(void);
 int    npxgetregs(struct thread *td);
 void   npxinit(void);
+void   npxresume(union savefpu *addr);
 void   npxsave(union savefpu *addr);
 void   npxsetregs(struct thread *td, union savefpu *addr);
+void   npxsuspend(union savefpu *addr);
 int    npxtrap_x87(void);
 int    npxtrap_sse(void);
 void   npxuserinited(struct thread *);

Modified: head/sys/i386/include/pcb.h
==============================================================================
--- head/sys/i386/include/pcb.h Sat Aug 30 17:39:28 2014        (r270849)
+++ head/sys/i386/include/pcb.h Sat Aug 30 17:48:38 2014        (r270850)
@@ -90,6 +90,8 @@ struct pcb {
        struct region_descriptor pcb_idt;
        uint16_t        pcb_ldt;
        uint16_t        pcb_tr;
+
+       union   savefpu pcb_fpususpend;
 };
 
 #ifdef _KERNEL

Modified: head/sys/i386/isa/npx.c
==============================================================================
--- head/sys/i386/isa/npx.c     Sat Aug 30 17:39:28 2014        (r270849)
+++ head/sys/i386/isa/npx.c     Sat Aug 30 17:48:38 2014        (r270850)
@@ -761,6 +761,43 @@ npxsave(addr)
        PCPU_SET(fpcurthread, NULL);
 }
 
+/*
+ * Unconditionally save the current co-processor state across suspend and
+ * resume.
+ */
+void
+npxsuspend(union savefpu *addr)
+{
+       register_t cr0;
+
+       if (!hw_float)
+               return;
+       if (PCPU_GET(fpcurthread) == NULL) {
+               *addr = npx_initialstate;
+               return;
+       }
+       cr0 = rcr0();
+       clts();
+       fpusave(addr);
+       load_cr0(cr0);
+}
+
+void
+npxresume(union savefpu *addr)
+{
+       register_t cr0;
+
+       if (!hw_float)
+               return;
+
+       cr0 = rcr0();
+       clts();
+       npxinit();
+       stop_emulating();
+       fpurstor(addr);
+       load_cr0(cr0);
+}
+
 void
 npxdrop()
 {

Modified: head/sys/x86/acpica/acpi_wakeup.c
==============================================================================
--- head/sys/x86/acpica/acpi_wakeup.c   Sat Aug 30 17:39:28 2014        
(r270849)
+++ head/sys/x86/acpica/acpi_wakeup.c   Sat Aug 30 17:48:38 2014        
(r270850)
@@ -30,6 +30,10 @@
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD$");
 
+#ifdef __i386__
+#include "opt_npx.h"
+#endif
+
 #include <sys/param.h>
 #include <sys/bus.h>
 #include <sys/eventhandler.h>
@@ -203,6 +207,8 @@ acpi_sleep_machdep(struct acpi_softc *sc
        if (savectx(susppcbs[0])) {
 #ifdef __amd64__
                fpususpend(susppcbs[0]->pcb_fpususpend);
+#elif defined(DEV_NPX)
+               npxsuspend(&susppcbs[0]->pcb_fpususpend);
 #endif
 #ifdef SMP
                if (!CPU_EMPTY(&suspcpus) && suspend_cpus(suspcpus) == 0) {
@@ -237,6 +243,10 @@ acpi_sleep_machdep(struct acpi_softc *sc
 
                for (;;)
                        ia32_pause();
+       } else {
+#ifdef DEV_NPX
+               npxresume(&susppcbs[0]->pcb_fpususpend);
+#endif
        }
 
        return (1);     /* wakeup successfully */
_______________________________________________
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to