Re: [PATCH v3 13/21] KVM: selftests: Use KVM's reported TSC KHz as L0's frequency (sanity checked)
From: Jim Mattson
Date: Tue Oct 06 2026 - 17:57:45 EST
On Wed, Sep 30, 2026 at 12:04 PM Sean Christopherson <seanjc@xxxxxxxxxx> wrote:
>
> Use KVM's reported default TSC frequency as L0's frequency instead of
> calibrating L0's frequency using RDTSC. Trying to calibrate the frequency
> in userspace is all but guaranteed to be wildly inaccurate, e.g. due to
> interrupts, preemption, etc, and no known CPU supports TSC scaling without
> also having a constant TSC. I.e. there's no need to calibrate the current
> frequency, as it should also be the same as KVM's default frequency.
>
> Opportunistically sanity check KVM's reported frequency against what is
> observed via RDTSC, e.g. so that KVM_GET_TSC_KHZ or platform issues show up
> much earlier in the test, before VMs get involved.
>
> Signed-off-by: Sean Christopherson <seanjc@xxxxxxxxxx>
> ---
> .../kvm/x86/nested_tsc_scaling_test.c | 25 +++++++++++++------
> 1 file changed, 17 insertions(+), 8 deletions(-)
>
> diff --git a/tools/testing/selftests/kvm/x86/nested_tsc_scaling_test.c b/tools/testing/selftests/kvm/x86/nested_tsc_scaling_test.c
> index d790ab36a198..a78585af0ffd 100644
> --- a/tools/testing/selftests/kvm/x86/nested_tsc_scaling_test.c
> +++ b/tools/testing/selftests/kvm/x86/nested_tsc_scaling_test.c
> @@ -137,7 +137,7 @@ static void l1_guest_code(void *data)
>
> static void test_tsc_scaling(u64 l0_tsc_freq, u64 l1_scale_factor, u64 l2_scale_factor)
> {
> - u64 tsc_khz, l1_tsc_freq, l2_tsc_freq;
> + u64 l1_tsc_freq, l2_tsc_freq;
> struct kvm_vcpu *vcpu;
> struct kvm_vm *vm;
> gva_t guest_gva;
> @@ -159,11 +159,8 @@ static void test_tsc_scaling(u64 l0_tsc_freq, u64 l1_scale_factor, u64 l2_scale_
>
> vcpu_args_set(vcpu, 1, guest_gva);
>
> - tsc_khz = __vcpu_ioctl(vcpu, KVM_GET_TSC_KHZ, NULL);
> - TEST_ASSERT(tsc_khz != -1, "vcpu ioctl KVM_GET_TSC_KHZ failed");
> -
> /* scale down L1's TSC frequency */
> - vcpu_ioctl(vcpu, KVM_SET_TSC_KHZ, (void *) (tsc_khz / l1_scale_factor));
> + vcpu_ioctl(vcpu, KVM_SET_TSC_KHZ, (void *) (l0_tsc_freq / l1_scale_factor));
Our internal Sashiko complains:
[Severity: Medium]
Is l0_tsc_freq passed to KVM_SET_TSC_KHZ in Hz rather than KHz?
In main(), l0_tsc_freq is calculated in Hz by multiplying the KVM_GET_TSC_KHZ
result by 1000. Passing this value divided by l1_scale_factor into
KVM_SET_TSC_KHZ configures the guest TSC frequency 1000x larger than
intended, since the ioctl expects a value in KHz.
I concur.