On 7/7/25 05:10, Nikunj A Dadhania wrote: > Add support for Secure TSC, allowing userspace to configure the Secure TSC > feature for SNP guests. Use the SNP specification's desired TSC frequency > parameter during the SNP_LAUNCH_START command to set the mean TSC > frequency in KHz for Secure TSC enabled guests. > > Always use kvm->arch.arch.default_tsc_khz as the TSC frequency that is > passed to SNP guests in the SNP_LAUNCH_START command. The default value > is the host TSC frequency. The userspace can optionally change the TSC > frequency via the KVM_SET_TSC_KHZ ioctl before calling the > SNP_LAUNCH_START ioctl. > > Introduce the read-only MSR GUEST_TSC_FREQ (0xc0010134) that returns > guest's effective frequency in MHZ when Secure TSC is enabled for SNP > guests. Disable interception of this MSR when Secure TSC is enabled. Note > that GUEST_TSC_FREQ MSR is accessible only to the guest and not from the > hypervisor context. > > Signed-off-by: Nikunj A Dadhania <nikunj@xxxxxxx> > Co-developed-by: Ketan Chaturvedi <Ketan.Chaturvedi@xxxxxxx> > Signed-off-by: Ketan Chaturvedi <Ketan.Chaturvedi@xxxxxxx> > Co-developed-by: Sean Christopherson <seanjc@xxxxxxxxxx> > Signed-off-by: Nikunj A Dadhania <nikunj@xxxxxxx> Reviewed-by: Tom Lendacky <thomas.lendacky@xxxxxxx> > > --- > > I have incorporated changes from Sean to prevent the setting of SecureTSC > for non-SNP guests. I have added his 'Co-developed-by' acknowledgment, but > I have not yet included his 'Signed-off-by'. I will leave that for him to > add. > --- > arch/x86/include/asm/svm.h | 1 + > arch/x86/kvm/svm/sev.c | 34 +++++++++++++++++++++++++++++++--- > 2 files changed, 32 insertions(+), 3 deletions(-) > > diff --git a/arch/x86/include/asm/svm.h b/arch/x86/include/asm/svm.h > index ffc27f676243..17f6c3fedeee 100644 > --- a/arch/x86/include/asm/svm.h > +++ b/arch/x86/include/asm/svm.h > @@ -299,6 +299,7 @@ static_assert((X2AVIC_MAX_PHYSICAL_ID & AVIC_PHYSICAL_MAX_INDEX_MASK) == X2AVIC_ > #define SVM_SEV_FEAT_RESTRICTED_INJECTION BIT(3) > #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 VMCB_ALLOWED_SEV_FEATURES_VALID BIT_ULL(63) > > diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c > index fde328ed3f78..5ac4841f925d 100644 > --- a/arch/x86/kvm/svm/sev.c > +++ b/arch/x86/kvm/svm/sev.c > @@ -146,6 +146,14 @@ static bool sev_vcpu_has_debug_swap(struct vcpu_svm *svm) > return sev->vmsa_features & SVM_SEV_FEAT_DEBUG_SWAP; > } > > +static bool snp_secure_tsc_enabled(struct kvm *kvm) > +{ > + struct kvm_sev_info *sev = to_kvm_sev_info(kvm); > + > + return (sev->vmsa_features & SVM_SEV_FEAT_SECURE_TSC) && > + !WARN_ON_ONCE(!sev_snp_guest(kvm)); > +} > + > /* Must be called with the sev_bitmap_lock held */ > static bool __sev_recycle_asids(unsigned int min_asid, unsigned int max_asid) > { > @@ -405,6 +413,7 @@ static int __sev_guest_init(struct kvm *kvm, struct kvm_sev_cmd *argp, > struct kvm_sev_info *sev = to_kvm_sev_info(kvm); > struct sev_platform_init_args init_args = {0}; > bool es_active = vm_type != KVM_X86_SEV_VM; > + bool snp_active = vm_type == KVM_X86_SNP_VM; > u64 valid_vmsa_features = es_active ? sev_supported_vmsa_features : 0; > int ret; > > @@ -414,6 +423,9 @@ static int __sev_guest_init(struct kvm *kvm, struct kvm_sev_cmd *argp, > if (data->flags) > return -EINVAL; > > + if (!snp_active) > + valid_vmsa_features &= ~SVM_SEV_FEAT_SECURE_TSC; > + > if (data->vmsa_features & ~valid_vmsa_features) > return -EINVAL; > > @@ -436,7 +448,7 @@ static int __sev_guest_init(struct kvm *kvm, struct kvm_sev_cmd *argp, > if (sev->es_active && !sev->ghcb_version) > sev->ghcb_version = GHCB_VERSION_DEFAULT; > > - if (vm_type == KVM_X86_SNP_VM) > + if (snp_active) > sev->vmsa_features |= SVM_SEV_FEAT_SNP_ACTIVE; > > ret = sev_asid_new(sev); > @@ -449,7 +461,7 @@ static int __sev_guest_init(struct kvm *kvm, struct kvm_sev_cmd *argp, > goto e_free; > > /* This needs to happen after SEV/SNP firmware initialization. */ > - if (vm_type == KVM_X86_SNP_VM) { > + if (snp_active) { > ret = snp_guest_req_init(kvm); > if (ret) > goto e_free; > @@ -2146,6 +2158,14 @@ static int snp_launch_start(struct kvm *kvm, struct kvm_sev_cmd *argp) > > start.gctx_paddr = __psp_pa(sev->snp_context); > start.policy = params.policy; > + > + if (snp_secure_tsc_enabled(kvm)) { > + if (!kvm->arch.default_tsc_khz) > + return -EINVAL; > + > + start.desired_tsc_khz = kvm->arch.default_tsc_khz; > + } > + > memcpy(start.gosvw, params.gosvw, sizeof(params.gosvw)); > rc = __sev_issue_cmd(argp->sev_fd, SEV_CMD_SNP_LAUNCH_START, &start, &argp->error); > if (rc) { > @@ -2386,7 +2406,9 @@ static int snp_launch_update_vmsa(struct kvm *kvm, struct kvm_sev_cmd *argp) > return ret; > } > > - svm->vcpu.arch.guest_state_protected = true; > + vcpu->arch.guest_state_protected = true; > + vcpu->arch.guest_tsc_protected = snp_secure_tsc_enabled(kvm); > + > /* > * SEV-ES (and thus SNP) guest mandates LBR Virtualization to > * be _always_ ON. Enable it only after setting > @@ -3036,6 +3058,9 @@ void __init sev_hardware_setup(void) > sev_supported_vmsa_features = 0; > if (sev_es_debug_swap_enabled) > sev_supported_vmsa_features |= SVM_SEV_FEAT_DEBUG_SWAP; > + > + if (sev_snp_enabled && cpu_feature_enabled(X86_FEATURE_SNP_SECURE_TSC)) > + sev_supported_vmsa_features |= SVM_SEV_FEAT_SECURE_TSC; > } > > void sev_hardware_unsetup(void) > @@ -4487,6 +4512,9 @@ static void sev_es_init_vmcb(struct vcpu_svm *svm) > > /* Can't intercept XSETBV, HV can't modify XCR0 directly */ > svm_clr_intercept(svm, INTERCEPT_XSETBV); > + > + if (snp_secure_tsc_enabled(svm->vcpu.kvm)) > + svm_disable_intercept_for_msr(&svm->vcpu, MSR_AMD64_GUEST_TSC_FREQ, MSR_TYPE_RW); > } > > void sev_init_vmcb(struct vcpu_svm *svm)