KVM: SVM: Clear the CR4 register on reset
diff mbox series

Message ID 161471109108.30811.6392805173629704166.stgit@bmoger-ubuntu
State Accepted
Commit 9e46f6c6c959d9bb45445c2e8f04a75324a0dfd0
Headers show
Series
  • KVM: SVM: Clear the CR4 register on reset
Related show

Commit Message

Babu Moger March 2, 2021, 6:51 p.m. UTC
This problem was reported on a SVM guest while executing kexec.
Kexec fails to load the new kernel when the PCID feature is enabled.

When kexec starts loading the new kernel, it starts the process by
resetting the vCPU's and then bringing each vCPU online one by one.
The vCPU reset is supposed to reset all the register states before the
vCPUs are brought online. However, the CR4 register is not reset during
this process. If this register is already setup during the last boot,
all the flags can remain intact. The X86_CR4_PCIDE bit can only be
enabled in long mode. So, it must be enabled much later in SMP
initialization.  Having the X86_CR4_PCIDE bit set during SMP boot can
cause a boot failures.

Fix the issue by resetting the CR4 register in init_vmcb().

Signed-off-by: Babu Moger <babu.moger@amd.com>
---
 arch/x86/kvm/svm/svm.c |    1 +
 1 file changed, 1 insertion(+)

Comments

Sean Christopherson March 2, 2021, 7:20 p.m. UTC | #1
On Tue, Mar 02, 2021, Babu Moger wrote:
> This problem was reported on a SVM guest while executing kexec.
> Kexec fails to load the new kernel when the PCID feature is enabled.
> 
> When kexec starts loading the new kernel, it starts the process by
> resetting the vCPU's and then bringing each vCPU online one by one.
> The vCPU reset is supposed to reset all the register states before the
> vCPUs are brought online. However, the CR4 register is not reset during
> this process. If this register is already setup during the last boot,
> all the flags can remain intact. The X86_CR4_PCIDE bit can only be
> enabled in long mode. So, it must be enabled much later in SMP
> initialization.  Having the X86_CR4_PCIDE bit set during SMP boot can
> cause a boot failures.
> 
> Fix the issue by resetting the CR4 register in init_vmcb().
> 
> Signed-off-by: Babu Moger <babu.moger@amd.com>

Cc: stable@vger.kernel.org

The bug goes back too far to have a meaningful Fixes.

Reviewed-by: Sean Christopherson <seanjc@google.com>


On a related topic, I think we can clean up the RESET/INIT flows by hoisting the
common code into kvm_vcpu_reset().  That would also provide good motivation for
removing the init_vmcb() call in svm_create_vcpu(), which is fully redundant
with the call in svm_vcpu_reset().  I'll put that on the todo list.
Babu Moger March 2, 2021, 7:29 p.m. UTC | #2
On 3/2/21 1:20 PM, Sean Christopherson wrote:
> On Tue, Mar 02, 2021, Babu Moger wrote:
>> This problem was reported on a SVM guest while executing kexec.
>> Kexec fails to load the new kernel when the PCID feature is enabled.
>>
>> When kexec starts loading the new kernel, it starts the process by
>> resetting the vCPU's and then bringing each vCPU online one by one.
>> The vCPU reset is supposed to reset all the register states before the
>> vCPUs are brought online. However, the CR4 register is not reset during
>> this process. If this register is already setup during the last boot,
>> all the flags can remain intact. The X86_CR4_PCIDE bit can only be
>> enabled in long mode. So, it must be enabled much later in SMP
>> initialization.  Having the X86_CR4_PCIDE bit set during SMP boot can
>> cause a boot failures.
>>
>> Fix the issue by resetting the CR4 register in init_vmcb().
>>
>> Signed-off-by: Babu Moger <babu.moger@amd.com>
> 
> Cc: stable@vger.kernel.org
> 
> The bug goes back too far to have a meaningful Fixes.
> 
> Reviewed-by: Sean Christopherson <seanjc@google.com>

Sean, Thanks
> 
> 
> On a related topic, I think we can clean up the RESET/INIT flows by hoisting the
> common code into kvm_vcpu_reset().  That would also provide good motivation for
> removing the init_vmcb() call in svm_create_vcpu(), which is fully redundant
> with the call in svm_vcpu_reset().  I'll put that on the todo list.

Yes.Please.Thought about cleaning init_vmcb and svm_vcpu_reset little bit.
That will require some more tests and review. We didn't want to delay the
fix for that now.
Thanks
Babu
Paolo Bonzini March 2, 2021, 7:39 p.m. UTC | #3
On 02/03/21 19:51, Babu Moger wrote:
> This problem was reported on a SVM guest while executing kexec.
> Kexec fails to load the new kernel when the PCID feature is enabled.
> 
> When kexec starts loading the new kernel, it starts the process by
> resetting the vCPU's and then bringing each vCPU online one by one.
> The vCPU reset is supposed to reset all the register states before the
> vCPUs are brought online. However, the CR4 register is not reset during
> this process. If this register is already setup during the last boot,
> all the flags can remain intact. The X86_CR4_PCIDE bit can only be
> enabled in long mode. So, it must be enabled much later in SMP
> initialization.  Having the X86_CR4_PCIDE bit set during SMP boot can
> cause a boot failures.
> 
> Fix the issue by resetting the CR4 register in init_vmcb().
> 
> Signed-off-by: Babu Moger <babu.moger@amd.com>
> ---
>   arch/x86/kvm/svm/svm.c |    1 +
>   1 file changed, 1 insertion(+)
> 
> diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c
> index c636021b066b..baee91c1e936 100644
> --- a/arch/x86/kvm/svm/svm.c
> +++ b/arch/x86/kvm/svm/svm.c
> @@ -1200,6 +1200,7 @@ static void init_vmcb(struct vcpu_svm *svm)
>   	init_sys_seg(&save->ldtr, SEG_TYPE_LDT);
>   	init_sys_seg(&save->tr, SEG_TYPE_BUSY_TSS16);
>   
> +	svm_set_cr4(&svm->vcpu, 0);
>   	svm_set_efer(&svm->vcpu, 0);
>   	save->dr6 = 0xffff0ff0;
>   	kvm_set_rflags(&svm->vcpu, X86_EFLAGS_FIXED);
> 

Queued, thanks.

Paolo

Patch
diff mbox series

diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c
index c636021b066b..baee91c1e936 100644
--- a/arch/x86/kvm/svm/svm.c
+++ b/arch/x86/kvm/svm/svm.c
@@ -1200,6 +1200,7 @@  static void init_vmcb(struct vcpu_svm *svm)
 	init_sys_seg(&save->ldtr, SEG_TYPE_LDT);
 	init_sys_seg(&save->tr, SEG_TYPE_BUSY_TSS16);
 
+	svm_set_cr4(&svm->vcpu, 0);
 	svm_set_efer(&svm->vcpu, 0);
 	save->dr6 = 0xffff0ff0;
 	kvm_set_rflags(&svm->vcpu, X86_EFLAGS_FIXED);