* [Patch v2 0/4] Introduce Enhanced SMT Protection for SEV-SNP
@ 2026-10-06 16:54 Pratik R. Sampat
2026-10-06 16:54 ` [Patch v2 1/4] KVM: SVM: Re-queue events that were never injected Pratik R. Sampat
` (3 more replies)
0 siblings, 4 replies; 14+ messages in thread
From: Pratik R. Sampat @ 2026-10-06 16:54 UTC (permalink / raw)
To: kvm, x86, linux-kernel
Cc: tglx, mingo, bp, dave.hansen, seanjc, pbonzini, thomas.lendacky,
kim.phillips, nikunj, michael.roth, ashish.kalra, prsampat
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 (unchanged from v1).
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
v2:
* Move idle wakeup ICR programming to svm_enable_virtualization_cpu()
instead of sev_hardware_setup() - Sashiko
* Remove cond_sched() in ESMTP exit paths - Sashiko
* Add a VMSA builing of ESMTP fields for hyperv - Sashiko
* Add ESMTP to SNP_FEATURES_IMPL and SNP_FEATURES_IMPL_REQ - Local
Claude Sashiko instance
* Cover hotplug CPUs / SMT changes by programming the ICR for all CPUs
- local Claude Sashiko instance
* Add esmtp timeout documentation to kernel paramters
Not syncing msr-index changes since several bits apart from ESMTP are
also changed and perf tooling maintainers generally sync that. However,
if needed I drop in a patch that syncs the MSRs too.
v1: https://lore.kernel.org/kvm/cover.1789399214.git.prsampat@amd.com
[1]: https://github.com/tianocore/edk2/pull/13128
[2]: https://lore.kernel.org/qemu-devel/cover.1789399242.git.prsampat@amd.com/
Pratik R. Sampat (4):
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
x86/hyperv: Add guest support for Enhanced SMT Protection
.../admin-guide/kernel-parameters.txt | 19 ++++++++
arch/x86/boot/compressed/sev.c | 6 ++-
arch/x86/coco/sev/core.c | 13 +++++
arch/x86/hyperv/ivm.c | 11 +++++
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 | 41 ++++++++++++++--
arch/x86/kvm/svm/svm.h | 2 +
12 files changed, 157 insertions(+), 11 deletions(-)
--
2.43.0
^ permalink raw reply [flat|nested] 14+ messages in thread* [Patch v2 1/4] KVM: SVM: Re-queue events that were never injected 2026-10-06 16:54 [Patch v2 0/4] Introduce Enhanced SMT Protection for SEV-SNP Pratik R. Sampat @ 2026-10-06 16:54 ` Pratik R. Sampat 2026-10-06 17:12 ` sashiko-bot 2026-10-09 19:21 ` Tom Lendacky 2026-10-06 16:54 ` [Patch v2 2/4] KVM: SVM: Add host support for Enhanced SMT Protection Pratik R. Sampat ` (2 subsequent siblings) 3 siblings, 2 replies; 14+ messages in thread From: Pratik R. Sampat @ 2026-10-06 16:54 UTC (permalink / raw) To: kvm, x86, linux-kernel Cc: tglx, mingo, bp, dave.hansen, seanjc, pbonzini, thomas.lendacky, kim.phillips, nikunj, michael.roth, ashish.kalra, prsampat 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 forever. 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. Signed-off-by: Pratik R. Sampat <prsampat@amd.com> --- v1..v2: No changes --- arch/x86/kvm/svm/svm.c | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c index 7d59d301e1e5..5d15c706e43b 100644 --- a/arch/x86/kvm/svm/svm.c +++ b/arch/x86/kvm/svm/svm.c @@ -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); } -- 2.43.0 ^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: [Patch v2 1/4] KVM: SVM: Re-queue events that were never injected 2026-10-06 16:54 ` [Patch v2 1/4] KVM: SVM: Re-queue events that were never injected Pratik R. Sampat @ 2026-10-06 17:12 ` sashiko-bot 2026-10-09 19:21 ` Tom Lendacky 1 sibling, 0 replies; 14+ messages in thread From: sashiko-bot @ 2026-10-06 17:12 UTC (permalink / raw) To: Pratik R. Sampat; +Cc: kvm Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: - [High] kvm: svm: unconditional use of non-zero EVENTINJ without VALID check clobbers EXITINTINFO -- commit ccdc89849239002e8efbee8f8c5f359259c07989 Author: Pratik R. Sampat <prsampat@amd.com> KVM: SVM: Re-queue events that were never injected This commit modifies SVM to re-queue undelivered events from the EVENTINJ field to EXITINTINFO upon #VMEXIT. It accommodates cases like Enhanced SMT Protection where VMRUN might stall and exit without entering guest mode. > diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c > index d0971685034b9..e2be2cd86c320 100644 > --- a/arch/x86/kvm/svm/svm.c > +++ b/arch/x86/kvm/svm/svm.c [ ... ] > @@ -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 > + * 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] Is it possible for a stale EVENTINJ to clobber a valid EXITINTINFO here in svm_complete_interrupts() in arch/x86/kvm/svm/svm.c? By checking for a non-zero value instead of checking the explicit VALID bit, this path might unconditionally overwrite EXITINTINFO when EVENTINJ has a leftover value with its VALID bit cleared. Since initial nested parameters and valid bit clearance are permitted by KVM's nested_svm_check_event_inj(), would a hardware exit with a valid fault record in EXITINTINFO be overwritten by the stale EVENTINJ? Could this lead to silent dropping of legitimate L2 hardware events such as page faults, debug exceptions, or machine checks during event delivery, resulting in nested guest corruption? > + 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 -- Sashiko AI review · https://sashiko.dev/#/patchset/cover.1791302373.git.prsampat@amd.com?part=1 ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [Patch v2 1/4] KVM: SVM: Re-queue events that were never injected 2026-10-06 16:54 ` [Patch v2 1/4] KVM: SVM: Re-queue events that were never injected Pratik R. Sampat 2026-10-06 17:12 ` sashiko-bot @ 2026-10-09 19:21 ` Tom Lendacky 1 sibling, 0 replies; 14+ messages in thread From: Tom Lendacky @ 2026-10-09 19:21 UTC (permalink / raw) To: Pratik R. Sampat, kvm, x86, linux-kernel Cc: tglx, mingo, bp, dave.hansen, seanjc, pbonzini, kim.phillips, nikunj, michael.roth, ashish.kalra On 10/6/26 11:54, Pratik R. Sampat wrote: > 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 forever. > > 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. > > Signed-off-by: Pratik R. Sampat <prsampat@amd.com> Reviewed-by: Tom Lendacky <thomas.lendacky@amd.com> > --- > v1..v2: No changes > --- > arch/x86/kvm/svm/svm.c | 33 +++++++++++++++++++++++++++++---- > 1 file changed, 29 insertions(+), 4 deletions(-) > > diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c > index 7d59d301e1e5..5d15c706e43b 100644 > --- a/arch/x86/kvm/svm/svm.c > +++ b/arch/x86/kvm/svm/svm.c > @@ -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); > } > ^ permalink raw reply [flat|nested] 14+ messages in thread
* [Patch v2 2/4] KVM: SVM: Add host support for Enhanced SMT Protection 2026-10-06 16:54 [Patch v2 0/4] Introduce Enhanced SMT Protection for SEV-SNP Pratik R. Sampat 2026-10-06 16:54 ` [Patch v2 1/4] KVM: SVM: Re-queue events that were never injected Pratik R. Sampat @ 2026-10-06 16:54 ` Pratik R. Sampat 2026-10-06 17:08 ` sashiko-bot 2026-10-09 19:05 ` Tom Lendacky 2026-10-06 16:55 ` [Patch v2 3/4] x86/sev: Add guest " Pratik R. Sampat 2026-10-06 16:55 ` [Patch v2 4/4] x86/hyperv: " Pratik R. Sampat 3 siblings, 2 replies; 14+ messages in thread From: Pratik R. Sampat @ 2026-10-06 16:54 UTC (permalink / raw) To: kvm, x86, linux-kernel Cc: tglx, mingo, bp, dave.hansen, seanjc, pbonzini, thomas.lendacky, kim.phillips, nikunj, michael.roth, ashish.kalra, prsampat Enhanced 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". Acked-by: Borislav Petkov (AMD) <bp@alien8.de> # non-virtualization changes Signed-off-by: Pratik R. Sampat <prsampat@amd.com> --- v1..v2 * Move idle wakeup ICR programming to svm_enable_virtualization_cpu() instead of sev_hardware_setup() * Remove cond_sched() in ESMTP exit paths * Program the IDLE_WAKEUP_ICR for all present CPU siblings * Add documentation for ESMTP timeout --- .../admin-guide/kernel-parameters.txt | 19 ++++++++ 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 | 8 ++++ arch/x86/kvm/svm/svm.h | 2 + 9 files changed, 97 insertions(+), 4 deletions(-) diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index 68647ff4bdd2..e09f18c0de34 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -3240,6 +3240,25 @@ Kernel parameters max_snp_asid == min_sev_asid-1, will effectively make SEV-ES unusable. + kvm-amd.esmtp_timeout_ns= + [KVM,AMD] Enhanced SMT Protection (ESMTP) VMRUN + timeout, in nanoseconds, for SEV-SNP guests that enable + ESMTP. When an ESMTP vCPU executes VMRUN, hardware + waits for every sibling thread to either be idle or + run a legal sibling vCPU of the same guest before + entering guest mode. If the wait exceeds this timeout, + VMRUN exits with VMEXIT_ESMTP_TIMEOUT and KVM retries + the VMRUN. + + The value is converted to TSC cycles and programmed + into the VMCB when a vCPU is initialized, so changing + it at runtime only affects vCPUs that are created or + reset afterwards. + + Default is 0, which disables the timeout, i.e. VMRUN + waits until the sibling condition is met or a physical + interrupt arrives. + kvm-arm.mode= [KVM,ARM,EARLY] Select one of KVM/arm64's modes of operation. diff --git a/arch/x86/include/asm/cpufeatures.h b/arch/x86/include/asm/cpufeatures.h index f70ee74b5f92..4cf477e95c58 100644 --- a/arch/x86/include/asm/cpufeatures.h +++ b/arch/x86/include/asm/cpufeatures.h @@ -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) diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h index 3a8e51a0c9e8..fbcb3313e946 100644 --- a/arch/x86/include/asm/msr-index.h +++ b/arch/x86/include/asm/msr-index.h @@ -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 diff --git a/arch/x86/include/asm/svm.h b/arch/x86/include/asm/svm.h index aa63431ba92c..323ab7089302 100644 --- a/arch/x86/include/asm/svm.h +++ b/arch/x86/include/asm/svm.h @@ -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); diff --git a/arch/x86/include/uapi/asm/svm.h b/arch/x86/include/uapi/asm/svm.h index 010a45c9f614..e59baf4b3c3f 100644 --- a/arch/x86/include/uapi/asm/svm.h +++ b/arch/x86/include/uapi/asm/svm.h @@ -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 */ diff --git a/arch/x86/kernel/cpu/scattered.c b/arch/x86/kernel/cpu/scattered.c index 8665a6474806..16620fa0e290 100644 --- a/arch/x86/kernel/cpu/scattered.c +++ b/arch/x86/kernel/cpu/scattered.c @@ -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 } }; diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c index 5705723f1f41..df836dfe3e55 100644 --- a/arch/x86/kvm/svm/sev.c +++ b/arch/x86/kvm/svm/sev.c @@ -67,6 +67,11 @@ module_param_named(sev_snp, sev_snp_enabled, bool, 0444); static unsigned int __ro_after_init nr_ciphertext_hiding_asids; module_param_named(ciphertext_hiding_asids, nr_ciphertext_hiding_asids, uint, 0444); +static unsigned long esmtp_timeout_ns; +module_param(esmtp_timeout_ns, ulong, 0644); +MODULE_PARM_DESC(esmtp_timeout_ns, + "ESMTP VMRUN sibling-wait timeout in nanoseconds (0 disables the timer)"); + #define AP_RESET_HOLD_NONE 0 #define AP_RESET_HOLD_NAE_EVENT 1 #define AP_RESET_HOLD_MSR_PROTO 2 @@ -506,7 +511,7 @@ static int __sev_guest_init(struct kvm *kvm, struct kvm_sev_cmd *argp, return -EINVAL; if (!snp_active) - valid_vmsa_features &= ~SVM_SEV_FEAT_SECURE_TSC; + valid_vmsa_features &= ~(SVM_SEV_FEAT_SECURE_TSC | SVM_SEV_FEAT_ESMTP); if (data->vmsa_features & ~valid_vmsa_features) return -EINVAL; @@ -1021,6 +1026,15 @@ static int sev_es_sync_vmsa(struct vcpu_svm *svm) save->sev_features = sev->vmsa_features; + if (sev->vmsa_features & SVM_SEV_FEAT_ESMTP) { + save->vcpu_id = vcpu->vcpu_id; + /* + * All vCPUs of a guest are put into one group and can be run + * co-resident on the sibling thread of the same core. + */ + save->vcpu_sibling_mask = U32_MAX; + } + /* * Skip FPU and AVX setup with KVM_SEV_ES_INIT to avoid * breaking older measurements. @@ -3259,6 +3273,9 @@ 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_supported_vmsa_features |= SVM_SEV_FEAT_ESMTP; } void sev_hardware_unsetup(void) @@ -3290,6 +3307,31 @@ int sev_cpu_init(struct svm_cpu_data *sd) return 0; } +void sev_esmtp_enable_wakeup_icr(void) +{ + unsigned int cpu, sibling, shift; + u32 core; + + if (!(sev_supported_vmsa_features & SVM_SEV_FEAT_ESMTP)) + return; + + cpu = raw_smp_processor_id(); + shift = topology_get_domain_shift(TOPO_CORE_DOMAIN); + core = per_cpu(x86_cpu_to_apicid, cpu) >> shift; + + for_each_present_cpu(sibling) { + u32 apicid = per_cpu(x86_cpu_to_apicid, sibling); + u64 icr; + + if (sibling == cpu || (apicid >> shift) != core) + continue; + + icr = (u64)apicid << 32; + icr |= LOCAL_TIMER_VECTOR; + WARN_ON_ONCE(wrmsrq_safe(MSR_AMD64_IDLE_WAKEUP_ICR, icr)); + } +} + /* * Pages used by hardware to hold guest encrypted state must be flushed before * returning them to the system. @@ -4792,6 +4834,10 @@ static void sev_es_init_vmcb(struct vcpu_svm *svm, bool init_event) svm->vmcb->control.allowed_sev_features = sev->vmsa_features | VMCB_ALLOWED_SEV_FEATURES_VALID; + if (sev->vmsa_features & SVM_SEV_FEAT_ESMTP) + svm->vmcb->control.esmtp_timeout = mul_u64_u32_div(esmtp_timeout_ns, + tsc_khz, 1000000); + /* Can't intercept CR register access, HV can't modify CR registers */ svm_clr_intercept(svm, INTERCEPT_CR0_READ); svm_clr_intercept(svm, INTERCEPT_CR4_READ); diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c index 5d15c706e43b..624675a12d51 100644 --- a/arch/x86/kvm/svm/svm.c +++ b/arch/x86/kvm/svm/svm.c @@ -591,6 +591,8 @@ static int svm_enable_virtualization_cpu(void) __svm_write_tsc_multiplier(SVM_TSC_RATIO_DEFAULT); } + sev_esmtp_enable_wakeup_icr(); + svm_init_os_visible_workarounds(); svm_init_erratum_383(); @@ -3743,6 +3745,12 @@ 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) { + return 1; + } + if (exit_fastpath != EXIT_FASTPATH_NONE) return 1; diff --git a/arch/x86/kvm/svm/svm.h b/arch/x86/kvm/svm/svm.h index e958943b8162..8cd8b825c9a0 100644 --- a/arch/x86/kvm/svm/svm.h +++ b/arch/x86/kvm/svm/svm.h @@ -1008,6 +1008,7 @@ void __init sev_set_cpu_caps(void); void __init sev_hardware_setup(void); void sev_hardware_unsetup(void); int sev_cpu_init(struct svm_cpu_data *sd); +void sev_esmtp_enable_wakeup_icr(void); int sev_dev_get_attr(u32 group, u64 attr, u64 *val); extern unsigned int max_sev_asid; void sev_handle_rmp_fault(struct kvm_vcpu *vcpu, gpa_t gpa, u64 error_code); @@ -1036,6 +1037,7 @@ static inline void __init sev_set_cpu_caps(void) {} static inline void __init sev_hardware_setup(void) {} static inline void sev_hardware_unsetup(void) {} static inline int sev_cpu_init(struct svm_cpu_data *sd) { return 0; } +static inline void sev_esmtp_enable_wakeup_icr(void) {} static inline int sev_dev_get_attr(u32 group, u64 attr, u64 *val) { return -ENXIO; } #define max_sev_asid 0 static inline void sev_handle_rmp_fault(struct kvm_vcpu *vcpu, gpa_t gpa, u64 error_code) {} -- 2.43.0 ^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: [Patch v2 2/4] KVM: SVM: Add host support for Enhanced SMT Protection 2026-10-06 16:54 ` [Patch v2 2/4] KVM: SVM: Add host support for Enhanced SMT Protection Pratik R. Sampat @ 2026-10-06 17:08 ` sashiko-bot 2026-10-09 19:05 ` Tom Lendacky 1 sibling, 0 replies; 14+ messages in thread From: sashiko-bot @ 2026-10-06 17:08 UTC (permalink / raw) To: Pratik R. Sampat; +Cc: kvm Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: - [High] kvm: svm: host #DE panic when esmtp_timeout_ns is excessively large -- commit ec4daa3c1cc021f9f7a5cc29bfa1c4493cc845b8 Author: Pratik R. Sampat <prsampat@amd.com> Subject: KVM: SVM: Add host support for Enhanced SMT Protection Enhanced SMT Protection (ESMTP) protects SEV-SNP guests from SMT side channels by stalling VMRUN until sibling threads are idle or running legal sibling vCPUs. This commit introduces the hardware enforcement logic, non-fatal exit handling, and a configurable timeout parameter. > diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c > index 944aaea6501f2..24701f06fce81 100644 > --- a/arch/x86/kvm/svm/sev.c > +++ b/arch/x86/kvm/svm/sev.c [ ... ] > @@ -67,6 +67,11 @@ module_param_named(sev_snp, sev_snp_enabled, bool, 0444); > static unsigned int __ro_after_init nr_ciphertext_hiding_asids; > module_param_named(ciphertext_hiding_asids, nr_ciphertext_hiding_asids, uint, 0444); > > +static unsigned long esmtp_timeout_ns; > +module_param(esmtp_timeout_ns, ulong, 0644); > +MODULE_PARM_DESC(esmtp_timeout_ns, > + "ESMTP VMRUN sibling-wait timeout in nanoseconds (0 disables the timer)"); > + [ ... ] > @@ -4708,6 +4750,10 @@ static void sev_es_init_vmcb(struct vcpu_svm *svm, bool init_event) > svm->vmcb->control.allowed_sev_features = sev->vmsa_features | > VMCB_ALLOWED_SEV_FEATURES_VALID; > > + if (sev->vmsa_features & SVM_SEV_FEAT_ESMTP) > + svm->vmcb->control.esmtp_timeout = mul_u64_u32_div(esmtp_timeout_ns, > + tsc_khz, 1000000); [Severity: High] Since esmtp_timeout_ns is writable by root (0644) without bounds validation, could a very large value here trigger a host kernel panic? The mul_u64_u32_div() function relies on the x86 divq instruction. If the resulting 128-by-64 bit division quotient does not fit in 64 bits (for example, if esmtp_timeout_ns is set near ULONG_MAX), divq unconditionally raises a #DE (Divide Error) exception. Because there is no exception table entry for this instruction in mul_u64_add_u64_div_u64(), this leads to an immediate panic. Would it be safer to enforce a maximum limit on esmtp_timeout_ns to prevent a sysfs write followed by a VM start from crashing the hypervisor? > + > /* Can't intercept CR register access, HV can't modify CR registers */ > svm_clr_intercept(svm, INTERCEPT_CR0_READ); > svm_clr_intercept(svm, INTERCEPT_CR4_READ); -- Sashiko AI review · https://sashiko.dev/#/patchset/cover.1791302373.git.prsampat@amd.com?part=2 ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [Patch v2 2/4] KVM: SVM: Add host support for Enhanced SMT Protection 2026-10-06 16:54 ` [Patch v2 2/4] KVM: SVM: Add host support for Enhanced SMT Protection Pratik R. Sampat 2026-10-06 17:08 ` sashiko-bot @ 2026-10-09 19:05 ` Tom Lendacky 2026-10-09 19:40 ` Pratik R. Sampat 1 sibling, 1 reply; 14+ messages in thread From: Tom Lendacky @ 2026-10-09 19:05 UTC (permalink / raw) To: Pratik R. Sampat, kvm, x86, linux-kernel Cc: tglx, mingo, bp, dave.hansen, seanjc, pbonzini, kim.phillips, nikunj, michael.roth, ashish.kalra On 10/6/26 11:54, Pratik R. Sampat wrote: > Enhanced 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". > > Acked-by: Borislav Petkov (AMD) <bp@alien8.de> # non-virtualization changes > Signed-off-by: Pratik R. Sampat <prsampat@amd.com> > --- > v1..v2 > * Move idle wakeup ICR programming to svm_enable_virtualization_cpu() > instead of sev_hardware_setup() > * Remove cond_sched() in ESMTP exit paths > * Program the IDLE_WAKEUP_ICR for all present CPU siblings > * Add documentation for ESMTP timeout > --- > .../admin-guide/kernel-parameters.txt | 19 ++++++++ > 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 | 8 ++++ > arch/x86/kvm/svm/svm.h | 2 + > 9 files changed, 97 insertions(+), 4 deletions(-) > > diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt > index 68647ff4bdd2..e09f18c0de34 100644 > --- a/Documentation/admin-guide/kernel-parameters.txt > +++ b/Documentation/admin-guide/kernel-parameters.txt > @@ -3240,6 +3240,25 @@ Kernel parameters > max_snp_asid == min_sev_asid-1, will effectively make > SEV-ES unusable. > > + kvm-amd.esmtp_timeout_ns= > + [KVM,AMD] Enhanced SMT Protection (ESMTP) VMRUN > + timeout, in nanoseconds, for SEV-SNP guests that enable > + ESMTP. When an ESMTP vCPU executes VMRUN, hardware > + waits for every sibling thread to either be idle or > + run a legal sibling vCPU of the same guest before > + entering guest mode. If the wait exceeds this timeout, > + VMRUN exits with VMEXIT_ESMTP_TIMEOUT and KVM retries > + the VMRUN. > + > + The value is converted to TSC cycles and programmed > + into the VMCB when a vCPU is initialized, so changing > + it at runtime only affects vCPUs that are created or > + reset afterwards. > + > + Default is 0, which disables the timeout, i.e. VMRUN > + waits until the sibling condition is met or a physical > + interrupt arrives. > + > kvm-arm.mode= > [KVM,ARM,EARLY] Select one of KVM/arm64's modes of > operation. > diff --git a/arch/x86/include/asm/cpufeatures.h b/arch/x86/include/asm/cpufeatures.h > index f70ee74b5f92..4cf477e95c58 100644 > --- a/arch/x86/include/asm/cpufeatures.h > +++ b/arch/x86/include/asm/cpufeatures.h > @@ -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) > diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h > index 3a8e51a0c9e8..fbcb3313e946 100644 > --- a/arch/x86/include/asm/msr-index.h > +++ b/arch/x86/include/asm/msr-index.h > @@ -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 > > diff --git a/arch/x86/include/asm/svm.h b/arch/x86/include/asm/svm.h > index aa63431ba92c..323ab7089302 100644 > --- a/arch/x86/include/asm/svm.h > +++ b/arch/x86/include/asm/svm.h > @@ -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); > diff --git a/arch/x86/include/uapi/asm/svm.h b/arch/x86/include/uapi/asm/svm.h > index 010a45c9f614..e59baf4b3c3f 100644 > --- a/arch/x86/include/uapi/asm/svm.h > +++ b/arch/x86/include/uapi/asm/svm.h > @@ -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 */ > diff --git a/arch/x86/kernel/cpu/scattered.c b/arch/x86/kernel/cpu/scattered.c > index 8665a6474806..16620fa0e290 100644 > --- a/arch/x86/kernel/cpu/scattered.c > +++ b/arch/x86/kernel/cpu/scattered.c > @@ -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 } > }; > diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c > index 5705723f1f41..df836dfe3e55 100644 > --- a/arch/x86/kvm/svm/sev.c > +++ b/arch/x86/kvm/svm/sev.c > @@ -67,6 +67,11 @@ module_param_named(sev_snp, sev_snp_enabled, bool, 0444); > static unsigned int __ro_after_init nr_ciphertext_hiding_asids; > module_param_named(ciphertext_hiding_asids, nr_ciphertext_hiding_asids, uint, 0444); > > +static unsigned long esmtp_timeout_ns; > +module_param(esmtp_timeout_ns, ulong, 0644); > +MODULE_PARM_DESC(esmtp_timeout_ns, > + "ESMTP VMRUN sibling-wait timeout in nanoseconds (0 disables the timer)"); "ESMTP VMRUN sibling-wait timeout, in nanoseconds. 0 (default) disables the timer." Not sure if that reads any better, main point is just to highlight the default is 0, timer disabled. > + > #define AP_RESET_HOLD_NONE 0 > #define AP_RESET_HOLD_NAE_EVENT 1 > #define AP_RESET_HOLD_MSR_PROTO 2 > @@ -506,7 +511,7 @@ static int __sev_guest_init(struct kvm *kvm, struct kvm_sev_cmd *argp, > return -EINVAL; > > if (!snp_active) > - valid_vmsa_features &= ~SVM_SEV_FEAT_SECURE_TSC; > + valid_vmsa_features &= ~(SVM_SEV_FEAT_SECURE_TSC | SVM_SEV_FEAT_ESMTP); > > if (data->vmsa_features & ~valid_vmsa_features) > return -EINVAL; > @@ -1021,6 +1026,15 @@ static int sev_es_sync_vmsa(struct vcpu_svm *svm) > > save->sev_features = sev->vmsa_features; > > + if (sev->vmsa_features & SVM_SEV_FEAT_ESMTP) { > + save->vcpu_id = vcpu->vcpu_id; > + /* > + * All vCPUs of a guest are put into one group and can be run > + * co-resident on the sibling thread of the same core. > + */ > + save->vcpu_sibling_mask = U32_MAX; > + } > + > /* > * Skip FPU and AVX setup with KVM_SEV_ES_INIT to avoid > * breaking older measurements. > @@ -3259,6 +3273,9 @@ 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_supported_vmsa_features |= SVM_SEV_FEAT_ESMTP; > } > > void sev_hardware_unsetup(void) > @@ -3290,6 +3307,31 @@ int sev_cpu_init(struct svm_cpu_data *sd) > return 0; > } > > +void sev_esmtp_enable_wakeup_icr(void) > +{ > + unsigned int cpu, sibling, shift; > + u32 core; > + > + if (!(sev_supported_vmsa_features & SVM_SEV_FEAT_ESMTP)) > + return; > + > + cpu = raw_smp_processor_id(); > + shift = topology_get_domain_shift(TOPO_CORE_DOMAIN); > + core = per_cpu(x86_cpu_to_apicid, cpu) >> shift; > + > + for_each_present_cpu(sibling) { > + u32 apicid = per_cpu(x86_cpu_to_apicid, sibling); > + u64 icr; > + > + if (sibling == cpu || (apicid >> shift) != core) > + continue; > + > + icr = (u64)apicid << 32; > + icr |= LOCAL_TIMER_VECTOR; > + WARN_ON_ONCE(wrmsrq_safe(MSR_AMD64_IDLE_WAKEUP_ICR, icr)); > + } Can you use cpu_sibling_map here instead of going through every present cpu? Thanks, Tom > +} > + > /* > * Pages used by hardware to hold guest encrypted state must be flushed before > * returning them to the system. > @@ -4792,6 +4834,10 @@ static void sev_es_init_vmcb(struct vcpu_svm *svm, bool init_event) > svm->vmcb->control.allowed_sev_features = sev->vmsa_features | > VMCB_ALLOWED_SEV_FEATURES_VALID; > > + if (sev->vmsa_features & SVM_SEV_FEAT_ESMTP) > + svm->vmcb->control.esmtp_timeout = mul_u64_u32_div(esmtp_timeout_ns, > + tsc_khz, 1000000); > + > /* Can't intercept CR register access, HV can't modify CR registers */ > svm_clr_intercept(svm, INTERCEPT_CR0_READ); > svm_clr_intercept(svm, INTERCEPT_CR4_READ); > diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c > index 5d15c706e43b..624675a12d51 100644 > --- a/arch/x86/kvm/svm/svm.c > +++ b/arch/x86/kvm/svm/svm.c > @@ -591,6 +591,8 @@ static int svm_enable_virtualization_cpu(void) > __svm_write_tsc_multiplier(SVM_TSC_RATIO_DEFAULT); > } > > + sev_esmtp_enable_wakeup_icr(); > + > svm_init_os_visible_workarounds(); > > svm_init_erratum_383(); > @@ -3743,6 +3745,12 @@ 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) { > + return 1; > + } > + > if (exit_fastpath != EXIT_FASTPATH_NONE) > return 1; > > diff --git a/arch/x86/kvm/svm/svm.h b/arch/x86/kvm/svm/svm.h > index e958943b8162..8cd8b825c9a0 100644 > --- a/arch/x86/kvm/svm/svm.h > +++ b/arch/x86/kvm/svm/svm.h > @@ -1008,6 +1008,7 @@ void __init sev_set_cpu_caps(void); > void __init sev_hardware_setup(void); > void sev_hardware_unsetup(void); > int sev_cpu_init(struct svm_cpu_data *sd); > +void sev_esmtp_enable_wakeup_icr(void); > int sev_dev_get_attr(u32 group, u64 attr, u64 *val); > extern unsigned int max_sev_asid; > void sev_handle_rmp_fault(struct kvm_vcpu *vcpu, gpa_t gpa, u64 error_code); > @@ -1036,6 +1037,7 @@ static inline void __init sev_set_cpu_caps(void) {} > static inline void __init sev_hardware_setup(void) {} > static inline void sev_hardware_unsetup(void) {} > static inline int sev_cpu_init(struct svm_cpu_data *sd) { return 0; } > +static inline void sev_esmtp_enable_wakeup_icr(void) {} > static inline int sev_dev_get_attr(u32 group, u64 attr, u64 *val) { return -ENXIO; } > #define max_sev_asid 0 > static inline void sev_handle_rmp_fault(struct kvm_vcpu *vcpu, gpa_t gpa, u64 error_code) {} ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [Patch v2 2/4] KVM: SVM: Add host support for Enhanced SMT Protection 2026-10-09 19:05 ` Tom Lendacky @ 2026-10-09 19:40 ` Pratik R. Sampat 2026-10-09 20:05 ` Tom Lendacky 0 siblings, 1 reply; 14+ messages in thread From: Pratik R. Sampat @ 2026-10-09 19:40 UTC (permalink / raw) To: Tom Lendacky, kvm, x86, linux-kernel Cc: tglx, mingo, bp, dave.hansen, seanjc, pbonzini, kim.phillips, nikunj, michael.roth, ashish.kalra Hi Tom, On 10/9/26 3:05 PM, Tom Lendacky wrote: > On 10/6/26 11:54, Pratik R. Sampat wrote: >> Enhanced 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". >> >> Acked-by: Borislav Petkov (AMD) <bp@alien8.de> # non-virtualization changes >> Signed-off-by: Pratik R. Sampat <prsampat@amd.com> >> --- >> v1..v2 >> * Move idle wakeup ICR programming to svm_enable_virtualization_cpu() >> instead of sev_hardware_setup() >> * Remove cond_sched() in ESMTP exit paths >> * Program the IDLE_WAKEUP_ICR for all present CPU siblings >> * Add documentation for ESMTP timeout >> --- >> .../admin-guide/kernel-parameters.txt | 19 ++++++++ >> 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 | 8 ++++ >> arch/x86/kvm/svm/svm.h | 2 + >> 9 files changed, 97 insertions(+), 4 deletions(-) >> >> diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt >> index 68647ff4bdd2..e09f18c0de34 100644 >> --- a/Documentation/admin-guide/kernel-parameters.txt >> +++ b/Documentation/admin-guide/kernel-parameters.txt >> @@ -3240,6 +3240,25 @@ Kernel parameters >> max_snp_asid == min_sev_asid-1, will effectively make >> SEV-ES unusable. >> >> + kvm-amd.esmtp_timeout_ns= >> + [KVM,AMD] Enhanced SMT Protection (ESMTP) VMRUN >> + timeout, in nanoseconds, for SEV-SNP guests that enable >> + ESMTP. When an ESMTP vCPU executes VMRUN, hardware >> + waits for every sibling thread to either be idle or >> + run a legal sibling vCPU of the same guest before >> + entering guest mode. If the wait exceeds this timeout, >> + VMRUN exits with VMEXIT_ESMTP_TIMEOUT and KVM retries >> + the VMRUN. >> + >> + The value is converted to TSC cycles and programmed >> + into the VMCB when a vCPU is initialized, so changing >> + it at runtime only affects vCPUs that are created or >> + reset afterwards. >> + >> + Default is 0, which disables the timeout, i.e. VMRUN >> + waits until the sibling condition is met or a physical >> + interrupt arrives. >> + >> kvm-arm.mode= >> [KVM,ARM,EARLY] Select one of KVM/arm64's modes of >> operation. >> diff --git a/arch/x86/include/asm/cpufeatures.h b/arch/x86/include/asm/cpufeatures.h >> index f70ee74b5f92..4cf477e95c58 100644 >> --- a/arch/x86/include/asm/cpufeatures.h >> +++ b/arch/x86/include/asm/cpufeatures.h >> @@ -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) >> diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h >> index 3a8e51a0c9e8..fbcb3313e946 100644 >> --- a/arch/x86/include/asm/msr-index.h >> +++ b/arch/x86/include/asm/msr-index.h >> @@ -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 >> >> diff --git a/arch/x86/include/asm/svm.h b/arch/x86/include/asm/svm.h >> index aa63431ba92c..323ab7089302 100644 >> --- a/arch/x86/include/asm/svm.h >> +++ b/arch/x86/include/asm/svm.h >> @@ -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); >> diff --git a/arch/x86/include/uapi/asm/svm.h b/arch/x86/include/uapi/asm/svm.h >> index 010a45c9f614..e59baf4b3c3f 100644 >> --- a/arch/x86/include/uapi/asm/svm.h >> +++ b/arch/x86/include/uapi/asm/svm.h >> @@ -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 */ >> diff --git a/arch/x86/kernel/cpu/scattered.c b/arch/x86/kernel/cpu/scattered.c >> index 8665a6474806..16620fa0e290 100644 >> --- a/arch/x86/kernel/cpu/scattered.c >> +++ b/arch/x86/kernel/cpu/scattered.c >> @@ -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 } >> }; >> diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c >> index 5705723f1f41..df836dfe3e55 100644 >> --- a/arch/x86/kvm/svm/sev.c >> +++ b/arch/x86/kvm/svm/sev.c >> @@ -67,6 +67,11 @@ module_param_named(sev_snp, sev_snp_enabled, bool, 0444); >> static unsigned int __ro_after_init nr_ciphertext_hiding_asids; >> module_param_named(ciphertext_hiding_asids, nr_ciphertext_hiding_asids, uint, 0444); >> >> +static unsigned long esmtp_timeout_ns; >> +module_param(esmtp_timeout_ns, ulong, 0644); >> +MODULE_PARM_DESC(esmtp_timeout_ns, >> + "ESMTP VMRUN sibling-wait timeout in nanoseconds (0 disables the timer)"); > > "ESMTP VMRUN sibling-wait timeout, in nanoseconds. 0 (default) disables > the timer." > > Not sure if that reads any better, main point is just to highlight the > default is 0, timer disabled. > Sure, your example reads fine. As an alternative: "ESMTP VMRUN sibling-wait timeout in nanoseconds (default: 0, timer disabled)" >> + >> #define AP_RESET_HOLD_NONE 0 >> #define AP_RESET_HOLD_NAE_EVENT 1 >> #define AP_RESET_HOLD_MSR_PROTO 2 >> @@ -506,7 +511,7 @@ static int __sev_guest_init(struct kvm *kvm, struct kvm_sev_cmd *argp, >> return -EINVAL; >> >> if (!snp_active) >> - valid_vmsa_features &= ~SVM_SEV_FEAT_SECURE_TSC; >> + valid_vmsa_features &= ~(SVM_SEV_FEAT_SECURE_TSC | SVM_SEV_FEAT_ESMTP); >> >> if (data->vmsa_features & ~valid_vmsa_features) >> return -EINVAL; >> @@ -1021,6 +1026,15 @@ static int sev_es_sync_vmsa(struct vcpu_svm *svm) >> >> save->sev_features = sev->vmsa_features; >> >> + if (sev->vmsa_features & SVM_SEV_FEAT_ESMTP) { >> + save->vcpu_id = vcpu->vcpu_id; >> + /* >> + * All vCPUs of a guest are put into one group and can be run >> + * co-resident on the sibling thread of the same core. >> + */ >> + save->vcpu_sibling_mask = U32_MAX; >> + } >> + >> /* >> * Skip FPU and AVX setup with KVM_SEV_ES_INIT to avoid >> * breaking older measurements. >> @@ -3259,6 +3273,9 @@ 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_supported_vmsa_features |= SVM_SEV_FEAT_ESMTP; >> } >> >> void sev_hardware_unsetup(void) >> @@ -3290,6 +3307,31 @@ int sev_cpu_init(struct svm_cpu_data *sd) >> return 0; >> } >> >> +void sev_esmtp_enable_wakeup_icr(void) >> +{ >> + unsigned int cpu, sibling, shift; >> + u32 core; >> + >> + if (!(sev_supported_vmsa_features & SVM_SEV_FEAT_ESMTP)) >> + return; >> + >> + cpu = raw_smp_processor_id(); >> + shift = topology_get_domain_shift(TOPO_CORE_DOMAIN); >> + core = per_cpu(x86_cpu_to_apicid, cpu) >> shift; >> + >> + for_each_present_cpu(sibling) { >> + u32 apicid = per_cpu(x86_cpu_to_apicid, sibling); >> + u64 icr; >> + >> + if (sibling == cpu || (apicid >> shift) != core) >> + continue; >> + >> + icr = (u64)apicid << 32; >> + icr |= LOCAL_TIMER_VECTOR; >> + WARN_ON_ONCE(wrmsrq_safe(MSR_AMD64_IDLE_WAKEUP_ICR, icr)); >> + } > > Can you use cpu_sibling_map here instead of going through every present cpu? > I think cpu_sibling_map only covers the list of online CPUs. If SMT was say turned off and then on again the CPU that stayed online would never be reprogrammed with its new sibling's APIC ID. Walking the present CPUs avoids that, because x86_cpu_to_apicid is already valid for offline siblings. I had used topology_sibling_cpumask() in v1 when Sashiko pointed out this case to me. Thank you! Pratik > Thanks, > Tom > >> +} >> + >> /* >> * Pages used by hardware to hold guest encrypted state must be flushed before >> * returning them to the system. >> @@ -4792,6 +4834,10 @@ static void sev_es_init_vmcb(struct vcpu_svm *svm, bool init_event) >> svm->vmcb->control.allowed_sev_features = sev->vmsa_features | >> VMCB_ALLOWED_SEV_FEATURES_VALID; >> >> + if (sev->vmsa_features & SVM_SEV_FEAT_ESMTP) >> + svm->vmcb->control.esmtp_timeout = mul_u64_u32_div(esmtp_timeout_ns, >> + tsc_khz, 1000000); >> + >> /* Can't intercept CR register access, HV can't modify CR registers */ >> svm_clr_intercept(svm, INTERCEPT_CR0_READ); >> svm_clr_intercept(svm, INTERCEPT_CR4_READ); >> diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c >> index 5d15c706e43b..624675a12d51 100644 >> --- a/arch/x86/kvm/svm/svm.c >> +++ b/arch/x86/kvm/svm/svm.c >> @@ -591,6 +591,8 @@ static int svm_enable_virtualization_cpu(void) >> __svm_write_tsc_multiplier(SVM_TSC_RATIO_DEFAULT); >> } >> >> + sev_esmtp_enable_wakeup_icr(); >> + >> svm_init_os_visible_workarounds(); >> >> svm_init_erratum_383(); >> @@ -3743,6 +3745,12 @@ 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) { >> + return 1; >> + } >> + >> if (exit_fastpath != EXIT_FASTPATH_NONE) >> return 1; >> >> diff --git a/arch/x86/kvm/svm/svm.h b/arch/x86/kvm/svm/svm.h >> index e958943b8162..8cd8b825c9a0 100644 >> --- a/arch/x86/kvm/svm/svm.h >> +++ b/arch/x86/kvm/svm/svm.h >> @@ -1008,6 +1008,7 @@ void __init sev_set_cpu_caps(void); >> void __init sev_hardware_setup(void); >> void sev_hardware_unsetup(void); >> int sev_cpu_init(struct svm_cpu_data *sd); >> +void sev_esmtp_enable_wakeup_icr(void); >> int sev_dev_get_attr(u32 group, u64 attr, u64 *val); >> extern unsigned int max_sev_asid; >> void sev_handle_rmp_fault(struct kvm_vcpu *vcpu, gpa_t gpa, u64 error_code); >> @@ -1036,6 +1037,7 @@ static inline void __init sev_set_cpu_caps(void) {} >> static inline void __init sev_hardware_setup(void) {} >> static inline void sev_hardware_unsetup(void) {} >> static inline int sev_cpu_init(struct svm_cpu_data *sd) { return 0; } >> +static inline void sev_esmtp_enable_wakeup_icr(void) {} >> static inline int sev_dev_get_attr(u32 group, u64 attr, u64 *val) { return -ENXIO; } >> #define max_sev_asid 0 >> static inline void sev_handle_rmp_fault(struct kvm_vcpu *vcpu, gpa_t gpa, u64 error_code) {} > ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [Patch v2 2/4] KVM: SVM: Add host support for Enhanced SMT Protection 2026-10-09 19:40 ` Pratik R. Sampat @ 2026-10-09 20:05 ` Tom Lendacky 0 siblings, 0 replies; 14+ messages in thread From: Tom Lendacky @ 2026-10-09 20:05 UTC (permalink / raw) To: Pratik R. Sampat, kvm, x86, linux-kernel Cc: tglx, mingo, bp, dave.hansen, seanjc, pbonzini, kim.phillips, nikunj, michael.roth, ashish.kalra On 10/9/26 14:40, Pratik R. Sampat wrote: > Hi Tom, > > On 10/9/26 3:05 PM, Tom Lendacky wrote: >> On 10/6/26 11:54, Pratik R. Sampat wrote: >>> Enhanced 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". >>> >>> Acked-by: Borislav Petkov (AMD) <bp@alien8.de> # non-virtualization changes >>> Signed-off-by: Pratik R. Sampat <prsampat@amd.com> >>> --- >>> v1..v2 >>> * Move idle wakeup ICR programming to svm_enable_virtualization_cpu() >>> instead of sev_hardware_setup() >>> * Remove cond_sched() in ESMTP exit paths >>> * Program the IDLE_WAKEUP_ICR for all present CPU siblings >>> * Add documentation for ESMTP timeout >>> --- >>> .../admin-guide/kernel-parameters.txt | 19 ++++++++ >>> 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 | 8 ++++ >>> arch/x86/kvm/svm/svm.h | 2 + >>> 9 files changed, 97 insertions(+), 4 deletions(-) >>> >>> --- a/arch/x86/kvm/svm/sev.c >>> +++ b/arch/x86/kvm/svm/sev.c >>> @@ -67,6 +67,11 @@ module_param_named(sev_snp, sev_snp_enabled, bool, 0444); >>> static unsigned int __ro_after_init nr_ciphertext_hiding_asids; >>> module_param_named(ciphertext_hiding_asids, nr_ciphertext_hiding_asids, uint, 0444); >>> >>> +static unsigned long esmtp_timeout_ns; >>> +module_param(esmtp_timeout_ns, ulong, 0644); >>> +MODULE_PARM_DESC(esmtp_timeout_ns, >>> + "ESMTP VMRUN sibling-wait timeout in nanoseconds (0 disables the timer)"); >> >> "ESMTP VMRUN sibling-wait timeout, in nanoseconds. 0 (default) disables >> the timer." >> >> Not sure if that reads any better, main point is just to highlight the >> default is 0, timer disabled. >> > > Sure, your example reads fine. As an alternative: > "ESMTP VMRUN sibling-wait timeout in nanoseconds (default: 0, timer disabled)" Ack > >>> + >>> +void sev_esmtp_enable_wakeup_icr(void) >>> +{ >>> + unsigned int cpu, sibling, shift; >>> + u32 core; >>> + >>> + if (!(sev_supported_vmsa_features & SVM_SEV_FEAT_ESMTP)) >>> + return; >>> + >>> + cpu = raw_smp_processor_id(); >>> + shift = topology_get_domain_shift(TOPO_CORE_DOMAIN); >>> + core = per_cpu(x86_cpu_to_apicid, cpu) >> shift; >>> + >>> + for_each_present_cpu(sibling) { >>> + u32 apicid = per_cpu(x86_cpu_to_apicid, sibling); >>> + u64 icr; >>> + >>> + if (sibling == cpu || (apicid >> shift) != core) >>> + continue; >>> + >>> + icr = (u64)apicid << 32; >>> + icr |= LOCAL_TIMER_VECTOR; >>> + WARN_ON_ONCE(wrmsrq_safe(MSR_AMD64_IDLE_WAKEUP_ICR, icr)); >>> + } >> >> Can you use cpu_sibling_map here instead of going through every present cpu? >> > > I think cpu_sibling_map only covers the list of online CPUs. If SMT was say > turned off and then on again the CPU that stayed online would never be > reprogrammed with its new sibling's APIC ID. Walking the present CPUs avoids > that, because x86_cpu_to_apicid is already valid for offline siblings. Makes sense. I know we disable hotplug when SNP is enabled, but this runs before that occurs. Thanks, Tom > > I had used topology_sibling_cpumask() in v1 when Sashiko pointed out this case > to me. > > Thank you! > Pratik > ^ permalink raw reply [flat|nested] 14+ messages in thread
* [Patch v2 3/4] x86/sev: Add guest support for Enhanced SMT Protection 2026-10-06 16:54 [Patch v2 0/4] Introduce Enhanced SMT Protection for SEV-SNP Pratik R. Sampat 2026-10-06 16:54 ` [Patch v2 1/4] KVM: SVM: Re-queue events that were never injected Pratik R. Sampat 2026-10-06 16:54 ` [Patch v2 2/4] KVM: SVM: Add host support for Enhanced SMT Protection Pratik R. Sampat @ 2026-10-06 16:55 ` Pratik R. Sampat 2026-10-06 17:03 ` sashiko-bot 2026-10-09 19:18 ` Tom Lendacky 2026-10-06 16:55 ` [Patch v2 4/4] x86/hyperv: " Pratik R. Sampat 3 siblings, 2 replies; 14+ messages in thread From: Pratik R. Sampat @ 2026-10-06 16:55 UTC (permalink / raw) To: kvm, x86, linux-kernel Cc: tglx, mingo, bp, dave.hansen, seanjc, pbonzini, thomas.lendacky, kim.phillips, nikunj, michael.roth, ashish.kalra, prsampat Enhanced 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. Signed-off-by: Pratik R. Sampat <prsampat@amd.com> --- v1..v2: * Add ESMTP to SNP_FEATURES_IMPL and SNP_FEATURES_IMPL_REQ --- arch/x86/boot/compressed/sev.c | 6 ++++-- arch/x86/coco/sev/core.c | 13 +++++++++++++ arch/x86/include/asm/msr-index.h | 4 +++- 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/arch/x86/boot/compressed/sev.c b/arch/x86/boot/compressed/sev.c index c6512f2ea31e..4e0fa5a5f70b 100644 --- a/arch/x86/boot/compressed/sev.c +++ b/arch/x86/boot/compressed/sev.c @@ -188,7 +188,8 @@ 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_ESMT_PROT | \ + MSR_AMD64_SNP_RESERVED_BITS20_22 | \ MSR_AMD64_SNP_RESERVED_MASK) #ifdef CONFIG_AMD_SECURE_AVIC @@ -204,7 +205,8 @@ bool sev_es_check_ghcb_fault(unsigned long address) */ #define SNP_FEATURES_IMPL (MSR_AMD64_SNP_DEBUG_SWAP | \ MSR_AMD64_SNP_SECURE_TSC | \ - SNP_FEATURE_SECURE_AVIC) + SNP_FEATURE_SECURE_AVIC | \ + MSR_AMD64_SNP_ESMT_PROT) u64 snp_get_unsupported_features(u64 status) { diff --git a/arch/x86/coco/sev/core.c b/arch/x86/coco/sev/core.c index cc292d7c6fd1..730cff2700d4 100644 --- a/arch/x86/coco/sev/core.c +++ b/arch/x86/coco/sev/core.c @@ -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; diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h index fbcb3313e946..6fd26151d146 100644 --- a/arch/x86/include/asm/msr-index.h +++ b/arch/x86/include/asm/msr-index.h @@ -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 -- 2.43.0 ^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: [Patch v2 3/4] x86/sev: Add guest support for Enhanced SMT Protection 2026-10-06 16:55 ` [Patch v2 3/4] x86/sev: Add guest " Pratik R. Sampat @ 2026-10-06 17:03 ` sashiko-bot 2026-10-09 19:18 ` Tom Lendacky 1 sibling, 0 replies; 14+ messages in thread From: sashiko-bot @ 2026-10-06 17:03 UTC (permalink / raw) To: Pratik R. Sampat; +Cc: kvm Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: - [Low] x86/sev: tools/arch/x86/include/asm/msr-index.h out of sync -- commit 52d51b6c190bcd07e516526d1a62088b4f2a3da6 Author: Pratik R. Sampat <prsampat@amd.com> x86/sev: Add guest support for Enhanced SMT Protection This commit adds guest support for Enhanced SMT Protection (ESMTP). It populates the VMSA with the vCPU's identity and sets the SMT sibling mask before the page is turned into a VMSA so that threads of the same guest trust each other. [ ... ] > diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h > index ee9fb820a1cd7..638867e7b4ec2 100644 > --- a/arch/x86/include/asm/msr-index.h > +++ b/arch/x86/include/asm/msr-index.h > @@ -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 also need to be updated to stay in sync with this change? This out-of-sync tools header will cause build warnings indicating that the kernel ABI header differs from the latest version, because it lacks the new ESMT_PROT and RESERVED_BITS20_22 macros. > #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 -- Sashiko AI review · https://sashiko.dev/#/patchset/cover.1791302373.git.prsampat@amd.com?part=3 ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [Patch v2 3/4] x86/sev: Add guest support for Enhanced SMT Protection 2026-10-06 16:55 ` [Patch v2 3/4] x86/sev: Add guest " Pratik R. Sampat 2026-10-06 17:03 ` sashiko-bot @ 2026-10-09 19:18 ` Tom Lendacky 2026-10-09 19:43 ` Pratik R. Sampat 1 sibling, 1 reply; 14+ messages in thread From: Tom Lendacky @ 2026-10-09 19:18 UTC (permalink / raw) To: Pratik R. Sampat, kvm, x86, linux-kernel Cc: tglx, mingo, bp, dave.hansen, seanjc, pbonzini, kim.phillips, nikunj, michael.roth, ashish.kalra On 10/6/26 11:55, Pratik R. Sampat wrote: > Enhanced 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. > > Signed-off-by: Pratik R. Sampat <prsampat@amd.com> Minor comment below, but otherwise: Reviewed-by: Tom Lendacky <thomas.lendacky@amd.com> > --- > v1..v2: > * Add ESMTP to SNP_FEATURES_IMPL and SNP_FEATURES_IMPL_REQ > --- > arch/x86/boot/compressed/sev.c | 6 ++++-- > arch/x86/coco/sev/core.c | 13 +++++++++++++ > arch/x86/include/asm/msr-index.h | 4 +++- > 3 files changed, 20 insertions(+), 3 deletions(-) > > diff --git a/arch/x86/boot/compressed/sev.c b/arch/x86/boot/compressed/sev.c > index c6512f2ea31e..4e0fa5a5f70b 100644 > --- a/arch/x86/boot/compressed/sev.c > +++ b/arch/x86/boot/compressed/sev.c > @@ -188,7 +188,8 @@ 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_ESMT_PROT | \ > + MSR_AMD64_SNP_RESERVED_BITS20_22 | \ > MSR_AMD64_SNP_RESERVED_MASK) > > #ifdef CONFIG_AMD_SECURE_AVIC > @@ -204,7 +205,8 @@ bool sev_es_check_ghcb_fault(unsigned long address) > */ > #define SNP_FEATURES_IMPL (MSR_AMD64_SNP_DEBUG_SWAP | \ > MSR_AMD64_SNP_SECURE_TSC | \ > - SNP_FEATURE_SECURE_AVIC) > + SNP_FEATURE_SECURE_AVIC | \ > + MSR_AMD64_SNP_ESMT_PROT) > > u64 snp_get_unsupported_features(u64 status) > { > diff --git a/arch/x86/coco/sev/core.c b/arch/x86/coco/sev/core.c > index cc292d7c6fd1..730cff2700d4 100644 > --- a/arch/x86/coco/sev/core.c > +++ b/arch/x86/coco/sev/core.c > @@ -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)) { You're using sev_status for ESMT_PROT, might as well use it for SNP, too, instead of calling cc_platform_has(). Thanks, Tom > + 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; > diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h > index fbcb3313e946..6fd26151d146 100644 > --- a/arch/x86/include/asm/msr-index.h > +++ b/arch/x86/include/asm/msr-index.h > @@ -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 ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [Patch v2 3/4] x86/sev: Add guest support for Enhanced SMT Protection 2026-10-09 19:18 ` Tom Lendacky @ 2026-10-09 19:43 ` Pratik R. Sampat 0 siblings, 0 replies; 14+ messages in thread From: Pratik R. Sampat @ 2026-10-09 19:43 UTC (permalink / raw) To: Tom Lendacky, kvm, x86, linux-kernel Cc: tglx, mingo, bp, dave.hansen, seanjc, pbonzini, kim.phillips, nikunj, michael.roth, ashish.kalra On 10/9/26 3:18 PM, Tom Lendacky wrote: > On 10/6/26 11:55, Pratik R. Sampat wrote: >> Enhanced 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. >> >> Signed-off-by: Pratik R. Sampat <prsampat@amd.com> > > Minor comment below, but otherwise: > > Reviewed-by: Tom Lendacky <thomas.lendacky@amd.com> > >> --- >> v1..v2: >> * Add ESMTP to SNP_FEATURES_IMPL and SNP_FEATURES_IMPL_REQ >> --- >> arch/x86/boot/compressed/sev.c | 6 ++++-- >> arch/x86/coco/sev/core.c | 13 +++++++++++++ >> arch/x86/include/asm/msr-index.h | 4 +++- >> 3 files changed, 20 insertions(+), 3 deletions(-) >> >> diff --git a/arch/x86/boot/compressed/sev.c b/arch/x86/boot/compressed/sev.c >> index c6512f2ea31e..4e0fa5a5f70b 100644 >> --- a/arch/x86/boot/compressed/sev.c >> +++ b/arch/x86/boot/compressed/sev.c >> @@ -188,7 +188,8 @@ 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_ESMT_PROT | \ >> + MSR_AMD64_SNP_RESERVED_BITS20_22 | \ >> MSR_AMD64_SNP_RESERVED_MASK) >> >> #ifdef CONFIG_AMD_SECURE_AVIC >> @@ -204,7 +205,8 @@ bool sev_es_check_ghcb_fault(unsigned long address) >> */ >> #define SNP_FEATURES_IMPL (MSR_AMD64_SNP_DEBUG_SWAP | \ >> MSR_AMD64_SNP_SECURE_TSC | \ >> - SNP_FEATURE_SECURE_AVIC) >> + SNP_FEATURE_SECURE_AVIC | \ >> + MSR_AMD64_SNP_ESMT_PROT) >> >> u64 snp_get_unsupported_features(u64 status) >> { >> diff --git a/arch/x86/coco/sev/core.c b/arch/x86/coco/sev/core.c >> index cc292d7c6fd1..730cff2700d4 100644 >> --- a/arch/x86/coco/sev/core.c >> +++ b/arch/x86/coco/sev/core.c >> @@ -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)) { > > You're using sev_status for ESMT_PROT, might as well use it for SNP, too, > instead of calling cc_platform_has(). > Sure, will do. Thank you! --Pratik > Thanks, > Tom > >> + 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; >> diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h >> index fbcb3313e946..6fd26151d146 100644 >> --- a/arch/x86/include/asm/msr-index.h >> +++ b/arch/x86/include/asm/msr-index.h >> @@ -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 > ^ permalink raw reply [flat|nested] 14+ messages in thread
* [Patch v2 4/4] x86/hyperv: Add guest support for Enhanced SMT Protection 2026-10-06 16:54 [Patch v2 0/4] Introduce Enhanced SMT Protection for SEV-SNP Pratik R. Sampat ` (2 preceding siblings ...) 2026-10-06 16:55 ` [Patch v2 3/4] x86/sev: Add guest " Pratik R. Sampat @ 2026-10-06 16:55 ` Pratik R. Sampat 3 siblings, 0 replies; 14+ messages in thread From: Pratik R. Sampat @ 2026-10-06 16:55 UTC (permalink / raw) To: kvm, x86, linux-kernel Cc: tglx, mingo, bp, dave.hansen, seanjc, pbonzini, thomas.lendacky, kim.phillips, nikunj, michael.roth, ashish.kalra, prsampat Add corresponding hyperv support for Enhanced SMT protection. A fully enlightened SEV-SNP guest on Hyper-V 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. Similar to KVM, fully set the sibling mask so that all threads of the same guest trust each other. Signed-off-by: Pratik R. Sampat <prsampat@amd.com> --- v1..v2: New patch --- arch/x86/hyperv/ivm.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/arch/x86/hyperv/ivm.c b/arch/x86/hyperv/ivm.c index 2ce4dfe53472..40dd252f333a 100644 --- a/arch/x86/hyperv/ivm.c +++ b/arch/x86/hyperv/ivm.c @@ -347,6 +347,17 @@ int hv_snp_boot_ap(u32 apic_id, unsigned long start_ip, unsigned int cpu) vmsa->vmpl = 0; vmsa->sev_features = sev_status >> 2; + if (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; + } + ret = snp_set_vmsa(vmsa, true); if (ret) { pr_err("RMPADJUST(%llx) failed: %llx\n", (u64)vmsa, ret); -- 2.43.0 ^ permalink raw reply related [flat|nested] 14+ messages in thread
end of thread, other threads:[~2026-10-09 20:05 UTC | newest] Thread overview: 14+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-10-06 16:54 [Patch v2 0/4] Introduce Enhanced SMT Protection for SEV-SNP Pratik R. Sampat 2026-10-06 16:54 ` [Patch v2 1/4] KVM: SVM: Re-queue events that were never injected Pratik R. Sampat 2026-10-06 17:12 ` sashiko-bot 2026-10-09 19:21 ` Tom Lendacky 2026-10-06 16:54 ` [Patch v2 2/4] KVM: SVM: Add host support for Enhanced SMT Protection Pratik R. Sampat 2026-10-06 17:08 ` sashiko-bot 2026-10-09 19:05 ` Tom Lendacky 2026-10-09 19:40 ` Pratik R. Sampat 2026-10-09 20:05 ` Tom Lendacky 2026-10-06 16:55 ` [Patch v2 3/4] x86/sev: Add guest " Pratik R. Sampat 2026-10-06 17:03 ` sashiko-bot 2026-10-09 19:18 ` Tom Lendacky 2026-10-09 19:43 ` Pratik R. Sampat 2026-10-06 16:55 ` [Patch v2 4/4] x86/hyperv: " Pratik R. Sampat
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox