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
This commit is contained in:
parent
53c7f22849
commit
0f68c1833b
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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 *);
|
||||
|
@ -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
|
||||
|
@ -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()
|
||||
{
|
||||
|
@ -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, int state)
|
||||
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, int state)
|
||||
|
||||
for (;;)
|
||||
ia32_pause();
|
||||
} else {
|
||||
#ifdef DEV_NPX
|
||||
npxresume(&susppcbs[0]->pcb_fpususpend);
|
||||
#endif
|
||||
}
|
||||
|
||||
return (1); /* wakeup successfully */
|
||||
|
Loading…
x
Reference in New Issue
Block a user