The previous patch to add GUEST_TSC_FREQ needs to squashed with this patch. It's impossible to review the snp_secure_tsc_enabled() logic in particular without the details added in this patch. And once you rebase on kvm-x86 next (i.e. the MSR interception rework), adding support for GUEST_TSC_FREQ will be like three lines of code, i.e. not worth landing in a separate patch. On Tue, Apr 08, 2025, Nikunj A Dadhania wrote: > From: Ketan Chaturvedi <Ketan.Chaturvedi@xxxxxxx> > > 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. > > As the frequency needs to be set in the SNP_LAUNCH_START command, userspace > should set the frequency using the KVM_CAP_SET_TSC_KHZ VM ioctl instead of > the VCPU ioctl. The desired_tsc_khz defaults to kvm->arch.default_tsc_khz. > > Signed-off-by: Ketan Chaturvedi <Ketan.Chaturvedi@xxxxxxx> > Co-developed-by: Nikunj A Dadhania <nikunj@xxxxxxx> > Tested-by: Vaishali Thakkar <vaishali.thakkar@xxxxxxxx> > Reviewed-by: Tom Lendacky <thomas.lendacky@xxxxxxx> > Signed-off-by: Nikunj A Dadhania <nikunj@xxxxxxx> > --- > arch/x86/include/uapi/asm/kvm.h | 3 ++- > arch/x86/kvm/svm/sev.c | 15 ++++++++++++++- > 2 files changed, 16 insertions(+), 2 deletions(-) > > diff --git a/arch/x86/include/uapi/asm/kvm.h b/arch/x86/include/uapi/asm/kvm.h > index 460306b35a4b..075af0dcee25 100644 > --- a/arch/x86/include/uapi/asm/kvm.h > +++ b/arch/x86/include/uapi/asm/kvm.h > @@ -839,7 +839,8 @@ struct kvm_sev_snp_launch_start { > __u64 policy; > __u8 gosvw[16]; > __u16 flags; > - __u8 pad0[6]; > + __u8 pad0[2]; > + __u32 desired_tsc_khz; > __u64 pad1[4]; > }; > > diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c > index 50263b473f95..bcb262ff42bb 100644 > --- a/arch/x86/kvm/svm/sev.c > +++ b/arch/x86/kvm/svm/sev.c > @@ -2205,6 +2205,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) Hmm, so there's an existing flaw related to the TSC frequency. Ideally, KVM shouldn't allow KVM_SET_TSC_KHZ on a vCPU with a "secure" TSC, i.e. on a TDX vCPU or on a newfangled SNP vCPU. I'm not sure that's worth addressing though, because it doesn't put KVM in any danger, it can only cause problems for guest timing. Yeah, I guess we leave it, because it's not really any different than enumerating a TSC frequency in CPUID 0x15 and then telling KVM something different. > + 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) { > @@ -2445,7 +2453,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 > @@ -3059,6 +3069,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; I don't see anything in here that prevents userspace from stuffing SECURE_TSC into vmsa_features, which means the WARN_ON_ONCE() in snp_secure_tsc_enabled is user-triggerable. Unless I'm missing something, this need to do something like: diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c index 45283a2d8c4a..09044f2524c2 100644 --- a/arch/x86/kvm/svm/sev.c +++ b/arch/x86/kvm/svm/sev.c @@ -405,9 +405,13 @@ 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; + if (!snp_active) + valid_vmsa_features &= ~SVM_SEV_FEAT_SECURE_TSC; + if (kvm->created_vcpus) return -EINVAL; @@ -436,7 +440,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 +453,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;