[PATCH 2/3] KVM: nVMX: Decouple INVVPID operand checks from flushing of vpid02

From: Yosry Ahmed

Date: Tue Jun 16 2026 - 17:48:24 EST


From: Sean Christopherson <seanjc@xxxxxxxxxx>

Separate the INVVPID operand checks from the actual flushing of vpid02 so
the flushing can be adjusted to do the right thing when vmcs12 was last
loaded on a different pCPU, without having to duplicate the logic across
multiple case-statements.

Opportunistically let the VM-Fail paths poke out past 80 chars.

No functional change intended.

Cc: stable@xxxxxxxxxxxxxxx
Signed-off-by: Sean Christopherson <seanjc@xxxxxxxxxx>
Signed-off-by: Yosry Ahmed <yosry@xxxxxxxxxx>
---
arch/x86/kvm/vmx/nested.c | 43 ++++++++++++---------------------------
1 file changed, 13 insertions(+), 30 deletions(-)

diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c
index a49115d9a5a54..596dec7ba2b78 100644
--- a/arch/x86/kvm/vmx/nested.c
+++ b/arch/x86/kvm/vmx/nested.c
@@ -6084,7 +6084,6 @@ static int handle_invvpid(struct kvm_vcpu *vcpu)
u64 vpid;
u64 gla;
} operand;
- u16 vpid02;
int r, gpr_index;

if (!(vmx->nested.msrs.secondary_ctls_high &
@@ -6119,8 +6118,15 @@ static int handle_invvpid(struct kvm_vcpu *vcpu)
return kvm_handle_memory_failure(vcpu, r, &e);

if (operand.vpid >> 16)
- return nested_vmx_fail(vcpu,
- VMXERR_INVALID_OPERAND_TO_INVEPT_INVVPID);
+ return nested_vmx_fail(vcpu, VMXERR_INVALID_OPERAND_TO_INVEPT_INVVPID);
+
+ if (type != VMX_VPID_EXTENT_ALL_CONTEXT && !operand.vpid)
+ return nested_vmx_fail(vcpu, VMXERR_INVALID_OPERAND_TO_INVEPT_INVVPID);
+
+ /* LAM doesn't apply to addresses that are inputs to TLB invalidation. */
+ if (type == VMX_VPID_EXTENT_INDIVIDUAL_ADDR &&
+ is_noncanonical_invlpg_address(operand.gla, vcpu))
+ return nested_vmx_fail(vcpu, VMXERR_INVALID_OPERAND_TO_INVEPT_INVVPID);

/*
* Always flush the effective vpid02, i.e. never flush the current VPID
@@ -6128,33 +6134,10 @@ static int handle_invvpid(struct kvm_vcpu *vcpu)
* VMCS, and so whether or not the current vmcs12 has VPID enabled is
* irrelevant (and there may not be a loaded vmcs12).
*/
- vpid02 = nested_get_vpid02(vcpu);
- switch (type) {
- case VMX_VPID_EXTENT_INDIVIDUAL_ADDR:
- /*
- * LAM doesn't apply to addresses that are inputs to TLB
- * invalidation.
- */
- if (!operand.vpid ||
- is_noncanonical_invlpg_address(operand.gla, vcpu))
- return nested_vmx_fail(vcpu,
- VMXERR_INVALID_OPERAND_TO_INVEPT_INVVPID);
- vpid_sync_vcpu_addr(vpid02, operand.gla);
- break;
- case VMX_VPID_EXTENT_SINGLE_CONTEXT:
- case VMX_VPID_EXTENT_SINGLE_NON_GLOBAL:
- if (!operand.vpid)
- return nested_vmx_fail(vcpu,
- VMXERR_INVALID_OPERAND_TO_INVEPT_INVVPID);
- vpid_sync_context(vpid02);
- break;
- case VMX_VPID_EXTENT_ALL_CONTEXT:
- vpid_sync_context(vpid02);
- break;
- default:
- WARN_ON_ONCE(1);
- return kvm_skip_emulated_instruction(vcpu);
- }
+ if (type == VMX_VPID_EXTENT_INDIVIDUAL_ADDR)
+ vpid_sync_vcpu_addr(nested_get_vpid02(vcpu), operand.gla);
+ else
+ vpid_sync_context(nested_get_vpid02(vcpu));

/*
* Sync the shadow page tables if EPT is disabled, L1 is invalidating
--
2.54.0.1136.gdb2ca164c4-goog