diff mbox series

[2/3] KVM: VMX: Remove a unnecessary cpu_has_vmx_desc() check in vmx_set_cr4()

Message ID 20230310125718.1442088-3-robert.hu@intel.com (mailing list archive)
State New, archived
Headers show
Series [1/3] KVM: VMX: Rename vmx_umip_emulated() to cpu_has_vmx_desc() | expand

Commit Message

Robert Hoo March 10, 2023, 12:57 p.m. UTC
Remove the unnecessary cpu_has_vmx_desc() check for emulating UMIP.

When it arrives vmx_set_cr4(), it has passed kvm_is_valid_cr4(), meaning
vmx_set_cpu_caps() has already assign X86_FEATURE_UMIP with this vcpu,
because of either host CPU has the capability or it can be emulated,

vmx_set_cpu_caps():
	if (cpu_has_vmx_desc())
		kvm_cpu_cap_set(X86_FEATURE_UMIP);

that is to say, if !boot_cpu_has(X86_FEATURE_UMIP) here,
cpu_has_vmx_desc() must be true, it should be a meaningless check here.

Signed-off-by: Robert Hoo <robert.hu@intel.com>
---
 arch/x86/kvm/vmx/vmx.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

Comments

Sean Christopherson March 10, 2023, 4:12 p.m. UTC | #1
On Fri, Mar 10, 2023, Robert Hoo wrote:
> Remove the unnecessary cpu_has_vmx_desc() check for emulating UMIP.

It's not unnecessary.  See commit 64f7a11586ab ("KVM: vmx: update sec exec controls
for UMIP iff emulating UMIP").  Dropping the check will cause KVM to execute

	secondary_exec_controls_clearbit(vmx, SECONDARY_EXEC_DESC);

on CPUs that don't have SECONDARY_VM_EXEC_CONTROL.
Robert Hoo March 11, 2023, 2:36 a.m. UTC | #2
Sean Christopherson <seanjc@google.com> 于2023年3月11日周六 00:12写道:
>
> On Fri, Mar 10, 2023, Robert Hoo wrote:
> > Remove the unnecessary cpu_has_vmx_desc() check for emulating UMIP.
>
> It's not unnecessary.  See commit 64f7a11586ab ("KVM: vmx: update sec exec controls
> for UMIP iff emulating UMIP").  Dropping the check will cause KVM to execute
>
>         secondary_exec_controls_clearbit(vmx, SECONDARY_EXEC_DESC);
>
> on CPUs that don't have SECONDARY_VM_EXEC_CONTROL.

Sorry I don't follow you.
My point is that, given it has passed kvm_is_valid_cr4() (in
kvm_set_cr4()), we can assert
boot_cpu_has(X86_FEATURE_UMIP)  and vmx_umip_emulated() must be at least one
true. Therefore when !boot_cpu_has(X86_FEATURE_UMIP),
vmx_umip_emulated() must be
true, therefore checking it is redundant.

Do you mean other call path other than kvm_set_cr4() --> vmx_set_cr4()? i.e.
vmx_set_cr0() --> vmx_set_cr4()?
nested_... --> vmx_set_cr4()?
Emm, they seem don't go through kvm_is_valid_cr4() firstly.
Sean Christopherson March 15, 2023, 4:35 p.m. UTC | #3
On Sat, Mar 11, 2023, Robert Hoo wrote:
> Sean Christopherson <seanjc@google.com> 于2023年3月11日周六 00:12写道:
> >
> > On Fri, Mar 10, 2023, Robert Hoo wrote:
> > > Remove the unnecessary cpu_has_vmx_desc() check for emulating UMIP.
> >
> > It's not unnecessary.  See commit 64f7a11586ab ("KVM: vmx: update sec exec controls
> > for UMIP iff emulating UMIP").  Dropping the check will cause KVM to execute
> >
> >         secondary_exec_controls_clearbit(vmx, SECONDARY_EXEC_DESC);
> >
> > on CPUs that don't have SECONDARY_VM_EXEC_CONTROL.
> 
> Sorry I don't follow you.
> My point is that, given it has passed kvm_is_valid_cr4() (in kvm_set_cr4()),
> we can assert boot_cpu_has(X86_FEATURE_UMIP)  and vmx_umip_emulated() must be
> at least one true.

This assertion is wrong for the case where guest.CR4.UMIP=0.  The below code is
not guarded with a check on guest.CR4.UMIP.  If the vmx_umip_emulated() check goes
away and guest.CR4.UMIP=0, KVM will attempt to write secondary controls.

Technically, now that controls_shadow exists, KVM won't actually do a VMWRITE,
but I most definitely don't want to rely on controls_shadow for functional
correctness.  And controls_shadow aside, the "vmx_umip_emulated()" effectively
serves as documentation for why KVM is mucking with UMIP when it's obviously not
supported in hardware.

	if (!boot_cpu_has(X86_FEATURE_UMIP) && vmx_umip_emulated()) {
		if (cr4 & X86_CR4_UMIP) {
			secondary_exec_controls_setbit(vmx, SECONDARY_EXEC_DESC);
			hw_cr4 &= ~X86_CR4_UMIP;
		} else if (!is_guest_mode(vcpu) ||
			!nested_cpu_has2(get_vmcs12(vcpu), SECONDARY_EXEC_DESC)) {
			secondary_exec_controls_clearbit(vmx, SECONDARY_EXEC_DESC);
		}
	}
Robert Hoo March 31, 2023, 9:48 a.m. UTC | #4
Sean Christopherson <seanjc@google.com> 于2023年3月16日周四 00:36写道:
> > Sorry I don't follow you.
> > My point is that, given it has passed kvm_is_valid_cr4() (in kvm_set_cr4()),
> > we can assert boot_cpu_has(X86_FEATURE_UMIP)  and vmx_umip_emulated() must be
> > at least one true.
>
> This assertion is wrong for the case where guest.CR4.UMIP=0.  The below code is
> not guarded with a check on guest.CR4.UMIP.  If the vmx_umip_emulated() check goes
> away and guest.CR4.UMIP=0, KVM will attempt to write secondary controls.
>

Sorry still don't follow you. Do you mean in nested case? the "guest"
above is L1?

> Technically, now that controls_shadow exists, KVM won't actually do a VMWRITE,
> but I most definitely don't want to rely on controls_shadow for functional
> correctness.  And controls_shadow aside, the "vmx_umip_emulated()" effectively
> serves as documentation for why KVM is mucking with UMIP when it's obviously not
> supported in hardware.
>
>         if (!boot_cpu_has(X86_FEATURE_UMIP) && vmx_umip_emulated()) {
>                 if (cr4 & X86_CR4_UMIP) {
>                         secondary_exec_controls_setbit(vmx, SECONDARY_EXEC_DESC);
>                         hw_cr4 &= ~X86_CR4_UMIP;
>                 } else if (!is_guest_mode(vcpu) ||
>                         !nested_cpu_has2(get_vmcs12(vcpu), SECONDARY_EXEC_DESC)) {
>                         secondary_exec_controls_clearbit(vmx, SECONDARY_EXEC_DESC);
>                 }
>         }
Sean Christopherson April 10, 2023, 6:35 p.m. UTC | #5
On Fri, Mar 31, 2023, Robert Hoo wrote:
> Sean Christopherson <seanjc@google.com> 于2023年3月16日周四 00:36写道:
> > > Sorry I don't follow you.
> > > My point is that, given it has passed kvm_is_valid_cr4() (in kvm_set_cr4()),
> > > we can assert boot_cpu_has(X86_FEATURE_UMIP)  and vmx_umip_emulated() must be
> > > at least one true.
> >
> > This assertion is wrong for the case where guest.CR4.UMIP=0.  The below code is
> > not guarded with a check on guest.CR4.UMIP.  If the vmx_umip_emulated() check goes
> > away and guest.CR4.UMIP=0, KVM will attempt to write secondary controls.
> >
> 
> Sorry still don't follow you. Do you mean in nested case? the "guest"
> above is L1?

Please take the time to walk through the code with possible inputs/scenarios before
asking these types of questions, e.g. if necessary use a whiteboard, pen+paper, etc.
I'm happy to explain subtleties and add answer specific questions, but as evidenced
by my delayed response, I simply do not have the bandwidth to answer questions where
the answer is literally a trace-through of a small, fully contained section of code.

	if (!boot_cpu_has(X86_FEATURE_UMIP)) {    <= evaluates true when UMIP is NOT supported
		if (cr4 & X86_CR4_UMIP) {         <= evaluates false when guest.CR4.UMIP == 0
			secondary_exec_controls_setbit(vmx, SECONDARY_EXEC_DESC);
			hw_cr4 &= ~X86_CR4_UMIP;
		} else if (!is_guest_mode(vcpu) || <= evalutes true when L2 is NOT active
			!nested_cpu_has2(get_vmcs12(vcpu), SECONDARY_EXEC_DESC)) {
			secondary_exec_controls_clearbit(vmx, SECONDARY_EXEC_DESC); <= KVM "blindly" writes secondary controls
		}
	}
Robert Hoo April 11, 2023, 5:04 a.m. UTC | #6
On 2023/4/11 2:35, Sean Christopherson wrote:
> On Fri, Mar 31, 2023, Robert Hoo wrote:
>> Sean Christopherson <seanjc@google.com> 于2023年3月16日周四 00:36写道:
>>>> Sorry I don't follow you.
>>>> My point is that, given it has passed kvm_is_valid_cr4() (in kvm_set_cr4()),
>>>> we can assert boot_cpu_has(X86_FEATURE_UMIP)  and vmx_umip_emulated() must be
>>>> at least one true.
>>>
>>> This assertion is wrong for the case where guest.CR4.UMIP=0.  The below code is
>>> not guarded with a check on guest.CR4.UMIP.  If the vmx_umip_emulated() check goes
>>> away and guest.CR4.UMIP=0, KVM will attempt to write secondary controls.
>>>
>>
>> Sorry still don't follow you. Do you mean in nested case? the "guest"
>> above is L1?
> 
> Please take the time to walk through the code with possible inputs/scenarios before
> asking these types of questions, e.g. if necessary use a whiteboard, pen+paper, etc.
> I'm happy to explain subtleties and add answer specific questions, but as evidenced
> by my delayed response, I simply do not have the bandwidth to answer questions where
> the answer is literally a trace-through of a small, fully contained section of code.

Sure, fully understand your busyness, thanks for still providing detailed 
explanation. Sorry for the annoyance.

Given that you've merged host UMIP cap check into vmx_umip_emulated(), I 
might have not tangled in this point.

We can close this thread of patch set now.
> 
> 	if (!boot_cpu_has(X86_FEATURE_UMIP)) {    <= evaluates true when UMIP is NOT supported
> 		if (cr4 & X86_CR4_UMIP) {         <= evaluates false when guest.CR4.UMIP == 0
> 			secondary_exec_controls_setbit(vmx, SECONDARY_EXEC_DESC);
> 			hw_cr4 &= ~X86_CR4_UMIP;
> 		} else if (!is_guest_mode(vcpu) || <= evalutes true when L2 is NOT active
> 			!nested_cpu_has2(get_vmcs12(vcpu), SECONDARY_EXEC_DESC)) {
> 			secondary_exec_controls_clearbit(vmx, SECONDARY_EXEC_DESC); <= KVM "blindly" writes secondary controls
> 		}
> 	}
diff mbox series

Patch

diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
index 96f7c9f37afd..bec5792acffe 100644
--- a/arch/x86/kvm/vmx/vmx.c
+++ b/arch/x86/kvm/vmx/vmx.c
@@ -3437,7 +3437,7 @@  void vmx_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)
 	 * guest been exposed with UMIP feature, i.e. either host has cap
 	 * of UMIP or vmx_set_cpu_caps() set it because of cpu_has_vmx_desc()
 	 */
-	if (!boot_cpu_has(X86_FEATURE_UMIP) && cpu_has_vmx_desc()) {
+	if (!boot_cpu_has(X86_FEATURE_UMIP)) {
 		if (cr4 & X86_CR4_UMIP) {
 			secondary_exec_controls_setbit(vmx, SECONDARY_EXEC_DESC);
 			hw_cr4 &= ~X86_CR4_UMIP;