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-head mailing list