[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [xen stable-4.6] x86/fpu: add a per-domain field to set the width of FIP/FDP
commit a5476a4b59df4fd206c203c3c0a2f4ed0dbcd5fd Author: David Vrabel <david.vrabel@xxxxxxxxxx> AuthorDate: Tue Mar 29 15:13:22 2016 +0200 Commit: Jan Beulich <jbeulich@xxxxxxxx> CommitDate: Tue Mar 29 15:13:22 2016 +0200 x86/fpu: add a per-domain field to set the width of FIP/FDP The x86 architecture allows either: a) the 64-bit FIP/FDP registers to be restored (clearing FCS and FDS); or b) the 32-bit FIP/FDP and FCS/FDS registers to be restored (clearing the upper 32-bits). Add a per-domain field to indicate which of these options a guest needs. The options are: 8, 4 or 0. Where 0 indicates that the hypervisor should automatically guess the FIP width by checking the value of FIP/FDP when saving the state (this is the existing behaviour). The FIP width is initially automatic but is set explicitly in the following cases: - 32-bit PV guest: 4 - Newer CPUs that do not save FCS/FDS: 8 The x87_fip_width field is placed into an existing 1 byte hole in struct arch_domain. Signed-off-by: David Vrabel <david.vrabel@xxxxxxxxxx> Fix build. Signed-off-by: Jan Beulich <jbeulich@xxxxxxxx> master commit: 879b44b041f26de35e4b527bf0f3c361eb52bd82 master date: 2016-02-26 12:29:21 +0100 --- xen/arch/x86/domain.c | 10 ++++++++ xen/arch/x86/i387.c | 19 +++++++++------ xen/arch/x86/xstate.c | 58 +++++++++++++++++++++++++++----------------- xen/include/asm-x86/domain.h | 15 ++++++++++++ 4 files changed, 73 insertions(+), 29 deletions(-) diff --git a/xen/arch/x86/domain.c b/xen/arch/x86/domain.c index 90f3ce5..e018c58 100644 --- a/xen/arch/x86/domain.c +++ b/xen/arch/x86/domain.c @@ -375,6 +375,8 @@ int switch_native(struct domain *d) release_compat_l4(v); } + d->arch.x87_fip_width = cpu_has_fpu_sel ? 0 : 8; + return 0; } @@ -408,6 +410,8 @@ int switch_compat(struct domain *d) domain_set_alloc_bitsize(d); + d->arch.x87_fip_width = 4; + return 0; undo_and_fail: @@ -657,6 +661,12 @@ int arch_domain_create(struct domain *d, unsigned int domcr_flags, /* PV/PVH guests get an emulated PIT too for video BIOSes to use. */ pit_init(d, cpu_khz); + /* + * If the FPU does not save FCS/FDS then we can always + * save/restore the 64-bit FIP/FDP and ignore the selectors. + */ + d->arch.x87_fip_width = cpu_has_fpu_sel ? 0 : 8; + return 0; fail: diff --git a/xen/arch/x86/i387.c b/xen/arch/x86/i387.c index 57eae28..e2d614e 100644 --- a/xen/arch/x86/i387.c +++ b/xen/arch/x86/i387.c @@ -152,9 +152,9 @@ static inline void fpu_xsave(struct vcpu *v) static inline void fpu_fxsave(struct vcpu *v) { typeof(v->arch.xsave_area->fpu_sse) *fpu_ctxt = v->arch.fpu_ctxt; - int word_size = cpu_has_fpu_sel ? 8 : 0; + unsigned int fip_width = v->domain->arch.x87_fip_width; - if ( !is_pv_32bit_vcpu(v) ) + if ( fip_width != 4 ) { /* * The only way to force fxsaveq on a wide range of gas versions. @@ -172,7 +172,11 @@ static inline void fpu_fxsave(struct vcpu *v) boot_cpu_data.x86_vendor == X86_VENDOR_AMD ) return; - if ( word_size > 0 && + /* + * If the FIP/FDP[63:32] are both zero, it is safe to use the + * 32-bit restore to also restore the selectors. + */ + if ( !fip_width && !((fpu_ctxt->fip.addr | fpu_ctxt->fdp.addr) >> 32) ) { struct ix87_env fpu_env; @@ -180,17 +184,18 @@ static inline void fpu_fxsave(struct vcpu *v) asm volatile ( "fnstenv %0" : "=m" (fpu_env) ); fpu_ctxt->fip.sel = fpu_env.fcs; fpu_ctxt->fdp.sel = fpu_env.fds; - word_size = 4; + fip_width = 4; } + else + fip_width = 8; } else { asm volatile ( "fxsave %0" : "=m" (*fpu_ctxt) ); - word_size = 4; + fip_width = 4; } - if ( word_size >= 0 ) - fpu_ctxt->x[FPU_WORD_SIZE_OFFSET] = word_size; + fpu_ctxt->x[FPU_WORD_SIZE_OFFSET] = fip_width; } /* Save x87 FPU state */ diff --git a/xen/arch/x86/xstate.c b/xen/arch/x86/xstate.c index d5f5e3b..a6ca814 100644 --- a/xen/arch/x86/xstate.c +++ b/xen/arch/x86/xstate.c @@ -70,9 +70,31 @@ void xsave(struct vcpu *v, uint64_t mask) struct xsave_struct *ptr = v->arch.xsave_area; uint32_t hmask = mask >> 32; uint32_t lmask = mask; - int word_size = mask & XSTATE_FP ? (cpu_has_fpu_sel ? 8 : 0) : -1; + unsigned int fip_width = v->domain->arch.x87_fip_width; - if ( word_size <= 0 || !is_pv_32bit_vcpu(v) ) + if ( fip_width == 8 || !(mask & XSTATE_FP) ) + { + if ( cpu_has_xsaveopt ) + asm volatile ( ".byte 0x48,0x0f,0xae,0x37" + : "=m" (*ptr) + : "a" (lmask), "d" (hmask), "D" (ptr) ); + else + asm volatile ( ".byte 0x48,0x0f,0xae,0x27" + : "=m" (*ptr) + : "a" (lmask), "d" (hmask), "D" (ptr) ); + } + else if ( fip_width == 4 ) + { + if ( cpu_has_xsaveopt ) + asm volatile ( ".byte 0x0f,0xae,0x37" + : "=m" (*ptr) + : "a" (lmask), "d" (hmask), "D" (ptr) ); + else + asm volatile ( ".byte 0x0f,0xae,0x27" + : "=m" (*ptr) + : "a" (lmask), "d" (hmask), "D" (ptr) ); + } + else { typeof(ptr->fpu_sse.fip.sel) fcs = ptr->fpu_sse.fip.sel; typeof(ptr->fpu_sse.fdp.sel) fds = ptr->fpu_sse.fdp.sel; @@ -85,9 +107,8 @@ void xsave(struct vcpu *v, uint64_t mask) * need to put the save image back into the state that it was in * right after the previous xsaveopt. */ - if ( word_size > 0 && - (ptr->fpu_sse.x[FPU_WORD_SIZE_OFFSET] == 4 || - ptr->fpu_sse.x[FPU_WORD_SIZE_OFFSET] == 2) ) + if ( ptr->fpu_sse.x[FPU_WORD_SIZE_OFFSET] == 4 || + ptr->fpu_sse.x[FPU_WORD_SIZE_OFFSET] == 2 ) { ptr->fpu_sse.fip.sel = 0; ptr->fpu_sse.fdp.sel = 0; @@ -109,7 +130,7 @@ void xsave(struct vcpu *v, uint64_t mask) (!(ptr->fpu_sse.fsw & 0x0080) && boot_cpu_data.x86_vendor == X86_VENDOR_AMD) ) { - if ( cpu_has_xsaveopt && word_size > 0 ) + if ( cpu_has_xsaveopt ) { ptr->fpu_sse.fip.sel = fcs; ptr->fpu_sse.fdp.sel = fds; @@ -117,31 +138,24 @@ void xsave(struct vcpu *v, uint64_t mask) return; } - if ( word_size > 0 && - !((ptr->fpu_sse.fip.addr | ptr->fpu_sse.fdp.addr) >> 32) ) + /* + * If the FIP/FDP[63:32] are both zero, it is safe to use the + * 32-bit restore to also restore the selectors. + */ + if ( !((ptr->fpu_sse.fip.addr | ptr->fpu_sse.fdp.addr) >> 32) ) { struct ix87_env fpu_env; asm volatile ( "fnstenv %0" : "=m" (fpu_env) ); ptr->fpu_sse.fip.sel = fpu_env.fcs; ptr->fpu_sse.fdp.sel = fpu_env.fds; - word_size = 4; + fip_width = 4; } - } - else - { - if ( cpu_has_xsaveopt ) - asm volatile ( ".byte 0x0f,0xae,0x37" - : "=m" (*ptr) - : "a" (lmask), "d" (hmask), "D" (ptr) ); else - asm volatile ( ".byte 0x0f,0xae,0x27" - : "=m" (*ptr) - : "a" (lmask), "d" (hmask), "D" (ptr) ); - word_size = 4; + fip_width = 8; } - if ( word_size >= 0 ) - ptr->fpu_sse.x[FPU_WORD_SIZE_OFFSET] = word_size; + if ( mask & XSTATE_FP ) + ptr->fpu_sse.x[FPU_WORD_SIZE_OFFSET] = fip_width; } void xrstor(struct vcpu *v, uint64_t mask) diff --git a/xen/include/asm-x86/domain.h b/xen/include/asm-x86/domain.h index c6c6e71..2707ebe 100644 --- a/xen/include/asm-x86/domain.h +++ b/xen/include/asm-x86/domain.h @@ -338,6 +338,21 @@ struct arch_domain u8 x86_vendor; /* CPU vendor */ u8 x86_model; /* CPU model */ + /* + * The width of the FIP/FDP register in the FPU that needs to be + * saved/restored during a context switch. This is needed because + * the FPU can either: a) restore the 64-bit FIP/FDP and clear FCS + * and FDS; or b) restore the 32-bit FIP/FDP (clearing the upper + * 32-bits of FIP/FDP) and restore FCS/FDS. + * + * Which one is needed depends on the guest. + * + * This can be either: 8, 4 or 0. 0 means auto-detect the size + * based on the width of FIP/FDP values that are written by the + * guest. + */ + uint8_t x87_fip_width; + cpuid_input_t *cpuids; struct PITState vpit; -- generated by git-patchbot for /home/xen/git/xen.git#stable-4.6 _______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxx http://lists.xensource.com/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |