Introduce Enhanced SMT Protection for SEV-SNP
cover Introduce Enhanced SMT Protection for SEV-SNP
Enhanced SMT Protection (ESMTP) allows an SEV-SNP VM to require that, while one of its vCPUs is in guest mode, every SMT sibling thread on that physical core is either idle in host mode or running a vCPU the guest itself has declared a legal sibling. This mitigates the side-channel risk of sharing core resources with untrusted host threads or with another guest.
Unlike core scheduling, where co-residency is a host kernel policy expressed with cookies, ESMTP is enforced by hardware. The sibling mask lives in the VMSA. The host is not trusted to run arbitrary kernel, userspace, or interrupt-handling work on a sibling thread while an ESMTP vCPU is active on that core.
Both KVM and the guest fully set the VCPU_SIBLING_MASK, which places every vCPU of the guest in one group so that any two of them may be co-resident. Combined with the ASID check, the sibling of a vCPU in guest mode is then always either another vCPU of that same guest or a thread idle in host mode.
Usage
-----
Requires patched OVMF [1] and QEMU [2] builds. Launch an SEV-SNP guest with ESMTP enabled on the sev-snp-guest object:
-object sev-snp-guest,id=sev0,cbitpos=51,reduced-phys-bits=1,esmtp=on
ESMTP is opt-in because it carries a performance cost as VMRUN stalls until the sibling runs work from a trusted vCPU or is in host idle.
The guest reports the feature in dmesg among the SNP feature names:
# dmesg | grep -i SEV ... SEV-SNP ... ESMTProt ...
Empirical test
--------------
* Identify siblings via:
cat /sys/devices/system/cpu/cpuX/topology/thread_siblings_list
* Pin the guest on the siblings
* Spawn a load in the guest e.g. via stress-ng --cpu 2 for SMT=2. Expect the guest utilization % for both sibling CPUs to be at 100% as the vCPU siblings are deemed trusted
* Spawn a load in the host latched onto one of the siblings. E.g. taskset -C X stress-ng --cpu 1
* Expect CPU X's utilization to be shared between host and guest %. Also expect drop in CPU utilization on the thread Sibling CPU as when the host task runs the guest will be forced idle.
Patches based on cryptodev-2.6
[1]: https://github.com/tianocore/edk2/pull/13128
[2]: https://lore.kernel.org/kvm/[email protected]/
Pratik R. Sampat (3):
KVM: SVM: Re-queue events that were never injected
KVM: SVM: Add host support for Enhanced SMT Protection x86/sev: Add guest support for Enhanced SMT Protection
arch/x86/boot/compressed/sev.c | 2 +- arch/x86/coco/sev/core.c | 13 ++++++++ arch/x86/include/asm/cpufeatures.h | 1 + arch/x86/include/asm/msr-index.h | 5 +++- arch/x86/include/asm/svm.h | 12 ++++++-- arch/x86/include/uapi/asm/svm.h | 9 +++++- arch/x86/kernel/cpu/scattered.c | 1 + arch/x86/kvm/svm/sev.c | 48 +++++++++++++++++++++++++++++- arch/x86/kvm/svm/svm.c | 40 ++++++++++++++++++++++--- 9 files changed, 121 insertions(+), 10 deletions(-)
Signature · 1 line
2.43.0
PATCH 1/3 KVM: SVM: Re-queue events that were never injected
When injecting an event into the guest via the event_inj field, a non-zero event_inj value on #VMEXIT means that the hardware was not able to inject the event into the guest. This used to only occur for the VMEXIT_INVALID intercept code, which was a fatal error and resulted in the guest being torn down.
Enhanced SMT Protection (ESMTP) invalidates that assumption. When ESMTP is enabled, VMRUN doesn't enter guest mode immediately; it stalls at a synchronization point until every sibling thread is either idle or has executed VMRUN for a legal sibling vCPU. If an ESMTP timeout / illegal sibling exit / interrupt arrives while VMRUN is stalled, VMRUN can now terminate with the corresponding #VMEXIT intercept code, without entering guest mode, and thus without injecting the event.
For example, on a 2-way SMT core running vCPU0 on thread 0 and vCPU1 on thread 1:
Thread 0 (vCPU0) Thread 1 (vCPU1)
---------------- ----------------
Interrupt A injected to the guest in host
VMRUN |
| |
v |
Stall waiting for sibling |
| |
| host INTR arrives on thread 0 |
| while it waits |
| |
v |
#VMEXIT v Interrupt B injected to the guest idle
VMRUN
In this case injecting interrupt B clobbers the last event. Interrupt A is never delivered and lost forvever.
Therefore, in preparation for ESMTP support, accommodate for potentially lost interrupts by detecting an undelivered injected event and re-queuing it so as not to lose the event.
svm_cancel_injection() already recovers a staged event this way and becomes redundant, so fold it in.
--- arch/x86/kvm/svm/svm.c | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-)
arch/x86/kvm/svm/svm.c +29 -4
@@ -4340,6 +4340,7 @@ static void svm_complete_interrupts(struct kvm_vcpu *vcpu)struct vcpu_svm *svm =to_svm (vcpu);u8 vector;int type; +struct vmcb_control_area *control = &svm->vmcb->control;u32 exitintinfo = svm->vmcb->control.exit_int_info;bool nmi_l1_to_l2 = svm->nmi_l1_to_l2;bool soft_int_injected = svm->soft_int_injected;
@@ -4347,6 +4348,27 @@ static void svm_complete_interrupts(struct kvm_vcpu *vcpu) svm->nmi_l1_to_l2 = false; svm->soft_int_injected = false; +/* +* Hardware clears EVENTINJ field when it injects an event. +* A non-empty EVENTINJ on #VMEXIT means the vCPU never entered guest +* mode, and thus that the event was never delivered. Migrate the event +* to EXITINTINFO so that it's requeued instead of being dropped. +* +* An undelivered event doesn't imply a fatal VMEXIT_INVALID. With +* Enhanced SMT Protection, VMRUN may exit with an ordinary #VMEXIT +* without having injected that event into the guest. +* +* Clobbering EXITINTINFO is safe precisely because the vCPU never +* entered guest mode. +*/ +if (control->event_inj) { + control->exit_int_info = control->event_inj; + control->exit_int_info_err = control->event_inj_err; + control->event_inj =0 ; + + exitintinfo = control->exit_int_info; + } +/* * If we've made progress since setting awaiting_iret_completion, we've * executed an IRET and can allow NMI injection.
@@ -4410,11 +4432,14 @@ static void svm_complete_interrupts(struct kvm_vcpu *vcpu)static void svm_cancel_injection (struct kvm_vcpu *vcpu) {struct vcpu_svm *svm =to_svm (vcpu); -struct vmcb_control_area *control = &svm->vmcb->control; - control->exit_int_info = control->event_inj; - control->exit_int_info_err = control->event_inj_err; - control->event_inj =0 ; +/* +* EXITINTINFO is stale as it holds the event from the previous #VMEXIT +* (or from the last time the current VMCB was run). Invalidate it so +* that svm_complete_interrupts() requeues if and only if KVM staged an +* event in EVENTINJ. +*/ + svm->vmcb->control.exit_int_info =0 ;svm_complete_interrupts (vcpu); }
Signature · 1 line
2.43.0
[email protected]
AI reviewRe: [PATCH 1/3] KVM: SVM: Re-queue events that were never injected
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: - [High] svm_complete_interrupts() incorrectly checks if (control->event_inj) instead of the…
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] svm_complete_interrupts() incorrectly checks if (control->event_inj) instead of the SVM_EVTINJ_VALID bit, which can silently drop valid hardware-reported events (like guest page faults) by clobbering EXITINTINFO. --
commit 50716e3ba11eb9d000a0186ffad984ac08df1dcb
Author: Pratik R. Sampat <[email protected]>
KVM: SVM: Re-queue events that were never injected
When injecting an event into the guest via the event_inj field, a non-zero event_inj value on #VMEXIT means the hardware was unable to inject it. This commit adds a check to recover potentially lost interrupts by detecting an undelivered injected event and re-queuing it.
Quoted 4 lines
arch/x86/kvm/svm/svm.c +0
-0
[ ... ]
Quoted 8 lines
arch/x86/kvm/svm/svm.c +4
-0@@ -4323,6 +4324,27 @@ static void svm_complete_interrupts(struct kvm_vcpu *vcpu) svm->nmi_l1_to_l2 = false; svm->soft_int_injected = false; +/* +* Hardware clears EVENTINJ field when it injects an event. +* A non-empty EVENTINJ on #VMEXIT means the vCPU never entered guest +* mode, and thus that the event was never delivered. Migrate the event
arch/x86/kvm/svm/svm.c static void svm_complete_interrupts(struct kvm_vcpu *vcpu) · line 4340
Quoted 10 lines
arch/x86/kvm/svm/svm.c +10
-0+* to EXITINTINFO so that it's requeued instead of being dropped. +* +* An undelivered event doesn't imply a fatal VMEXIT_INVALID. With +* Enhanced SMT Protection, VMRUN may exit with an ordinary #VMEXIT +* without having injected that event into the guest. +* +* Clobbering EXITINTINFO is safe precisely because the vCPU never +* entered guest mode. +*/ +if (control->event_inj) {
[Severity: High]
Does this code silently drop valid hardware-reported events?
If an L1 hypervisor sets event_inj to a non-zero value but leaves the SVM_EVTINJ_VALID bit clear, hardware will ignore the injection and won't clear EVENTINJ.
If a genuine exception occurs in the L2 guest that populates EXITINTINFO, this check incorrectly evaluates to true since event_inj is non-zero.
This causes EXITINTINFO to be clobbered with the L1's invalid event_inj data. Because the clobbered value lacks the VALID bit, KVM will then ignore it and drop the event.
Should this code check the SVM_EVTINJ_VALID bit instead of checking for a non-zero event_inj value?
Quoted 7 lines
arch/x86/kvm/svm/svm.c +7
-0+ control->exit_int_info = control->event_inj; + control->exit_int_info_err = control->event_inj_err; + control->event_inj =0 ; + + exitintinfo = control->exit_int_info; + } +
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=1
Re: [PATCH 1/3] KVM: SVM: Re-queue events that were never injected
Quoted 42 lines · On 9/14/26 1:16 PM, [email protected] wrote:
[You don't often get email from [email protected]. Learn why this is important at https://aka.ms/LearnAboutSenderIdentification ]
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High]svm_complete_interrupts()incorrectly checks if (control->event_inj) instead of theSVM_EVTINJ_VALIDbit, which can silently drop valid hardware-reported events (like guest page faults) by clobbering EXITINTINFO. --commit
50716e3ba11eb9d000a0186ffad984ac08df1dcb
Author: Pratik R. Sampat <[email protected]>KVM: SVM: Re-queue events that were never injected
When injecting an event into the guest via the
event_injfield, a non-zeroevent_injvalue on #VMEXIT means the hardware was unable to inject it. This commit adds a check to recover potentially lost interrupts by detecting an undelivered injected event and re-queuing it.Quoted 4 lines
arch/x86/kvm/svm/svm.c +0
-0[ ... ]
Quoted 8 lines
arch/x86/kvm/svm/svm.c +4
-0@@ -4323,6 +4324,27 @@ static void svm_complete_interrupts(struct kvm_vcpu *vcpu) svm->nmi_l1_to_l2 = false; svm->soft_int_injected = false; +/* +* Hardware clears EVENTINJ field when it injects an event. +* A non-empty EVENTINJ on #VMEXIT means the vCPU never entered guest +* mode, and thus that the event was never delivered. Migrate the event arch/x86/kvm/svm/svm.c static void svm_complete_interrupts(struct kvm_vcpu *vcpu) · line 4340
Quoted 10 lines
arch/x86/kvm/svm/svm.c +10
-0+* to EXITINTINFO so that it's requeued instead of being dropped. +* +* An undelivered event doesn't imply a fatal VMEXIT_INVALID. With +* Enhanced SMT Protection, VMRUN may exit with an ordinary #VMEXIT +* without having injected that event into the guest. +* +* Clobbering EXITINTINFO is safe precisely because the vCPU never +* entered guest mode. +*/ +if (control->event_inj) {[Severity: High]
Does this code silently drop valid hardware-reported events?
Quoted 3 lines
If an L1 hypervisor sets
event_injto a non-zero value but leaves theSVM_EVTINJ_VALIDbit clear, hardware will ignore the injection and won't clear EVENTINJ.
The first half is right, nested_svm_check_event_inj() intentionally returns true when V is clear, so vmcb02->control.event_inj can be non-zero with V=0.
The second half isn't. Clearing EVENTINJ is not part of injection, it's part of #VMEXIT, and it's unconditional. APM vol 3, VMRUN:
Upon #VMEXIT, the processor performs the following actions in order to return to the host execution context:
...
EXITINTINFO
clear EVENTINJ field in VMCB
KVM already relies on this, nested_svm_vmexit_update_vmcb12() zeroes vmcb12's EVENTINJ rather than propagating vmcb02's, citing the same thing.
Quoted 10 lines
If a genuine exception occurs in the L2 guest that populates EXITINTINFO, this check incorrectly evaluates to true since
event_injis non-zero.This causes EXITINTINFO to be clobbered with the L1's invalid
event_injdata. Because the clobbered value lacks the VALID bit, KVM will then ignore it and drop the event.Should this code check the
SVM_EVTINJ_VALIDbit instead of checking for a non-zeroevent_injvalue?
I believe we don't need to since the valid check is made later below.
-- Pratik
Quoted 11 lines
arch/x86/kvm/svm/svm.c static void svm_complete_interrupts(struct kvm_vcpu *vcpu) · line 4371
Quoted 8 lines
arch/x86/kvm/svm/svm.c +7
-0+ control->exit_int_info = control->event_inj; + control->exit_int_info_err = control->event_inj_err; + control->event_inj =0 ; + + exitintinfo = control->exit_int_info; + } +--
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=1
Sean Christopherson
maintainerRe: [PATCH 1/3] KVM: SVM: Re-queue events that were never injected
Quoted 50 lines · Pratik R. Sampat
Quoted 42 lines · On 9/14/26 1:16 PM, [email protected] wrote:
[You don't often get email from [email protected]. Learn why this is important at https://aka.ms/LearnAboutSenderIdentification ]
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High]svm_complete_interrupts()incorrectly checks if (control->event_inj) instead of theSVM_EVTINJ_VALIDbit, which can silently drop valid hardware-reported events (like guest page faults) by clobbering EXITINTINFO. --commit
50716e3ba11eb9d000a0186ffad984ac08df1dcb
Author: Pratik R. Sampat <[email protected]>KVM: SVM: Re-queue events that were never injected
When injecting an event into the guest via the
event_injfield, a non-zeroevent_injvalue on #VMEXIT means the hardware was unable to inject it. This commit adds a check to recover potentially lost interrupts by detecting an undelivered injected event and re-queuing it.Quoted 4 lines
arch/x86/kvm/svm/svm.c +0
-0[ ... ]
Quoted 8 lines
arch/x86/kvm/svm/svm.c +4
-0@@ -4323,6 +4324,27 @@ static void svm_complete_interrupts(struct kvm_vcpu *vcpu) svm->nmi_l1_to_l2 = false; svm->soft_int_injected = false; +/* +* Hardware clears EVENTINJ field when it injects an event. +* A non-empty EVENTINJ on #VMEXIT means the vCPU never entered guest +* mode, and thus that the event was never delivered. Migrate the event arch/x86/kvm/svm/svm.c static void svm_complete_interrupts(struct kvm_vcpu *vcpu) · line 4340
Quoted 10 lines
arch/x86/kvm/svm/svm.c +10
-0+* to EXITINTINFO so that it's requeued instead of being dropped. +* +* An undelivered event doesn't imply a fatal VMEXIT_INVALID. With +* Enhanced SMT Protection, VMRUN may exit with an ordinary #VMEXIT +* without having injected that event into the guest. +* +* Clobbering EXITINTINFO is safe precisely because the vCPU never +* entered guest mode. +*/ +if (control->event_inj) {[Severity: High]
Does this code silently drop valid hardware-reported events?Quoted 3 lines
If an L1 hypervisor sets
event_injto a non-zero value but leaves theSVM_EVTINJ_VALIDbit clear, hardware will ignore the injection and won't clear EVENTINJ.
Quoted 5 lines
The first half is right,
nested_svm_check_event_inj()intentionally returns true when V is clear, sovmcb02->control.event_injcan be non-zero with V=0.The second half isn't. Clearing EVENTINJ is not part of injection, it's part of #VMEXIT, and it's unconditional.
So that doesn't mesh with the above comment, which says:
Hardware clears EVENTINJ field when it injects an event.
And it begs the question of how this patch is at all useful. Because all this fancy new paranoia is clearly generating #VMEXITs, and if #VMEXIT unconditionally clears control->event_inj, I don't see how control->event_inj can be non-zero if KVM attempted VMRUN.
I.e. either this is all broken, or the APM is buggy.
Re: [PATCH 1/3] KVM: SVM: Re-queue events that were never injected
Hi Sean,
Quoted 28 lines · Sean Christopherson
Quoted 21 lines
Quoted 14 lines
Quoted 4 lines
arch/x86/kvm/svm/svm.c +4
-0+/* +* Hardware clears EVENTINJ field when it injects an event. +* A non-empty EVENTINJ on #VMEXIT means the vCPU never entered guest +* mode, and thus that the event was never delivered. Migrate the event arch/x86/kvm/svm/svm.c static void svm_complete_interrupts(struct kvm_vcpu *vcpu) · line 4364
Quoted 10 lines
arch/x86/kvm/svm/svm.c +10
-0+* to EXITINTINFO so that it's requeued instead of being dropped. +* +* An undelivered event doesn't imply a fatal VMEXIT_INVALID. With +* Enhanced SMT Protection, VMRUN may exit with an ordinary #VMEXIT +* without having injected that event into the guest. +* +* Clobbering EXITINTINFO is safe precisely because the vCPU never +* entered guest mode. +*/ +if (control->event_inj) {Quoted 6 lines
[Severity: High]
Does this code silently drop valid hardware-reported events?If an L1 hypervisor sets
event_injto a non-zero value but leaves theSVM_EVTINJ_VALIDbit clear, hardware will ignore the injection and won't clear EVENTINJ.Quoted 5 lines
The first half is right,
nested_svm_check_event_inj()intentionally returns true when V is clear, sovmcb02->control.event_injcan be non-zero with V=0.The second half isn't. Clearing EVENTINJ is not part of injection, it's part of #VMEXIT, and it's unconditional.
So that doesn't mesh with the above comment, which says:
Quoted 8 lines
Hardware clears EVENTINJ field when it injects an event.
And it begs the question of how this patch is at all useful. Because all this fancy new paranoia is clearly generating #VMEXITs, and if #VMEXIT unconditionally clears
control->event_inj, I don't see howcontrol->event_injcan be non-zero if KVM attempted VMRUN.I.e. either this is all broken, or the APM is buggy.
My wording in the comment is misleading. The clear is part of the #VMEXIT path out of guest mode, where it is indeed unconditional. However, VMRUN can terminate even before the guest mode is ever entered. With ESMTP, the hardware can give out a garden variety of exits at the sync point. In this case we get a VMEXIT that implies the VMRUN never actually ran any guest code then EVENTINJ won't be cleared. Since the exit code isn't a reliable discriminator, a non-zero EVENTINJ is the only way to tell.
Thanks,
--Pratik
Sean Christopherson
maintainerRe: [PATCH 1/3] KVM: SVM: Re-queue events that were never injected
In reply to Pratik R. SampatQuoted 29 lines · Pratik R. Sampat
When injecting an event into the guest via the
event_injfield, a non-zeroevent_injvalue on #VMEXIT means that the hardware was not able to inject the event into the guest. This used to only occur for theVMEXIT_INVALIDintercept code, which was a fatal error and resulted in the guest being torn down.Enhanced SMT Protection (ESMTP) invalidates that assumption. When ESMTP is enabled, VMRUN doesn't enter guest mode immediately; it stalls at a synchronization point until every sibling thread is either idle or has executed VMRUN for a legal sibling vCPU. If an ESMTP timeout / illegal sibling exit / interrupt arrives while VMRUN is stalled, VMRUN can now terminate with the corresponding #VMEXIT intercept code, without entering guest mode, and thus without injecting the event.
For example, on a 2-way SMT core running vCPU0 on thread 0 and vCPU1 on thread 1:
Thread 0 (vCPU0) Thread 1 (vCPU1)
---------------- ----------------
Interrupt A injected to the guest in hostVMRUN | | | v | Stall waiting for sibling | | | | host INTR arrives on thread 0 | | while it waits | | | v | #VMEXIT v
Quoted 2 lines
Interrupt B injected to the guest idle
VMRUN
So how is KVM_RUN_FORCE_IMMEDIATE_EXIT supposed to work?
Re: [PATCH 1/3] KVM: SVM: Re-queue events that were never injected
Quoted 33 lines · Sean Christopherson
Quoted 29 lines · Pratik R. Sampat
When injecting an event into the guest via the
event_injfield, a non-zeroevent_injvalue on #VMEXIT means that the hardware was not able to inject the event into the guest. This used to only occur for theVMEXIT_INVALIDintercept code, which was a fatal error and resulted in the guest being torn down.Enhanced SMT Protection (ESMTP) invalidates that assumption. When ESMTP is enabled, VMRUN doesn't enter guest mode immediately; it stalls at a synchronization point until every sibling thread is either idle or has executed VMRUN for a legal sibling vCPU. If an ESMTP timeout / illegal sibling exit / interrupt arrives while VMRUN is stalled, VMRUN can now terminate with the corresponding #VMEXIT intercept code, without entering guest mode, and thus without injecting the event.
For example, on a 2-way SMT core running vCPU0 on thread 0 and vCPU1 on thread 1:
Thread 0 (vCPU0) Thread 1 (vCPU1)
---------------- ----------------
Interrupt A injected to the guest in hostVMRUN | | | v | Stall waiting for sibling | | | | host INTR arrives on thread 0 | | while it waits | | | v | #VMEXIT vQuoted 2 lines
Interrupt B injected to the guest idle
VMRUN
Quoted 1 line
So how is
KVM_RUN_FORCE_IMMEDIATE_EXITsupposed to work?
I don't think KVM_RUN_FORCE_IMMEDIATE_EXIT should be affected negatively right?
On SVM, it queues a self-IPI before VMRUN. Normally, VMRUN enters the guest, consumes EVENTINJ, and then exits with VMEXIT_INTR; EXITINTINFO may describe interrupted event delivery.
With ESMTP, the pending IPI could terminate a stalled VMRUN before guest entry. EVENTINJ would remain valid, and this patch would requeue it for another attempt. That should preserve the intended behavior across retries. Of course, progress would still be gated on it being a legal sibling to begin with, but that should be fine.
Thanks,
--Pratik
PATCH 2/3 KVM: SVM: Add host support for Enhanced SMT Protection
In reply to Pratik R. SampatEnhanced SMT Protection (ESMTP) protects an SEV-SNP guest from SMT side channels by requiring that, while a vCPU is in guest mode, its SMT sibling thread is either idle in host mode or executing a vCPU the guest has declared to be a legal sibling. A legal sibling is another ESMTP vCPU of the same guest that carries the same VCPU_SIBLING_MASK and agrees on VCPU_ID outside that mask.
Hardware enforces this at VMRUN, which no longer enters guest mode right away but stalls until the condition holds. Three new exits report that it could not be met, all of them non-fatal:
ESMTP_ILLSIB: a sibling thread is running a vCPU that is not a legal sibling of this one.
ESMTP_TIMEOUT: the stall exceeded the timeout programmed in the VMCB. The timer bounds how long VMRUN waits for the core to settle. A module parameter exposes an interface to program this timer.
ESMTP_RETRY: If DBREQ is detected, VMRUN exits. ESMTP_RETRY indicates an internal event and the hypervisor should execute a VMRUN.
Refer to the AMD64 APM Vol 2, section "AMD64 Enhanced SMT Protection".
--- arch/x86/include/asm/cpufeatures.h | 1 + arch/x86/include/asm/msr-index.h | 1 + arch/x86/include/asm/svm.h | 12 ++++++-- arch/x86/include/uapi/asm/svm.h | 9 +++++- arch/x86/kernel/cpu/scattered.c | 1 + arch/x86/kvm/svm/sev.c | 48 +++++++++++++++++++++++++++++- arch/x86/kvm/svm/svm.c | 7 +++++ 7 files changed, 75 insertions(+), 4 deletions(-)
arch/x86/include/asm/cpufeatures.h +1 -0
@@ -529,6 +529,7 @@* and purposes if CLEAR_CPU_BUF_VM is set). */ #define X86_FEATURE_X2AVIC_EXT (21*32+20)/* AMD SVM x2AVIC support for 4k vCPUs */ +#define X86_FEATURE_AMD_ESMTP (21*32+21)/* AMD Enhanced SMT Protection */ /* * BUG word(s)
arch/x86/include/asm/msr-index.h +1 -0
@@ -761,6 +761,7 @@#define MSR_AMD64_SEG_RMP_ENABLED_BIT 0#define MSR_AMD64_SEG_RMP_ENABLED BIT_ULL(MSR_AMD64_SEG_RMP_ENABLED_BIT)#define MSR_AMD64_RMP_SEGMENT_SHIFT (x) (((x) & GENMASK_ULL(13, 8)) >> 8) +#define MSR_AMD64_IDLE_WAKEUP_ICR 0xc0010137#define MSR_SVSM_CAA 0xc001f000
arch/x86/include/asm/svm.h +10 -2
@@ -165,7 +165,8 @@ struct __attribute__ ((__packed__)) vmcb_control_area {u8 reserved_9[22 ];u64 allowed_sev_features;/* Offset 0x138 */ u64 guest_sev_features;/* Offset 0x140 */ -u8 reserved_10[664 ]; +u64 esmtp_timeout;/* Offset 0x148 */ +u8 reserved_10[656 ];/* * Offset 0x3e0, 32 bytes reserved * for use by hypervisor/software.
@@ -310,6 +311,7 @@ static_assert((X2AVIC_4K_MAX_PHYSICAL_ID & AVIC_PHYSICAL_MAX_INDEX_MASK) == X2AV#define SVM_SEV_FEAT_ALTERNATE_INJECTION BIT(4)#define SVM_SEV_FEAT_DEBUG_SWAP BIT(5)#define SVM_SEV_FEAT_SECURE_TSC BIT(9) +#define SVM_SEV_FEAT_ESMTP BIT(17)#define VMCB_ALLOWED_SEV_FEATURES_VALID BIT_ULL(63)
@@ -482,6 +484,11 @@ struct sev_es_save_area {u8 fpreg_x87[80 ];u8 fpreg_xmm[256 ];u8 fpreg_ymm[256 ]; +u8 reserved_0x670[560 ]; + +/* Enhanced SMT Protection */ +u32 vcpu_id; +u32 vcpu_sibling_mask; } __packed;struct ghcb_save_area {
@@ -554,7 +561,7 @@ struct vmcb {#define EXPECTED_VMCB_SAVE_AREA_SIZE 744#define EXPECTED_GHCB_SAVE_AREA_SIZE 1032 -#define EXPECTED_SEV_ES_SAVE_AREA_SIZE 1648 +#define EXPECTED_SEV_ES_SAVE_AREA_SIZE 2216#define EXPECTED_VMCB_CONTROL_AREA_SIZE 1024#define EXPECTED_GHCB_SIZE PAGE_SIZE
@@ -589,6 +596,7 @@ static inline void __unused_size_checks(void)BUILD_BUG_RESERVED_OFFSET (sev_es_save_area,0x320 );BUILD_BUG_RESERVED_OFFSET (sev_es_save_area,0x380 );BUILD_BUG_RESERVED_OFFSET (sev_es_save_area,0x3f0 ); +BUILD_BUG_RESERVED_OFFSET (sev_es_save_area,0x670 );BUILD_BUG_RESERVED_OFFSET (ghcb_save_area,0x0 );BUILD_BUG_RESERVED_OFFSET (ghcb_save_area,0xcc );
arch/x86/include/uapi/asm/svm.h +8 -1
@@ -135,6 +135,10 @@#define SVM_EXIT_SW 0xf0000000ull#define SVM_EXIT_ERR -1ull +/* Enhanced SMT Protection VM exits taken during VMRUN sibling sync */ +#define SVM_EXIT_ESMTP_ILLSIB -5ull/* Illegal ESMTP sibling */ +#define SVM_EXIT_ESMTP_TIMEOUT -6ull/* ESMTP_TIMEOUT expired */ +#define SVM_EXIT_ESMTP_RETRY -7ull/* Internal event; retry VMRUN */ #define SVM_EXIT_REASONS \ { SVM_EXIT_READ_CR0, "read_cr0" }, \
@@ -246,7 +250,10 @@ { SVM_VMGEXIT_EXT_GUEST_REQUEST, "vmgexit_ext_guest_request" }, \ { SVM_VMGEXIT_AP_CREATION, "vmgexit_ap_creation" }, \ { SVM_VMGEXIT_HV_FEATURES, "vmgexit_hypervisor_feature" }, \ - { SVM_EXIT_ERR, "invalid_guest_state" } + { SVM_EXIT_ERR, "invalid_guest_state" }, \ + { SVM_EXIT_ESMTP_ILLSIB, "esmtp_illsib" }, \ + { SVM_EXIT_ESMTP_TIMEOUT, "esmtp_timeout" }, \ + { SVM_EXIT_ESMTP_RETRY, "esmtp_retry" } #endif /* _UAPI__SVM_H */
arch/x86/kernel/cpu/scattered.c +1 -0
@@ -67,6 +67,7 @@ static const struct cpuid_bit cpuid_bits[] = { { X86_FEATURE_PERFMON_V2, CPUID_EAX, 0, 0x80000022, 0 }, { X86_FEATURE_AMD_LBR_V2, CPUID_EAX, 1, 0x80000022, 0 }, { X86_FEATURE_AMD_LBR_PMC_FREEZE, CPUID_EAX, 2, 0x80000022, 0 }, + { X86_FEATURE_AMD_ESMTP, CPUID_EDX, 1, 0x80000025, 0 }, { X86_FEATURE_AMD_HTR_CORES, CPUID_EAX, 30, 0x80000026, 0 }, { 0, 0, 0, 0, 0 } };
arch/x86/kvm/svm/sev.c +47 -1
84 lines not on this page · raw message
arch/x86/kvm/svm/svm.c +7 -0
@@ -3743,6 +3743,13 @@ static int svm_handle_exit(struct kvm_vcpu *vcpu, fastpath_t exit_fastpath)return 0 ; } +if (svm->vmcb->control.exit_code ==SVM_EXIT_ESMTP_RETRY || + svm->vmcb->control.exit_code ==SVM_EXIT_ESMTP_ILLSIB || + svm->vmcb->control.exit_code ==SVM_EXIT_ESMTP_TIMEOUT ) { +cond_resched (); +return 1 ; + } +if (exit_fastpath !=EXIT_FASTPATH_NONE )return 1 ;
Signature · 1 line
2.43.0
[email protected]
AI reviewRe: [PATCH 2/3] KVM: SVM: Add host support for Enhanced SMT Protection
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider: - [High] MSR_AMD64_IDLE_WAKEUP_ICR is only programmed for online CPUs during module load without CPU…
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [High] MSR_AMD64_IDLE_WAKEUP_ICR is only programmed for online CPUs during module load without CPU hotplug locks, breaking ESMTP on hotplugged CPUs.
- [High] Immediate retry on ESMTP_ILLSIB and ESMTP_TIMEOUT exits with cond_resched() causes a kernel livelock and violates SRCU locking invariants.
- [Medium] Missing teardown of MSR_AMD64_IDLE_WAKEUP_ICR on KVM module unload leads to permanent spurious IPIs.
--
commit 6679aa4cd87f7de484f6cabf547ea6d6220bfceb
Author: Pratik R. Sampat <[email protected]>
KVM: SVM: Add host support for Enhanced SMT Protection
This commit introduces support for Enhanced SMT Protection (ESMTP) to protect SEV-SNP guests from SMT side channels. It adds logic to program the host's wakeup IPIs and handles three new non-fatal VMRUN exits (ESMTP_ILLSIB, ESMTP_TIMEOUT, ESMTP_RETRY) by yielding the CPU.
Quoted 4 lines
arch/x86/kvm/svm/sev.c +0
-0
[ ... ]
arch/x86/kvm/svm/sev.c static const char * __init sev_str_feature_state(bool is_supported, bool is_usable) · line 3068
Quoted 11 lines
arch/x86/kvm/svm/sev.c +7
-0@@ -3045,6 +3059,30 @@ static const char * __init sev_str_feature_state(bool is_supported, bool is_usable)return is_supported ? is_usable ?"enabled" :"unusable" :"disabled" ; } +static bool sev_esmtp_setup_wakeup_icr (void ) +{ +unsigned int cpu, sibling; +bool wrmsr_success = true; + +for_each_online_cpu (cpu) { +for_each_cpu (sibling,topology_sibling_cpumask (cpu)) {
[Severity: High]
Could this break ESMTP on hotplugged CPUs?
This loop only touches currently online CPUs during module load and does so without holding cpus_read_lock(). Because this is a one-time invocation during module init, any CPU brought online after the KVM module is loaded will lack the required MSR programming.
Hardware will then fail to wake the sibling upon CC6 idle, causing VMRUN to indefinitely stall and trigger ESMTP_TIMEOUT exits on those hotplugged CPUs.
Quoted 20 lines
arch/x86/kvm/svm/sev.c +17
-0+u64 icr; +int ret; + +if (sibling == cpu) +continue ; + + icr = (u64 )per_cpu (x86_cpu_to_apicid, sibling) <<32 ; + icr |=LOCAL_TIMER_VECTOR &0xff ; + ret =wrmsrq_safe_on_cpu (cpu,MSR_AMD64_IDLE_WAKEUP_ICR , icr); +if (ret) + wrmsr_success = false; + } + } + +return wrmsr_success; +} +void __init sev_hardware_setup (void ) {unsigned int eax, ebx, ecx, edx, sev_asid_count, sev_es_asid_count;
[ ... ]
arch/x86/kvm/svm/sev.c void __init sev_hardware_setup(void) · line 3265
Quoted 8 lines
arch/x86/kvm/svm/sev.c +4
-0@@ -3221,6 +3259,10 @@ void __init sev_hardware_setup(void)if (sev_snp_enabled && tsc_khz &&cpu_feature_enabled (X86_FEATURE_SNP_SECURE_TSC )) sev_supported_vmsa_features |=SVM_SEV_FEAT_SECURE_TSC ; + +if (sev_snp_enabled &&cpu_feature_enabled (X86_FEATURE_AMD_ESMTP ) && +sev_esmtp_setup_wakeup_icr ()) + sev_supported_vmsa_features |=SVM_SEV_FEAT_ESMTP ;
[Severity: Medium]
Will this lead to permanent spurious IPIs when the KVM module is unloaded?
MSR_AMD64_IDLE_WAKEUP_ICR is programmed globally on all online CPUs to send a local timer IPI when a CPU enters CC6 idle. However, I don't see a teardown path (like in sev_hardware_unsetup) restoring this MSR to zero.
After the KVM module is unloaded, the CPUs will permanently continue sending spurious local timer IPIs to their siblings upon idling, which could cause host power regressions and prevent deep sleep.
Quoted 3 lines
arch/x86/kvm/svm/sev.c +0
-0}void sev_hardware_unsetup (void )
[ ... ]
Quoted 4 lines
arch/x86/kvm/svm/svm.c +0
-0
[ ... ]
arch/x86/kvm/svm/svm.c static int svm_handle_exit(struct kvm_vcpu *vcpu, fastpath_t exit_fastpath) · line 3740
Quoted 10 lines
arch/x86/kvm/svm/svm.c +6
-0@@ -3732,6 +3732,13 @@ static int svm_handle_exit(struct kvm_vcpu *vcpu, fastpath_t exit_fastpath)return 0 ; } +if (svm->vmcb->control.exit_code ==SVM_EXIT_ESMTP_RETRY || + svm->vmcb->control.exit_code ==SVM_EXIT_ESMTP_ILLSIB || + svm->vmcb->control.exit_code ==SVM_EXIT_ESMTP_TIMEOUT ) { +cond_resched (); +return 1 ; + }
[Severity: High]
Does this immediate retry create a kernel livelock and violate SRCU invariants?
If the runqueue has no other tasks (TIF_NEED_RESCHED is false), cond_resched() does nothing. The vCPU immediately attempts VMRUN again, hits the exact same hardware conflict, and exits again. This creates a tight spin loop that can peg the host CPU at 100% utilization.
Additionally, if a task is pending, cond_resched() yields the CPU while holding KVM's SRCU read lock, because svm_handle_exit() is invoked within the vcpu_enter_guest() SRCU critical section. This would stall synchronize_srcu() indefinitely and bypass KVM's safe xfer_to_guest_mode_handle_work() protocol.
Quoted 4 lines
arch/x86/kvm/svm/svm.c +1
-0+if (exit_fastpath !=EXIT_FASTPATH_NONE )return 1 ;
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=2
Re: [PATCH 2/3] KVM: SVM: Add host support for Enhanced SMT Protection
Quoted 38 lines · On 9/14/26 1:13 PM, [email protected] wrote:
[You don't often get email from [email protected]. Learn why this is important at https://aka.ms/LearnAboutSenderIdentification ]
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [High]MSR_AMD64_IDLE_WAKEUP_ICRis only programmed for online CPUs during module load without CPU hotplug locks, breaking ESMTP on hotplugged CPUs.
- [High] Immediate retry onESMTP_ILLSIBandESMTP_TIMEOUTexits withcond_resched()causes a kernel livelock and violates SRCU locking invariants.
- [Medium] Missing teardown ofMSR_AMD64_IDLE_WAKEUP_ICRon KVM module unload leads to permanent spurious IPIs.
--commit
6679aa4cd87f7de484f6cabf547ea6d6220bfceb
Author: Pratik R. Sampat <[email protected]>KVM: SVM: Add host support for Enhanced SMT Protection
This commit introduces support for Enhanced SMT Protection (ESMTP) to protect SEV-SNP guests from SMT side channels. It adds logic to program the host's wakeup IPIs and handles three new non-fatal VMRUN exits (
ESMTP_ILLSIB,ESMTP_TIMEOUT,ESMTP_RETRY) by yielding the CPU.Quoted 4 lines
arch/x86/kvm/svm/sev.c +0
-0[ ... ]
arch/x86/kvm/svm/sev.c static const char * __init sev_str_feature_state(bool is_supported, bool is_usable) · line 3068
Quoted 11 lines
arch/x86/kvm/svm/sev.c +7
-0@@ -3045,6 +3059,30 @@ static const char * __init sev_str_feature_state(bool is_supported, bool is_usable)return is_supported ? is_usable ?"enabled" :"unusable" :"disabled" ; } +static bool sev_esmtp_setup_wakeup_icr (void ) +{ +unsigned int cpu, sibling; +bool wrmsr_success = true; + +for_each_online_cpu (cpu) { +for_each_cpu (sibling,topology_sibling_cpumask (cpu)) {[Severity: High]
Could this break ESMTP on hotplugged CPUs?
Quoted 8 lines
This loop only touches currently online CPUs during module load and does so without holding
cpus_read_lock(). Because this is a one-time invocation during module init, any CPU brought online after the KVM module is loaded will lack the required MSR programming.Hardware will then fail to wake the sibling upon CC6 idle, causing VMRUN to indefinitely stall and trigger
ESMTP_TIMEOUTexits on those hotplugged CPUs.
Having is in the svm_enable_virtualization_cpu() probably makes sense.
Quoted 34 lines
Quoted 21 lines
arch/x86/kvm/svm/sev.c +17
-0+u64 icr; +int ret; + +if (sibling == cpu) +continue ; + + icr = (u64 )per_cpu (x86_cpu_to_apicid, sibling) <<32 ; + icr |=LOCAL_TIMER_VECTOR &0xff ; + ret =wrmsrq_safe_on_cpu (cpu,MSR_AMD64_IDLE_WAKEUP_ICR , icr); +if (ret) + wrmsr_success = false; + } + } + +return wrmsr_success; +} +void __init sev_hardware_setup (void ) {unsigned int eax, ebx, ecx, edx, sev_asid_count, sev_es_asid_count;[ ... ]
arch/x86/kvm/svm/sev.c void __init sev_hardware_setup(void) · line 3265
Quoted 8 lines
arch/x86/kvm/svm/sev.c +4
-0@@ -3221,6 +3259,10 @@ void __init sev_hardware_setup(void)if (sev_snp_enabled && tsc_khz &&cpu_feature_enabled (X86_FEATURE_SNP_SECURE_TSC )) sev_supported_vmsa_features |=SVM_SEV_FEAT_SECURE_TSC ; + +if (sev_snp_enabled &&cpu_feature_enabled (X86_FEATURE_AMD_ESMTP ) && +sev_esmtp_setup_wakeup_icr ()) + sev_supported_vmsa_features |=SVM_SEV_FEAT_ESMTP ;[Severity: Medium]
Will this lead to permanent spurious IPIs when the KVM module is unloaded?
Quoted 8 lines
MSR_AMD64_IDLE_WAKEUP_ICRis programmed globally on all online CPUs to send a local timer IPI when a CPU enters CC6 idle. However, I don't see a teardown path (like insev_hardware_unsetup) restoring this MSR to zero.After the KVM module is unloaded, the CPUs will permanently continue sending spurious local timer IPIs to their siblings upon idling, which could cause host power regressions and prevent deep sleep.
Described this way is likely not possible. If the KVM module is unloaded, an ESMTP enabled guest cannot be spawned. The ICR only fires when a VMEXIT routine of a guest with ESMTP enabled, when a sibling thread is still executing guest code or still trying to complete a VMRUN.
I could clear the MSR in svm_disable_virtualization_cpu() but I don't think that is needed.
Quoted 23 lines
Quoted 3 lines
arch/x86/kvm/svm/sev.c +0
-0}void sev_hardware_unsetup (void )[ ... ]
Quoted 4 lines
arch/x86/kvm/svm/svm.c +0
-0[ ... ]
arch/x86/kvm/svm/svm.c static int svm_handle_exit(struct kvm_vcpu *vcpu, fastpath_t exit_fastpath) · line 3740
Quoted 10 lines
arch/x86/kvm/svm/svm.c +6
-0@@ -3732,6 +3732,13 @@ static int svm_handle_exit(struct kvm_vcpu *vcpu, fastpath_t exit_fastpath)return 0 ; } +if (svm->vmcb->control.exit_code ==SVM_EXIT_ESMTP_RETRY || + svm->vmcb->control.exit_code ==SVM_EXIT_ESMTP_ILLSIB || + svm->vmcb->control.exit_code ==SVM_EXIT_ESMTP_TIMEOUT ) { +cond_resched (); +return 1 ; + }[Severity: High]
Does this immediate retry create a kernel livelock and violate SRCU invariants?
Quoted 5 lines
If the runqueue has no other tasks (
TIF_NEED_RESCHEDis false),cond_resched()does nothing. The vCPU immediately attempts VMRUN again, hits the exact same hardware conflict, and exits again. This creates a tight spin loop that can peg the host CPU at 100% utilization.
Right, the retry can spin, but mainly only for ILLSIB. This also seems more likely to occur when vCPUs are pinned. RETRY and TIMEOUT are transient by construction.
Having said that, I was toying with the idea of having bounded number of consecutive retries and that would fix it entirely.
Quoted 6 lines
Additionally, if a task is pending,
cond_resched()yields the CPU while holding KVM's SRCU read lock, becausesvm_handle_exit()is invoked within thevcpu_enter_guest()SRCU critical section. This would stallsynchronize_srcu()indefinitely and bypass KVM's safexfer_to_guest_mode_handle_work()protocol.
Yeah, cond_resched() seems like the wrong thing to do here. Although probably for a different reason. It consumes NEED_RESCHED with kvm->srcu held, so the outer unlock-then-schedule() path is skipped. It is a worse preemption point than the one KVM already has. I will drop it and plain return 1 instead.
Quoted 7 lines
arch/x86/kvm/svm/svm.c static int svm_handle_exit(struct kvm_vcpu *vcpu, fastpath_t exit_fastpath) · line 3755
Quoted 4 lines
arch/x86/kvm/svm/svm.c +1
-0+if (exit_fastpath !=EXIT_FASTPATH_NONE )return 1 ;--
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=2
Re: [PATCH 2/3] KVM: SVM: Add host support for Enhanced SMT Protection
In reply to Pratik R. Sampatarch/x86/include/asm/cpufeatures.h line 532
Quoted 9 lines · Pratik R. Sampat
arch/x86/include/asm/cpufeatures.h +1
-0@@ -529,6 +529,7 @@* and purposes if CLEAR_CPU_BUF_VM is set). */ #define X86_FEATURE_X2AVIC_EXT (21*32+20)/* AMD SVM x2AVIC support for 4k vCPUs */ +#define X86_FEATURE_AMD_ESMTP (21*32+21)/* AMD Enhanced SMT Protection */
For the non-virt bits like this one and in scattered.c:
And Sashiko has comments:
https://sashiko.dev/#/patchset/cover.1789399214.git.prsampat%40amd.com
Please address them: if valid, fix them, if not, explain why they don't need to be fixed.
Thx.
Signature · 4 lines
Regards/Gruss,
Boris.
https://people.kernel.org/tglx/notes-about-netiquetteRe: [PATCH 2/3] KVM: SVM: Add host support for Enhanced SMT Protection
Quoted 13 lines · Borislav Petkov
arch/x86/include/asm/cpufeatures.h line 532
Quoted 9 lines · Pratik R. Sampat
arch/x86/include/asm/cpufeatures.h +1
-0@@ -529,6 +529,7 @@* and purposes if CLEAR_CPU_BUF_VM is set). */ #define X86_FEATURE_X2AVIC_EXT (21*32+20)/* AMD SVM x2AVIC support for 4k vCPUs */ +#define X86_FEATURE_AMD_ESMTP (21*32+21)/* AMD Enhanced SMT Protection */ For the non-virt bits like this one and in
scattered.c:
Quoted 2 lines
Thanks, Boris!
Quoted 6 lines
And Sashiko has comments:
https://sashiko.dev/#/patchset/cover.1789399214.git.prsampat%40amd.com
Please address them: if valid, fix them, if not, explain why they don't need to be fixed.
Ack, will do.
Thanks!
--Pratik
PATCH 3/3 x86/sev: Add guest support for Enhanced SMT Protection
In reply to Pratik R. SampatEnhanced SMT Protection requires every VMSA to carry the vCPU's identity and the mask of SMT siblings it may co-run with. The guest builds the VMSA itself when bringing up an AP, so populate both fields there, before the page is turned into a VMSA and while it is still writable.
Fully set the sibling mask so that all threads of the same guest trust each other.
--- arch/x86/boot/compressed/sev.c | 2 +- arch/x86/coco/sev/core.c | 13 +++++++++++++ arch/x86/include/asm/msr-index.h | 4 +++- 3 files changed, 17 insertions(+), 2 deletions(-)
arch/x86/boot/compressed/sev.c +1 -1
@@ -188,7 +188,7 @@ bool sev_es_check_ghcb_fault(unsigned long address)MSR_AMD64_SNP_RESERVED_BIT13 | \MSR_AMD64_SNP_RESERVED_BIT15 | \MSR_AMD64_SNP_SECURE_AVIC | \ -MSR_AMD64_SNP_RESERVED_BITS19_22 | \ +MSR_AMD64_SNP_RESERVED_BITS20_22 | \ MSR_AMD64_SNP_RESERVED_MASK) #ifdef CONFIG_AMD_SECURE_AVIC
arch/x86/coco/sev/core.c +13 -0
@@ -89,6 +89,7 @@ static const char * const sev_status_feat_names[] = { [MSR_AMD64_SNP_VMSA_REG_PROT_BIT] = "VMSARegProt", [MSR_AMD64_SNP_SMT_PROT_BIT] = "SMTProt", [MSR_AMD64_SNP_SECURE_AVIC_BIT] = "SecureAVIC", + [MSR_AMD64_SNP_ESMT_PROT_BIT] = "ESMTProt", [MSR_AMD64_SNP_IBPB_ON_ENTRY_BIT] = "IBPBOnEntry", };
@@ -849,6 +850,18 @@ static int wakeup_cpu_via_vmgexit(u32 apic_id, unsigned long start_ip, unsigned vmsa->vmpl = snp_vmpl; vmsa->sev_features = sev_status >>2 ; +if (cc_platform_has (CC_ATTR_GUEST_SEV_SNP ) && + (sev_status &MSR_AMD64_SNP_ESMT_PROT )) { + vmsa->vcpu_id = apic_id; +/* +* The mask fully set puts every vCPU in one group, so any two +* of them may be co-resident. A legal ESMTP sibling must +* also match on ASID, so the sibling of a vCPU in guest mode is +* always either another vCPU of this same guest or idle. +*/ + vmsa->vcpu_sibling_mask =U32_MAX ; + } +/* Populate AP's TSC scale/offset to get accurate TSC values. */ if (cc_platform_has (CC_ATTR_GUEST_SNP_SECURE_TSC )) { vmsa->tsc_scale = snp_tsc_scale;
arch/x86/include/asm/msr-index.h +3 -1
@@ -745,7 +745,9 @@#define MSR_AMD64_SNP_SMT_PROT BIT_ULL(MSR_AMD64_SNP_SMT_PROT_BIT)#define MSR_AMD64_SNP_SECURE_AVIC_BIT 18#define MSR_AMD64_SNP_SECURE_AVIC BIT_ULL(MSR_AMD64_SNP_SECURE_AVIC_BIT) -#define MSR_AMD64_SNP_RESERVED_BITS19_22 GENMASK_ULL(22, 19) +#define MSR_AMD64_SNP_ESMT_PROT_BIT 19 +#define MSR_AMD64_SNP_ESMT_PROT BIT_ULL(MSR_AMD64_SNP_ESMT_PROT_BIT) +#define MSR_AMD64_SNP_RESERVED_BITS20_22 GENMASK_ULL(22, 20)#define MSR_AMD64_SNP_IBPB_ON_ENTRY_BIT 23#define MSR_AMD64_SNP_IBPB_ON_ENTRY BIT_ULL(MSR_AMD64_SNP_IBPB_ON_ENTRY_BIT)#define MSR_AMD64_SNP_RESV_BIT 24
Signature · 1 line
2.43.0
[email protected]
AI reviewRe: [PATCH 3/3] x86/sev: Add guest support for Enhanced SMT Protection
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider: - [High] Hyper-V SEV-SNP AP boot path entirely ignores ESMT, leaving VMSA fields as zeroes. - [Low] The…
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] Hyper-V SEV-SNP AP boot path entirely ignores ESMT, leaving VMSA fields as zeroes.
- [Low] The tools header for msr-index.h was not synchronized with the kernel header changes. --
commit 8604f276ddd2e9fc69ba0b3ddf175ec09324c70a
Author: Pratik R. Sampat <[email protected]>
x86/sev: Add guest support for Enhanced SMT Protection
This commit enables guest support for Enhanced SMT Protection by populating the vCPU's identity and SMT sibling mask in the VMSA during AP bringup. The sibling mask is fully set to allow threads of the same guest to be co-resident.
Quoted 4 lines
arch/x86/coco/sev/core.c +0
-0
[ ... ]
Quoted 8 lines
arch/x86/coco/sev/core.c +4
-0@@ -849,6 +850,18 @@ static int wakeup_cpu_via_vmgexit(u32 apic_id, unsigned long start_ip, unsigned vmsa->vmpl = snp_vmpl; vmsa->sev_features = sev_status >>2 ; +if (cc_platform_has (CC_ATTR_GUEST_SEV_SNP ) && + (sev_status &MSR_AMD64_SNP_ESMT_PROT )) { + vmsa->vcpu_id = apic_id; +/*
arch/x86/coco/sev/core.c static int wakeup_cpu_via_vmgexit(u32 apic_id, unsigned long start_ip, unsigned · line 866
Quoted 10 lines
arch/x86/coco/sev/core.c +8
-0+* The mask fully set puts every vCPU in one group, so any two +* of them may be co-resident. A legal ESMTP sibling must +* also match on ASID, so the sibling of a vCPU in guest mode is +* always either another vCPU of this same guest or idle. +*/ + vmsa->vcpu_sibling_mask =U32_MAX ; + } +/* Populate AP's TSC scale/offset to get accurate TSC values. */ if (cc_platform_has (CC_ATTR_GUEST_SNP_SECURE_TSC )) {
[Severity: High]
Does the Hyper-V SEV-SNP AP boot path also need to initialize ESMT fields?
Looking at hv_snp_boot_ap() in arch/x86/hyperv/ivm.c, the VMSA is initialized without the new ESMT fields:
arch/x86/hyperv/ivm.c:hv_snp_boot_ap() {
...
vmsa->vmpl = 0;
vmsa->sev_features = sev_status >> 2;
ret = snp_set_vmsa(vmsa, true);
...
}If a Hyper-V SEV-SNP guest with >1 vCPUs is booted with ESMT enabled, the APs will be launched with a sibling mask of 0. A mask of 0 does not intersect with any other mask, which could prevent the AP from being co-scheduled with any sibling, leading to a hardware violation or a failure to boot APs.
arch/x86/include/asm/msr-index.h line 750
Quoted 12 lines
arch/x86/include/asm/msr-index.h +3
-1@@ -745,7 +745,9 @@#define MSR_AMD64_SNP_SMT_PROT BIT_ULL(MSR_AMD64_SNP_SMT_PROT_BIT)#define MSR_AMD64_SNP_SECURE_AVIC_BIT 18#define MSR_AMD64_SNP_SECURE_AVIC BIT_ULL(MSR_AMD64_SNP_SECURE_AVIC_BIT) -#define MSR_AMD64_SNP_RESERVED_BITS19_22 GENMASK_ULL(22, 19) +#define MSR_AMD64_SNP_ESMT_PROT_BIT 19 +#define MSR_AMD64_SNP_ESMT_PROT BIT_ULL(MSR_AMD64_SNP_ESMT_PROT_BIT) +#define MSR_AMD64_SNP_RESERVED_BITS20_22 GENMASK_ULL(22, 20)
[Severity: Low]
Does tools/arch/x86/include/asm/msr-index.h need to be synchronized with these changes?
Currently, MSR_AMD64_SNP_RESERVED_BITS19_22 remains defined in the tools header without the ESMT_PROT definitions. This missed synchronization could lead to inconsistencies or warnings when building tools that depend on this header.
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=3
Re: [PATCH 3/3] x86/sev: Add guest support for Enhanced SMT Protection
Quoted 56 lines · On 9/14/26 1:11 PM, [email protected] wrote:
[You don't often get email from [email protected]. Learn why this is important at https://aka.ms/LearnAboutSenderIdentification ]
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] Hyper-V SEV-SNP AP boot path entirely ignores ESMT, leaving VMSA fields as zeroes.
- [Low] The tools header formsr-index.hwas not synchronized with the kernel header changes. --commit
8604f276ddd2e9fc69ba0b3ddf175ec09324c70a
Author: Pratik R. Sampat <[email protected]>x86/sev: Add guest support for Enhanced SMT Protection
This commit enables guest support for Enhanced SMT Protection by populating the vCPU's identity and SMT sibling mask in the VMSA during AP bringup. The sibling mask is fully set to allow threads of the same guest to be co-resident.
Quoted 4 lines
arch/x86/coco/sev/core.c +0
-0[ ... ]
Quoted 8 lines
arch/x86/coco/sev/core.c +4
-0@@ -849,6 +850,18 @@ static int wakeup_cpu_via_vmgexit(u32 apic_id, unsigned long start_ip, unsigned vmsa->vmpl = snp_vmpl; vmsa->sev_features = sev_status >>2 ; +if (cc_platform_has (CC_ATTR_GUEST_SEV_SNP ) && + (sev_status &MSR_AMD64_SNP_ESMT_PROT )) { + vmsa->vcpu_id = apic_id; +/* arch/x86/coco/sev/core.c static int wakeup_cpu_via_vmgexit(u32 apic_id, unsigned long start_ip, unsigned · line 866
Quoted 10 lines
arch/x86/coco/sev/core.c +8
-0+* The mask fully set puts every vCPU in one group, so any two +* of them may be co-resident. A legal ESMTP sibling must +* also match on ASID, so the sibling of a vCPU in guest mode is +* always either another vCPU of this same guest or idle. +*/ + vmsa->vcpu_sibling_mask =U32_MAX ; + } +/* Populate AP's TSC scale/offset to get accurate TSC values. */ if (cc_platform_has (CC_ATTR_GUEST_SNP_SECURE_TSC )) {[Severity: High]
Does the Hyper-V SEV-SNP AP boot path also need to initialize ESMT fields?Looking at
hv_snp_boot_ap()inarch/x86/hyperv/ivm.c, the VMSA is initialized without the new ESMT fields:arch/x86/hyperv/ivm.c:hv_snp_boot_ap() { ... vmsa->vmpl = 0; vmsa->sev_features = sev_status >> 2; ret = snp_set_vmsa(vmsa, true); ... }
Quoted 4 lines
If a Hyper-V SEV-SNP guest with >1 vCPUs is booted with ESMT enabled, the APs will be launched with a sibling mask of 0. A mask of 0 does not intersect with any other mask, which could prevent the AP from being co-scheduled with any sibling, leading to a hardware violation or a failure to boot APs.
Yes would need to replicate the same for Hyper-V.
Quoted 18 lines
arch/x86/include/asm/msr-index.h line 750
Quoted 13 lines
arch/x86/include/asm/msr-index.h +3
-1@@ -745,7 +745,9 @@#define MSR_AMD64_SNP_SMT_PROT BIT_ULL(MSR_AMD64_SNP_SMT_PROT_BIT)#define MSR_AMD64_SNP_SECURE_AVIC_BIT 18#define MSR_AMD64_SNP_SECURE_AVIC BIT_ULL(MSR_AMD64_SNP_SECURE_AVIC_BIT) -#define MSR_AMD64_SNP_RESERVED_BITS19_22 GENMASK_ULL(22, 19) +#define MSR_AMD64_SNP_ESMT_PROT_BIT 19 +#define MSR_AMD64_SNP_ESMT_PROT BIT_ULL(MSR_AMD64_SNP_ESMT_PROT_BIT) +#define MSR_AMD64_SNP_RESERVED_BITS20_22 GENMASK_ULL(22, 20)[Severity: Low]
Doestools/arch/x86/include/asm/msr-index.hneed to be synchronized with these changes?
Quoted 5 lines
Currently,
MSR_AMD64_SNP_RESERVED_BITS19_22remains defined in the tools header without theESMT_PROTdefinitions. This missed synchronization could lead to inconsistencies or warnings when building tools that depend on this header.
Ack.
Quoted 2 lines
--
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=3