Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

KVM: nVMX: Allow the caller to provide instruction length on nested VM-Exit

Rework the nested VM-Exit helper to take the instruction length as a
parameter, and convert nested_vmx_vmexit() into a "default" wrapper that
grabs the length from vmcs02 as appropriate. This will allow KVM to set
the correct instruction length when synthesizing a nested VM-Exit when
emulating an instruction that L1 wants to intercept.

No functional change intended, as the path to prepare_vmcs12()'s reading
of vmcs02.VM_EXIT_INSTRUCTION_LEN is gated on the same set of conditions
as the VMREAD in the new nested_vmx_vmexit().

Link: https://lore.kernel.org/r/20250201015518.689704-10-seanjc@google.com
Signed-off-by: Sean Christopherson <seanjc@google.com>

+27 -7
+7 -5
arch/x86/kvm/vmx/nested.c
··· 4618 4618 */ 4619 4619 static void prepare_vmcs12(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12, 4620 4620 u32 vm_exit_reason, u32 exit_intr_info, 4621 - unsigned long exit_qualification) 4621 + unsigned long exit_qualification, u32 exit_insn_len) 4622 4622 { 4623 4623 /* update exit information fields: */ 4624 4624 vmcs12->vm_exit_reason = vm_exit_reason; ··· 4646 4646 vm_exit_reason, exit_intr_info); 4647 4647 4648 4648 vmcs12->vm_exit_intr_info = exit_intr_info; 4649 - vmcs12->vm_exit_instruction_len = vmcs_read32(VM_EXIT_INSTRUCTION_LEN); 4649 + vmcs12->vm_exit_instruction_len = exit_insn_len; 4650 4650 vmcs12->vmx_instruction_info = vmcs_read32(VMX_INSTRUCTION_INFO); 4651 4651 4652 4652 /* ··· 4930 4930 * and modify vmcs12 to make it see what it would expect to see there if 4931 4931 * L2 was its real guest. Must only be called when in L2 (is_guest_mode()) 4932 4932 */ 4933 - void nested_vmx_vmexit(struct kvm_vcpu *vcpu, u32 vm_exit_reason, 4934 - u32 exit_intr_info, unsigned long exit_qualification) 4933 + void __nested_vmx_vmexit(struct kvm_vcpu *vcpu, u32 vm_exit_reason, 4934 + u32 exit_intr_info, unsigned long exit_qualification, 4935 + u32 exit_insn_len) 4935 4936 { 4936 4937 struct vcpu_vmx *vmx = to_vmx(vcpu); 4937 4938 struct vmcs12 *vmcs12 = get_vmcs12(vcpu); ··· 4982 4981 4983 4982 if (vm_exit_reason != -1) 4984 4983 prepare_vmcs12(vcpu, vmcs12, vm_exit_reason, 4985 - exit_intr_info, exit_qualification); 4984 + exit_intr_info, exit_qualification, 4985 + exit_insn_len); 4986 4986 4987 4987 /* 4988 4988 * Must happen outside of sync_vmcs02_to_vmcs12() as it will
+20 -2
arch/x86/kvm/vmx/nested.h
··· 26 26 enum nvmx_vmentry_status nested_vmx_enter_non_root_mode(struct kvm_vcpu *vcpu, 27 27 bool from_vmentry); 28 28 bool nested_vmx_reflect_vmexit(struct kvm_vcpu *vcpu); 29 - void nested_vmx_vmexit(struct kvm_vcpu *vcpu, u32 vm_exit_reason, 30 - u32 exit_intr_info, unsigned long exit_qualification); 29 + void __nested_vmx_vmexit(struct kvm_vcpu *vcpu, u32 vm_exit_reason, 30 + u32 exit_intr_info, unsigned long exit_qualification, 31 + u32 exit_insn_len); 32 + 33 + static inline void nested_vmx_vmexit(struct kvm_vcpu *vcpu, u32 vm_exit_reason, 34 + u32 exit_intr_info, 35 + unsigned long exit_qualification) 36 + { 37 + u32 exit_insn_len; 38 + 39 + if (to_vmx(vcpu)->fail || vm_exit_reason == -1 || 40 + (vm_exit_reason & VMX_EXIT_REASONS_FAILED_VMENTRY)) 41 + exit_insn_len = 0; 42 + else 43 + exit_insn_len = vmcs_read32(VM_EXIT_INSTRUCTION_LEN); 44 + 45 + __nested_vmx_vmexit(vcpu, vm_exit_reason, exit_intr_info, 46 + exit_qualification, exit_insn_len); 47 + } 48 + 31 49 void nested_sync_vmcs12_to_shadow(struct kvm_vcpu *vcpu); 32 50 int vmx_set_vmx_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data); 33 51 int vmx_get_vmx_msr(struct nested_vmx_msrs *msrs, u32 msr_index, u64 *pdata);