]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
KVM: SVM: Enable Secure TSC for SNP guests
authorNikunj A Dadhania <nikunj@amd.com>
Tue, 19 Aug 2025 23:48:33 +0000 (16:48 -0700)
committerSean Christopherson <seanjc@google.com>
Thu, 21 Aug 2025 15:51:39 +0000 (08:51 -0700)
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.

Co-developed-by: Ketan Chaturvedi <Ketan.Chaturvedi@amd.com>
Signed-off-by: Ketan Chaturvedi <Ketan.Chaturvedi@amd.com>
Reviewed-by: Kai Huang <kai.huang@intel.com>
Reviewed-by: Tom Lendacky <thomas.lendacky@amd.com>
Signed-off-by: Nikunj A Dadhania <nikunj@amd.com>
[sean: contain Secure TSC to sev.c]
Link: https://lore.kernel.org/r/20250819234833.3080255-9-seanjc@google.com
[sean: return -EINVAL if TSC frequency is '0']
Signed-off-by: Sean Christopherson <seanjc@google.com>
arch/x86/include/asm/svm.h
arch/x86/kvm/svm/sev.c

index ffc27f67624398e3b82f982ef4ce359541a2b2b5..17f6c3fedeee7443eb48f2330795a108c42c604f 100644 (file)
@@ -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)
 
index 7d1d34e45310c348f9a603d3e680e5f5e4af2c44..86fd270a1d6ed9933269dd3aa430e3e82a347b69 100644 (file)
@@ -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_is_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)
 {
@@ -415,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;
 
@@ -2187,6 +2198,13 @@ static int snp_launch_start(struct kvm *kvm, struct kvm_sev_cmd *argp)
        if (!(params.policy & SNP_POLICY_MASK_RSVD_MBO))
                return -EINVAL;
 
+       if (snp_is_secure_tsc_enabled(kvm)) {
+               if (WARN_ON_ONCE(!kvm->arch.default_tsc_khz))
+                       return -EINVAL;
+
+               start.desired_tsc_khz = kvm->arch.default_tsc_khz;
+       }
+
        sev->policy = params.policy;
 
        sev->snp_context = snp_context_create(kvm, argp);
@@ -2195,6 +2213,7 @@ 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;
+
        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) {
@@ -3085,6 +3104,9 @@ out:
        sev_supported_vmsa_features = 0;
        if (sev_es_debug_swap_enabled)
                sev_supported_vmsa_features |= SVM_SEV_FEAT_DEBUG_SWAP;
+
+       if (sev_snp_enabled && tsc_khz && cpu_feature_enabled(X86_FEATURE_SNP_SECURE_TSC))
+               sev_supported_vmsa_features |= SVM_SEV_FEAT_SECURE_TSC;
 }
 
 void sev_hardware_unsetup(void)
@@ -4452,6 +4474,9 @@ void sev_es_recalc_msr_intercepts(struct kvm_vcpu *vcpu)
                                          !guest_cpu_cap_has(vcpu, X86_FEATURE_RDTSCP) &&
                                          !guest_cpu_cap_has(vcpu, X86_FEATURE_RDPID));
 
+       svm_set_intercept_for_msr(vcpu, MSR_AMD64_GUEST_TSC_FREQ, MSR_TYPE_R,
+                                 !snp_is_secure_tsc_enabled(vcpu->kvm));
+
        /*
         * For SEV-ES, accesses to MSR_IA32_XSS should not be intercepted if
         * the host/guest supports its use.
@@ -4591,6 +4616,9 @@ int sev_vcpu_create(struct kvm_vcpu *vcpu)
                return -ENOMEM;
 
        svm->sev_es.vmsa = page_address(vmsa_page);
+
+       vcpu->arch.guest_tsc_protected = snp_is_secure_tsc_enabled(vcpu->kvm);
+
        return 0;
 }