aboutsummaryrefslogtreecommitdiffstats
path: root/xen/arch/x86/i387.c
diff options
context:
space:
mode:
authorJan Beulich <jbeulich@suse.com>2013-07-02 08:42:49 +0200
committerJan Beulich <jbeulich@suse.com>2013-07-02 08:42:49 +0200
commitf6c8c791522d6a2ef5e6abd44d0ed005446242b5 (patch)
tree7795e2a9b5e5832b13b6a91136149a8d5c155b7d /xen/arch/x86/i387.c
parentf9755488bf17c056111d1e442be394cfb63d7788 (diff)
downloadxen-f6c8c791522d6a2ef5e6abd44d0ed005446242b5.tar.gz
xen-f6c8c791522d6a2ef5e6abd44d0ed005446242b5.tar.bz2
xen-f6c8c791522d6a2ef5e6abd44d0ed005446242b5.zip
x86/fxsave: bring in line with recent xsave adjustments
Defer the FIP/FDP pointer reset needed on AMD CPUs to the restore path, and switch from using EMMS to FFREE here too (to be resistant against eventual future CPUs without MMX support). Also switch from using an almost typeless pointer in fpu_fxrstor() to a properly typed one, thus telling the compiler the truth about which memory gets accessed. Signed-off-by: Jan Beulich <jbeulich@suse.com> Acked-by: Keir Fraser <keir@xen.org>
Diffstat (limited to 'xen/arch/x86/i387.c')
-rw-r--r--xen/arch/x86/i387.c47
1 files changed, 21 insertions, 26 deletions
diff --git a/xen/arch/x86/i387.c b/xen/arch/x86/i387.c
index dbf24af83e..bd162a8e1e 100644
--- a/xen/arch/x86/i387.c
+++ b/xen/arch/x86/i387.c
@@ -52,14 +52,30 @@ static inline void fpu_xrstor(struct vcpu *v, uint64_t mask)
/* Restor x87 FPU, MMX, SSE and SSE2 state */
static inline void fpu_fxrstor(struct vcpu *v)
{
- const char *fpu_ctxt = v->arch.fpu_ctxt;
+ const typeof(v->arch.xsave_area->fpu_sse) *fpu_ctxt = v->arch.fpu_ctxt;
+
+ /*
+ * AMD CPUs don't save/restore FDP/FIP/FOP unless an exception
+ * is pending. Clear the x87 state here by setting it to fixed
+ * values. The hypervisor data segment can be sometimes 0 and
+ * sometimes new user value. Both should be ok. Use the FPU saved
+ * data block as a safe address because it should be in L1.
+ */
+ if ( !(fpu_ctxt->fsw & 0x0080) &&
+ boot_cpu_data.x86_vendor == X86_VENDOR_AMD )
+ {
+ asm volatile ( "fnclex\n\t"
+ "ffree %%st(7)\n\t" /* clear stack tag */
+ "fildl %0" /* load to clear state */
+ : : "m" (*fpu_ctxt) );
+ }
/*
* FXRSTOR can fault if passed a corrupted data block. We handle this
* possibility, which may occur if the block was passed to us by control
* tools or through VCPUOP_initialise, by silently clearing the block.
*/
- switch ( __builtin_expect(fpu_ctxt[FPU_WORD_SIZE_OFFSET], 8) )
+ switch ( __builtin_expect(fpu_ctxt->x[FPU_WORD_SIZE_OFFSET], 8) )
{
default:
asm volatile (
@@ -80,8 +96,7 @@ static inline void fpu_fxrstor(struct vcpu *v)
".previous \n"
_ASM_EXTABLE(1b, 2b)
:
- : "m" (*fpu_ctxt),
- "i" (sizeof(v->arch.xsave_area->fpu_sse) / 4),
+ : "m" (*fpu_ctxt), "i" (sizeof(*fpu_ctxt) / 4),
"cdaSDb" (fpu_ctxt) );
break;
case 4: case 2:
@@ -102,8 +117,7 @@ static inline void fpu_fxrstor(struct vcpu *v)
".previous \n"
_ASM_EXTABLE(1b, 2b)
:
- : "m" (*fpu_ctxt),
- "i" (sizeof(v->arch.xsave_area->fpu_sse) / 4) );
+ : "m" (*fpu_ctxt), "i" (sizeof(*fpu_ctxt) / 4) );
break;
}
}
@@ -156,7 +170,7 @@ static inline void fpu_fxsave(struct vcpu *v)
*/
if ( !(fpu_ctxt->fsw & 0x0080) &&
boot_cpu_data.x86_vendor == X86_VENDOR_AMD )
- word_size = -1;
+ return;
if ( word_size > 0 &&
!((fpu_ctxt->fip.addr | fpu_ctxt->fdp.addr) >> 32) )
@@ -177,25 +191,6 @@ static inline void fpu_fxsave(struct vcpu *v)
if ( word_size >= 0 )
fpu_ctxt->x[FPU_WORD_SIZE_OFFSET] = word_size;
-
- /* Clear exception flags if FSW.ES is set. */
- if ( unlikely(fpu_ctxt->fsw & 0x0080) )
- asm volatile ("fnclex");
-
- /*
- * AMD CPUs don't save/restore FDP/FIP/FOP unless an exception
- * is pending. Clear the x87 state here by setting it to fixed
- * values. The hypervisor data segment can be sometimes 0 and
- * sometimes new user value. Both should be ok. Use the FPU saved
- * data block as a safe address because it should be in L1.
- */
- if ( boot_cpu_data.x86_vendor == X86_VENDOR_AMD )
- {
- asm volatile (
- "emms\n\t" /* clear stack tags */
- "fildl %0" /* load to clear state */
- : : "m" (*fpu_ctxt) );
- }
}
/* Save x87 FPU state */