1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (C) 2021, Google LLC.
5 * Tests for adjusting the KVM clock from userspace
7 #include <asm/kvm_para.h>
8 #include <asm/pvclock.h>
9 #include <asm/pvclock-abi.h>
15 #include "test_util.h"
17 #include "processor.h"
20 uint64_t kvmclock_base
;
21 int64_t realtime_offset
;
24 static struct test_case test_cases
[] = {
25 { .kvmclock_base
= 0 },
26 { .kvmclock_base
= 180 * NSEC_PER_SEC
},
27 { .kvmclock_base
= 0, .realtime_offset
= -180 * NSEC_PER_SEC
},
28 { .kvmclock_base
= 0, .realtime_offset
= 180 * NSEC_PER_SEC
},
31 #define GUEST_SYNC_CLOCK(__stage, __val) \
32 GUEST_SYNC_ARGS(__stage, __val, 0, 0, 0)
34 static void guest_main(vm_paddr_t pvti_pa
, struct pvclock_vcpu_time_info
*pvti
)
38 wrmsr(MSR_KVM_SYSTEM_TIME_NEW
, pvti_pa
| KVM_MSR_ENABLED
);
39 for (i
= 0; i
< ARRAY_SIZE(test_cases
); i
++)
40 GUEST_SYNC_CLOCK(i
, __pvclock_read_cycles(pvti
, rdtsc()));
43 #define EXPECTED_FLAGS (KVM_CLOCK_REALTIME | KVM_CLOCK_HOST_TSC)
45 static inline void assert_flags(struct kvm_clock_data
*data
)
47 TEST_ASSERT((data
->flags
& EXPECTED_FLAGS
) == EXPECTED_FLAGS
,
48 "unexpected clock data flags: %x (want set: %x)",
49 data
->flags
, EXPECTED_FLAGS
);
52 static void handle_sync(struct ucall
*uc
, struct kvm_clock_data
*start
,
53 struct kvm_clock_data
*end
)
55 uint64_t obs
, exp_lo
, exp_hi
;
58 exp_lo
= start
->clock
;
64 TEST_ASSERT(exp_lo
<= obs
&& obs
<= exp_hi
,
65 "unexpected kvm-clock value: %"PRIu64
" expected range: [%"PRIu64
", %"PRIu64
"]",
68 pr_info("kvm-clock value: %"PRIu64
" expected range [%"PRIu64
", %"PRIu64
"]\n",
72 static void handle_abort(struct ucall
*uc
)
74 REPORT_GUEST_ASSERT(*uc
);
77 static void setup_clock(struct kvm_vm
*vm
, struct test_case
*test_case
)
79 struct kvm_clock_data data
;
81 memset(&data
, 0, sizeof(data
));
83 data
.clock
= test_case
->kvmclock_base
;
84 if (test_case
->realtime_offset
) {
88 data
.flags
|= KVM_CLOCK_REALTIME
;
90 r
= clock_gettime(CLOCK_REALTIME
, &ts
);
93 } while (errno
== EINTR
);
95 TEST_ASSERT(!r
, "clock_gettime() failed: %d", r
);
97 data
.realtime
= ts
.tv_sec
* NSEC_PER_SEC
;
98 data
.realtime
+= ts
.tv_nsec
;
99 data
.realtime
+= test_case
->realtime_offset
;
102 vm_ioctl(vm
, KVM_SET_CLOCK
, &data
);
105 static void enter_guest(struct kvm_vcpu
*vcpu
)
107 struct kvm_clock_data start
, end
;
108 struct kvm_vm
*vm
= vcpu
->vm
;
112 for (i
= 0; i
< ARRAY_SIZE(test_cases
); i
++) {
113 setup_clock(vm
, &test_cases
[i
]);
115 vm_ioctl(vm
, KVM_GET_CLOCK
, &start
);
118 vm_ioctl(vm
, KVM_GET_CLOCK
, &end
);
120 TEST_ASSERT_KVM_EXIT_REASON(vcpu
, KVM_EXIT_IO
);
122 switch (get_ucall(vcpu
, &uc
)) {
124 handle_sync(&uc
, &start
, &end
);
130 TEST_ASSERT(0, "unhandled ucall: %ld", uc
.cmd
);
137 struct kvm_vcpu
*vcpu
;
143 flags
= kvm_check_cap(KVM_CAP_ADJUST_CLOCK
);
144 TEST_REQUIRE(flags
& KVM_CLOCK_REALTIME
);
146 TEST_REQUIRE(sys_clocksource_is_based_on_tsc());
148 vm
= vm_create_with_one_vcpu(&vcpu
, guest_main
);
150 pvti_gva
= vm_vaddr_alloc(vm
, getpagesize(), 0x10000);
151 pvti_gpa
= addr_gva2gpa(vm
, pvti_gva
);
152 vcpu_args_set(vcpu
, 2, pvti_gpa
, pvti_gva
);