[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [PATCH] x86/vmx: Fix vmentry failure because of invalid LER on Broadwell
On 25/05/17 13:15, Ross Lagerwall wrote: > Occasionally, the top three bits of MSR_IA32_LASTINTTOIP > (MSR_LER_TO_LIP) may be incorrect, as though the MSR is using the > LBR_FORMAT_EIP_FLAGS_TSX format. The MSR should contain an offset into > the current code segment according to the Intel documentation. It is not > clear why this happens. It may be due to erratum BDF14, or some other > errata. The result is a vmentry failure. > > Workaround the issue by sign-extending into bits 61:63 for this MSR on > Broadwell CPUs. > --- > xen/arch/x86/hvm/vmx/vmx.c | 29 +++++++++++++++++++++++++++++ > xen/include/asm-x86/hvm/vmx/vmcs.h | 1 + > 2 files changed, 30 insertions(+) > > diff --git a/xen/arch/x86/hvm/vmx/vmx.c b/xen/arch/x86/hvm/vmx/vmx.c > index c8ef18a..7d729af 100644 > --- a/xen/arch/x86/hvm/vmx/vmx.c > +++ b/xen/arch/x86/hvm/vmx/vmx.c > @@ -2434,6 +2434,7 @@ static void pi_notification_interrupt(struct > cpu_user_regs *regs) > } > > static void __init lbr_tsx_fixup_check(void); > +static void __init ler_bdw_fixup_check(void); > > const struct hvm_function_table * __init start_vmx(void) > { > @@ -2499,6 +2500,7 @@ const struct hvm_function_table * __init start_vmx(void) > setup_vmcs_dump(); > > lbr_tsx_fixup_check(); > + ler_bdw_fixup_check(); > > return &vmx_function_table; > } > @@ -2790,8 +2792,10 @@ enum > }; > > #define LBR_FROM_SIGNEXT_2MSB ((1ULL << 59) | (1ULL << 60)) > +#define LER_TO_SIGNEXT_3MSB (LBR_FROM_SIGNEXT_2MSB | (1ULL << 58)) > > static bool __read_mostly lbr_tsx_fixup_needed; > +static bool __read_mostly ler_bdw_fixup_needed; > static uint32_t __read_mostly lbr_from_start; > static uint32_t __read_mostly lbr_from_end; > static uint32_t __read_mostly lbr_lastint_from; > @@ -2828,6 +2832,13 @@ static void __init lbr_tsx_fixup_check(void) > } > } > > +static void __init ler_bdw_fixup_check(void) > +{ > + /* Broadwell E5-2600 v4 processors need to work around erratum BDF14. */ > + if ( boot_cpu_data.x86 == 6 && boot_cpu_data.x86_model == 79 ) > + ler_bdw_fixup_needed = true; > +} > + > static int is_last_branch_msr(u32 ecx) > { > const struct lbr_info *lbr = last_branch_msr_get(); > @@ -3089,6 +3100,8 @@ static int vmx_msr_write_intercept(unsigned int msr, > uint64_t msr_content) > vmx_disable_intercept_for_msr(v, lbr->base + i, > MSR_TYPE_R | MSR_TYPE_W); > v->arch.hvm_vmx.lbr_tsx_fixup_enabled = > lbr_tsx_fixup_needed; > + v->arch.hvm_vmx.ler_bdw_fixup_enabled = > + ler_bdw_fixup_needed; > } > } > > @@ -4174,6 +4187,20 @@ static void lbr_tsx_fixup(void) > msr->data |= ((LBR_FROM_SIGNEXT_2MSB & msr->data) << 2); > } > > +static void ler_bdw_fixup(void) Could we work the erratum identifier into the name? How about bdw_erratum_bdf14_fixup() ? > +{ > + struct vmx_msr_entry *msr; > + > + /* > + * Occasionally, the top three bits of MSR_IA32_LASTINTTOIP may be > + * incorrect (possibly due to BDF14), as though the MSR is using the > + * LBR_FORMAT_EIP_FLAGS_TSX format. This is incorrect and causes a > vmentry > + * failure -- the MSR should contain an offset into the current code > + * segment. Fix it up by sign-extending into bits 61:63. */ */ on newline. > + if ( (msr = vmx_find_msr(MSR_IA32_LASTINTTOIP, VMX_GUEST_MSR)) != NULL ) > + msr->data |= ((LER_TO_SIGNEXT_3MSB & msr->data) << 3); Thinking more about this logic, use diff --git a/xen/include/asm-x86/x86_64/page.h b/xen/include/asm-x86/x86_64/page.h index 1a6cae6..4025e3c 100644 --- a/xen/include/asm-x86/x86_64/page.h +++ b/xen/include/asm-x86/x86_64/page.h @@ -28,6 +28,9 @@ #define PADDR_MASK ((1UL << PADDR_BITS)-1) #define VADDR_MASK ((1UL << VADDR_BITS)-1) +#define VADDR_TOP_BIT (1UL << (VADDR_BITS - 1)) +#define CANONICAL_MASK (((1UL << 63) - 1) & ~((1UL << VADDR_BITS) - 1)) + #define is_canonical_address(x) (((long)(x) >> 47) == ((long)(x) >> 63)) #ifndef __ASSEMBLY__ BDF14 says that the values are unreliable, and we are only guessing at LBR_FORMAT_EIP_FLAGS_TSX. As a result, when re-canonicalising them, we should do it properly, to cover other eventualities. Something like this: if ( msr->data & VADDR_TOP_BIT ) msr->data |= CANONICAL_MASK; else msr->data &= ~CANONICAL_MASK; Also, per BDF14, this adjustment needs to happen to MSR_IA32_LASTINTFROMIP, even if we haven't actually observed a specific failure there. ~Andrew > +} > + > void vmx_vmenter_helper(const struct cpu_user_regs *regs) > { > struct vcpu *curr = current; > @@ -4232,6 +4259,8 @@ void vmx_vmenter_helper(const struct cpu_user_regs > *regs) > out: > if ( unlikely(curr->arch.hvm_vmx.lbr_tsx_fixup_enabled) ) > lbr_tsx_fixup(); > + if ( unlikely(curr->arch.hvm_vmx.ler_bdw_fixup_enabled) ) > + ler_bdw_fixup(); > > HVMTRACE_ND(VMENTRY, 0, 1/*cycles*/, 0, 0, 0, 0, 0, 0, 0); > > diff --git a/xen/include/asm-x86/hvm/vmx/vmcs.h > b/xen/include/asm-x86/hvm/vmx/vmcs.h > index 9507bd2..aedef82 100644 > --- a/xen/include/asm-x86/hvm/vmx/vmcs.h > +++ b/xen/include/asm-x86/hvm/vmx/vmcs.h > @@ -137,6 +137,7 @@ struct arch_vmx_struct { > uint8_t vmx_emulate; > > bool lbr_tsx_fixup_enabled; > + bool ler_bdw_fixup_enabled; > > /* Bitmask of segments that we can't safely use in virtual 8086 mode */ > uint16_t vm86_segment_mask; _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx https://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |