Re: [PATCH v7 34/36] KVM: selftests: Add master clock offset test
Sean Christopherson <[email protected]> Fri, 31 Jul 2026 16:38:36 -0700
| Newsgroups | gmane.comp.emulators.xen.devel,gmane.comp.emulators.kvm.devel,gmane.linux.documentation,gmane.linux.kernel |
|---|---|
| Message-ID | <[email protected]> |
On Tue, Jul 28, 2026, David Woodhouse wrote: > From: David Woodhouse <[email protected]> >=20 > Verify that KVM master clock mode remains active when vCPUs have > different TSC offsets but the same frequency. Creates three vCPUs, > sets one to a different TSC value, and confirms: >=20 > - KVM_CLOCK_HOST_TSC is set (master clock active) > - KVM_CLOCK_TSC_STABLE IS set (master clock =E2=87=92 stable flag) > - PVCLOCK_TSC_STABLE_BIT is NOT set (offsets differ) >=20 > Signed-off-by: David Woodhouse <[email protected]> > Assisted-by: Kiro (claude-opus-4.6-1m) > --- > tools/testing/selftests/kvm/Makefile.kvm | 1 + > .../kvm/x86/masterclock_offset_test.c | 180 ++++++++++++++++++ > 2 files changed, 181 insertions(+) > create mode 100644 tools/testing/selftests/kvm/x86/masterclock_offset_te= st.c >=20 > diff --git a/tools/testing/selftests/kvm/Makefile.kvm b/tools/testing/sel= ftests/kvm/Makefile.kvm > index 95539deea266..f6027a35f790 100644 > --- a/tools/testing/selftests/kvm/Makefile.kvm > +++ b/tools/testing/selftests/kvm/Makefile.kvm > @@ -108,6 +108,7 @@ TEST_GEN_PROGS_x86 +=3D x86/pmu_event_filter_test > TEST_GEN_PROGS_x86 +=3D x86/private_mem_conversions_test > TEST_GEN_PROGS_x86 +=3D x86/private_mem_kvm_exits_test > TEST_GEN_PROGS_x86 +=3D x86/pvclock_test > +TEST_GEN_PROGS_x86 +=3D x86/masterclock_offset_test Keep these sorted alphabetically. > TEST_GEN_PROGS_x86 +=3D x86/pvclock_migration_test > TEST_GEN_PROGS_x86 +=3D x86/set_boot_cpu_id > TEST_GEN_PROGS_x86 +=3D x86/set_sregs_test > diff --git a/tools/testing/selftests/kvm/x86/masterclock_offset_test.c b/= tools/testing/selftests/kvm/x86/masterclock_offset_test.c > new file mode 100644 > index 000000000000..88e2bd2edab5 > --- /dev/null > +++ b/tools/testing/selftests/kvm/x86/masterclock_offset_test.c > @@ -0,0 +1,180 @@ > +// SPDX-License-Identifier: GPL-2.0-only > +/* > + * Test that KVM master clock mode works with different TSC offsets > + * as long as all vCPUs have the same TSC frequency. > + */ > +#include <stdint.h> > +#include <string.h> > + > +#include "test_util.h" > +#include "kvm_util.h" > +#include "processor.h" > + > +#include <asm/pvclock-abi.h> > + > +#define KVMCLOCK_GPA 0xc0000000ull > +#define TSC_OFFSET (1000000000ULL) > + > +static uint64_t pvclock_calc(struct pvclock_vcpu_time_info *pvti, uint64= _t guest_tsc) > +{ > + uint64_t delta =3D guest_tsc - pvti->tsc_timestamp; > + > + if (pvti->tsc_shift >=3D 0) > + delta <<=3D pvti->tsc_shift; > + else > + delta >>=3D -(int)pvti->tsc_shift; > + > + return pvti->system_time + ((__uint128_t)delta * pvti->tsc_to_system_mu= l >> 32); > +} > + > +static void guest_code(void) > +{ > + wrmsr(MSR_KVM_SYSTEM_TIME_NEW, KVMCLOCK_GPA | KVM_MSR_ENABLED); > + for (;;) > + GUEST_SYNC(0); > +} > + > +int main(void) > +{ > + struct kvm_vcpu *vcpus[3]; > + struct kvm_clock_data clock; > + struct pvclock_vcpu_time_info pvti[3]; > + struct kvm_vm *vm; > + uint64_t offset0, host_tsc, clk0, clk2; > + int i; > + > + TEST_REQUIRE(sys_clocksource_is_based_on_tsc()); > + > + vm =3D vm_create_with_vcpus(3, guest_code, vcpus); > + > + TEST_REQUIRE(!__vcpu_has_device_attr(vcpus[0], KVM_VCPU_TSC_CTRL, > + KVM_VCPU_TSC_OFFSET)); > + > + vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS, > + KVMCLOCK_GPA, 1, > + vm_calc_num_guest_pages(VM_MODE_DEFAULT, > + getpagesize()), 0); > + virt_map(vm, KVMCLOCK_GPA, KVMCLOCK_GPA, > + vm_calc_num_guest_pages(VM_MODE_DEFAULT, getpagesize())); > + > + /* Get vCPU 0's default offset and set vCPU 2's offset higher */ > + vcpu_device_attr_get(vcpus[0], KVM_VCPU_TSC_CTRL, > + KVM_VCPU_TSC_OFFSET, &offset0); > + uint64_t offset2 =3D offset0 + TSC_OFFSET; > + vcpu_device_attr_set(vcpus[2], KVM_VCPU_TSC_CTRL, > + KVM_VCPU_TSC_OFFSET, &offset2); > + > + /* Run each vCPU to enable kvmclock (with offset already set) */ > + for (i =3D 0; i < 3; i++) { ARRAY_SIZE(vcpus) > + vcpu_run(vcpus[i]); > + TEST_ASSERT_KVM_EXIT_REASON(vcpus[i], KVM_EXIT_IO); > + } > + > + /* Check master clock is active */ > + memset(&clock, 0, sizeof(clock)); > + vm_ioctl(vm, KVM_GET_CLOCK, &clock); Provide an API. > + pr_info("KVM_GET_CLOCK flags: 0x%x\n", clock.flags); > + TEST_ASSERT(clock.flags & KVM_CLOCK_HOST_TSC, > + "Master clock should be active, flags=3D0x%x", clock.flags); > + TEST_ASSERT(clock.flags & KVM_CLOCK_TSC_STABLE, > + "KVM_CLOCK_TSC_STABLE should be set, flags=3D0x%x", clock.flags); > + > + /* Get per-vCPU pvclock in order 0, 2, 1 */ > + int order[] =3D {0, 2, 1}; Please don't declare variables in the middle code. Yes, it's now technical= ly possible thanks to all the guard() magic, but it's still against preferred = kernel style. Though this itself is probably a really, really good indication that this n= eeds to be split into multiple testcases. Maybe using TEST_F() and a custom fix= ture?