Kernel KVM virtualization development
 help / color / mirror / Atom feed
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) {}


  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