Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (C) 2021, Google LLC.
0004  *
0005  * Tests for adjusting the system counter from userspace
0006  */
0007 #include <asm/kvm_para.h>
0008 #include <stdint.h>
0009 #include <string.h>
0010 #include <sys/stat.h>
0011 #include <time.h>
0012 
0013 #include "test_util.h"
0014 #include "kvm_util.h"
0015 #include "processor.h"
0016 
0017 #ifdef __x86_64__
0018 
0019 struct test_case {
0020     uint64_t tsc_offset;
0021 };
0022 
0023 static struct test_case test_cases[] = {
0024     { 0 },
0025     { 180 * NSEC_PER_SEC },
0026     { -180 * NSEC_PER_SEC },
0027 };
0028 
0029 static void check_preconditions(struct kvm_vcpu *vcpu)
0030 {
0031     __TEST_REQUIRE(!__vcpu_has_device_attr(vcpu, KVM_VCPU_TSC_CTRL,
0032                            KVM_VCPU_TSC_OFFSET),
0033                "KVM_VCPU_TSC_OFFSET not supported; skipping test");
0034 }
0035 
0036 static void setup_system_counter(struct kvm_vcpu *vcpu, struct test_case *test)
0037 {
0038     vcpu_device_attr_set(vcpu, KVM_VCPU_TSC_CTRL, KVM_VCPU_TSC_OFFSET,
0039                  &test->tsc_offset);
0040 }
0041 
0042 static uint64_t guest_read_system_counter(struct test_case *test)
0043 {
0044     return rdtsc();
0045 }
0046 
0047 static uint64_t host_read_guest_system_counter(struct test_case *test)
0048 {
0049     return rdtsc() + test->tsc_offset;
0050 }
0051 
0052 #else /* __x86_64__ */
0053 
0054 #error test not implemented for this architecture!
0055 
0056 #endif
0057 
0058 #define GUEST_SYNC_CLOCK(__stage, __val)            \
0059         GUEST_SYNC_ARGS(__stage, __val, 0, 0, 0)
0060 
0061 static void guest_main(void)
0062 {
0063     int i;
0064 
0065     for (i = 0; i < ARRAY_SIZE(test_cases); i++) {
0066         struct test_case *test = &test_cases[i];
0067 
0068         GUEST_SYNC_CLOCK(i, guest_read_system_counter(test));
0069     }
0070 }
0071 
0072 static void handle_sync(struct ucall *uc, uint64_t start, uint64_t end)
0073 {
0074     uint64_t obs = uc->args[2];
0075 
0076     TEST_ASSERT(start <= obs && obs <= end,
0077             "unexpected system counter value: %"PRIu64" expected range: [%"PRIu64", %"PRIu64"]",
0078             obs, start, end);
0079 
0080     pr_info("system counter value: %"PRIu64" expected range [%"PRIu64", %"PRIu64"]\n",
0081         obs, start, end);
0082 }
0083 
0084 static void handle_abort(struct ucall *uc)
0085 {
0086     REPORT_GUEST_ASSERT(*uc);
0087 }
0088 
0089 static void enter_guest(struct kvm_vcpu *vcpu)
0090 {
0091     uint64_t start, end;
0092     struct ucall uc;
0093     int i;
0094 
0095     for (i = 0; i < ARRAY_SIZE(test_cases); i++) {
0096         struct test_case *test = &test_cases[i];
0097 
0098         setup_system_counter(vcpu, test);
0099         start = host_read_guest_system_counter(test);
0100         vcpu_run(vcpu);
0101         end = host_read_guest_system_counter(test);
0102 
0103         switch (get_ucall(vcpu, &uc)) {
0104         case UCALL_SYNC:
0105             handle_sync(&uc, start, end);
0106             break;
0107         case UCALL_ABORT:
0108             handle_abort(&uc);
0109             return;
0110         default:
0111             TEST_ASSERT(0, "unhandled ucall %ld\n",
0112                     get_ucall(vcpu, &uc));
0113         }
0114     }
0115 }
0116 
0117 int main(void)
0118 {
0119     struct kvm_vcpu *vcpu;
0120     struct kvm_vm *vm;
0121 
0122     vm = vm_create_with_one_vcpu(&vcpu, guest_main);
0123     check_preconditions(vcpu);
0124     ucall_init(vm, NULL);
0125 
0126     enter_guest(vcpu);
0127     kvm_vm_free(vm);
0128 }