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-stable-10
mailing list