summaryrefslogtreecommitdiffstats
path: root/sys/i386
diff options
context:
space:
mode:
authorjhb <jhb@FreeBSD.org>2014-09-22 20:34:36 +0000
committerjhb <jhb@FreeBSD.org>2014-09-22 20:34:36 +0000
commit09bff45095d2101db8b3ff94ac79129598b7cfe7 (patch)
tree9aca44b47e0ae8505d550d52451704b9bce3514e /sys/i386
parent33a793a3e6389b4322cbb2871185706462c9cc55 (diff)
downloadFreeBSD-src-09bff45095d2101db8b3ff94ac79129598b7cfe7.zip
FreeBSD-src-09bff45095d2101db8b3ff94ac79129598b7cfe7.tar.gz
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)
Diffstat (limited to 'sys/i386')
-rw-r--r--sys/i386/i386/mp_machdep.c6
-rw-r--r--sys/i386/i386/swtch.s43
-rw-r--r--sys/i386/include/npx.h2
-rw-r--r--sys/i386/include/pcb.h5
-rw-r--r--sys/i386/isa/npx.c37
5 files changed, 48 insertions, 45 deletions
diff --git a/sys/i386/i386/mp_machdep.c b/sys/i386/i386/mp_machdep.c
index 222e8e2..acc4989 100644
--- a/sys/i386/i386/mp_machdep.c
+++ b/sys/i386/i386/mp_machdep.c
@@ -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);
diff --git a/sys/i386/i386/swtch.s b/sys/i386/i386/swtch.s
index 80aa6c4..e810434 100644
--- a/sys/i386/i386/swtch.s
+++ b/sys/i386/i386/swtch.s
@@ -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
diff --git a/sys/i386/include/npx.h b/sys/i386/include/npx.h
index 19e9b31..de55207 100644
--- a/sys/i386/include/npx.h
+++ b/sys/i386/include/npx.h
@@ -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 *);
diff --git a/sys/i386/include/pcb.h b/sys/i386/include/pcb.h
index 9cefed1..01ace72 100644
--- a/sys/i386/include/pcb.h
+++ b/sys/i386/include/pcb.h
@@ -92,6 +92,11 @@ struct pcb {
uint16_t pcb_tr;
};
+struct susppcb {
+ struct pcb sp_pcb;
+ union savefpu sp_fpususpend;
+};
+
#ifdef _KERNEL
struct trapframe;
diff --git a/sys/i386/isa/npx.c b/sys/i386/isa/npx.c
index dec7366..dd8403a 100644
--- a/sys/i386/isa/npx.c
+++ b/sys/i386/isa/npx.c
@@ -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()
{
OpenPOWER on IntegriCloud