svn commit: r270850 - in head/sys: i386/i386 i386/include i386/isa x86/acpica
John Baldwin
jhb at FreeBSD.org
Sat Aug 30 17:48:40 UTC 2014
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 */
More information about the svn-src-all
mailing list