* [PATCH V4 0/4] Align SVM with APM defined behaviors
@ 2026-02-28 3:33 Kevin Cheng
2026-02-28 3:33 ` [PATCH V4 1/4] KVM: SVM: Move STGI and CLGI intercept handling Kevin Cheng
` (5 more replies)
0 siblings, 6 replies; 17+ messages in thread
From: Kevin Cheng @ 2026-02-28 3:33 UTC (permalink / raw)
To: seanjc, pbonzini; +Cc: kvm, linux-kernel, yosry, Kevin Cheng
The APM lists the following behaviors
- The VMRUN, VMLOAD, VMSAVE, CLGI, VMMCALL, and INVLPGA instructions
can be used when the EFER.SVME is set to 1; otherwise, these
instructions generate a #UD exception.
- If VMMCALL instruction is not intercepted, the instruction raises a
#UD exception.
The patches in this series fix current SVM bugs that do not adhere to
the APM listed behaviors.
v3 -> v4:
- Dropped "KVM: SVM: Inject #UD for STGI if EFER.SVME=0 and SVM Lock
and DEV are not available" as per Sean
- Added back STGI and CLGI intercept clearing in init_vmcb to maintain
previous behavior on intel guests. Previously intel guests always
had STGI and CLGI intercepts cleared if vgif was enabled. In V3,
because the clearing of the intercepts was moved from init_vmcb() to
the !guest_cpuid_is_intel_compatible() case in
svm_recalc_instruction_intercepts(), the CLGI intercept would be
indefinitely set on intel guests. I added back the clearing to
init_vmcb() to retain intel guest behavior before this patch.
- In "Raise #UD if VMMCALL instruction is not intercepted" patch:
- Exempt Hyper-V L2 TLB flush hypercalls from the #UD injection,
as L0 intentionally intercepts these VMMCALLs on behalf of L1
via the direct hypercall enlightenment.
- Added nested_svm_is_l2_tlb_flush_hcall() which just returns true
if the hypercall was a Hyper-V L2 TLB flush hypercall.
v3: https://lore.kernel.org/kvm/20260122045755.205203-1-chengkev@google.com/
v2 -> v3:
- Elaborated on 'Move STGI and CLGI intercept handling' commit message
as per Sean
- Fixed bug due to interaction with svm_enable_nmi_window() and 'Move
STGI and CLGI intercept handling' as pointed out by Yosry. Code
changes suggested by Sean/Yosry.
- Removed open-coded nested_svm_check_permissions() in STGI
interception function as per Yosry
v2: https://lore.kernel.org/all/20260112174535.3132800-1-chengkev@google.com/
v1 -> v2:
- Split up the series into smaller more logical changes as suggested
by Sean
- Added patch for injecting #UD for STGI under APM defined conditions
as suggested by Sean
- Combined EFER.SVME=0 conditional with intel CPU logic in
svm_recalc_instruction_intercepts
Kevin Cheng (4):
KVM: SVM: Move STGI and CLGI intercept handling
KVM: SVM: Inject #UD for INVLPGA if EFER.SVME=0
KVM: SVM: Recalc instructions intercepts when EFER.SVME is toggled
KVM: SVM: Raise #UD if VMMCALL instruction is not intercepted
arch/x86/kvm/svm/hyperv.h | 11 ++++++++
arch/x86/kvm/svm/nested.c | 4 +--
arch/x86/kvm/svm/svm.c | 59 +++++++++++++++++++++++++++++++++++----
3 files changed, 65 insertions(+), 9 deletions(-)
--
2.53.0.473.g4a7958ca14-goog
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH V4 1/4] KVM: SVM: Move STGI and CLGI intercept handling
2026-02-28 3:33 [PATCH V4 0/4] Align SVM with APM defined behaviors Kevin Cheng
@ 2026-02-28 3:33 ` Kevin Cheng
2026-02-28 3:33 ` [PATCH V4 2/4] KVM: SVM: Inject #UD for INVLPGA if EFER.SVME=0 Kevin Cheng
` (4 subsequent siblings)
5 siblings, 0 replies; 17+ messages in thread
From: Kevin Cheng @ 2026-02-28 3:33 UTC (permalink / raw)
To: seanjc, pbonzini; +Cc: kvm, linux-kernel, yosry, Kevin Cheng
Add STGI/CLGI intercept handling to svm_recalc_instruction_intercepts()
in preparation for making the function EFER-aware. A later patch will
recalculate instruction intercepts when EFER.SVME is toggled, which is
needed to inject #UD on STGI/CLGI when the guest clears EFER.SVME.
When clearing the STGI intercept with vgif enabled, request
KVM_REQ_EVENT if there is a pending GIF-controlled event. This avoids
breaking NMI/SMI window tracking, as enable_{nmi,smi}_window() sets
INTERCEPT_STGI to detect when NMIs become unblocked. KVM_REQ_EVENT
forces kvm_check_and_inject_events() to re-evaluate pending events and
re-enable the intercept if needed.
Extract the pending GIF event check into a helper function
svm_has_pending_gif_event() to deduplicate the logic between
svm_recalc_instruction_intercepts() and svm_set_gif().
Signed-off-by: Kevin Cheng <chengkev@google.com>
---
arch/x86/kvm/svm/svm.c | 27 +++++++++++++++++++++++----
1 file changed, 23 insertions(+), 4 deletions(-)
diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c
index 8f8bc863e2143..25b15934330bb 100644
--- a/arch/x86/kvm/svm/svm.c
+++ b/arch/x86/kvm/svm/svm.c
@@ -1009,6 +1009,14 @@ void svm_write_tsc_multiplier(struct kvm_vcpu *vcpu)
preempt_enable();
}
+static bool svm_has_pending_gif_event(struct vcpu_svm *svm)
+{
+ return svm->vcpu.arch.smi_pending ||
+ svm->vcpu.arch.nmi_pending ||
+ kvm_cpu_has_injectable_intr(&svm->vcpu) ||
+ kvm_apic_has_pending_init_or_sipi(&svm->vcpu);
+}
+
/* Evaluate instruction intercepts that depend on guest CPUID features. */
static void svm_recalc_instruction_intercepts(struct kvm_vcpu *vcpu)
{
@@ -1050,6 +1058,20 @@ static void svm_recalc_instruction_intercepts(struct kvm_vcpu *vcpu)
svm_clr_intercept(svm, INTERCEPT_VMLOAD);
svm_clr_intercept(svm, INTERCEPT_VMSAVE);
}
+
+ if (vgif) {
+ /*
+ * If there is a pending interrupt controlled by GIF, set
+ * KVM_REQ_EVENT to re-evaluate if the intercept needs to be set
+ * again to track when GIF is re-enabled (e.g. for NMI
+ * injection).
+ */
+ svm_clr_intercept(svm, INTERCEPT_STGI);
+ if (svm_has_pending_gif_event(svm))
+ kvm_make_request(KVM_REQ_EVENT, &svm->vcpu);
+
+ svm_clr_intercept(svm, INTERCEPT_CLGI);
+ }
}
if (kvm_need_rdpmc_intercept(vcpu))
@@ -2320,10 +2342,7 @@ void svm_set_gif(struct vcpu_svm *svm, bool value)
svm_clear_vintr(svm);
enable_gif(svm);
- if (svm->vcpu.arch.smi_pending ||
- svm->vcpu.arch.nmi_pending ||
- kvm_cpu_has_injectable_intr(&svm->vcpu) ||
- kvm_apic_has_pending_init_or_sipi(&svm->vcpu))
+ if (svm_has_pending_gif_event(svm))
kvm_make_request(KVM_REQ_EVENT, &svm->vcpu);
} else {
disable_gif(svm);
--
2.53.0.473.g4a7958ca14-goog
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH V4 2/4] KVM: SVM: Inject #UD for INVLPGA if EFER.SVME=0
2026-02-28 3:33 [PATCH V4 0/4] Align SVM with APM defined behaviors Kevin Cheng
2026-02-28 3:33 ` [PATCH V4 1/4] KVM: SVM: Move STGI and CLGI intercept handling Kevin Cheng
@ 2026-02-28 3:33 ` Kevin Cheng
2026-02-28 3:33 ` [PATCH V4 3/4] KVM: SVM: Recalc instructions intercepts when EFER.SVME is toggled Kevin Cheng
` (3 subsequent siblings)
5 siblings, 0 replies; 17+ messages in thread
From: Kevin Cheng @ 2026-02-28 3:33 UTC (permalink / raw)
To: seanjc, pbonzini; +Cc: kvm, linux-kernel, yosry, Kevin Cheng, Yosry Ahmed
INVLPGA should cause a #UD when EFER.SVME is not set. Add a check to
properly inject #UD when EFER.SVME=0.
Signed-off-by: Kevin Cheng <chengkev@google.com>
Reviewed-by: Yosry Ahmed <yosry.ahmed@linux.dev>
---
arch/x86/kvm/svm/svm.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c
index 25b15934330bb..249bc3efe993a 100644
--- a/arch/x86/kvm/svm/svm.c
+++ b/arch/x86/kvm/svm/svm.c
@@ -2386,6 +2386,9 @@ static int invlpga_interception(struct kvm_vcpu *vcpu)
gva_t gva = kvm_rax_read(vcpu);
u32 asid = kvm_rcx_read(vcpu);
+ if (nested_svm_check_permissions(vcpu))
+ return 1;
+
/* FIXME: Handle an address size prefix. */
if (!is_long_mode(vcpu))
gva = (u32)gva;
--
2.53.0.473.g4a7958ca14-goog
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH V4 3/4] KVM: SVM: Recalc instructions intercepts when EFER.SVME is toggled
2026-02-28 3:33 [PATCH V4 0/4] Align SVM with APM defined behaviors Kevin Cheng
2026-02-28 3:33 ` [PATCH V4 1/4] KVM: SVM: Move STGI and CLGI intercept handling Kevin Cheng
2026-02-28 3:33 ` [PATCH V4 2/4] KVM: SVM: Inject #UD for INVLPGA if EFER.SVME=0 Kevin Cheng
@ 2026-02-28 3:33 ` Kevin Cheng
2026-02-28 3:33 ` [PATCH V4 4/4] KVM: SVM: Raise #UD if VMMCALL instruction is not intercepted Kevin Cheng
` (2 subsequent siblings)
5 siblings, 0 replies; 17+ messages in thread
From: Kevin Cheng @ 2026-02-28 3:33 UTC (permalink / raw)
To: seanjc, pbonzini; +Cc: kvm, linux-kernel, yosry, Kevin Cheng
The AMD APM states that VMRUN, VMLOAD, VMSAVE, CLGI, VMMCALL, and
INVLPGA instructions should generate a #UD when EFER.SVME is cleared.
Currently, when VMLOAD, VMSAVE, or CLGI are executed in L1 with
EFER.SVME cleared, no #UD is generated in certain cases. This is because
the intercepts for these instructions are cleared based on whether or
not vls or vgif is enabled. The #UD fails to be generated when the
intercepts are absent.
Fix the missing #UD generation by ensuring that all relevant
instructions have intercepts set when SVME.EFER is disabled.
VMMCALL is special because KVM's ABI is that VMCALL/VMMCALL are always
supported for L1 and never fault.
Signed-off-by: Kevin Cheng <chengkev@google.com>
---
arch/x86/kvm/svm/svm.c | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)
diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c
index 249bc3efe993a..f8f9b7a124c36 100644
--- a/arch/x86/kvm/svm/svm.c
+++ b/arch/x86/kvm/svm/svm.c
@@ -244,6 +244,8 @@ int svm_set_efer(struct kvm_vcpu *vcpu, u64 efer)
if (svm_gp_erratum_intercept && !sev_guest(vcpu->kvm))
set_exception_intercept(svm, GP_VECTOR);
}
+
+ kvm_make_request(KVM_REQ_RECALC_INTERCEPTS, vcpu);
}
svm->vmcb->save.efer = efer | EFER_SVME;
@@ -1021,6 +1023,7 @@ static bool svm_has_pending_gif_event(struct vcpu_svm *svm)
static void svm_recalc_instruction_intercepts(struct kvm_vcpu *vcpu)
{
struct vcpu_svm *svm = to_svm(vcpu);
+ u64 efer = vcpu->arch.efer;
/*
* Intercept INVPCID if shadow paging is enabled to sync/free shadow
@@ -1045,8 +1048,13 @@ static void svm_recalc_instruction_intercepts(struct kvm_vcpu *vcpu)
* No need to toggle VIRTUAL_VMLOAD_VMSAVE_ENABLE_MASK here, it is
* always set if vls is enabled. If the intercepts are set, the bit is
* meaningless anyway.
+ *
+ * Intercept instructions that #UD if EFER.SVME=0, as SVME must be set even
+ * when running the guest, i.e. hardware will only ever see EFER.SVME=1.
*/
- if (guest_cpuid_is_intel_compatible(vcpu)) {
+ if (guest_cpuid_is_intel_compatible(vcpu) || !(efer & EFER_SVME)) {
+ svm_set_intercept(svm, INTERCEPT_CLGI);
+ svm_set_intercept(svm, INTERCEPT_STGI);
svm_set_intercept(svm, INTERCEPT_VMLOAD);
svm_set_intercept(svm, INTERCEPT_VMSAVE);
} else {
--
2.53.0.473.g4a7958ca14-goog
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH V4 4/4] KVM: SVM: Raise #UD if VMMCALL instruction is not intercepted
2026-02-28 3:33 [PATCH V4 0/4] Align SVM with APM defined behaviors Kevin Cheng
` (2 preceding siblings ...)
2026-02-28 3:33 ` [PATCH V4 3/4] KVM: SVM: Recalc instructions intercepts when EFER.SVME is toggled Kevin Cheng
@ 2026-02-28 3:33 ` Kevin Cheng
2026-03-03 2:22 ` Sean Christopherson
2026-03-02 16:21 ` [PATCH V4 0/4] Align SVM with APM defined behaviors Yosry Ahmed
2026-03-05 17:08 ` Sean Christopherson
5 siblings, 1 reply; 17+ messages in thread
From: Kevin Cheng @ 2026-02-28 3:33 UTC (permalink / raw)
To: seanjc, pbonzini; +Cc: kvm, linux-kernel, yosry, Kevin Cheng
The AMD APM states that if VMMCALL instruction is not intercepted, the
instruction raises a #UD exception.
Create a vmmcall exit handler that generates a #UD if a VMMCALL exit
from L2 is being handled by L0, which means that L1 did not intercept
the VMMCALL instruction. The exception to this is if the exiting
instruction was for Hyper-V L2 TLB flush hypercalls as they are handled
by L0.
Suggested-by: Sean Christopherson <seanjc@google.com>
Signed-off-by: Kevin Cheng <chengkev@google.com>
---
arch/x86/kvm/svm/hyperv.h | 11 +++++++++++
arch/x86/kvm/svm/nested.c | 4 +---
arch/x86/kvm/svm/svm.c | 19 ++++++++++++++++++-
3 files changed, 30 insertions(+), 4 deletions(-)
diff --git a/arch/x86/kvm/svm/hyperv.h b/arch/x86/kvm/svm/hyperv.h
index d3f8bfc05832e..9af03970d40c2 100644
--- a/arch/x86/kvm/svm/hyperv.h
+++ b/arch/x86/kvm/svm/hyperv.h
@@ -41,6 +41,13 @@ static inline bool nested_svm_l2_tlb_flush_enabled(struct kvm_vcpu *vcpu)
return hv_vcpu->vp_assist_page.nested_control.features.directhypercall;
}
+static inline bool nested_svm_is_l2_tlb_flush_hcall(struct kvm_vcpu *vcpu)
+{
+ return guest_hv_cpuid_has_l2_tlb_flush(vcpu) &&
+ nested_svm_l2_tlb_flush_enabled(vcpu) &&
+ kvm_hv_is_tlb_flush_hcall(vcpu);
+}
+
void svm_hv_inject_synthetic_vmexit_post_tlb_flush(struct kvm_vcpu *vcpu);
#else /* CONFIG_KVM_HYPERV */
static inline void nested_svm_hv_update_vm_vp_ids(struct kvm_vcpu *vcpu) {}
@@ -48,6 +55,10 @@ static inline bool nested_svm_l2_tlb_flush_enabled(struct kvm_vcpu *vcpu)
{
return false;
}
+static inline bool nested_svm_is_l2_tlb_flush_hcall(struct kvm_vcpu *vcpu)
+{
+ return false;
+}
static inline void svm_hv_inject_synthetic_vmexit_post_tlb_flush(struct kvm_vcpu *vcpu) {}
#endif /* CONFIG_KVM_HYPERV */
diff --git a/arch/x86/kvm/svm/nested.c b/arch/x86/kvm/svm/nested.c
index de90b104a0dd5..45d1496031a74 100644
--- a/arch/x86/kvm/svm/nested.c
+++ b/arch/x86/kvm/svm/nested.c
@@ -1674,9 +1674,7 @@ int nested_svm_exit_special(struct vcpu_svm *svm)
}
case SVM_EXIT_VMMCALL:
/* Hyper-V L2 TLB flush hypercall is handled by L0 */
- if (guest_hv_cpuid_has_l2_tlb_flush(vcpu) &&
- nested_svm_l2_tlb_flush_enabled(vcpu) &&
- kvm_hv_is_tlb_flush_hcall(vcpu))
+ if (nested_svm_is_l2_tlb_flush_hcall(vcpu))
return NESTED_EXIT_HOST;
break;
default:
diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c
index f8f9b7a124c36..d662d5ce986ac 100644
--- a/arch/x86/kvm/svm/svm.c
+++ b/arch/x86/kvm/svm/svm.c
@@ -52,6 +52,7 @@
#include "svm.h"
#include "svm_ops.h"
+#include "hyperv.h"
#include "kvm_onhyperv.h"
#include "svm_onhyperv.h"
@@ -3258,6 +3259,22 @@ static int bus_lock_exit(struct kvm_vcpu *vcpu)
return 0;
}
+static int vmmcall_interception(struct kvm_vcpu *vcpu)
+{
+ /*
+ * Per the AMD APM, VMMCALL raises #UD if the VMMCALL intercept
+ * is not set. For an L2 guest, inject #UD as L1 did not intercept
+ * VMMCALL, except for Hyper-V L2 TLB flush hypercalls as they
+ * are handled by L0.
+ */
+ if (is_guest_mode(vcpu) && !nested_svm_is_l2_tlb_flush_hcall(vcpu)) {
+ kvm_queue_exception(vcpu, UD_VECTOR);
+ return 1;
+ }
+
+ return kvm_emulate_hypercall(vcpu);
+}
+
static int (*const svm_exit_handlers[])(struct kvm_vcpu *vcpu) = {
[SVM_EXIT_READ_CR0] = cr_interception,
[SVM_EXIT_READ_CR3] = cr_interception,
@@ -3308,7 +3325,7 @@ static int (*const svm_exit_handlers[])(struct kvm_vcpu *vcpu) = {
[SVM_EXIT_TASK_SWITCH] = task_switch_interception,
[SVM_EXIT_SHUTDOWN] = shutdown_interception,
[SVM_EXIT_VMRUN] = vmrun_interception,
- [SVM_EXIT_VMMCALL] = kvm_emulate_hypercall,
+ [SVM_EXIT_VMMCALL] = vmmcall_interception,
[SVM_EXIT_VMLOAD] = vmload_interception,
[SVM_EXIT_VMSAVE] = vmsave_interception,
[SVM_EXIT_STGI] = stgi_interception,
--
2.53.0.473.g4a7958ca14-goog
^ permalink raw reply related [flat|nested] 17+ messages in thread
* Re: [PATCH V4 0/4] Align SVM with APM defined behaviors
2026-02-28 3:33 [PATCH V4 0/4] Align SVM with APM defined behaviors Kevin Cheng
` (3 preceding siblings ...)
2026-02-28 3:33 ` [PATCH V4 4/4] KVM: SVM: Raise #UD if VMMCALL instruction is not intercepted Kevin Cheng
@ 2026-03-02 16:21 ` Yosry Ahmed
2026-03-02 18:32 ` Sean Christopherson
2026-03-03 21:48 ` Kevin Cheng
2026-03-05 17:08 ` Sean Christopherson
5 siblings, 2 replies; 17+ messages in thread
From: Yosry Ahmed @ 2026-03-02 16:21 UTC (permalink / raw)
To: Kevin Cheng; +Cc: seanjc, pbonzini, kvm, linux-kernel
On Fri, Feb 27, 2026 at 7:33 PM Kevin Cheng <chengkev@google.com> wrote:
>
> The APM lists the following behaviors
> - The VMRUN, VMLOAD, VMSAVE, CLGI, VMMCALL, and INVLPGA instructions
> can be used when the EFER.SVME is set to 1; otherwise, these
> instructions generate a #UD exception.
> - If VMMCALL instruction is not intercepted, the instruction raises a
> #UD exception.
>
> The patches in this series fix current SVM bugs that do not adhere to
> the APM listed behaviors.
>
> v3 -> v4:
> - Dropped "KVM: SVM: Inject #UD for STGI if EFER.SVME=0 and SVM Lock
> and DEV are not available" as per Sean
> - Added back STGI and CLGI intercept clearing in init_vmcb to maintain
> previous behavior on intel guests. Previously intel guests always
> had STGI and CLGI intercepts cleared if vgif was enabled. In V3,
> because the clearing of the intercepts was moved from init_vmcb() to
> the !guest_cpuid_is_intel_compatible() case in
> svm_recalc_instruction_intercepts(), the CLGI intercept would be
> indefinitely set on intel guests. I added back the clearing to
> init_vmcb() to retain intel guest behavior before this patch.
I am a bit confused by this. v4 kept initializing the intercepts as
cleared for all guests, but we still set the CLGI/STGI intercepts for
Intel-compatible guests in svm_recalc_instruction_intercepts() patch
3. So what difference did this make?
Also taking a step back, I am not really sure what's the right thing
to do for Intel-compatible guests here. It also seems like even if we
set the intercept, svm_set_gif() will clear the STGI intercept, even
on Intel-compatible guests.
Maybe we should leave that can of worms alone, go back to removing
initializing the CLGI/STGI intercepts in init_vmcb(), and in
svm_recalc_instruction_intercepts() set/clear these intercepts based
on EFER.SVME alone, irrespective of Intel-compatibility?
> - In "Raise #UD if VMMCALL instruction is not intercepted" patch:
> - Exempt Hyper-V L2 TLB flush hypercalls from the #UD injection,
> as L0 intentionally intercepts these VMMCALLs on behalf of L1
> via the direct hypercall enlightenment.
> - Added nested_svm_is_l2_tlb_flush_hcall() which just returns true
> if the hypercall was a Hyper-V L2 TLB flush hypercall.
>
> v3: https://lore.kernel.org/kvm/20260122045755.205203-1-chengkev@google.com/
>
> v2 -> v3:
> - Elaborated on 'Move STGI and CLGI intercept handling' commit message
> as per Sean
> - Fixed bug due to interaction with svm_enable_nmi_window() and 'Move
> STGI and CLGI intercept handling' as pointed out by Yosry. Code
> changes suggested by Sean/Yosry.
> - Removed open-coded nested_svm_check_permissions() in STGI
> interception function as per Yosry
>
> v2: https://lore.kernel.org/all/20260112174535.3132800-1-chengkev@google.com/
>
> v1 -> v2:
> - Split up the series into smaller more logical changes as suggested
> by Sean
> - Added patch for injecting #UD for STGI under APM defined conditions
> as suggested by Sean
> - Combined EFER.SVME=0 conditional with intel CPU logic in
> svm_recalc_instruction_intercepts
>
> Kevin Cheng (4):
> KVM: SVM: Move STGI and CLGI intercept handling
> KVM: SVM: Inject #UD for INVLPGA if EFER.SVME=0
> KVM: SVM: Recalc instructions intercepts when EFER.SVME is toggled
> KVM: SVM: Raise #UD if VMMCALL instruction is not intercepted
>
> arch/x86/kvm/svm/hyperv.h | 11 ++++++++
> arch/x86/kvm/svm/nested.c | 4 +--
> arch/x86/kvm/svm/svm.c | 59 +++++++++++++++++++++++++++++++++++----
> 3 files changed, 65 insertions(+), 9 deletions(-)
>
> --
> 2.53.0.473.g4a7958ca14-goog
>
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH V4 0/4] Align SVM with APM defined behaviors
2026-03-02 16:21 ` [PATCH V4 0/4] Align SVM with APM defined behaviors Yosry Ahmed
@ 2026-03-02 18:32 ` Sean Christopherson
2026-03-02 23:17 ` Sean Christopherson
2026-03-03 21:48 ` Kevin Cheng
1 sibling, 1 reply; 17+ messages in thread
From: Sean Christopherson @ 2026-03-02 18:32 UTC (permalink / raw)
To: Yosry Ahmed; +Cc: Kevin Cheng, pbonzini, kvm, linux-kernel
On Mon, Mar 02, 2026, Yosry Ahmed wrote:
> On Fri, Feb 27, 2026 at 7:33 PM Kevin Cheng <chengkev@google.com> wrote:
> >
> > The APM lists the following behaviors
> > - The VMRUN, VMLOAD, VMSAVE, CLGI, VMMCALL, and INVLPGA instructions
> > can be used when the EFER.SVME is set to 1; otherwise, these
> > instructions generate a #UD exception.
> > - If VMMCALL instruction is not intercepted, the instruction raises a
> > #UD exception.
> >
> > The patches in this series fix current SVM bugs that do not adhere to
> > the APM listed behaviors.
> >
> > v3 -> v4:
> > - Dropped "KVM: SVM: Inject #UD for STGI if EFER.SVME=0 and SVM Lock
> > and DEV are not available" as per Sean
> > - Added back STGI and CLGI intercept clearing in init_vmcb to maintain
> > previous behavior on intel guests. Previously intel guests always
> > had STGI and CLGI intercepts cleared if vgif was enabled. In V3,
> > because the clearing of the intercepts was moved from init_vmcb() to
> > the !guest_cpuid_is_intel_compatible() case in
> > svm_recalc_instruction_intercepts(), the CLGI intercept would be
> > indefinitely set on intel guests. I added back the clearing to
> > init_vmcb() to retain intel guest behavior before this patch.
>
> I am a bit confused by this. v4 kept initializing the intercepts as
> cleared for all guests, but we still set the CLGI/STGI intercepts for
> Intel-compatible guests in svm_recalc_instruction_intercepts() patch
> 3. So what difference did this make?
>
> Also taking a step back, I am not really sure what's the right thing
> to do for Intel-compatible guests here. It also seems like even if we
> set the intercept, svm_set_gif() will clear the STGI intercept, even
> on Intel-compatible guests.
>
> Maybe we should leave that can of worms alone, go back to removing
> initializing the CLGI/STGI intercepts in init_vmcb(), and in
> svm_recalc_instruction_intercepts() set/clear these intercepts based
> on EFER.SVME alone, irrespective of Intel-compatibility?
Ya, guest_cpuid_is_intel_compatible() should only be applied to VMLOAD/VMSAVE.
KVM intercepts VMLOAD/VMSAVE to fixup SYSENTER MSRs, not to inject #UD. I.e. KVM
is handling (the absoutely absurd) case that FMS reports an Intel CPU, but the
guest enables and uses SVM.
/*
* Intercept VMLOAD if the vCPU model is Intel in order to emulate that
* VMLOAD drops bits 63:32 of SYSENTER (ignoring the fact that exposing
* SVM on Intel is bonkers and extremely unlikely to work).
*/
if (guest_cpuid_is_intel_compatible(vcpu))
guest_cpu_cap_clear(vcpu, X86_FEATURE_V_VMSAVE_VMLOAD);
Sorry for not catching this in previous versions.
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH V4 0/4] Align SVM with APM defined behaviors
2026-03-02 18:32 ` Sean Christopherson
@ 2026-03-02 23:17 ` Sean Christopherson
2026-03-03 0:34 ` Sean Christopherson
2026-03-03 21:52 ` Kevin Cheng
0 siblings, 2 replies; 17+ messages in thread
From: Sean Christopherson @ 2026-03-02 23:17 UTC (permalink / raw)
To: Yosry Ahmed; +Cc: Kevin Cheng, pbonzini, kvm, linux-kernel
On Mon, Mar 02, 2026, Sean Christopherson wrote:
> On Mon, Mar 02, 2026, Yosry Ahmed wrote:
> > On Fri, Feb 27, 2026 at 7:33 PM Kevin Cheng <chengkev@google.com> wrote:
> > >
> > > The APM lists the following behaviors
> > > - The VMRUN, VMLOAD, VMSAVE, CLGI, VMMCALL, and INVLPGA instructions
> > > can be used when the EFER.SVME is set to 1; otherwise, these
> > > instructions generate a #UD exception.
> > > - If VMMCALL instruction is not intercepted, the instruction raises a
> > > #UD exception.
> > >
> > > The patches in this series fix current SVM bugs that do not adhere to
> > > the APM listed behaviors.
> > >
> > > v3 -> v4:
> > > - Dropped "KVM: SVM: Inject #UD for STGI if EFER.SVME=0 and SVM Lock
> > > and DEV are not available" as per Sean
> > > - Added back STGI and CLGI intercept clearing in init_vmcb to maintain
> > > previous behavior on intel guests. Previously intel guests always
> > > had STGI and CLGI intercepts cleared if vgif was enabled. In V3,
> > > because the clearing of the intercepts was moved from init_vmcb() to
> > > the !guest_cpuid_is_intel_compatible() case in
> > > svm_recalc_instruction_intercepts(), the CLGI intercept would be
> > > indefinitely set on intel guests. I added back the clearing to
> > > init_vmcb() to retain intel guest behavior before this patch.
> >
> > I am a bit confused by this. v4 kept initializing the intercepts as
> > cleared for all guests, but we still set the CLGI/STGI intercepts for
> > Intel-compatible guests in svm_recalc_instruction_intercepts() patch
> > 3. So what difference did this make?
> >
> > Also taking a step back, I am not really sure what's the right thing
> > to do for Intel-compatible guests here. It also seems like even if we
> > set the intercept, svm_set_gif() will clear the STGI intercept, even
> > on Intel-compatible guests.
> >
> > Maybe we should leave that can of worms alone, go back to removing
> > initializing the CLGI/STGI intercepts in init_vmcb(), and in
> > svm_recalc_instruction_intercepts() set/clear these intercepts based
> > on EFER.SVME alone, irrespective of Intel-compatibility?
>
> Ya, guest_cpuid_is_intel_compatible() should only be applied to VMLOAD/VMSAVE.
> KVM intercepts VMLOAD/VMSAVE to fixup SYSENTER MSRs, not to inject #UD. I.e. KVM
> is handling (the absoutely absurd) case that FMS reports an Intel CPU, but the
> guest enables and uses SVM.
>
> /*
> * Intercept VMLOAD if the vCPU model is Intel in order to emulate that
> * VMLOAD drops bits 63:32 of SYSENTER (ignoring the fact that exposing
> * SVM on Intel is bonkers and extremely unlikely to work).
> */
> if (guest_cpuid_is_intel_compatible(vcpu))
> guest_cpu_cap_clear(vcpu, X86_FEATURE_V_VMSAVE_VMLOAD);
>
> Sorry for not catching this in previous versions.
Because I got all kinds of confused trying to recall what was different between
v3 and v4, I went ahead and spliced them together.
Does the below look right? If so, I'll formally post just patches 1 and 3 as v5.
I'll take 2 and 4 directly from here; I want to switch the ordering anyways so
that the vgif movement immediately precedes the Recalc "instructions" patch.
/*
* Intercept instructions that #UD if EFER.SVME=0, as SVME must be set
* even when running the guest, i.e. hardware will only ever see
* EFER.SVME=1.
*
* No need to toggle any of the vgif/vls/etc. enable bits here, as they
* are set when the VMCB is initialized and never cleared (if the
* relevant intercepts are set, the enablements are meaningless anyway).
*/
if (!(vcpu->arch.efer & EFER_SVME)) {
svm_set_intercept(svm, INTERCEPT_VMLOAD);
svm_set_intercept(svm, INTERCEPT_VMSAVE);
svm_set_intercept(svm, INTERCEPT_CLGI);
svm_set_intercept(svm, INTERCEPT_STGI);
} else {
/*
* If hardware supports Virtual VMLOAD VMSAVE then enable it
* in VMCB and clear intercepts to avoid #VMEXIT.
*/
if (guest_cpuid_is_intel_compatible(vcpu)) {
svm_set_intercept(svm, INTERCEPT_VMLOAD);
svm_set_intercept(svm, INTERCEPT_VMSAVE);
} else if (vls) {
svm_clr_intercept(svm, INTERCEPT_VMLOAD);
svm_clr_intercept(svm, INTERCEPT_VMSAVE);
}
/*
* Process pending events when clearing STGI/CLGI intercepts if
* there's at least one pending event that is masked by GIF, so
* that KVM re-evaluates if the intercept needs to be set again
* to track when GIF is re-enabled (e.g. for NMI injection).
*/
if (vgif) {
svm_clr_intercept(svm, INTERCEPT_CLGI);
svm_clr_intercept(svm, INTERCEPT_STGI);
if (svm_has_pending_gif_event(svm))
kvm_make_request(KVM_REQ_EVENT, &svm->vcpu);
}
}
where init_vmcb() is (like v3):
if (vnmi)
svm->vmcb->control.int_ctl |= V_NMI_ENABLE_MASK;
if (vgif)
svm->vmcb->control.int_ctl |= V_GIF_ENABLE_MASK;
if (vls)
svm->vmcb->control.virt_ext |= VIRTUAL_VMLOAD_VMSAVE_ENABLE_MASK;
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH V4 0/4] Align SVM with APM defined behaviors
2026-03-02 23:17 ` Sean Christopherson
@ 2026-03-03 0:34 ` Sean Christopherson
2026-03-03 21:56 ` Kevin Cheng
2026-03-03 21:52 ` Kevin Cheng
1 sibling, 1 reply; 17+ messages in thread
From: Sean Christopherson @ 2026-03-03 0:34 UTC (permalink / raw)
To: Yosry Ahmed; +Cc: Kevin Cheng, pbonzini, kvm, linux-kernel
On Mon, Mar 02, 2026, Sean Christopherson wrote:
> On Mon, Mar 02, 2026, Sean Christopherson wrote:
> > On Mon, Mar 02, 2026, Yosry Ahmed wrote:
> > > Also taking a step back, I am not really sure what's the right thing
> > > to do for Intel-compatible guests here. It also seems like even if we
> > > set the intercept, svm_set_gif() will clear the STGI intercept, even
> > > on Intel-compatible guests.
> > >
> > > Maybe we should leave that can of worms alone, go back to removing
> > > initializing the CLGI/STGI intercepts in init_vmcb(), and in
> > > svm_recalc_instruction_intercepts() set/clear these intercepts based
> > > on EFER.SVME alone, irrespective of Intel-compatibility?
> >
> > Ya, guest_cpuid_is_intel_compatible() should only be applied to VMLOAD/VMSAVE.
> > KVM intercepts VMLOAD/VMSAVE to fixup SYSENTER MSRs, not to inject #UD. I.e. KVM
> > is handling (the absoutely absurd) case that FMS reports an Intel CPU, but the
> > guest enables and uses SVM.
> >
> > /*
> > * Intercept VMLOAD if the vCPU model is Intel in order to emulate that
> > * VMLOAD drops bits 63:32 of SYSENTER (ignoring the fact that exposing
> > * SVM on Intel is bonkers and extremely unlikely to work).
> > */
> > if (guest_cpuid_is_intel_compatible(vcpu))
> > guest_cpu_cap_clear(vcpu, X86_FEATURE_V_VMSAVE_VMLOAD);
> >
> > Sorry for not catching this in previous versions.
>
> Because I got all kinds of confused trying to recall what was different between
> v3 and v4, I went ahead and spliced them together.
>
> Does the below look right? If so, I'll formally post just patches 1 and 3 as v5.
> I'll take 2 and 4 directly from here; I want to switch the ordering anyways so
> that the vgif movement immediately precedes the Recalc "instructions" patch.
Actually, I partially take that back. I'm going to send a separate v5 for patch
4, as there are additional cleanups that can be done related to Hyper-V stubs.
P.S. This is a good example of why bundling unrelated patches into series is
discouraged.
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH V4 4/4] KVM: SVM: Raise #UD if VMMCALL instruction is not intercepted
2026-02-28 3:33 ` [PATCH V4 4/4] KVM: SVM: Raise #UD if VMMCALL instruction is not intercepted Kevin Cheng
@ 2026-03-03 2:22 ` Sean Christopherson
2026-03-03 9:36 ` Vitaly Kuznetsov
0 siblings, 1 reply; 17+ messages in thread
From: Sean Christopherson @ 2026-03-03 2:22 UTC (permalink / raw)
To: Kevin Cheng; +Cc: pbonzini, kvm, linux-kernel, yosry, Vitaly Kuznetsov
+Vitaly
On Sat, Feb 28, 2026, Kevin Cheng wrote:
> The AMD APM states that if VMMCALL instruction is not intercepted, the
> instruction raises a #UD exception.
>
> Create a vmmcall exit handler that generates a #UD if a VMMCALL exit
> from L2 is being handled by L0, which means that L1 did not intercept
> the VMMCALL instruction. The exception to this is if the exiting
> instruction was for Hyper-V L2 TLB flush hypercalls as they are handled
> by L0.
*sigh*
Except this changelog doesn't capture *any* of the subtlety. And were it not for
an internal bug discussion, I would have literally no clue WTF is going on.
There's not generic missed #UD bug, because this code in recalc_intercepts()
effectively disables the VMMCALL intercept in vmcb02 if the intercept isn't set
in vmcb12.
/*
* We want to see VMMCALLs from a nested guest only when Hyper-V L2 TLB
* flush feature is enabled.
*/
if (!nested_svm_l2_tlb_flush_enabled(&svm->vcpu))
vmcb_clr_intercept(c, INTERCEPT_VMMCALL);
I.e. the only bug *knowingly* being fixed, maybe, is an edge case where Hyper-V
TLB flushes are enabled for L2 and the hypercall is something other than one of
the blessed Hyper-V hypercalls. But in that case, it's not at all clear to me
that synthesizing a #UD into L2 is correct. I can't find anything in the TLFS
(not surprising), so I guess anything goes?
Vitaly,
The scenario in question is where HV_X64_NESTED_DIRECT_FLUSH is enabled, L1 doesn't
intercept VMMCALL, and L2 executes VMMCALL with something other than one of the
Hyper-V TLB flush hypercalls. The proposed change is to synthesize #UD (which
is what happens if HV_X64_NESTED_DIRECT_FLUSH isn't enable). Does that sound
sane? Should KVM instead return an error.
As for bugs that are *unknowingly* being fixed, intercepting VMMCALL and manually
injecting a #UD effectively fixes a bad interaction with KVM's asinine
KVM_X86_QUIRK_FIX_HYPERCALL_INSN. If KVM doesn't intercept VMMCALL while L2
is active (L1 doesn't wants to intercept VMMCALL and the Hyper-V L2 TLB flush
hypercall is disabled), then L2 will hang on the VMMCALL as KVM will intercept
the #UD, then "emulate" VMMCALL by trying to fixup the opcode and restarting the
instruction.
That can be "fixed" by disabling the quirk, or by hacking the fixup like so:
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index db3f393192d9..3f6d9950f8f8 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -10506,17 +10506,22 @@ static int emulator_fix_hypercall(struct x86_emulate_ctxt *ctxt)
* If the quirk is disabled, synthesize a #UD and let the guest pick up
* the pieces.
*/
- if (!kvm_check_has_quirk(vcpu->kvm, KVM_X86_QUIRK_FIX_HYPERCALL_INSN)) {
- ctxt->exception.error_code_valid = false;
- ctxt->exception.vector = UD_VECTOR;
- ctxt->have_exception = true;
- return X86EMUL_PROPAGATE_FAULT;
- }
+ if (!kvm_check_has_quirk(vcpu->kvm, KVM_X86_QUIRK_FIX_HYPERCALL_INSN))
+ goto inject_ud;
kvm_x86_call(patch_hypercall)(vcpu, instruction);
+ if (is_guest_mode(vcpu) && !memcmp(instruction, ctxt->fetch.data, 3))
+ goto inject_ud;
+
return emulator_write_emulated(ctxt, rip, instruction, 3,
&ctxt->exception);
+
+inject_ud:
+ ctxt->exception.error_code_valid = false;
+ ctxt->exception.vector = UD_VECTOR;
+ ctxt->have_exception = true;
+ return X86EMUL_PROPAGATE_FAULT;
}
static int dm_request_for_irq_injection(struct kvm_vcpu *vcpu)
--
But that's extremely convoluted for no purpose that I can see. Not intercepting
VMMCALL requires _more_ code and is overall more complex.
So unless I'm missing something, I'm going to tack on this to fix the L2 infinite
loop, and then figure out what to do about Hyper-V, pending Vitaly's input.
diff --git a/arch/x86/kvm/svm/nested.c b/arch/x86/kvm/svm/nested.c
index 45d1496031a7..a55af647649c 100644
--- a/arch/x86/kvm/svm/nested.c
+++ b/arch/x86/kvm/svm/nested.c
@@ -156,13 +156,6 @@ void recalc_intercepts(struct vcpu_svm *svm)
vmcb_clr_intercept(c, INTERCEPT_VINTR);
}
- /*
- * We want to see VMMCALLs from a nested guest only when Hyper-V L2 TLB
- * flush feature is enabled.
- */
- if (!nested_svm_l2_tlb_flush_enabled(&svm->vcpu))
- vmcb_clr_intercept(c, INTERCEPT_VMMCALL);
-
for (i = 0; i < MAX_INTERCEPT; i++)
c->intercepts[i] |= g->intercepts[i];
^ permalink raw reply related [flat|nested] 17+ messages in thread
* Re: [PATCH V4 4/4] KVM: SVM: Raise #UD if VMMCALL instruction is not intercepted
2026-03-03 2:22 ` Sean Christopherson
@ 2026-03-03 9:36 ` Vitaly Kuznetsov
0 siblings, 0 replies; 17+ messages in thread
From: Vitaly Kuznetsov @ 2026-03-03 9:36 UTC (permalink / raw)
To: Sean Christopherson, Kevin Cheng; +Cc: pbonzini, kvm, linux-kernel, yosry
Sean Christopherson <seanjc@google.com> writes:
> +Vitaly
>
> On Sat, Feb 28, 2026, Kevin Cheng wrote:
>> The AMD APM states that if VMMCALL instruction is not intercepted, the
>> instruction raises a #UD exception.
>>
>> Create a vmmcall exit handler that generates a #UD if a VMMCALL exit
>> from L2 is being handled by L0, which means that L1 did not intercept
>> the VMMCALL instruction. The exception to this is if the exiting
>> instruction was for Hyper-V L2 TLB flush hypercalls as they are handled
>> by L0.
>
> *sigh*
>
> Except this changelog doesn't capture *any* of the subtlety. And were it not for
> an internal bug discussion, I would have literally no clue WTF is going on.
>
> There's not generic missed #UD bug, because this code in recalc_intercepts()
> effectively disables the VMMCALL intercept in vmcb02 if the intercept isn't set
> in vmcb12.
>
> /*
> * We want to see VMMCALLs from a nested guest only when Hyper-V L2 TLB
> * flush feature is enabled.
> */
> if (!nested_svm_l2_tlb_flush_enabled(&svm->vcpu))
> vmcb_clr_intercept(c, INTERCEPT_VMMCALL);
>
> I.e. the only bug *knowingly* being fixed, maybe, is an edge case where Hyper-V
> TLB flushes are enabled for L2 and the hypercall is something other than one of
> the blessed Hyper-V hypercalls. But in that case, it's not at all clear to me
> that synthesizing a #UD into L2 is correct. I can't find anything in the TLFS
> (not surprising), so I guess anything goes?
>
> Vitaly,
>
> The scenario in question is where HV_X64_NESTED_DIRECT_FLUSH is enabled, L1 doesn't
> intercept VMMCALL, and L2 executes VMMCALL with something other than one of the
> Hyper-V TLB flush hypercalls. The proposed change is to synthesize #UD (which
> is what happens if HV_X64_NESTED_DIRECT_FLUSH isn't enable). Does that sound
> sane? Should KVM instead return an error.
I think this does sound sane. In the situation, when the hypercall
issued by L2 is not a TLB flush hypercall, I believe the behavior should
be exactly the same whether HV_X64_NESTED_DIRECT_FLUSH is enabled or
not.
Also, I'm tempted to say that L1 not intercepting VMMCALL and at the
same time using extended features like HV_X64_NESTED_DIRECT_FLUSH can be
an unsupported combo and we can just refuse to run L2 or crash L1 for
misbehaving but I'm afraid this can backfire. E.g. when Hyper-V is
shutting down or in some other 'special' situation.
>
> As for bugs that are *unknowingly* being fixed, intercepting VMMCALL and manually
> injecting a #UD effectively fixes a bad interaction with KVM's asinine
> KVM_X86_QUIRK_FIX_HYPERCALL_INSN. If KVM doesn't intercept VMMCALL while L2
> is active (L1 doesn't wants to intercept VMMCALL and the Hyper-V L2 TLB flush
> hypercall is disabled), then L2 will hang on the VMMCALL as KVM will intercept
> the #UD, then "emulate" VMMCALL by trying to fixup the opcode and restarting the
> instruction.
>
> That can be "fixed" by disabling the quirk, or by hacking the fixup like so:
>
> diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
> index db3f393192d9..3f6d9950f8f8 100644
> --- a/arch/x86/kvm/x86.c
> +++ b/arch/x86/kvm/x86.c
> @@ -10506,17 +10506,22 @@ static int emulator_fix_hypercall(struct x86_emulate_ctxt *ctxt)
> * If the quirk is disabled, synthesize a #UD and let the guest pick up
> * the pieces.
> */
> - if (!kvm_check_has_quirk(vcpu->kvm, KVM_X86_QUIRK_FIX_HYPERCALL_INSN)) {
> - ctxt->exception.error_code_valid = false;
> - ctxt->exception.vector = UD_VECTOR;
> - ctxt->have_exception = true;
> - return X86EMUL_PROPAGATE_FAULT;
> - }
> + if (!kvm_check_has_quirk(vcpu->kvm, KVM_X86_QUIRK_FIX_HYPERCALL_INSN))
> + goto inject_ud;
>
> kvm_x86_call(patch_hypercall)(vcpu, instruction);
>
> + if (is_guest_mode(vcpu) && !memcmp(instruction, ctxt->fetch.data, 3))
> + goto inject_ud;
> +
> return emulator_write_emulated(ctxt, rip, instruction, 3,
> &ctxt->exception);
> +
> +inject_ud:
> + ctxt->exception.error_code_valid = false;
> + ctxt->exception.vector = UD_VECTOR;
> + ctxt->have_exception = true;
> + return X86EMUL_PROPAGATE_FAULT;
> }
>
> static int dm_request_for_irq_injection(struct kvm_vcpu *vcpu)
> --
>
> But that's extremely convoluted for no purpose that I can see. Not intercepting
> VMMCALL requires _more_ code and is overall more complex.
>
> So unless I'm missing something, I'm going to tack on this to fix the L2 infinite
> loop, and then figure out what to do about Hyper-V, pending Vitaly's input.
>
> diff --git a/arch/x86/kvm/svm/nested.c b/arch/x86/kvm/svm/nested.c
> index 45d1496031a7..a55af647649c 100644
> --- a/arch/x86/kvm/svm/nested.c
> +++ b/arch/x86/kvm/svm/nested.c
> @@ -156,13 +156,6 @@ void recalc_intercepts(struct vcpu_svm *svm)
> vmcb_clr_intercept(c, INTERCEPT_VINTR);
> }
>
> - /*
> - * We want to see VMMCALLs from a nested guest only when Hyper-V L2 TLB
> - * flush feature is enabled.
> - */
> - if (!nested_svm_l2_tlb_flush_enabled(&svm->vcpu))
> - vmcb_clr_intercept(c, INTERCEPT_VMMCALL);
> -
> for (i = 0; i < MAX_INTERCEPT; i++)
> c->intercepts[i] |= g->intercepts[i];
>
>
--
Vitaly
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH V4 0/4] Align SVM with APM defined behaviors
2026-03-02 16:21 ` [PATCH V4 0/4] Align SVM with APM defined behaviors Yosry Ahmed
2026-03-02 18:32 ` Sean Christopherson
@ 2026-03-03 21:48 ` Kevin Cheng
1 sibling, 0 replies; 17+ messages in thread
From: Kevin Cheng @ 2026-03-03 21:48 UTC (permalink / raw)
To: Yosry Ahmed; +Cc: seanjc, pbonzini, kvm, linux-kernel
On Mon, Mar 2, 2026 at 11:21 AM Yosry Ahmed <yosry@kernel.org> wrote:
>
> On Fri, Feb 27, 2026 at 7:33 PM Kevin Cheng <chengkev@google.com> wrote:
> >
> > The APM lists the following behaviors
> > - The VMRUN, VMLOAD, VMSAVE, CLGI, VMMCALL, and INVLPGA instructions
> > can be used when the EFER.SVME is set to 1; otherwise, these
> > instructions generate a #UD exception.
> > - If VMMCALL instruction is not intercepted, the instruction raises a
> > #UD exception.
> >
> > The patches in this series fix current SVM bugs that do not adhere to
> > the APM listed behaviors.
> >
> > v3 -> v4:
> > - Dropped "KVM: SVM: Inject #UD for STGI if EFER.SVME=0 and SVM Lock
> > and DEV are not available" as per Sean
> > - Added back STGI and CLGI intercept clearing in init_vmcb to maintain
> > previous behavior on intel guests. Previously intel guests always
> > had STGI and CLGI intercepts cleared if vgif was enabled. In V3,
> > because the clearing of the intercepts was moved from init_vmcb() to
> > the !guest_cpuid_is_intel_compatible() case in
> > svm_recalc_instruction_intercepts(), the CLGI intercept would be
> > indefinitely set on intel guests. I added back the clearing to
> > init_vmcb() to retain intel guest behavior before this patch.
>
> I am a bit confused by this. v4 kept initializing the intercepts as
> cleared for all guests, but we still set the CLGI/STGI intercepts for
> Intel-compatible guests in svm_recalc_instruction_intercepts() patch
> 3. So what difference did this make?
>
Yes I was mistaken in that comment. Please ignore that comment as it
is incorrect.
> Also taking a step back, I am not really sure what's the right thing
> to do for Intel-compatible guests here. It also seems like even if we
> set the intercept, svm_set_gif() will clear the STGI intercept, even
> on Intel-compatible guests.
>
> Maybe we should leave that can of worms alone, go back to removing
> initializing the CLGI/STGI intercepts in init_vmcb(), and in
> svm_recalc_instruction_intercepts() set/clear these intercepts based
> on EFER.SVME alone, irrespective of Intel-compatibility?
>
>
>
> > - In "Raise #UD if VMMCALL instruction is not intercepted" patch:
> > - Exempt Hyper-V L2 TLB flush hypercalls from the #UD injection,
> > as L0 intentionally intercepts these VMMCALLs on behalf of L1
> > via the direct hypercall enlightenment.
> > - Added nested_svm_is_l2_tlb_flush_hcall() which just returns true
> > if the hypercall was a Hyper-V L2 TLB flush hypercall.
> >
> > v3: https://lore.kernel.org/kvm/20260122045755.205203-1-chengkev@google.com/
> >
> > v2 -> v3:
> > - Elaborated on 'Move STGI and CLGI intercept handling' commit message
> > as per Sean
> > - Fixed bug due to interaction with svm_enable_nmi_window() and 'Move
> > STGI and CLGI intercept handling' as pointed out by Yosry. Code
> > changes suggested by Sean/Yosry.
> > - Removed open-coded nested_svm_check_permissions() in STGI
> > interception function as per Yosry
> >
> > v2: https://lore.kernel.org/all/20260112174535.3132800-1-chengkev@google.com/
> >
> > v1 -> v2:
> > - Split up the series into smaller more logical changes as suggested
> > by Sean
> > - Added patch for injecting #UD for STGI under APM defined conditions
> > as suggested by Sean
> > - Combined EFER.SVME=0 conditional with intel CPU logic in
> > svm_recalc_instruction_intercepts
> >
> > Kevin Cheng (4):
> > KVM: SVM: Move STGI and CLGI intercept handling
> > KVM: SVM: Inject #UD for INVLPGA if EFER.SVME=0
> > KVM: SVM: Recalc instructions intercepts when EFER.SVME is toggled
> > KVM: SVM: Raise #UD if VMMCALL instruction is not intercepted
> >
> > arch/x86/kvm/svm/hyperv.h | 11 ++++++++
> > arch/x86/kvm/svm/nested.c | 4 +--
> > arch/x86/kvm/svm/svm.c | 59 +++++++++++++++++++++++++++++++++++----
> > 3 files changed, 65 insertions(+), 9 deletions(-)
> >
> > --
> > 2.53.0.473.g4a7958ca14-goog
> >
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH V4 0/4] Align SVM with APM defined behaviors
2026-03-02 23:17 ` Sean Christopherson
2026-03-03 0:34 ` Sean Christopherson
@ 2026-03-03 21:52 ` Kevin Cheng
1 sibling, 0 replies; 17+ messages in thread
From: Kevin Cheng @ 2026-03-03 21:52 UTC (permalink / raw)
To: Sean Christopherson; +Cc: Yosry Ahmed, pbonzini, kvm, linux-kernel
On Mon, Mar 2, 2026 at 6:17 PM Sean Christopherson <seanjc@google.com> wrote:
>
> On Mon, Mar 02, 2026, Sean Christopherson wrote:
> > On Mon, Mar 02, 2026, Yosry Ahmed wrote:
> > > On Fri, Feb 27, 2026 at 7:33 PM Kevin Cheng <chengkev@google.com> wrote:
> > > >
> > > > The APM lists the following behaviors
> > > > - The VMRUN, VMLOAD, VMSAVE, CLGI, VMMCALL, and INVLPGA instructions
> > > > can be used when the EFER.SVME is set to 1; otherwise, these
> > > > instructions generate a #UD exception.
> > > > - If VMMCALL instruction is not intercepted, the instruction raises a
> > > > #UD exception.
> > > >
> > > > The patches in this series fix current SVM bugs that do not adhere to
> > > > the APM listed behaviors.
> > > >
> > > > v3 -> v4:
> > > > - Dropped "KVM: SVM: Inject #UD for STGI if EFER.SVME=0 and SVM Lock
> > > > and DEV are not available" as per Sean
> > > > - Added back STGI and CLGI intercept clearing in init_vmcb to maintain
> > > > previous behavior on intel guests. Previously intel guests always
> > > > had STGI and CLGI intercepts cleared if vgif was enabled. In V3,
> > > > because the clearing of the intercepts was moved from init_vmcb() to
> > > > the !guest_cpuid_is_intel_compatible() case in
> > > > svm_recalc_instruction_intercepts(), the CLGI intercept would be
> > > > indefinitely set on intel guests. I added back the clearing to
> > > > init_vmcb() to retain intel guest behavior before this patch.
> > >
> > > I am a bit confused by this. v4 kept initializing the intercepts as
> > > cleared for all guests, but we still set the CLGI/STGI intercepts for
> > > Intel-compatible guests in svm_recalc_instruction_intercepts() patch
> > > 3. So what difference did this make?
> > >
> > > Also taking a step back, I am not really sure what's the right thing
> > > to do for Intel-compatible guests here. It also seems like even if we
> > > set the intercept, svm_set_gif() will clear the STGI intercept, even
> > > on Intel-compatible guests.
> > >
> > > Maybe we should leave that can of worms alone, go back to removing
> > > initializing the CLGI/STGI intercepts in init_vmcb(), and in
> > > svm_recalc_instruction_intercepts() set/clear these intercepts based
> > > on EFER.SVME alone, irrespective of Intel-compatibility?
> >
> > Ya, guest_cpuid_is_intel_compatible() should only be applied to VMLOAD/VMSAVE.
> > KVM intercepts VMLOAD/VMSAVE to fixup SYSENTER MSRs, not to inject #UD. I.e. KVM
> > is handling (the absoutely absurd) case that FMS reports an Intel CPU, but the
> > guest enables and uses SVM.
> >
> > /*
> > * Intercept VMLOAD if the vCPU model is Intel in order to emulate that
> > * VMLOAD drops bits 63:32 of SYSENTER (ignoring the fact that exposing
> > * SVM on Intel is bonkers and extremely unlikely to work).
> > */
> > if (guest_cpuid_is_intel_compatible(vcpu))
> > guest_cpu_cap_clear(vcpu, X86_FEATURE_V_VMSAVE_VMLOAD);
> >
> > Sorry for not catching this in previous versions.
>
> Because I got all kinds of confused trying to recall what was different between
> v3 and v4, I went ahead and spliced them together.
>
> Does the below look right? If so, I'll formally post just patches 1 and 3 as v5.
> I'll take 2 and 4 directly from here; I want to switch the ordering anyways so
> that the vgif movement immediately precedes the Recalc "instructions" patch.
>
> /*
> * Intercept instructions that #UD if EFER.SVME=0, as SVME must be set
> * even when running the guest, i.e. hardware will only ever see
> * EFER.SVME=1.
> *
> * No need to toggle any of the vgif/vls/etc. enable bits here, as they
> * are set when the VMCB is initialized and never cleared (if the
> * relevant intercepts are set, the enablements are meaningless anyway).
> */
> if (!(vcpu->arch.efer & EFER_SVME)) {
> svm_set_intercept(svm, INTERCEPT_VMLOAD);
> svm_set_intercept(svm, INTERCEPT_VMSAVE);
> svm_set_intercept(svm, INTERCEPT_CLGI);
> svm_set_intercept(svm, INTERCEPT_STGI);
> } else {
> /*
> * If hardware supports Virtual VMLOAD VMSAVE then enable it
> * in VMCB and clear intercepts to avoid #VMEXIT.
> */
> if (guest_cpuid_is_intel_compatible(vcpu)) {
> svm_set_intercept(svm, INTERCEPT_VMLOAD);
> svm_set_intercept(svm, INTERCEPT_VMSAVE);
> } else if (vls) {
> svm_clr_intercept(svm, INTERCEPT_VMLOAD);
> svm_clr_intercept(svm, INTERCEPT_VMSAVE);
> }
>
> /*
> * Process pending events when clearing STGI/CLGI intercepts if
> * there's at least one pending event that is masked by GIF, so
> * that KVM re-evaluates if the intercept needs to be set again
> * to track when GIF is re-enabled (e.g. for NMI injection).
> */
> if (vgif) {
> svm_clr_intercept(svm, INTERCEPT_CLGI);
> svm_clr_intercept(svm, INTERCEPT_STGI);
>
> if (svm_has_pending_gif_event(svm))
> kvm_make_request(KVM_REQ_EVENT, &svm->vcpu);
> }
> }
>
> where init_vmcb() is (like v3):
>
> if (vnmi)
> svm->vmcb->control.int_ctl |= V_NMI_ENABLE_MASK;
>
> if (vgif)
> svm->vmcb->control.int_ctl |= V_GIF_ENABLE_MASK;
>
> if (vls)
> svm->vmcb->control.virt_ext |= VIRTUAL_VMLOAD_VMSAVE_ENABLE_MASK;
Yup this looks correct to me.
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH V4 0/4] Align SVM with APM defined behaviors
2026-03-03 0:34 ` Sean Christopherson
@ 2026-03-03 21:56 ` Kevin Cheng
2026-03-03 22:08 ` Sean Christopherson
0 siblings, 1 reply; 17+ messages in thread
From: Kevin Cheng @ 2026-03-03 21:56 UTC (permalink / raw)
To: Sean Christopherson; +Cc: Yosry Ahmed, pbonzini, kvm, linux-kernel
On Mon, Mar 2, 2026 at 7:35 PM Sean Christopherson <seanjc@google.com> wrote:
>
> On Mon, Mar 02, 2026, Sean Christopherson wrote:
> > On Mon, Mar 02, 2026, Sean Christopherson wrote:
> > > On Mon, Mar 02, 2026, Yosry Ahmed wrote:
> > > > Also taking a step back, I am not really sure what's the right thing
> > > > to do for Intel-compatible guests here. It also seems like even if we
> > > > set the intercept, svm_set_gif() will clear the STGI intercept, even
> > > > on Intel-compatible guests.
> > > >
> > > > Maybe we should leave that can of worms alone, go back to removing
> > > > initializing the CLGI/STGI intercepts in init_vmcb(), and in
> > > > svm_recalc_instruction_intercepts() set/clear these intercepts based
> > > > on EFER.SVME alone, irrespective of Intel-compatibility?
> > >
> > > Ya, guest_cpuid_is_intel_compatible() should only be applied to VMLOAD/VMSAVE.
> > > KVM intercepts VMLOAD/VMSAVE to fixup SYSENTER MSRs, not to inject #UD. I.e. KVM
> > > is handling (the absoutely absurd) case that FMS reports an Intel CPU, but the
> > > guest enables and uses SVM.
> > >
> > > /*
> > > * Intercept VMLOAD if the vCPU model is Intel in order to emulate that
> > > * VMLOAD drops bits 63:32 of SYSENTER (ignoring the fact that exposing
> > > * SVM on Intel is bonkers and extremely unlikely to work).
> > > */
> > > if (guest_cpuid_is_intel_compatible(vcpu))
> > > guest_cpu_cap_clear(vcpu, X86_FEATURE_V_VMSAVE_VMLOAD);
> > >
> > > Sorry for not catching this in previous versions.
> >
> > Because I got all kinds of confused trying to recall what was different between
> > v3 and v4, I went ahead and spliced them together.
> >
> > Does the below look right? If so, I'll formally post just patches 1 and 3 as v5.
> > I'll take 2 and 4 directly from here; I want to switch the ordering anyways so
> > that the vgif movement immediately precedes the Recalc "instructions" patch.
>
> Actually, I partially take that back. I'm going to send a separate v5 for patch
> 4, as there are additional cleanups that can be done related to Hyper-V stubs.
>
Gotcha, if you're sending just patch 4 as v5, then should I send
patches 1 and 3 (with fixes) as a new series?
> P.S. This is a good example of why bundling unrelated patches into series is
> discouraged.
>
Noted :)
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH V4 0/4] Align SVM with APM defined behaviors
2026-03-03 21:56 ` Kevin Cheng
@ 2026-03-03 22:08 ` Sean Christopherson
2026-03-03 22:27 ` Kevin Cheng
0 siblings, 1 reply; 17+ messages in thread
From: Sean Christopherson @ 2026-03-03 22:08 UTC (permalink / raw)
To: Kevin Cheng; +Cc: Yosry Ahmed, pbonzini, kvm, linux-kernel
On Tue, Mar 03, 2026, Kevin Cheng wrote:
> On Mon, Mar 2, 2026 at 7:35 PM Sean Christopherson <seanjc@google.com> wrote:
> >
> > On Mon, Mar 02, 2026, Sean Christopherson wrote:
> > > On Mon, Mar 02, 2026, Sean Christopherson wrote:
> > > > On Mon, Mar 02, 2026, Yosry Ahmed wrote:
> > > > > Also taking a step back, I am not really sure what's the right thing
> > > > > to do for Intel-compatible guests here. It also seems like even if we
> > > > > set the intercept, svm_set_gif() will clear the STGI intercept, even
> > > > > on Intel-compatible guests.
> > > > >
> > > > > Maybe we should leave that can of worms alone, go back to removing
> > > > > initializing the CLGI/STGI intercepts in init_vmcb(), and in
> > > > > svm_recalc_instruction_intercepts() set/clear these intercepts based
> > > > > on EFER.SVME alone, irrespective of Intel-compatibility?
> > > >
> > > > Ya, guest_cpuid_is_intel_compatible() should only be applied to VMLOAD/VMSAVE.
> > > > KVM intercepts VMLOAD/VMSAVE to fixup SYSENTER MSRs, not to inject #UD. I.e. KVM
> > > > is handling (the absoutely absurd) case that FMS reports an Intel CPU, but the
> > > > guest enables and uses SVM.
> > > >
> > > > /*
> > > > * Intercept VMLOAD if the vCPU model is Intel in order to emulate that
> > > > * VMLOAD drops bits 63:32 of SYSENTER (ignoring the fact that exposing
> > > > * SVM on Intel is bonkers and extremely unlikely to work).
> > > > */
> > > > if (guest_cpuid_is_intel_compatible(vcpu))
> > > > guest_cpu_cap_clear(vcpu, X86_FEATURE_V_VMSAVE_VMLOAD);
> > > >
> > > > Sorry for not catching this in previous versions.
> > >
> > > Because I got all kinds of confused trying to recall what was different between
> > > v3 and v4, I went ahead and spliced them together.
> > >
> > > Does the below look right? If so, I'll formally post just patches 1 and 3 as v5.
> > > I'll take 2 and 4 directly from here; I want to switch the ordering anyways so
> > > that the vgif movement immediately precedes the Recalc "instructions" patch.
> >
> > Actually, I partially take that back. I'm going to send a separate v5 for patch
> > 4, as there are additional cleanups that can be done related to Hyper-V stubs.
> >
>
> Gotcha, if you're sending just patch 4 as v5, then should I send
> patches 1 and 3 (with fixes) as a new series?
No need, I'll send a v5 for 1 and 3 as well.
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH V4 0/4] Align SVM with APM defined behaviors
2026-03-03 22:08 ` Sean Christopherson
@ 2026-03-03 22:27 ` Kevin Cheng
0 siblings, 0 replies; 17+ messages in thread
From: Kevin Cheng @ 2026-03-03 22:27 UTC (permalink / raw)
To: Sean Christopherson; +Cc: Yosry Ahmed, pbonzini, kvm, linux-kernel
On Tue, Mar 3, 2026 at 5:08 PM Sean Christopherson <seanjc@google.com> wrote:
>
> On Tue, Mar 03, 2026, Kevin Cheng wrote:
> > On Mon, Mar 2, 2026 at 7:35 PM Sean Christopherson <seanjc@google.com> wrote:
> > >
> > > On Mon, Mar 02, 2026, Sean Christopherson wrote:
> > > > On Mon, Mar 02, 2026, Sean Christopherson wrote:
> > > > > On Mon, Mar 02, 2026, Yosry Ahmed wrote:
> > > > > > Also taking a step back, I am not really sure what's the right thing
> > > > > > to do for Intel-compatible guests here. It also seems like even if we
> > > > > > set the intercept, svm_set_gif() will clear the STGI intercept, even
> > > > > > on Intel-compatible guests.
> > > > > >
> > > > > > Maybe we should leave that can of worms alone, go back to removing
> > > > > > initializing the CLGI/STGI intercepts in init_vmcb(), and in
> > > > > > svm_recalc_instruction_intercepts() set/clear these intercepts based
> > > > > > on EFER.SVME alone, irrespective of Intel-compatibility?
> > > > >
> > > > > Ya, guest_cpuid_is_intel_compatible() should only be applied to VMLOAD/VMSAVE.
> > > > > KVM intercepts VMLOAD/VMSAVE to fixup SYSENTER MSRs, not to inject #UD. I.e. KVM
> > > > > is handling (the absoutely absurd) case that FMS reports an Intel CPU, but the
> > > > > guest enables and uses SVM.
> > > > >
> > > > > /*
> > > > > * Intercept VMLOAD if the vCPU model is Intel in order to emulate that
> > > > > * VMLOAD drops bits 63:32 of SYSENTER (ignoring the fact that exposing
> > > > > * SVM on Intel is bonkers and extremely unlikely to work).
> > > > > */
> > > > > if (guest_cpuid_is_intel_compatible(vcpu))
> > > > > guest_cpu_cap_clear(vcpu, X86_FEATURE_V_VMSAVE_VMLOAD);
> > > > >
> > > > > Sorry for not catching this in previous versions.
> > > >
> > > > Because I got all kinds of confused trying to recall what was different between
> > > > v3 and v4, I went ahead and spliced them together.
> > > >
> > > > Does the below look right? If so, I'll formally post just patches 1 and 3 as v5.
> > > > I'll take 2 and 4 directly from here; I want to switch the ordering anyways so
> > > > that the vgif movement immediately precedes the Recalc "instructions" patch.
> > >
> > > Actually, I partially take that back. I'm going to send a separate v5 for patch
> > > 4, as there are additional cleanups that can be done related to Hyper-V stubs.
> > >
> >
> > Gotcha, if you're sending just patch 4 as v5, then should I send
> > patches 1 and 3 (with fixes) as a new series?
>
> No need, I'll send a v5 for 1 and 3 as well.
Sounds good. Thanks Sean
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH V4 0/4] Align SVM with APM defined behaviors
2026-02-28 3:33 [PATCH V4 0/4] Align SVM with APM defined behaviors Kevin Cheng
` (4 preceding siblings ...)
2026-03-02 16:21 ` [PATCH V4 0/4] Align SVM with APM defined behaviors Yosry Ahmed
@ 2026-03-05 17:08 ` Sean Christopherson
5 siblings, 0 replies; 17+ messages in thread
From: Sean Christopherson @ 2026-03-05 17:08 UTC (permalink / raw)
To: Sean Christopherson, pbonzini, Kevin Cheng; +Cc: kvm, linux-kernel, yosry
On Sat, 28 Feb 2026 03:33:24 +0000, Kevin Cheng wrote:
> The APM lists the following behaviors
> - The VMRUN, VMLOAD, VMSAVE, CLGI, VMMCALL, and INVLPGA instructions
> can be used when the EFER.SVME is set to 1; otherwise, these
> instructions generate a #UD exception.
> - If VMMCALL instruction is not intercepted, the instruction raises a
> #UD exception.
>
> [...]
Applied patch 2 to kvm-x86 nested (the rest are coming separately). Thanks!
[2/4] KVM: SVM: Inject #UD for INVLPGA if EFER.SVME=0
https://github.com/kvm-x86/linux/commit/d99df02ff427
--
https://github.com/kvm-x86/linux/tree/next
^ permalink raw reply [flat|nested] 17+ messages in thread
end of thread, other threads:[~2026-03-05 17:11 UTC | newest]
Thread overview: 17+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-02-28 3:33 [PATCH V4 0/4] Align SVM with APM defined behaviors Kevin Cheng
2026-02-28 3:33 ` [PATCH V4 1/4] KVM: SVM: Move STGI and CLGI intercept handling Kevin Cheng
2026-02-28 3:33 ` [PATCH V4 2/4] KVM: SVM: Inject #UD for INVLPGA if EFER.SVME=0 Kevin Cheng
2026-02-28 3:33 ` [PATCH V4 3/4] KVM: SVM: Recalc instructions intercepts when EFER.SVME is toggled Kevin Cheng
2026-02-28 3:33 ` [PATCH V4 4/4] KVM: SVM: Raise #UD if VMMCALL instruction is not intercepted Kevin Cheng
2026-03-03 2:22 ` Sean Christopherson
2026-03-03 9:36 ` Vitaly Kuznetsov
2026-03-02 16:21 ` [PATCH V4 0/4] Align SVM with APM defined behaviors Yosry Ahmed
2026-03-02 18:32 ` Sean Christopherson
2026-03-02 23:17 ` Sean Christopherson
2026-03-03 0:34 ` Sean Christopherson
2026-03-03 21:56 ` Kevin Cheng
2026-03-03 22:08 ` Sean Christopherson
2026-03-03 22:27 ` Kevin Cheng
2026-03-03 21:52 ` Kevin Cheng
2026-03-03 21:48 ` Kevin Cheng
2026-03-05 17:08 ` Sean Christopherson
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox