~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/tools/testing/selftests/kvm/x86_64/kvm_clock_test.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0-only
  2 /*
  3  * Copyright (C) 2021, Google LLC.
  4  *
  5  * Tests for adjusting the KVM clock from userspace
  6  */
  7 #include <asm/kvm_para.h>
  8 #include <asm/pvclock.h>
  9 #include <asm/pvclock-abi.h>
 10 #include <stdint.h>
 11 #include <string.h>
 12 #include <sys/stat.h>
 13 #include <time.h>
 14 
 15 #include "test_util.h"
 16 #include "kvm_util.h"
 17 #include "processor.h"
 18 
 19 struct test_case {
 20         uint64_t kvmclock_base;
 21         int64_t realtime_offset;
 22 };
 23 
 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 },
 29 };
 30 
 31 #define GUEST_SYNC_CLOCK(__stage, __val)                        \
 32                 GUEST_SYNC_ARGS(__stage, __val, 0, 0, 0)
 33 
 34 static void guest_main(vm_paddr_t pvti_pa, struct pvclock_vcpu_time_info *pvti)
 35 {
 36         int i;
 37 
 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()));
 41 }
 42 
 43 #define EXPECTED_FLAGS (KVM_CLOCK_REALTIME | KVM_CLOCK_HOST_TSC)
 44 
 45 static inline void assert_flags(struct kvm_clock_data *data)
 46 {
 47         TEST_ASSERT((data->flags & EXPECTED_FLAGS) == EXPECTED_FLAGS,
 48                     "unexpected clock data flags: %x (want set: %x)",
 49                     data->flags, EXPECTED_FLAGS);
 50 }
 51 
 52 static void handle_sync(struct ucall *uc, struct kvm_clock_data *start,
 53                         struct kvm_clock_data *end)
 54 {
 55         uint64_t obs, exp_lo, exp_hi;
 56 
 57         obs = uc->args[2];
 58         exp_lo = start->clock;
 59         exp_hi = end->clock;
 60 
 61         assert_flags(start);
 62         assert_flags(end);
 63 
 64         TEST_ASSERT(exp_lo <= obs && obs <= exp_hi,
 65                     "unexpected kvm-clock value: %"PRIu64" expected range: [%"PRIu64", %"PRIu64"]",
 66                     obs, exp_lo, exp_hi);
 67 
 68         pr_info("kvm-clock value: %"PRIu64" expected range [%"PRIu64", %"PRIu64"]\n",
 69                 obs, exp_lo, exp_hi);
 70 }
 71 
 72 static void handle_abort(struct ucall *uc)
 73 {
 74         REPORT_GUEST_ASSERT(*uc);
 75 }
 76 
 77 static void setup_clock(struct kvm_vm *vm, struct test_case *test_case)
 78 {
 79         struct kvm_clock_data data;
 80 
 81         memset(&data, 0, sizeof(data));
 82 
 83         data.clock = test_case->kvmclock_base;
 84         if (test_case->realtime_offset) {
 85                 struct timespec ts;
 86                 int r;
 87 
 88                 data.flags |= KVM_CLOCK_REALTIME;
 89                 do {
 90                         r = clock_gettime(CLOCK_REALTIME, &ts);
 91                         if (!r)
 92                                 break;
 93                 } while (errno == EINTR);
 94 
 95                 TEST_ASSERT(!r, "clock_gettime() failed: %d", r);
 96 
 97                 data.realtime = ts.tv_sec * NSEC_PER_SEC;
 98                 data.realtime += ts.tv_nsec;
 99                 data.realtime += test_case->realtime_offset;
100         }
101 
102         vm_ioctl(vm, KVM_SET_CLOCK, &data);
103 }
104 
105 static void enter_guest(struct kvm_vcpu *vcpu)
106 {
107         struct kvm_clock_data start, end;
108         struct kvm_vm *vm = vcpu->vm;
109         struct ucall uc;
110         int i;
111 
112         for (i = 0; i < ARRAY_SIZE(test_cases); i++) {
113                 setup_clock(vm, &test_cases[i]);
114 
115                 vm_ioctl(vm, KVM_GET_CLOCK, &start);
116 
117                 vcpu_run(vcpu);
118                 vm_ioctl(vm, KVM_GET_CLOCK, &end);
119 
120                 TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_IO);
121 
122                 switch (get_ucall(vcpu, &uc)) {
123                 case UCALL_SYNC:
124                         handle_sync(&uc, &start, &end);
125                         break;
126                 case UCALL_ABORT:
127                         handle_abort(&uc);
128                         return;
129                 default:
130                         TEST_ASSERT(0, "unhandled ucall: %ld", uc.cmd);
131                 }
132         }
133 }
134 
135 int main(void)
136 {
137         struct kvm_vcpu *vcpu;
138         vm_vaddr_t pvti_gva;
139         vm_paddr_t pvti_gpa;
140         struct kvm_vm *vm;
141         int flags;
142 
143         flags = kvm_check_cap(KVM_CAP_ADJUST_CLOCK);
144         TEST_REQUIRE(flags & KVM_CLOCK_REALTIME);
145 
146         TEST_REQUIRE(sys_clocksource_is_based_on_tsc());
147 
148         vm = vm_create_with_one_vcpu(&vcpu, guest_main);
149 
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);
153 
154         enter_guest(vcpu);
155         kvm_vm_free(vm);
156 }
157 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php