summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSean Christopherson <seanjc@google.com>2026-07-31 10:33:35 -0700
committerSean Christopherson <seanjc@google.com>2026-07-31 14:03:07 -0700
commita40764607eab2a4361794bf2af619624de4e1c55 (patch)
tree0cecf81fd8bfe62e10eb5cc60d1e7b78410db694
parente186d4e34ad515f8ec45831f4386c677b3967092 (diff)
downloadlinux-next-a40764607eab2a4361794bf2af619624de4e1c55.tar.gz
linux-next-a40764607eab2a4361794bf2af619624de4e1c55.zip
KVM: x86: Extract VMX's unhandleable emulation check to common x86
Expose VMX's check for unhandleable emulation as its own kvm_x86_ops hook, and move the actual pre-KVM_RUN check into common x86. This will allow sharing the core logic with KVM's RSM emulation without needed to add a post-RSM hook, and is a step towards removing the .vcpu_pre_run() hook entirely. Alternatively, KVM could provide a post-RSM hook as mentioned, but pre/post hooks tend to be unwieldy as the exact "timing" of the call often matters greatly. E.g. in this case, the call must slot in exactly between loading guest state from SMRAM and the hack to force the vCPU out of L2 on SHUTDOWN. Link: https://patch.msgid.link/20260731173340.2644656-2-seanjc@google.com Signed-off-by: Sean Christopherson <seanjc@google.com>
-rw-r--r--arch/x86/include/asm/kvm-x86-ops.h1
-rw-r--r--arch/x86/include/asm/kvm_host.h2
-rw-r--r--arch/x86/kvm/vmx/main.c11
-rw-r--r--arch/x86/kvm/vmx/vmx.c7
-rw-r--r--arch/x86/kvm/vmx/x86_ops.h1
-rw-r--r--arch/x86/kvm/x86.c5
6 files changed, 21 insertions, 6 deletions
diff --git a/arch/x86/include/asm/kvm-x86-ops.h b/arch/x86/include/asm/kvm-x86-ops.h
index d5e9a1b1dba3..e001ddac2e79 100644
--- a/arch/x86/include/asm/kvm-x86-ops.h
+++ b/arch/x86/include/asm/kvm-x86-ops.h
@@ -68,6 +68,7 @@ KVM_X86_OP(vcpu_run)
KVM_X86_OP(handle_exit)
KVM_X86_OP(skip_emulated_instruction)
KVM_X86_OP_OPTIONAL(update_emulated_instruction)
+KVM_X86_OP_OPTIONAL_RET0(unhandleable_emulation_required)
KVM_X86_OP(set_interrupt_shadow)
KVM_X86_OP(get_interrupt_shadow)
KVM_X86_OP(patch_hypercall)
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index 6077f4e00d79..afe31fce67bd 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -1591,6 +1591,8 @@ struct kvm_x86_ops {
enum exit_fastpath_completion exit_fastpath);
int (*skip_emulated_instruction)(struct kvm_vcpu *vcpu);
void (*update_emulated_instruction)(struct kvm_vcpu *vcpu);
+ bool (*unhandleable_emulation_required)(struct kvm_vcpu *vcpu);
+
void (*set_interrupt_shadow)(struct kvm_vcpu *vcpu, int mask);
u32 (*get_interrupt_shadow)(struct kvm_vcpu *vcpu);
void (*patch_hypercall)(struct kvm_vcpu *vcpu,
diff --git a/arch/x86/kvm/vmx/main.c b/arch/x86/kvm/vmx/main.c
index 04f986e3d439..2a69dc3ac690 100644
--- a/arch/x86/kvm/vmx/main.c
+++ b/arch/x86/kvm/vmx/main.c
@@ -165,6 +165,16 @@ static int vt_handle_exit(struct kvm_vcpu *vcpu,
return vmx_handle_exit(vcpu, fastpath);
}
+static bool vt_unhandleable_emulation_required(struct kvm_vcpu *vcpu)
+{
+ if (is_td_vcpu(vcpu)) {
+ WARN_ON_ONCE(to_vt(vcpu)->emulation_required);
+ return false;
+ }
+
+ return vmx_unhandleable_emulation_required(vcpu);
+}
+
static int vt_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
{
if (unlikely(is_td_vcpu(vcpu)))
@@ -944,6 +954,7 @@ struct kvm_x86_ops vt_x86_ops __initdata = {
.handle_exit = vt_op(handle_exit),
.skip_emulated_instruction = vmx_skip_emulated_instruction,
.update_emulated_instruction = vmx_update_emulated_instruction,
+ .unhandleable_emulation_required = vt_op(unhandleable_emulation_required),
.set_interrupt_shadow = vt_op(set_interrupt_shadow),
.get_interrupt_shadow = vt_op(get_interrupt_shadow),
.patch_hypercall = vt_op(patch_hypercall),
diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
index 5ef6bdb334c7..b69062db3825 100644
--- a/arch/x86/kvm/vmx/vmx.c
+++ b/arch/x86/kvm/vmx/vmx.c
@@ -6034,7 +6034,7 @@ static int handle_nmi_window(struct kvm_vcpu *vcpu)
* with unsrestricted guest mode disabled) and KVM can't faithfully emulate the
* current vCPU state.
*/
-static bool vmx_unhandleable_emulation_required(struct kvm_vcpu *vcpu)
+bool vmx_unhandleable_emulation_required(struct kvm_vcpu *vcpu)
{
struct vcpu_vmx *vmx = to_vmx(vcpu);
@@ -6111,11 +6111,6 @@ static int handle_invalid_guest_state(struct kvm_vcpu *vcpu)
int vmx_vcpu_pre_run(struct kvm_vcpu *vcpu)
{
- if (vmx_unhandleable_emulation_required(vcpu)) {
- kvm_prepare_emulation_failure_exit(vcpu);
- return 0;
- }
-
return 1;
}
diff --git a/arch/x86/kvm/vmx/x86_ops.h b/arch/x86/kvm/vmx/x86_ops.h
index 409858074246..551b4195bc1b 100644
--- a/arch/x86/kvm/vmx/x86_ops.h
+++ b/arch/x86/kvm/vmx/x86_ops.h
@@ -31,6 +31,7 @@ int vmx_handle_exit(struct kvm_vcpu *vcpu, fastpath_t exit_fastpath);
void vmx_handle_exit_irqoff(struct kvm_vcpu *vcpu);
int vmx_skip_emulated_instruction(struct kvm_vcpu *vcpu);
void vmx_update_emulated_instruction(struct kvm_vcpu *vcpu);
+bool vmx_unhandleable_emulation_required(struct kvm_vcpu *vcpu);
int vmx_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info);
#ifdef CONFIG_KVM_SMM
int vmx_smi_allowed(struct kvm_vcpu *vcpu, bool for_injection);
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 3be5024045da..4836f2d17cd4 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -8862,6 +8862,11 @@ static int kvm_x86_vcpu_pre_run(struct kvm_vcpu *vcpu)
!kvm_apic_init_sipi_allowed(vcpu))
return -EINVAL;
+ if (kvm_x86_call(unhandleable_emulation_required)(vcpu)) {
+ kvm_prepare_emulation_failure_exit(vcpu);
+ return 0;
+ }
+
return kvm_x86_call(vcpu_pre_run)(vcpu);
}