diff options
author | jhb <jhb@FreeBSD.org> | 2014-09-22 20:34:36 +0000 |
---|---|---|
committer | jhb <jhb@FreeBSD.org> | 2014-09-22 20:34:36 +0000 |
commit | 09bff45095d2101db8b3ff94ac79129598b7cfe7 (patch) | |
tree | 9aca44b47e0ae8505d550d52451704b9bce3514e /sys/i386 | |
parent | 33a793a3e6389b4322cbb2871185706462c9cc55 (diff) | |
download | FreeBSD-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.c | 6 | ||||
-rw-r--r-- | sys/i386/i386/swtch.s | 43 | ||||
-rw-r--r-- | sys/i386/include/npx.h | 2 | ||||
-rw-r--r-- | sys/i386/include/pcb.h | 5 | ||||
-rw-r--r-- | sys/i386/isa/npx.c | 37 |
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() { |