[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

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.