Use WARN_ON_ONCE for missing X86_FEATURE_NRIPS
PATCH 1/1 Use WARN_ON_ONCE for missing X86_FEATURE_NRIPS
The cpu feature flags are not ever going to change, so warning everytime can cause a lot of kernel log spam
(in our case more than 10GB/hour).
Signature · 1 line
SUSE Linux GmbH, GF: Felix Imendörffer, Jane Smithard, Graham Norton, HRB 21284 (AG Nürnberg)
Quoted 1 line
From
40c7213e34a1a1caf0b98db832c06c593f888b11Mon Sep 17 00:00:00 2001
From: Dirk Mueller <[email protected]>
Date: Thu, 1 Oct 2015 13:10:10 +0200
Subject: [PATCH] Use WARN_ON_ONCE for missing X86_FEATURE_NRIPS
The cpu feature flags are not ever going to change, so warning everytime can cause a lot of kernel log spam
(in our case more than 10GB/hour).
--- arch/x86/kvm/svm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
arch/x86/kvm/svm.c +1 -1
@@ -514,7 +514,7 @@ static void skip_emulated_instruction(struct kvm_vcpu *vcpu)struct vcpu_svm *svm =to_svm (vcpu);if (svm->vmcb->control.next_rip !=0 ) { -WARN_ON (!static_cpu_has (X86_FEATURE_NRIPS )); +WARN_ON_ONCE (!static_cpu_has (X86_FEATURE_NRIPS )); svm->next_rip = svm->vmcb->control.next_rip; }
Signature · 1 line
2.5.1
Quoted 6 lines · Dirk Müller
The cpu feature flags are not ever going to change, so warning everytime can cause a lot of kernel log spam
(in our case more than 10GB/hour).Signed-off-by Dirk Mueller <[email protected]>
Applied. Do you also know what caused the warning, and/or would you like me to take a look?
Paolo
On 01.10.2015 14:25, Paolo Bonzini wrote:
Hi Paolo,
Quoted 2 lines
Applied. Do you also know what caused the warning, and/or would you like me to take a look?
The trace we're getting is this:
[<ffffffff8100471d>] dump_trace+0x7d/0x2d0 [<ffffffff81004a04>] show_stack_log_lvl+0x94/0x170 [<ffffffff81005cc1>] show_stack+0x21/0x50 [<ffffffff81510f42>] dump_stack+0x41/0x51 [<ffffffff81055362>] warn_slowpath_common+0x82/0xc0 [<ffffffffa0388cc1>] skip_emulated_instruction+0xe1/0x160 [kvm_amd] [<ffffffffa038908b>] io_interception+0x3b/0x80 [kvm_amd] [<ffffffffa031667c>] vcpu_enter_guest+0x6bc/0xc70 [kvm] [<ffffffffa031aa08>] kvm_arch_vcpu_ioctl_run+0x1d8/0x450 [kvm] [<ffffffffa0305ec1>] kvm_vcpu_ioctl+0x2e1/0x580 [kvm] [<ffffffff811b3f24>] do_vfs_ioctl+0x2d4/0x4b0 [<ffffffff811b4188>] SyS_ioctl+0x88/0xa0 [<ffffffff8151f209>] system_call_fastpath+0x16/0x1b [<00007f8f7b5fabe7>] 0x7f8f7b5fabe6
The colleague who was investigating this is not here today, but from what I remember it seems to only happen when nested virtualisation is being used. I don't know more about it right now, bisecting pointed out f104765b4f81fd74d69e0eb161e89096deade2db . Since it was logging so rapidly on our autotester machines (which are running 200-250 VMs nested) that we are continuously run out of disk space I just tried to come up with a stop-gap fix until this has been properly analyzed.
Thanks,
Dirk
Paolo Bonzini
maintainerarch/x86/kvm/svm.c static void skip_emulated_instruction(struct kvm_vcpu *vcpu) · line 520
Quoted 13 lines · Dirk Müller
arch/x86/kvm/svm.c +1
-1@@ -514,7 +514,7 @@ static void skip_emulated_instruction(struct kvm_vcpu *vcpu)struct vcpu_svm *svm =to_svm (vcpu);if (svm->vmcb->control.next_rip !=0 ) { -WARN_ON (!static_cpu_has (X86_FEATURE_NRIPS )); +WARN_ON_ONCE (!static_cpu_has (X86_FEATURE_NRIPS )); svm->next_rip = svm->vmcb->control.next_rip; }
Bandan, what was the reason for warning here?
Should we change the "if" condition to static_cpu_has(X86_FEATURE_NRIPS) instead of Dirk's patch?
Paolo
Quoted 8 lines · Paolo Bonzini
Quoted 7 lines · Dirk Müller
arch/x86/kvm/svm.c +0
-0@@ -514,7 +514,7 @@ static void skip_emulated_instruction(struct kvm_vcpu *vcpu)struct vcpu_svm *svm =to_svm (vcpu);
Quoted 8 lines
arch/x86/kvm/svm.c static void skip_emulated_instruction(struct kvm_vcpu *vcpu) · line 520
Quoted 6 lines
arch/x86/kvm/svm.c +1
-1if (svm->vmcb->control.next_rip !=0 ) { -WARN_ON (!static_cpu_has (X86_FEATURE_NRIPS )); +WARN_ON_ONCE (!static_cpu_has (X86_FEATURE_NRIPS )); svm->next_rip = svm->vmcb->control.next_rip; }Bandan, what was the reason for warning here?
I added the warning so that we catch if the next_rip field is being written to (even if the feature isn't supported) by a buggy L1 hypervisor.
From the commit:
- if (svm->vmcb->control.next_rip != 0)
+ if (svm->vmcb->control.next_rip != 0) {
+ WARN_ON(!static_cpu_has(X86_FEATURE_NRIPS));
svm->next_rip = svm->vmcb->control.next_rip;
+ }
if (!svm->next_rip) {
if (emulate_instruction(vcpu, EMULTYPE_SKIP) !=
@@ -4317,7 +4319,9 @@ static int svm_check_intercept(struct kvm_vcpu *vcpu,
break;
}
- vmcb->control.next_rip = info->next_rip;
+ /* TODO: Advertise NRIPS to guest hypervisor unconditionally */
+ if (static_cpu_has(X86_FEATURE_NRIPS))
+ vmcb->control.next_rip = info->next_rip;
vmcb->control.exit_code = icpt_info.exit_code; vmexit = nested_svm_exit_handled(svm);
...
Quoted 2 lines
Should we change the "if" condition to
static_cpu_has(X86_FEATURE_NRIPS)instead of Dirk's patch?
Yes, seems ok to me. If decodeassist isn't supported then it's mostly a stale value. It's interesting that that L1 still works even after we hit this warning!
Quoted 1 line
Paolo
Quoted 3 lines
I added the warning so that we catch if the
next_ripfield is being written to (even if the feature isn't supported) by a buggy L1 hypervisor.
Interesting, so how about this patch?
From c5c8ea255d680f972cbdfc835cdf352fa78897ae Mon Sep 17 00:00:00 2001
From: Dirk Mueller <[email protected]>
Date: Fri, 2 Oct 2015 08:35:24 +0200
Subject: [PATCH] KVM: nSVM: Check for NRIP support before accepting
control.next_rip
NRIP support itself depends on cpuid Fn8000_000A_EDX[NRIPS], remove a WARN_ON_(once) and check for it directly.
--- arch/x86/kvm/svm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
arch/x86/kvm/svm.c +2 -2
@@ -513,8 +513,8 @@ static void skip_emulated_instruction(struct kvm_vcpu *vcpu) {struct vcpu_svm *svm =to_svm (vcpu); -if (svm->vmcb->control.next_rip !=0 ) { -WARN_ON_ONCE (!static_cpu_has (X86_FEATURE_NRIPS )); +if (static_cpu_has (X86_FEATURE_NRIPS ) && + svm->vmcb->control.next_rip !=0 ) { svm->next_rip = svm->vmcb->control.next_rip; }
Signature · 1 line
2.5.1
Thanks,
Dirk
Quoted 25 lines · Dirk Müller
Quoted 2 lines
I added the warning so that we catch if the
next_ripfield is being written to (even if the feature isn't supported) by a buggy L1 hypervisor.Interesting, so how about this patch?
From
c5c8ea255d680f972cbdfc835cdf352fa78897aeMon Sep 17 00:00:00 2001
From: Dirk Mueller <[email protected]>
Date: Fri, 2 Oct 2015 08:35:24 +0200
Subject: [PATCH] KVM: nSVM: Check for NRIP support before accepting
control.next_ripNRIP support itself depends on cpuid Fn8000_000A_EDX[NRIPS], remove a
WARN_ON_(once)and check for it directly.Signed-off-by Dirk Mueller <[email protected]>--- arch/x86/kvm/svm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)arch/x86/kvm/svm.c +0
-0
arch/x86/kvm/svm.c static void skip_emulated_instruction(struct kvm_vcpu *vcpu) · line 519
Quoted 9 lines
arch/x86/kvm/svm.c +2
-2@@ -513,8 +513,8 @@ static void skip_emulated_instruction(struct kvm_vcpu *vcpu) {struct vcpu_svm *svm =to_svm (vcpu); -if (svm->vmcb->control.next_rip !=0 ) { -WARN_ON_ONCE (!static_cpu_has (X86_FEATURE_NRIPS )); +if (static_cpu_has (X86_FEATURE_NRIPS ) && + svm->vmcb->control.next_rip !=0 ) { svm->next_rip = svm->vmcb->control.next_rip; }
Ok, looks good to me. Still, probably a good idea to let the user know if this condition is hit.
Bandan
Quoted 19 lines · Bandan Das
Quoted 8 lines · Paolo Bonzini
Quoted 7 lines · Dirk Müller
arch/x86/kvm/svm.c +0
-0@@ -514,7 +514,7 @@ static void skip_emulated_instruction(struct kvm_vcpu *vcpu)struct vcpu_svm *svm =to_svm (vcpu);Quoted 8 lines
arch/x86/kvm/svm.c static void skip_emulated_instruction(struct kvm_vcpu *vcpu) · line 520
Quoted 6 lines
arch/x86/kvm/svm.c +1
-1if (svm->vmcb->control.next_rip !=0 ) { -WARN_ON (!static_cpu_has (X86_FEATURE_NRIPS )); +WARN_ON_ONCE (!static_cpu_has (X86_FEATURE_NRIPS )); svm->next_rip = svm->vmcb->control.next_rip; }Bandan, what was the reason for warning here?
Quoted 2 lines
I added the warning so that we catch if the
next_ripfield is being written to (even if the feature isn't supported) by a buggy L1 hypervisor.
Even if the L1 hypervisor writes to the next_rip field in the VMCB, we would never see it in this code path, as we access the shadow VMCB in this statement.
We don't even care if the L1 hypervisor writes to its next_rip field because we only write to this field on an emulatated VMEXIT and never read it back.
So what's the point in adding a guest-triggerable warning at all?
Joerg
Quoted 23 lines · Joerg Roedel
Quoted 19 lines · Bandan Das
Quoted 8 lines · Paolo Bonzini
Quoted 7 lines · Dirk Müller
arch/x86/kvm/svm.c +0
-0@@ -514,7 +514,7 @@ static void skip_emulated_instruction(struct kvm_vcpu *vcpu)struct vcpu_svm *svm =to_svm (vcpu);Quoted 8 lines
arch/x86/kvm/svm.c static void skip_emulated_instruction(struct kvm_vcpu *vcpu) · line 520
Quoted 6 lines
arch/x86/kvm/svm.c +1
-1if (svm->vmcb->control.next_rip !=0 ) { -WARN_ON (!static_cpu_has (X86_FEATURE_NRIPS )); +WARN_ON_ONCE (!static_cpu_has (X86_FEATURE_NRIPS )); svm->next_rip = svm->vmcb->control.next_rip; }Bandan, what was the reason for warning here?
Quoted 2 lines
I added the warning so that we catch if the
next_ripfield is being written to (even if the feature isn't supported) by a buggy L1 hypervisor.
Quoted 7 lines
Even if the L1 hypervisor writes to the
next_ripfield in the VMCB, we would never see it in this code path, as we access the shadow VMCB in this statement.We don't even care if the L1 hypervisor writes to its
next_ripfield because we only write to this field on an emulatated VMEXIT and never read it back.
The problems is that the next_rip field could be stale. If the processor supports next_rip, then it will clear it out on the next entry. If it doesn't, an old value just sits there (no matter who wrote it) and the problem happens when skip_emulated_instruction advances the rip with an incorrect value.
Quoted 1 line
So what's the point in adding a guest-triggerable warning at all?
So, yes, maybe this doesn't have to be a guest specific warning but we still need to warn if this unsupported field is being written to.
Quoted 3 lines
Joerg
Quoted 6 lines · Bandan Das
Joerg Roedel <[email protected]> writes:
The problems is that thenext_ripfield could be stale. If the processor supportsnext_rip, then it will clear it out on the next entry. If it doesn't, an old value just sits there (no matter who wrote it) and the problem happens whenskip_emulated_instructionadvances the rip with an incorrect value.
So the right fix would be to just set the guests next_rip to 0 when we emulate vmrun, just like real hardware does, no?
Joerg
Quoted 10 lines · Joerg Roedel
Quoted 6 lines · Bandan Das
Joerg Roedel <[email protected]> writes:
The problems is that thenext_ripfield could be stale. If the processor supportsnext_rip, then it will clear it out on the next entry. If it doesn't, an old value just sits there (no matter who wrote it) and the problem happens whenskip_emulated_instructionadvances the rip with an incorrect value.So the right fix would be to just set the guests
next_ripto 0 when we emulate vmrun, just like real hardware does, no?
Agreed, resetting to 0 if nrips isn't supported seems right. It would still help having a printk_once in this case IMO :)
Quoted 7 lines
Joerg
--
To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Quoted 10 lines · Bandan Das
Quoted 8 lines · Joerg Roedel
Quoted 6 lines · Bandan Das
Joerg Roedel <[email protected]> writes:
The problems is that thenext_ripfield could be stale. If the processor supportsnext_rip, then it will clear it out on the next entry. If it doesn't, an old value just sits there (no matter who wrote it) and the problem happens whenskip_emulated_instructionadvances the rip with an incorrect value.
Quoted 5 lines
Quoted 2 lines
So the right fix would be to just set the guests
next_ripto 0 when we emulate vmrun, just like real hardware does, no?Agreed, resetting to 0 if nrips isn't supported seems right. It would still help having a
printk_oncein this case IMO :)
I meant to reset it always to 0 on vmrun, like real hardware does.
Joerg
Quoted 11 lines · Joerg Roedel
Quoted 10 lines · Bandan Das
Quoted 8 lines · Joerg Roedel
Quoted 6 lines · Bandan Das
Joerg Roedel <[email protected]> writes:
The problems is that thenext_ripfield could be stale. If the processor supportsnext_rip, then it will clear it out on the next entry. If it doesn't, an old value just sits there (no matter who wrote it) and the problem happens whenskip_emulated_instructionadvances the rip with an incorrect value.
Quoted 7 lines
Quoted 5 lines
Quoted 2 lines
So the right fix would be to just set the guests
next_ripto 0 when we emulate vmrun, just like real hardware does, no?Agreed, resetting to 0 if nrips isn't supported seems right. It would still help having a
printk_oncein this case IMO :)I meant to reset it always to 0 on vmrun, like real hardware does.
Atleast the spec don't mention this, I don't know how I got that idea :) The spec just say that it gets written to by hardware on certain intercepts and for others it gets reset to 0 on #VMEXIT.
Quoted 3 lines
Joerg
Quoted 2 lines
So the right fix would be to just set the guests
next_ripto 0 when we emulate vmrun, just like real hardware does, no?
Like this? (Note: I’m not sure what I’m doing here..). I Agree with you that the warning for this seems excessive, I’ve just removed it.
From 47db81837b6fe58aa302317bbf2a092b40af0a36 Mon Sep 17 00:00:00 2001
From: Dirk Mueller <[email protected]>
Date: Fri, 2 Oct 2015 08:35:24 +0200
Subject: [PATCH] KVM: nSVM: Check for NRIP support before passing on
control.next_rip
NRIP support itself depends on cpuid Fn8000_000A_EDX[NRIPS], so ignore it if the cpu feature is not available. Remove the guest-triggerable WARN_ON for this as it just emulates real hardware behavior.
--- arch/x86/kvm/svm.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
arch/x86/kvm/svm.c +4 -2
@@ -514,8 +514,10 @@ static void skip_emulated_instruction(struct kvm_vcpu *vcpu)struct vcpu_svm *svm =to_svm (vcpu);if (svm->vmcb->control.next_rip !=0 ) { -WARN_ON_ONCE (!static_cpu_has (X86_FEATURE_NRIPS )); - svm->next_rip = svm->vmcb->control.next_rip; +if (static_cpu_has (X86_FEATURE_NRIPS )) + svm->next_rip = svm->vmcb->control.next_rip; +else + svm->next_rip =0 ; }if (!svm->next_rip) {
Signature · 1 line
2.5.1
Thanks,
Dirk
Quoted 28 lines · Dirk Müller
Quoted 2 lines
So the right fix would be to just set the guests
next_ripto 0 when we emulate vmrun, just like real hardware does, no?Like this? (Note: I’m not sure what I’m doing here..). I Agree with you that the warning for this seems excessive, I’ve just removed it.
From
47db81837b6fe58aa302317bbf2a092b40af0a36Mon Sep 17 00:00:00 2001
From: Dirk Mueller <[email protected]>
Date: Fri, 2 Oct 2015 08:35:24 +0200
Subject: [PATCH] KVM: nSVM: Check for NRIP support before passing on
control.next_ripNRIP support itself depends on cpuid Fn8000_000A_EDX[NRIPS], so ignore it if the cpu feature is not available. Remove the guest-triggerable
WARN_ONfor this as it just emulates real hardware behavior.Signed-off-by Dirk Mueller <[email protected]>--- arch/x86/kvm/svm.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)arch/x86/kvm/svm.c +0
-0
arch/x86/kvm/svm.c static void skip_emulated_instruction(struct kvm_vcpu *vcpu) · line 520
Quoted 9 lines
arch/x86/kvm/svm.c +4
-2@@ -514,8 +514,10 @@ static void skip_emulated_instruction(struct kvm_vcpu *vcpu)struct vcpu_svm *svm =to_svm (vcpu);if (svm->vmcb->control.next_rip !=0 ) { -WARN_ON_ONCE (!static_cpu_has (X86_FEATURE_NRIPS )); - svm->next_rip = svm->vmcb->control.next_rip; +if (static_cpu_has (X86_FEATURE_NRIPS )) + svm->next_rip = svm->vmcb->control.next_rip; +else + svm->next_rip =0 ;
skip_emulated_instruction probably isn't the right place.
arch/x86/kvm/svm.c static void skip_emulated_instruction(struct kvm_vcpu *vcpu) · line 521
Quoted 1 line
arch/x86/kvm/svm.c +0
-0}
So, L1 writes this field in svm_check_intercept.
I went back to the spec and it says (15.7.1):
The next sequential instruction pointer (nRIP) is saved in the guest VMCB control area at location C8h on all #VMEXITs that are due to instruction intercepts, as defined in Section 15.9 on page 458, as well as MSR and IOIO intercepts and exceptions caused by the INT3, INTO, and BOUND instructions. For all other intercepts, nRIP is reset to zero.
So, I think a better way would be to reset the field on vmexit from L2 to L0 if NRIP isn't supported. Maybe it's enough to do this only for the intercepts mentioned above but I am not sure.
Also, please include a debug message (pr_debug_once will do). It seems unnecessary today, but in 2 years when someone is scratching his head why his nested guests won't run, he will thank you!
BTW, it seems possible to unconditionally advertise SVM_FEATURE_NRIP..
Quoted 1 line
arch/x86/kvm/svm.c +0
-0if (!svm->next_rip) {
Quoted 8 lines · Bandan Das
Quoted 8 lines
arch/x86/kvm/svm.c static void skip_emulated_instruction(struct kvm_vcpu *vcpu) · line 519
Quoted 8 lines
arch/x86/kvm/svm.c +1
-1@@ -514,7 +514,7 @@ static void skip_emulated_instruction(struct kvm_vcpu *vcpu)struct vcpu_svm *svm =to_svm (vcpu);if (svm->vmcb->control.next_rip !=0 ) { -WARN_ON (!static_cpu_has (X86_FEATURE_NRIPS )); +WARN_ON_ONCE (!static_cpu_has (X86_FEATURE_NRIPS )); svm->next_rip = svm->vmcb->control.next_rip; }
I looked again how this could possibly be triggered, and I am somewhat confused now.
So svm->vmcb->control.next_rip is only written by hardware or in svm_check_intercept(). Both cases write only to this field, if the hardware supports X86_FEATURE_NRIPS. The write in nested_svm_vmexit only targets the guests VMCB, and we don't use that one again.
So I can't see how the WARN_ON above could be triggered. Do I miss something or might this also be a miscompilation of static_cpu_has?
Joerg
Quoted 13 lines · Joerg Roedel
Quoted 8 lines · Bandan Das
Quoted 8 lines
arch/x86/kvm/svm.c static void skip_emulated_instruction(struct kvm_vcpu *vcpu) · line 519
Quoted 8 lines
arch/x86/kvm/svm.c +1
-1@@ -514,7 +514,7 @@ static void skip_emulated_instruction(struct kvm_vcpu *vcpu)struct vcpu_svm *svm =to_svm (vcpu);if (svm->vmcb->control.next_rip !=0 ) { -WARN_ON (!static_cpu_has (X86_FEATURE_NRIPS )); +WARN_ON_ONCE (!static_cpu_has (X86_FEATURE_NRIPS )); svm->next_rip = svm->vmcb->control.next_rip; }I looked again how this could possibly be triggered, and I am somewhat confused now.
Quoted 3 lines
So
svm->vmcb->control.next_ripis only written by hardware or insvm_check_intercept(). Both cases write only to this field, if the hardware supportsX86_FEATURE_NRIPS. The write innested_svm_vmexitonly
Not until commit f104765b4f81fd74d69e0eb161e89096deade2db. So, an older L1 kernel will trigger it.
Quoted 7 lines
targets the guests VMCB, and we don't use that one again.
So I can't see how the
WARN_ONabove could be triggered. Do I miss something or might this also be a miscompilation ofstatic_cpu_has?Joerg
Quoted 8 lines · Bandan Das
Quoted 4 lines · Joerg Roedel
So
svm->vmcb->control.next_ripis only written by hardware or insvm_check_intercept(). Both cases write only to this field, if the hardware supportsX86_FEATURE_NRIPS. The write innested_svm_vmexitonlyNot until commit
f104765b4f81fd74d69e0eb161e89096deade2db. So, an older L1 kernel will trigger it.
But we don't care if L1 writes something into its own next_rip, as we never read this value from its VMCB. We only copy the next_rip value we get from our shadow-vmcb to it on an emulated vmexit. So I still don't understand what triggers the reported problem or why the WARN_ON is necessary.
Joerg
PATCH 1/1 kvm: svm: Only propagate next_rip when guest supports it
Quoted 5 lines · Joerg Roedel
But we don't care if L1 writes something into its own
next_rip, as we never read this value from its VMCB. We only copy thenext_ripvalue we get from our shadow-vmcb to it on an emulated vmexit. So I still don't understand what triggers the reported problem or why theWARN_ONis necessary.
Okay, I think I have an idea now. I talked a bit with Dirk and the WARN_ON triggers in the guest, and not on the host. This makes a lot more sense.
In nested-svm we always copy the next_rip from the shadow-vmcb to the guests vmcb, even when the nrips bit in cpuid is not set for the guest. This obviously triggers the WARN_ON() in the L1 KVM (I still don't understand why the WARN_ON was introduced in the first place).
So the right fix is to only copy next_rip to the guests vmcb when its cpuid indicates that next_rip is supported there, like in this patch:
Quoted 1 line
From
019afc60507618b8e44e0c67d5ea2d850d88c9ddMon Sep 17 00:00:00 2001
From: Joerg Roedel <[email protected]>
Date: Wed, 7 Oct 2015 13:38:19 +0200
Subject: [PATCH] kvm: svm: Only propagate next_rip when guest supports it
Currently we always write the next_rip of the shadow vmcb to the guests vmcb when we emulate a vmexit. This could confuse the guest when its cpuid indicated no support for the next_rip feature.
Fix this by only propagating next_rip if the guest actually supports it.
--- arch/x86/kvm/cpuid.h | 21 +++++++++++++++++++++ arch/x86/kvm/svm.c | 7 ++++++- 2 files changed, 27 insertions(+), 1 deletion(-)
arch/x86/kvm/cpuid.h +21 -0
@@ -133,4 +133,25 @@ static inline bool guest_cpuid_has_mpx(struct kvm_vcpu *vcpu) best =kvm_find_cpuid_entry (vcpu,7 ,0 ); return best && (best->ebx & bit(X86_FEATURE_MPX)); } + +/* +* NRIPS is provided through cpuidfn 0x8000000a.edx bit 3 +*/ +#define BIT_NRIPS 3 + +static inline bool guest_cpuid_has_nrips (struct kvm_vcpu *vcpu) +{ +struct kvm_cpuid_entry2 *best; + + best =kvm_find_cpuid_entry (vcpu,0x8000000a ,0 ); + +/* +* NRIPS is a scattered cpuid feature, so we can't use +* X86_FEATURE_NRIPS here (X86_FEATURE_NRIPS would be bit +* position 8, not 3). +*/ +return best && (best->edx &bit (BIT_NRIPS )); +} +#undef BIT_NRIPS +#endif
arch/x86/kvm/svm.c +6 -1
@@ -2459,7 +2459,9 @@ static int nested_svm_vmexit(struct vcpu_svm *svm) nested_vmcb->control.exit_info_2 = vmcb->control.exit_info_2; nested_vmcb->control.exit_int_info = vmcb->control.exit_int_info; nested_vmcb->control.exit_int_info_err = vmcb->control.exit_int_info_err; - nested_vmcb->control.next_rip = vmcb->control.next_rip; + +if (guest_cpuid_has_nrips (vcpu)) + nested_vmcb->control.next_rip = vmcb->control.next_rip;/* * If we emulate a VMRUN/#VMEXIT in the same host #vmexit cycle we have
@@ -2714,6 +2716,9 @@ static bool nested_svm_vmrun(struct vcpu_svm *svm) svm->vmcb->control.event_inj = nested_vmcb->control.event_inj; svm->vmcb->control.event_inj_err = nested_vmcb->control.event_inj_err; +/* Clear next_rip, as real hardware would do */ + nested_vmcb->control.next_rip =0 ; +nested_svm_unmap (page);/* Enter Guest-Mode */
Signature · 1 line
1.8.4.5
kbuild test robot
build botRe: [PATCH] kvm: svm: Only propagate next_rip when guest supports it
config: i386-randconfig-x009-201540 (attached as .config) reproduce:
Hi Joerg,
[auto build test ERROR on v4.3-rc4 -- if it's inappropriate base, please ignore]
config: i386-randconfig-x009-201540 (attached as .config) reproduce:
# save the attached .config to linux build tree
make ARCH=i386 All errors (new ones prefixed by >>):
arch/x86/kvm/svm.c: In function 'nested_svm_vmexit':
>> arch/x86/kvm/svm.c:2369:28: error: 'vcpu' undeclared (first use in this function)
if (guest_cpuid_has_nrips(vcpu))
^ arch/x86/kvm/svm.c:2369:28: note: each undeclared identifier is reported only once for each function it appears in
vim +/vcpu +2369 arch/x86/kvm/svm.c
2363 nested_vmcb->control.exit_code_hi = vmcb->control.exit_code_hi; 2364 nested_vmcb->control.exit_info_1 = vmcb->control.exit_info_1; 2365 nested_vmcb->control.exit_info_2 = vmcb->control.exit_info_2; 2366 nested_vmcb->control.exit_int_info = vmcb->control.exit_int_info; 2367 nested_vmcb->control.exit_int_info_err = vmcb->control.exit_int_info_err; 2368 > 2369 if (guest_cpuid_has_nrips(vcpu))
2370 nested_vmcb->control.next_rip = vmcb->control.next_rip;
2371
2372 /*
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
Re: [PATCH] kvm: svm: Only propagate next_rip when guest supports it
In reply to Joerg RoedelQuoted 7 lines · Joerg Roedel
Quoted 5 lines · Joerg Roedel
But we don't care if L1 writes something into its own
next_rip, as we never read this value from its VMCB. We only copy thenext_ripvalue we get from our shadow-vmcb to it on an emulated vmexit. So I still don't understand what triggers the reported problem or why theWARN_ONis necessary.
Quoted 8 lines
Okay, I think I have an idea now. I talked a bit with Dirk and the
WARN_ONtriggers in the guest, and not on the host. This makes a lot more sense.In nested-svm we always copy the
next_ripfrom the shadow-vmcb to the guests vmcb, even when the nrips bit in cpuid is not set for the guest. This obviously triggers theWARN_ON()in the L1 KVM (I still don't understand why theWARN_ONwas introduced in the first place).
Ok, understood now. The warn_on would trigger in L1 only if it has decided to disable nrips for some reason as was the case here. So, my reasoning behind putting the warning was incorrect.
Quoted 2 lines
So the right fix is to only copy
next_ripto the guests vmcb when its cpuid indicates thatnext_ripis supported there, like in this patch:
Yep, agreed.
Quoted 65 lines
From
019afc60507618b8e44e0c67d5ea2d850d88c9ddMon Sep 17 00:00:00 2001
From: Joerg Roedel <[email protected]>
Date: Wed, 7 Oct 2015 13:38:19 +0200
Subject: [PATCH] kvm: svm: Only propagatenext_ripwhen guest supports itCurrently we always write the
next_ripof the shadow vmcb to the guests vmcb when we emulate a vmexit. This could confuse the guest when its cpuid indicated no support for thenext_ripfeature.Fix this by only propagating
next_ripif the guest actually supports it.Signed-off-by Joerg Roedel <[email protected]>--- arch/x86/kvm/cpuid.h | 21 +++++++++++++++++++++ arch/x86/kvm/svm.c | 7 ++++++- 2 files changed, 27 insertions(+), 1 deletion(-)arch/x86/kvm/cpuid.h +21
-0@@ -133,4 +133,25 @@ static inline bool guest_cpuid_has_mpx(struct kvm_vcpu *vcpu) best =kvm_find_cpuid_entry (vcpu,7 ,0 ); return best && (best->ebx & bit(X86_FEATURE_MPX)); } + +/* +* NRIPS is provided through cpuidfn 0x8000000a.edx bit 3 +*/ +#define BIT_NRIPS 3 + +static inline bool guest_cpuid_has_nrips (struct kvm_vcpu *vcpu) +{ +struct kvm_cpuid_entry2 *best; + + best =kvm_find_cpuid_entry (vcpu,0x8000000a ,0 ); + +/* +* NRIPS is a scattered cpuid feature, so we can't use +* X86_FEATURE_NRIPS here (X86_FEATURE_NRIPS would be bit +* position 8, not 3). +*/ +return best && (best->edx &bit (BIT_NRIPS )); +} +#undef BIT_NRIPS +#endif arch/x86/kvm/svm.c +3
-1@@ -2459,7 +2459,9 @@ static int nested_svm_vmexit(struct vcpu_svm *svm) nested_vmcb->control.exit_info_2 = vmcb->control.exit_info_2; nested_vmcb->control.exit_int_info = vmcb->control.exit_int_info; nested_vmcb->control.exit_int_info_err = vmcb->control.exit_int_info_err; - nested_vmcb->control.next_rip = vmcb->control.next_rip; + +if (guest_cpuid_has_nrips (vcpu)) + nested_vmcb->control.next_rip = vmcb->control.next_rip;/* * If we emulate a VMRUN/#VMEXIT in the same host #vmexit cycle we have
arch/x86/kvm/svm.c static bool nested_svm_vmrun(struct vcpu_svm *svm) · line 2721
Quoted 6 lines
arch/x86/kvm/svm.c +3
-0@@ -2714,6 +2716,9 @@ static bool nested_svm_vmrun(struct vcpu_svm *svm) svm->vmcb->control.event_inj = nested_vmcb->control.event_inj; svm->vmcb->control.event_inj_err = nested_vmcb->control.event_inj_err; +/* Clear next_rip, as real hardware would do */ + nested_vmcb->control.next_rip =0 ; +
Why do we need this ? And are you sure this is what real hardware does ? I couldn't find anything in the spec.
Quoted 3 lines
arch/x86/kvm/svm.c +0
-0nested_svm_unmap (page);/* Enter Guest-Mode */
Re: [PATCH] kvm: svm: Only propagate next_rip when guest supports it
Quoted 3 lines · Bandan Das
Ok, understood now. The
warn_onwould trigger in L1 only if it has decided to disable nrips for some reason as was the case here. So, my reasoning behind putting the warning was incorrect.
Okay, so I think the warning can be removed.
Quoted 3 lines
arch/x86/kvm/svm.c static int nested_svm_vmexit(struct vcpu_svm *svm) · line 2464
Quoted 3 lines
arch/x86/kvm/svm.c +3
-0+ +if (guest_cpuid_has_nrips (vcpu)) + nested_vmcb->control.next_rip = vmcb->control.next_rip;
Note that there is a bug here, instead of vcpu it must be &svm->vcpu. Somehow I missed to at least compile-test this.
Dirk is currently testing whether this (fixed) patch solves the problem in his setup.
Quoted 7 lines
Quoted 7 lines
arch/x86/kvm/svm.c +0
-0/* * If we emulate a VMRUN/#VMEXIT in the same host #vmexit cycle we have @@ -2714,6 +2716,9 @@ static bool nested_svm_vmrun(struct vcpu_svm *svm) svm->vmcb->control.event_inj = nested_vmcb->control.event_inj; svm->vmcb->control.event_inj_err = nested_vmcb->control.event_inj_err;
Quoted 6 lines
arch/x86/kvm/svm.c static bool nested_svm_vmrun(struct vcpu_svm *svm) · line 2721
Quoted 3 lines
arch/x86/kvm/svm.c +3
-0+/* Clear next_rip, as real hardware would do */ + nested_vmcb->control.next_rip =0 ; +Why do we need this ? And are you sure this is what real hardware does ? I couldn't find anything in the spec.
Yeah, probably right. Since we only write guests next_rip when the guest supports it via cpuid, there is probably no point in resetting it at vmrun emulation.
Joerg
Dirk Müller
Tested-byRe: [PATCH] kvm: svm: Only propagate next_rip when guest supports it
Quoted 2 lines · Joerg Roedel
Dirk is currently testing whether this (fixed) patch solves the problem in his setup.
Works fine here. Thanks!
Greetings,
Dirk
Quoted 7 lines · Joerg Roedel
Quoted 6 lines · Bandan Das
Quoted 4 lines · Joerg Roedel
So
svm->vmcb->control.next_ripis only written by hardware or insvm_check_intercept(). Both cases write only to this field, if the hardware supportsX86_FEATURE_NRIPS. The write innested_svm_vmexitonly
Quoted 8 lines
Quoted 2 lines
Not until commit
f104765b4f81fd74d69e0eb161e89096deade2db. So, an older L1 kernel will trigger it.But we don't care if L1 writes something into its own
next_rip, as we never read this value from its VMCB. We only copy thenext_ripvalue we get from our shadow-vmcb to it on an emulated vmexit. So I still don't understand what triggers the reported problem or why theWARN_ONis necessary.
Ok, looks like I am making some incorrect "vmx" assumptions here. What happens when we exit from L2 to L0, arent' we looking at the VMCB L1 is using to run L2 ? Wouldn't that trigger the warning if the host processor does not support nrips and the field is set ?
Quoted 2 lines
Joerg
Quoted 4 lines · Bandan Das
Ok, looks like I am making some incorrect "vmx" assumptions here. What happens when we exit from L2 to L0, arent' we looking at the VMCB L1 is using to run L2 ? Wouldn't that trigger the warning if the host processor does not support nrips and the field is set ?
No, because the L1 hypervisor can't write to the shadow-vmcb, and this is the only one where we _read_ next_rip from.
Joerg