[PATCH 22/24] KVM: SEV: Handle unknown #VMGEXIT reasons in sev_handle_vmgexit()
From: Paolo Bonzini
Date: Fri May 29 2026 - 14:48:00 EST
From: Sean Christopherson <seanjc@xxxxxxxxxx>
Handle unknown #VMGEXIT reasons in sev_handle_vmgexit(), not in
sev_es_validate_vmgexit(). This makes it _much_ more obvious that KVM
simply funnels "legacy" exits to the standard SVM interception handlers,
and is the final preparatory change needed to reduce the scope of
sev_es_validate_vmgexit().
No functional change intended.
Reviewed-by: Tom Lendacky <thomas.lendacky@xxxxxxx>
Signed-off-by: Sean Christopherson <seanjc@xxxxxxxxxx>
Message-ID: <20260501202250.2115252-23-seanjc@xxxxxxxxxx>
Signed-off-by: Paolo Bonzini <pbonzini@xxxxxxxxxx>
---
arch/x86/kvm/svm/sev.c | 74 +++++++++++++++++++-----------------------
1 file changed, 33 insertions(+), 41 deletions(-)
diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c
index 84421d9a116b..864d6aea544b 100644
--- a/arch/x86/kvm/svm/sev.c
+++ b/arch/x86/kvm/svm/sev.c
@@ -3414,9 +3414,6 @@ static int sev_es_validate_vmgexit(struct vcpu_svm *svm)
{
struct vmcb_control_area *control = &svm->vmcb->control;
struct kvm_vcpu *vcpu = &svm->vcpu;
- u64 reason;
-
- reason = GHCB_ERR_MISSING_INPUT;
if (!kvm_ghcb_sw_exit_code_is_valid(svm) ||
!kvm_ghcb_sw_exit_info_1_is_valid(svm) ||
@@ -3424,14 +3421,10 @@ static int sev_es_validate_vmgexit(struct vcpu_svm *svm)
goto vmgexit_err;
switch (control->exit_code) {
- case SVM_EXIT_READ_DR7:
- break;
case SVM_EXIT_WRITE_DR7:
if (!kvm_ghcb_rax_is_valid(svm))
goto vmgexit_err;
break;
- case SVM_EXIT_RDTSC:
- break;
case SVM_EXIT_RDPMC:
if (!kvm_ghcb_rcx_is_valid(svm))
goto vmgexit_err;
@@ -3444,8 +3437,6 @@ static int sev_es_validate_vmgexit(struct vcpu_svm *svm)
if (!kvm_ghcb_xcr0_is_valid(svm))
goto vmgexit_err;
break;
- case SVM_EXIT_INVD:
- break;
case SVM_EXIT_IOIO:
if (control->exit_info_1 & SVM_IOIO_STR_MASK) {
if (!kvm_ghcb_sw_scratch_is_valid(svm))
@@ -3470,10 +3461,6 @@ static int sev_es_validate_vmgexit(struct vcpu_svm *svm)
!kvm_ghcb_cpl_is_valid(svm))
goto vmgexit_err;
break;
- case SVM_EXIT_RDTSCP:
- break;
- case SVM_EXIT_WBINVD:
- break;
case SVM_EXIT_MONITOR:
if (!kvm_ghcb_rax_is_valid(svm) ||
!kvm_ghcb_rcx_is_valid(svm) ||
@@ -3495,23 +3482,12 @@ static int sev_es_validate_vmgexit(struct vcpu_svm *svm)
if (!kvm_ghcb_rax_is_valid(svm))
goto vmgexit_err;
break;
- case SVM_VMGEXIT_NMI_COMPLETE:
- case SVM_VMGEXIT_AP_HLT_LOOP:
- case SVM_VMGEXIT_AP_JUMP_TABLE:
- case SVM_VMGEXIT_UNSUPPORTED_EVENT:
- case SVM_VMGEXIT_HV_FEATURES:
- case SVM_VMGEXIT_TERM_REQUEST:
- break;
case SVM_VMGEXIT_PSC:
if (!kvm_ghcb_sw_scratch_is_valid(svm))
goto vmgexit_err;
break;
- case SVM_VMGEXIT_GUEST_REQUEST:
- case SVM_VMGEXIT_EXT_GUEST_REQUEST:
- break;
default:
- reason = GHCB_ERR_INVALID_EVENT;
- goto vmgexit_err;
+ break;
}
return 0;
@@ -3521,16 +3497,10 @@ static int sev_es_validate_vmgexit(struct vcpu_svm *svm)
* Print the exit code even though it may not be marked valid as it
* could help with debugging.
*/
- if (reason == GHCB_ERR_INVALID_EVENT) {
- vcpu_unimpl(vcpu, "vmgexit: exit code %#llx is not valid\n",
- control->exit_code);
- } else {
- vcpu_unimpl(vcpu, "vmgexit: exit code %#llx input is not valid\n",
- control->exit_code);
- dump_ghcb(svm);
- }
-
- svm_vmgexit_bad_input(svm, reason);
+ vcpu_unimpl(vcpu, "vmgexit: exit code %#llx input is not valid\n",
+ control->exit_code);
+ dump_ghcb(svm);
+ svm_vmgexit_bad_input(svm, GHCB_ERR_MISSING_INPUT);
/* Resume the guest to "return" the error code. */
return 1;
@@ -4547,6 +4517,25 @@ int sev_handle_vmgexit(struct kvm_vcpu *vcpu)
svm_vmgexit_success(svm, 0);
switch (control->exit_code) {
+ case SVM_EXIT_IOIO:
+ if (!((control->exit_info_1 & SVM_IOIO_SIZE_MASK) >> SVM_IOIO_SIZE_SHIFT))
+ return 1;
+
+ fallthrough;
+ case SVM_EXIT_READ_DR7:
+ case SVM_EXIT_WRITE_DR7:
+ case SVM_EXIT_RDTSC:
+ case SVM_EXIT_RDTSCP:
+ case SVM_EXIT_RDPMC:
+ case SVM_EXIT_CPUID:
+ case SVM_EXIT_INVD:
+ case SVM_EXIT_MSR:
+ case SVM_EXIT_VMMCALL:
+ case SVM_EXIT_WBINVD:
+ case SVM_EXIT_MONITOR:
+ case SVM_EXIT_MWAIT:
+ ret = svm_invoke_exit_handler(vcpu, control->exit_code);
+ break;
case SVM_VMGEXIT_MMIO_READ:
case SVM_VMGEXIT_MMIO_WRITE: {
bool is_write = control->exit_code == SVM_VMGEXIT_MMIO_WRITE;
@@ -4643,18 +4632,21 @@ int sev_handle_vmgexit(struct kvm_vcpu *vcpu)
control->exit_info_2);
break;
case SVM_VMGEXIT_UNSUPPORTED_EVENT:
+ /*
+ * Note, the _guest_ is reporting an unsupported #VC, i.e. this
+ * isn't the same thing as KVM getting an unsupported #VMGEXIT.
+ */
vcpu_unimpl(vcpu,
"vmgexit: unsupported event - exit_info_1=%#llx, exit_info_2=%#llx\n",
control->exit_info_1, control->exit_info_2);
ret = -EINVAL;
break;
- case SVM_EXIT_IOIO:
- if (!((control->exit_info_1 & SVM_IOIO_SIZE_MASK) >> SVM_IOIO_SIZE_SHIFT))
- return 1;
-
- fallthrough;
default:
- ret = svm_invoke_exit_handler(vcpu, control->exit_code);
+ vcpu_unimpl(vcpu, "vmgexit: exit code %#llx is not valid\n",
+ control->exit_code);
+ svm_vmgexit_bad_input(svm, GHCB_ERR_INVALID_EVENT);
+ ret = 1;
+ break;
}
return ret;
--
2.54.0