From: Tom Lendacky <thomas.lendacky@amd.com>
To: "Pratik R. Sampat" <prsampat@amd.com>,
kvm@vger.kernel.org, x86@kernel.org,
linux-kernel@vger.kernel.org
Cc: tglx@kernel.org, mingo@redhat.com, bp@alien8.de,
dave.hansen@linux.intel.com, seanjc@google.com,
pbonzini@redhat.com, kim.phillips@amd.com, nikunj@amd.com,
michael.roth@amd.com, ashish.kalra@amd.com
Subject: Re: [Patch v2 2/4] KVM: SVM: Add host support for Enhanced SMT Protection
Date: Fri, 9 Oct 2026 14:05:18 -0500 [thread overview]
Message-ID: <961ba3a4-3fe2-45de-af56-92efa43ca2b2@amd.com> (raw)
In-Reply-To: <64ea6ba62315d33b7bfb48ec6cab29ac4ee2fa06.1791302373.git.prsampat@amd.com>
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) {}
next prev parent reply other threads:[~2026-10-09 19:05 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
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 [this message]
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-06 16:55 ` [Patch v2 4/4] x86/hyperv: " Pratik R. Sampat
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=961ba3a4-3fe2-45de-af56-92efa43ca2b2@amd.com \
--to=thomas.lendacky@amd.com \
--cc=ashish.kalra@amd.com \
--cc=bp@alien8.de \
--cc=dave.hansen@linux.intel.com \
--cc=kim.phillips@amd.com \
--cc=kvm@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=michael.roth@amd.com \
--cc=mingo@redhat.com \
--cc=nikunj@amd.com \
--cc=pbonzini@redhat.com \
--cc=prsampat@amd.com \
--cc=seanjc@google.com \
--cc=tglx@kernel.org \
--cc=x86@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox