diff options
-rw-r--r-- | sys/amd64/amd64/fpu.c | 36 | ||||
-rw-r--r-- | sys/i386/isa/npx.c | 42 |
2 files changed, 76 insertions, 2 deletions
diff --git a/sys/amd64/amd64/fpu.c b/sys/amd64/amd64/fpu.c index eeb39e8..06a7d5d 100644 --- a/sys/amd64/amd64/fpu.c +++ b/sys/amd64/amd64/fpu.c @@ -96,6 +96,8 @@ void stop_emulating(void); typedef u_char bool_t; +static void fpu_clean_state(void); + int hw_float = 1; SYSCTL_INT(_hw,HW_FLOATINGPT, floatingpoint, CTLFLAG_RD, &hw_float, 0, @@ -407,6 +409,8 @@ fpudna() PCPU_SET(fpcurthread, curthread); pcb = PCPU_GET(curpcb); + fpu_clean_state(); + if ((pcb->pcb_flags & PCB_FPUINITDONE) == 0) { /* * This is the first time this thread has used the FPU, @@ -474,6 +478,7 @@ fpusetregs(struct thread *td, struct savefpu *addr) s = intr_disable(); if (td == PCPU_GET(fpcurthread)) { + fpu_clean_state(); fxrstor(addr); intr_restore(s); } else { @@ -484,6 +489,37 @@ fpusetregs(struct thread *td, struct savefpu *addr) } /* + * On AuthenticAMD processors, the fxrstor instruction does not restore + * the x87's stored last instruction pointer, last data pointer, and last + * opcode values, except in the rare case in which the exception summary + * (ES) bit in the x87 status word is set to 1. + * + * In order to avoid leaking this information across processes, we clean + * these values by performing a dummy load before executing fxrstor(). + */ +static double dummy_variable = 0.0; +static void +fpu_clean_state(void) +{ + u_short status; + + /* + * Clear the ES bit in the x87 status word if it is currently + * set, in order to avoid causing a fault in the upcoming load. + */ + fnstsw(&status); + if (status & 0x80) + fnclex(); + + /* + * Load the dummy variable into the x87 stack. This mangles + * the x87 stack, but we don't care since we're about to call + * fxrstor() anyway. + */ + __asm __volatile("ffree %%st(7); fld %0" : : "m" (dummy_variable)); +} + +/* * This really sucks. We want the acpi version only, but it requires * the isa_if.h file in order to get the definitions. */ diff --git a/sys/i386/isa/npx.c b/sys/i386/isa/npx.c index 18fc4a7..4121e3f 100644 --- a/sys/i386/isa/npx.c +++ b/sys/i386/isa/npx.c @@ -142,6 +142,10 @@ void stop_emulating(void); typedef u_char bool_t; +#ifdef CPU_ENABLE_SSE +static void fpu_clean_state(void); +#endif + static void fpusave(union savefpu *); static void fpurstor(union savefpu *); static int npx_attach(device_t dev); @@ -952,15 +956,49 @@ fpusave(addr) fnsave(addr); } +#ifdef CPU_ENABLE_SSE +/* + * On AuthenticAMD processors, the fxrstor instruction does not restore + * the x87's stored last instruction pointer, last data pointer, and last + * opcode values, except in the rare case in which the exception summary + * (ES) bit in the x87 status word is set to 1. + * + * In order to avoid leaking this information across processes, we clean + * these values by performing a dummy load before executing fxrstor(). + */ +static double dummy_variable = 0.0; +static void +fpu_clean_state(void) +{ + u_short status; + + /* + * Clear the ES bit in the x87 status word if it is currently + * set, in order to avoid causing a fault in the upcoming load. + */ + fnstsw(&status); + if (status & 0x80) + fnclex(); + + /* + * Load the dummy variable into the x87 stack. This mangles + * the x87 stack, but we don't care since we're about to call + * fxrstor() anyway. + */ + __asm __volatile("ffree %%st(7); fld %0" : : "m" (dummy_variable)); +} +#endif /* CPU_ENABLE_SSE */ + static void fpurstor(addr) union savefpu *addr; { #ifdef CPU_ENABLE_SSE - if (cpu_fxsr) + if (cpu_fxsr) { + fpu_clean_state(); fxrstor(addr); - else + } else #endif frstor(addr); } |