svn commit: r271999 - in stable/10/sys: amd64/amd64 amd64/include i386/i386 i386/include i386/isa x86/acpica

John Baldwin jhb at FreeBSD.org
Mon Sep 22 20:34:40 UTC 2014


Author: jhb
Date: Mon Sep 22 20:34:36 2014
New Revision: 271999
URL: http://svnweb.freebsd.org/changeset/base/271999

Log:
  MFC 270850,271053,271192,271717:
  Save and restore FPU state across suspend and resume on i386.
  - Create a separate structure for per-CPU state saved across suspend and
    resume that is a superset of a pcb.
  - Store the FPU state for suspend and resume in the new structure
    (for amd64, this moves it out of the PCB)
  - On both i386 and amd64, all of the FPU suspend/resume handling is now
    done in C.
  
  Approved by:	re (hrs)

Modified:
  stable/10/sys/amd64/amd64/cpu_switch.S
  stable/10/sys/amd64/amd64/fpu.c
  stable/10/sys/amd64/amd64/genassym.c
  stable/10/sys/amd64/amd64/mp_machdep.c
  stable/10/sys/amd64/include/fpu.h
  stable/10/sys/amd64/include/pcb.h
  stable/10/sys/i386/i386/mp_machdep.c
  stable/10/sys/i386/i386/swtch.s
  stable/10/sys/i386/include/npx.h
  stable/10/sys/i386/include/pcb.h
  stable/10/sys/i386/isa/npx.c
  stable/10/sys/x86/acpica/acpi_wakeup.c
Directory Properties:
  stable/10/   (props changed)

Modified: stable/10/sys/amd64/amd64/cpu_switch.S
==============================================================================
--- stable/10/sys/amd64/amd64/cpu_switch.S	Mon Sep 22 20:10:45 2014	(r271998)
+++ stable/10/sys/amd64/amd64/cpu_switch.S	Mon Sep 22 20:34:36 2014	(r271999)
@@ -399,10 +399,6 @@ ENTRY(savectx)
 	rdmsr
 	movl	%eax,PCB_SFMASK(%rdi)
 	movl	%edx,PCB_SFMASK+4(%rdi)
-	movl	xsave_mask,%eax
-	movl	%eax,PCB_XSMASK(%rdi)
-	movl	xsave_mask+4,%eax
-	movl	%eax,PCB_XSMASK+4(%rdi)
 
 	sgdt	PCB_GDT(%rdi)
 	sidt	PCB_IDT(%rdi)
@@ -467,12 +463,9 @@ ENTRY(resumectx)
 	movl	PCB_SFMASK(%rdi),%eax
 	wrmsr
 
-	/* Restore CR0 except for FPU mode. */
+	/* Restore CR0, CR2, CR4 and CR3. */
 	movq	PCB_CR0(%rdi),%rax
-	andq	$~(CR0_EM | CR0_TS),%rax
 	movq	%rax,%cr0
-
-	/* Restore CR2, CR4 and CR3. */
 	movq	PCB_CR2(%rdi),%rax
 	movq	%rax,%cr2
 	movq	PCB_CR4(%rdi),%rax
@@ -510,26 +503,6 @@ ENTRY(resumectx)
 	movq	PCB_DR7(%rdi),%rax
 	movq	%rax,%dr7
 
-	/* Restore FPU state. */
-	fninit
-	movq	PCB_FPUSUSPEND(%rdi),%rbx
-	movq	PCB_XSMASK(%rdi),%rax
-	testq	%rax,%rax
-	jz	1f
-	movq	%rax,%rdx
-	shrq	$32,%rdx
-	movl	$XCR0,%ecx
-	xsetbv
-	xrstor	(%rbx)
-	jmp	2f
-1:
-	fxrstor	(%rbx)
-2:
-
-	/* Reload CR0. */
-	movq	PCB_CR0(%rdi),%rax
-	movq	%rax,%cr0
-
 	/* Restore other callee saved registers. */
 	movq	PCB_R15(%rdi),%r15
 	movq	PCB_R14(%rdi),%r14

Modified: stable/10/sys/amd64/amd64/fpu.c
==============================================================================
--- stable/10/sys/amd64/amd64/fpu.c	Mon Sep 22 20:10:45 2014	(r271998)
+++ stable/10/sys/amd64/amd64/fpu.c	Mon Sep 22 20:34:36 2014	(r271999)
@@ -173,6 +173,20 @@ fpususpend(void *addr)
 	load_cr0(cr0);
 }
 
+void
+fpuresume(void *addr)
+{
+	u_long cr0;
+
+	cr0 = rcr0();
+	stop_emulating();
+	fninit();
+	if (use_xsave)
+		load_xcr(XCR0, xsave_mask);
+	fpurestore(addr);
+	load_cr0(cr0);
+}
+
 /*
  * Enable XSAVE if supported and allowed by user.
  * Calculate the xsave_mask.

Modified: stable/10/sys/amd64/amd64/genassym.c
==============================================================================
--- stable/10/sys/amd64/amd64/genassym.c	Mon Sep 22 20:10:45 2014	(r271998)
+++ stable/10/sys/amd64/amd64/genassym.c	Mon Sep 22 20:34:36 2014	(r271999)
@@ -163,8 +163,6 @@ ASSYM(PCB_STAR, offsetof(struct pcb, pcb
 ASSYM(PCB_LSTAR, offsetof(struct pcb, pcb_lstar));
 ASSYM(PCB_CSTAR, offsetof(struct pcb, pcb_cstar));
 ASSYM(PCB_SFMASK, offsetof(struct pcb, pcb_sfmask));
-ASSYM(PCB_XSMASK, offsetof(struct pcb, pcb_xsmask));
-ASSYM(PCB_FPUSUSPEND, offsetof(struct pcb, pcb_fpususpend));
 ASSYM(PCB_SIZE, sizeof(struct pcb));
 ASSYM(PCB_FULL_IRET, PCB_FULL_IRET);
 ASSYM(PCB_DBREGS, PCB_DBREGS);

Modified: stable/10/sys/amd64/amd64/mp_machdep.c
==============================================================================
--- stable/10/sys/amd64/amd64/mp_machdep.c	Mon Sep 22 20:10:45 2014	(r271998)
+++ stable/10/sys/amd64/amd64/mp_machdep.c	Mon Sep 22 20:34:36 2014	(r271999)
@@ -101,7 +101,7 @@ char *nmi_stack;
 void *dpcpu;
 
 struct pcb stoppcbs[MAXCPU];
-struct pcb **susppcbs;
+struct susppcb **susppcbs;
 
 /* Variables needed for SMP tlb shootdown. */
 vm_offset_t smp_tlb_addr2;
@@ -1463,11 +1463,12 @@ cpususpend_handler(void)
 	mtx_assert(&smp_ipi_mtx, MA_NOTOWNED);
 
 	cpu = PCPU_GET(cpuid);
-	if (savectx(susppcbs[cpu])) {
-		fpususpend(susppcbs[cpu]->pcb_fpususpend);
+	if (savectx(&susppcbs[cpu]->sp_pcb)) {
+		fpususpend(susppcbs[cpu]->sp_fpususpend);
 		wbinvd();
 		CPU_SET_ATOMIC(cpu, &suspended_cpus);
 	} else {
+		fpuresume(susppcbs[cpu]->sp_fpususpend);
 		pmap_init_pat();
 		initializecpu();
 		PCPU_SET(switchtime, 0);

Modified: stable/10/sys/amd64/include/fpu.h
==============================================================================
--- stable/10/sys/amd64/include/fpu.h	Mon Sep 22 20:10:45 2014	(r271998)
+++ stable/10/sys/amd64/include/fpu.h	Mon Sep 22 20:34:36 2014	(r271999)
@@ -58,6 +58,7 @@ int	fpuformat(void);
 int	fpugetregs(struct thread *td);
 void	fpuinit(void);
 void	fpurestore(void *addr);
+void	fpuresume(void *addr);
 void	fpusave(void *addr);
 int	fpusetregs(struct thread *td, struct savefpu *addr,
 	    char *xfpustate, size_t xfpustate_size);

Modified: stable/10/sys/amd64/include/pcb.h
==============================================================================
--- stable/10/sys/amd64/include/pcb.h	Mon Sep 22 20:10:45 2014	(r271998)
+++ stable/10/sys/amd64/include/pcb.h	Mon Sep 22 20:34:36 2014	(r271999)
@@ -97,14 +97,18 @@ struct pcb {
 	register_t	pcb_lstar;
 	register_t	pcb_cstar;
 	register_t	pcb_sfmask;
-	register_t	pcb_xsmask;
-
-	/* fpu context for suspend/resume */
-	void		*pcb_fpususpend;
 
 	struct savefpu	*pcb_save;
 
-	uint64_t	pcb_pad[3];
+	uint64_t	pcb_pad[5];
+};
+
+/* Per-CPU state saved during suspend and resume. */
+struct susppcb {
+	struct pcb	sp_pcb;
+
+	/* fpu context for suspend/resume */
+	void		*sp_fpususpend;
 };
 #endif
 

Modified: stable/10/sys/i386/i386/mp_machdep.c
==============================================================================
--- stable/10/sys/i386/i386/mp_machdep.c	Mon Sep 22 20:10:45 2014	(r271998)
+++ stable/10/sys/i386/i386/mp_machdep.c	Mon Sep 22 20:34:36 2014	(r271999)
@@ -147,7 +147,7 @@ void *bootstacks[MAXCPU];
 static void *dpcpu;
 
 struct pcb stoppcbs[MAXCPU];
-struct pcb **susppcbs = NULL;
+struct susppcb **susppcbs;
 
 /* Variables needed for SMP tlb shootdown. */
 vm_offset_t smp_tlb_addr1;
@@ -1523,10 +1523,12 @@ cpususpend_handler(void)
 	mtx_assert(&smp_ipi_mtx, MA_NOTOWNED);
 
 	cpu = PCPU_GET(cpuid);
-	if (savectx(susppcbs[cpu])) {
+	if (savectx(&susppcbs[cpu]->sp_pcb)) {
+		npxsuspend(&susppcbs[cpu]->sp_fpususpend);
 		wbinvd();
 		CPU_SET_ATOMIC(cpu, &suspended_cpus);
 	} else {
+		npxresume(&susppcbs[cpu]->sp_fpususpend);
 		pmap_init_pat();
 		PCPU_SET(switchtime, 0);
 		PCPU_SET(switchticks, ticks);

Modified: stable/10/sys/i386/i386/swtch.s
==============================================================================
--- stable/10/sys/i386/i386/swtch.s	Mon Sep 22 20:10:45 2014	(r271998)
+++ stable/10/sys/i386/i386/swtch.s	Mon Sep 22 20:34:36 2014	(r271999)
@@ -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: stable/10/sys/i386/include/npx.h
==============================================================================
--- stable/10/sys/i386/include/npx.h	Mon Sep 22 20:10:45 2014	(r271998)
+++ stable/10/sys/i386/include/npx.h	Mon Sep 22 20:34:36 2014	(r271999)
@@ -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: stable/10/sys/i386/include/pcb.h
==============================================================================
--- stable/10/sys/i386/include/pcb.h	Mon Sep 22 20:10:45 2014	(r271998)
+++ stable/10/sys/i386/include/pcb.h	Mon Sep 22 20:34:36 2014	(r271999)
@@ -92,6 +92,11 @@ struct pcb {
 	uint16_t	pcb_tr;
 };
 
+struct susppcb {
+	struct pcb	sp_pcb;
+	union savefpu	sp_fpususpend;
+};
+
 #ifdef _KERNEL
 struct trapframe;
 

Modified: stable/10/sys/i386/isa/npx.c
==============================================================================
--- stable/10/sys/i386/isa/npx.c	Mon Sep 22 20:10:45 2014	(r271998)
+++ stable/10/sys/i386/isa/npx.c	Mon Sep 22 20:34:36 2014	(r271999)
@@ -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: stable/10/sys/x86/acpica/acpi_wakeup.c
==============================================================================
--- stable/10/sys/x86/acpica/acpi_wakeup.c	Mon Sep 22 20:10:45 2014	(r271998)
+++ stable/10/sys/x86/acpica/acpi_wakeup.c	Mon Sep 22 20:34:36 2014	(r271999)
@@ -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>
@@ -71,10 +75,10 @@ extern int		acpi_resume_beep;
 extern int		acpi_reset_video;
 
 #ifdef SMP
-extern struct pcb	**susppcbs;
+extern struct susppcb	**susppcbs;
 static cpuset_t		suspcpus;
 #else
-static struct pcb	**susppcbs;
+static struct susppcb	**susppcbs;
 #endif
 
 static void		*acpi_alloc_wakeup_handler(void);
@@ -113,14 +117,15 @@ acpi_stop_beep(void *arg)
 static int
 acpi_wakeup_ap(struct acpi_softc *sc, int cpu)
 {
+	struct pcb *pcb;
 	int		vector = (WAKECODE_PADDR(sc) >> 12) & 0xff;
 	int		apic_id = cpu_apic_ids[cpu];
 	int		ms;
 
-	WAKECODE_FIXUP(wakeup_pcb, struct pcb *, susppcbs[cpu]);
-	WAKECODE_FIXUP(wakeup_gdt, uint16_t, susppcbs[cpu]->pcb_gdt.rd_limit);
-	WAKECODE_FIXUP(wakeup_gdt + 2, uint64_t,
-	    susppcbs[cpu]->pcb_gdt.rd_base);
+	pcb = &susppcbs[cpu]->sp_pcb;
+	WAKECODE_FIXUP(wakeup_pcb, struct pcb *, pcb);
+	WAKECODE_FIXUP(wakeup_gdt, uint16_t, pcb->pcb_gdt.rd_limit);
+	WAKECODE_FIXUP(wakeup_gdt + 2, uint64_t, pcb->pcb_gdt.rd_base);
 
 	ipi_startup(apic_id, vector);
 
@@ -184,6 +189,7 @@ int
 acpi_sleep_machdep(struct acpi_softc *sc, int state)
 {
 	ACPI_STATUS	status;
+	struct pcb	*pcb;
 
 	if (sc->acpi_wakeaddr == 0ul)
 		return (-1);	/* couldn't alloc wake memory */
@@ -200,9 +206,12 @@ acpi_sleep_machdep(struct acpi_softc *sc
 
 	intr_suspend();
 
-	if (savectx(susppcbs[0])) {
+	pcb = &susppcbs[0]->sp_pcb;
+	if (savectx(pcb)) {
 #ifdef __amd64__
-		fpususpend(susppcbs[0]->pcb_fpususpend);
+		fpususpend(susppcbs[0]->sp_fpususpend);
+#elif defined(DEV_NPX)
+		npxsuspend(&susppcbs[0]->sp_fpususpend);
 #endif
 #ifdef SMP
 		if (!CPU_EMPTY(&suspcpus) && suspend_cpus(suspcpus) == 0) {
@@ -215,13 +224,11 @@ acpi_sleep_machdep(struct acpi_softc *sc
 		WAKECODE_FIXUP(reset_video, uint8_t, (acpi_reset_video != 0));
 
 #ifndef __amd64__
-		WAKECODE_FIXUP(wakeup_cr4, register_t, susppcbs[0]->pcb_cr4);
+		WAKECODE_FIXUP(wakeup_cr4, register_t, pcb->pcb_cr4);
 #endif
-		WAKECODE_FIXUP(wakeup_pcb, struct pcb *, susppcbs[0]);
-		WAKECODE_FIXUP(wakeup_gdt, uint16_t,
-		    susppcbs[0]->pcb_gdt.rd_limit);
-		WAKECODE_FIXUP(wakeup_gdt + 2, uint64_t,
-		    susppcbs[0]->pcb_gdt.rd_base);
+		WAKECODE_FIXUP(wakeup_pcb, struct pcb *, pcb);
+		WAKECODE_FIXUP(wakeup_gdt, uint16_t, pcb->pcb_gdt.rd_limit);
+		WAKECODE_FIXUP(wakeup_gdt + 2, uint64_t, pcb->pcb_gdt.rd_base);
 
 		/* Call ACPICA to enter the desired sleep state */
 		if (state == ACPI_STATE_S4 && sc->acpi_s4bios)
@@ -237,6 +244,12 @@ acpi_sleep_machdep(struct acpi_softc *sc
 
 		for (;;)
 			ia32_pause();
+	} else {
+#ifdef __amd64__
+		fpuresume(susppcbs[0]->sp_fpususpend);
+#elif defined(DEV_NPX)
+		npxresume(&susppcbs[0]->sp_fpususpend);
+#endif
 	}
 
 	return (1);	/* wakeup successfully */
@@ -315,7 +328,7 @@ acpi_alloc_wakeup_handler(void)
 	for (i = 0; i < mp_ncpus; i++) {
 		susppcbs[i] = malloc(sizeof(**susppcbs), M_DEVBUF, M_WAITOK);
 #ifdef __amd64__
-		susppcbs[i]->pcb_fpususpend = alloc_fpusave(M_WAITOK);
+		susppcbs[i]->sp_fpususpend = alloc_fpusave(M_WAITOK);
 #endif
 	}
 


More information about the svn-src-all mailing list