Re: 4.16 kernel: vmwrite error: reg 401e value 2021 (err 12)

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



2018-04-18 0:26 GMT+08:00 Christopherson, Sean J
<sean.j.christopherson@xxxxxxxxx>:
> On Tue, 2018-04-17, Paolo Bonzini wrote:
>> On 17/04/2018 17:46, Christopherson, Sean J wrote:
>> > On Tue, 2018-04-17, Zdenek Kaspar wrote:
>> >> Hello, I did quick test with latest stable kernel (4.16.2) and got tons
>> >> of vmwrite errors immediately when starting VM:
>> >
>> > Code related to UMIP emulation is effectively doing an unconditional
>> > RMW on SECONDARY_VM_EXEC_CONTROL, which isn't guaranteed to exist on
>> > older processors.  KVM already ensures it only advertises UMIP (via
>> > emulation) when SECONDARY_EXEC_DESC can be set, i.e. KVM is already
>> > implicitly checking for SECONDARY_VM_EXEC_CONTROL, so fixing the bug
>> > is just a matter of omitting the unneeded VMREAD/VMWRITE sequence.
>>
>> Thanks for the report!
>>
>> This should be a fix:
>>
>> diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
>> index aa66ccd6ed6c..c5dd185825c7 100644
>> --- a/arch/x86/kvm/vmx.c
>> +++ b/arch/x86/kvm/vmx.c
>> @@ -4767,14 +4767,16 @@ static int vmx_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)
>>       else
>>               hw_cr4 |= KVM_PMODE_VM_CR4_ALWAYS_ON;
>>
>> -     if ((cr4 & X86_CR4_UMIP) && !boot_cpu_has(X86_FEATURE_UMIP)) {
>> -             vmcs_set_bits(SECONDARY_VM_EXEC_CONTROL,
>> -                           SECONDARY_EXEC_DESC);
>> -             hw_cr4 &= ~X86_CR4_UMIP;
>> -     } else if (!is_guest_mode(vcpu) ||
>> -                !nested_cpu_has2(get_vmcs12(vcpu), SECONDARY_EXEC_DESC))
>> -             vmcs_clear_bits(SECONDARY_VM_EXEC_CONTROL,
>> -                             SECONDARY_EXEC_DESC);
>> +     if (!boot_cpu_has(X86_FEATURE_UMIP) && vmx_umip_emulated()) {
>> +             if (cr4 & X86_CR4_UMIP) {
>> +                     vmcs_set_bits(SECONDARY_VM_EXEC_CONTROL,
>> +                                   SECONDARY_EXEC_DESC);
>> +                     hw_cr4 &= ~X86_CR4_UMIP;
>> +             } else if (!is_guest_mode(vcpu) ||
>> +                        !nested_cpu_has2(get_vmcs12(vcpu), SECONDARY_EXEC_DESC))
>> +                     vmcs_clear_bits(SECONDARY_VM_EXEC_CONTROL,
>> +                                     SECONDARY_EXEC_DESC);
>> +     }
>>
>>       if (cr4 & X86_CR4_VMXE) {
>>               /*
>>
>> I'll test it and send the patch more formally.
>
> Below is what I was thinking for a patch.  We should avoid the
> VMREAD/VMWRITE when possible even when we're emulating UMIP.
>
>
> From: Sean Christopherson <sean.j.christopherson@xxxxxxxxx>
> Subject: [PATCH] KVM: vmx: update SECONDARY_EXEC_DESC only if CR4.UMIP changes
>
> Update SECONDARY_EXEC_DESC in SECONDARY_VM_EXEC_CONTROL for UMIP
> emulation if and only if CR4.UMIP is being modified and UMIP is
> not supported by hardware, i.e. we're emulating UMIP.  If CR4.UMIP
> is not being changed then it's safe to assume that the previous
> invocation of vmx_set_cr4() correctly set SECONDARY_EXEC_DESC,
> i.e. the desired value is already the current value.  This avoids
> unnecessary VMREAD/VMWRITE to SECONDARY_VM_EXEC_CONTROL, which
> is critical as not all processors support SECONDARY_VM_EXEC_CONTROL.
>
> WARN once and signal a fault if CR4.UMIP is changing and UMIP can't
> be emulated, i.e. SECONDARY_EXEC_DESC can't be set.  Prior checks
> should prevent setting UMIP if it can't be emulated, i.e. UMIP
> shouldn't have been advertised to the guest if it can't be emulated,
> regardless of whether or not UMIP is supported in bare metal.
>
> Fixes: 0367f205a3b7 ("KVM: vmx: add support for emulating UMIP")
> Signed-off-by: Sean Christopherson <sean.j.christopherson@xxxxxxxxx>
> ---
>  arch/x86/kvm/vmx.c | 34 ++++++++++++++++++++--------------
>  1 file changed, 20 insertions(+), 14 deletions(-)
>
> diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
> index aafcc9881e88..31b36b9801bb 100644
> --- a/arch/x86/kvm/vmx.c
> +++ b/arch/x86/kvm/vmx.c
> @@ -1494,6 +1494,12 @@ static inline bool cpu_has_vmx_vmfunc(void)
>                 SECONDARY_EXEC_ENABLE_VMFUNC;
>  }
>
> +static bool vmx_umip_emulated(void)
> +{
> +       return vmcs_config.cpu_based_2nd_exec_ctrl &
> +               SECONDARY_EXEC_DESC;
> +}
> +
>  static inline bool report_flexpriority(void)
>  {
>         return flexpriority_enabled;
> @@ -4776,14 +4782,20 @@ static int vmx_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)
>         else
>                 hw_cr4 |= KVM_PMODE_VM_CR4_ALWAYS_ON;
>
> -       if ((cr4 & X86_CR4_UMIP) && !boot_cpu_has(X86_FEATURE_UMIP)) {
> -               vmcs_set_bits(SECONDARY_VM_EXEC_CONTROL,
> -                             SECONDARY_EXEC_DESC);
> -               hw_cr4 &= ~X86_CR4_UMIP;
> -       } else if (!is_guest_mode(vcpu) ||
> -                  !nested_cpu_has2(get_vmcs12(vcpu), SECONDARY_EXEC_DESC))
> -               vmcs_clear_bits(SECONDARY_VM_EXEC_CONTROL,
> -                               SECONDARY_EXEC_DESC);
> +       if (((cr4 ^ kvm_read_cr4(vcpu)) & X86_CR4_UMIP) &&
> +           !boot_cpu_has(X86_FEATURE_UMIP)) {
> +               if (WARN_ON_ONCE(!vmx_umip_emulated()))
> +                       return 1;

Two questions here:
1) cr4 is set to 0 during reset, however, the calltrace occurs during
reset, why cr4 & X86_CR4_UMIP can be true?
2) UMIP cpuid flag is not exposed to the guest since
vmx_umip_emulated() fails, why there is a place set cr4 & X86_CR4_UMIP
to true?

Regards,
Wanpeng Li

> +
> +               if (cr4 & X86_CR4_UMIP) {
> +                       vmcs_set_bits(SECONDARY_VM_EXEC_CONTROL,
> +                                       SECONDARY_EXEC_DESC);
> +                       hw_cr4 &= ~X86_CR4_UMIP;
> +               } else if (!is_guest_mode(vcpu) ||
> +                       !nested_cpu_has2(get_vmcs12(vcpu), SECONDARY_EXEC_DESC))
> +                       vmcs_clear_bits(SECONDARY_VM_EXEC_CONTROL,
> +                                       SECONDARY_EXEC_DESC);
> +       }
>
>         if (cr4 & X86_CR4_VMXE) {
>                 /*
> @@ -9512,12 +9524,6 @@ static bool vmx_xsaves_supported(void)
>                 SECONDARY_EXEC_XSAVES;
>  }
>
> -static bool vmx_umip_emulated(void)
> -{
> -       return vmcs_config.cpu_based_2nd_exec_ctrl &
> -               SECONDARY_EXEC_DESC;
> -}
> -
>  static void vmx_recover_nmi_blocking(struct vcpu_vmx *vmx)
>  {
>         u32 exit_intr_info;
> --
>
>
>>
>> Thanks,
>>
>> Paolo



[Index of Archives]     [KVM ARM]     [KVM ia64]     [KVM ppc]     [Virtualization Tools]     [Spice Development]     [Libvirt]     [Libvirt Users]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite Questions]     [Linux Kernel]     [Linux SCSI]     [XFree86]

  Powered by Linux