Use asm goto rather than hiding a memset() in the fixup section. With the compiler now able to see the write into fpu_ctxt (as opposed to the asm constraint erroneously stating it as input-only), it validly objects to the pointer being const.
While FXRSTOR oughtn't to fault on an all-zeros input, avoid a risk of an infinite loop entirely by using a fixup scheme similar to xrstor(), and crashing the domain if we run out options. No functional change. Signed-off-by: Andrew Cooper <[email protected]> --- CC: Jan Beulich <[email protected]> CC: Roger Pau Monné <[email protected]> --- xen/arch/x86/i387.c | 65 ++++++++++++++++++++------------------------- 1 file changed, 29 insertions(+), 36 deletions(-) diff --git a/xen/arch/x86/i387.c b/xen/arch/x86/i387.c index b84cd6f7a9e1..e0714ab2267d 100644 --- a/xen/arch/x86/i387.c +++ b/xen/arch/x86/i387.c @@ -38,7 +38,8 @@ static inline void fpu_xrstor(struct vcpu *v, uint64_t mask) /* Restore x87 FPU, MMX, SSE and SSE2 state */ static inline void fpu_fxrstor(struct vcpu *v) { - const fpusse_t *fpu_ctxt = &v->arch.xsave_area->fpu_sse; + fpusse_t *fpu_ctxt = &v->arch.xsave_area->fpu_sse; + unsigned int faults = 0; /* * Some CPUs don't save/restore FDP/FIP/FOP unless an exception @@ -59,49 +60,41 @@ static inline void fpu_fxrstor(struct vcpu *v) * possibility, which may occur if the block was passed to us by control * tools or through VCPUOP_initialise, by silently clearing the block. */ + retry: switch ( __builtin_expect(fpu_ctxt->x[FPU_WORD_SIZE_OFFSET], 8) ) { default: - asm_inline volatile ( + asm_inline volatile goto ( "1: fxrstorq %0\n" - ".section .fixup,\"ax\" \n" - "2: push %%"__OP"ax \n" - " push %%"__OP"cx \n" - " push %%"__OP"di \n" - " lea %0,%%"__OP"di \n" - " mov %1,%%ecx \n" - " xor %%eax,%%eax \n" - " rep ; stosl \n" - " pop %%"__OP"di \n" - " pop %%"__OP"cx \n" - " pop %%"__OP"ax \n" - " jmp 1b \n" - ".previous \n" - _ASM_EXTABLE(1b, 2b) - : - : "m" (*fpu_ctxt), "i" (sizeof(*fpu_ctxt) / 4) ); + _ASM_EXTABLE(1b, %l[fault]) + :: "m" (*fpu_ctxt) + :: fault ); break; + case 4: case 2: - asm_inline volatile ( - "1: fxrstor %0 \n" - ".section .fixup,\"ax\"\n" - "2: push %%"__OP"ax \n" - " push %%"__OP"cx \n" - " push %%"__OP"di \n" - " lea %0,%%"__OP"di \n" - " mov %1,%%ecx \n" - " xor %%eax,%%eax \n" - " rep ; stosl \n" - " pop %%"__OP"di \n" - " pop %%"__OP"cx \n" - " pop %%"__OP"ax \n" - " jmp 1b \n" - ".previous \n" - _ASM_EXTABLE(1b, 2b) - : - : "m" (*fpu_ctxt), "i" (sizeof(*fpu_ctxt) / 4) ); + asm_inline volatile goto ( + "1: fxrstor %0\n" + _ASM_EXTABLE(1b, %l[fault]) + :: "m" (*fpu_ctxt) + :: fault ); break; } + + return; + + fault: + faults++; + + switch ( faults ) + { + case 1: /* Stage 1: Reset all state. */ + memset(fpu_ctxt, 0, sizeof(*fpu_ctxt)); + goto retry; + + default: /* Stage 2: Nothing else to do. */ + domain_crash(v->domain, "Uncorrectable FXRSTOR fault\n"); + return; + } } /*******************************/ -- 2.39.5
