0001
0002
0003
0004
0005
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
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 }