13f9808caSOliver Upton // SPDX-License-Identifier: GPL-2.0-only 23f9808caSOliver Upton /* 33f9808caSOliver Upton * Copyright (C) 2021, Google LLC. 43f9808caSOliver Upton * 53f9808caSOliver Upton * Tests for adjusting the system counter from userspace 63f9808caSOliver Upton */ 73f9808caSOliver Upton #include <asm/kvm_para.h> 83f9808caSOliver Upton #include <stdint.h> 93f9808caSOliver Upton #include <string.h> 103f9808caSOliver Upton #include <sys/stat.h> 113f9808caSOliver Upton #include <time.h> 123f9808caSOliver Upton 133f9808caSOliver Upton #include "test_util.h" 143f9808caSOliver Upton #include "kvm_util.h" 153f9808caSOliver Upton #include "processor.h" 163f9808caSOliver Upton 173f9808caSOliver Upton #ifdef __x86_64__ 183f9808caSOliver Upton 193f9808caSOliver Upton struct test_case { 203f9808caSOliver Upton uint64_t tsc_offset; 213f9808caSOliver Upton }; 223f9808caSOliver Upton 233f9808caSOliver Upton static struct test_case test_cases[] = { 243f9808caSOliver Upton { 0 }, 253f9808caSOliver Upton { 180 * NSEC_PER_SEC }, 263f9808caSOliver Upton { -180 * NSEC_PER_SEC }, 273f9808caSOliver Upton }; 283f9808caSOliver Upton 29*10f0b222SSean Christopherson static void check_preconditions(struct kvm_vcpu *vcpu) 303f9808caSOliver Upton { 31*10f0b222SSean Christopherson if (!__vcpu_has_device_attr(vcpu->vm, vcpu->id, KVM_VCPU_TSC_CTRL, 32*10f0b222SSean Christopherson KVM_VCPU_TSC_OFFSET)) 333f9808caSOliver Upton return; 343f9808caSOliver Upton 353f9808caSOliver Upton print_skip("KVM_VCPU_TSC_OFFSET not supported; skipping test"); 363f9808caSOliver Upton exit(KSFT_SKIP); 373f9808caSOliver Upton } 383f9808caSOliver Upton 39*10f0b222SSean Christopherson static void setup_system_counter(struct kvm_vcpu *vcpu, struct test_case *test) 403f9808caSOliver Upton { 41*10f0b222SSean Christopherson vcpu_device_attr_set(vcpu->vm, vcpu->id, KVM_VCPU_TSC_CTRL, 4240918184SSean Christopherson KVM_VCPU_TSC_OFFSET, &test->tsc_offset); 433f9808caSOliver Upton } 443f9808caSOliver Upton 453f9808caSOliver Upton static uint64_t guest_read_system_counter(struct test_case *test) 463f9808caSOliver Upton { 473f9808caSOliver Upton return rdtsc(); 483f9808caSOliver Upton } 493f9808caSOliver Upton 503f9808caSOliver Upton static uint64_t host_read_guest_system_counter(struct test_case *test) 513f9808caSOliver Upton { 523f9808caSOliver Upton return rdtsc() + test->tsc_offset; 533f9808caSOliver Upton } 543f9808caSOliver Upton 553f9808caSOliver Upton #else /* __x86_64__ */ 563f9808caSOliver Upton 573f9808caSOliver Upton #error test not implemented for this architecture! 583f9808caSOliver Upton 593f9808caSOliver Upton #endif 603f9808caSOliver Upton 613f9808caSOliver Upton #define GUEST_SYNC_CLOCK(__stage, __val) \ 623f9808caSOliver Upton GUEST_SYNC_ARGS(__stage, __val, 0, 0, 0) 633f9808caSOliver Upton 643f9808caSOliver Upton static void guest_main(void) 653f9808caSOliver Upton { 663f9808caSOliver Upton int i; 673f9808caSOliver Upton 683f9808caSOliver Upton for (i = 0; i < ARRAY_SIZE(test_cases); i++) { 693f9808caSOliver Upton struct test_case *test = &test_cases[i]; 703f9808caSOliver Upton 713f9808caSOliver Upton GUEST_SYNC_CLOCK(i, guest_read_system_counter(test)); 723f9808caSOliver Upton } 733f9808caSOliver Upton } 743f9808caSOliver Upton 753f9808caSOliver Upton static void handle_sync(struct ucall *uc, uint64_t start, uint64_t end) 763f9808caSOliver Upton { 773f9808caSOliver Upton uint64_t obs = uc->args[2]; 783f9808caSOliver Upton 793f9808caSOliver Upton TEST_ASSERT(start <= obs && obs <= end, 803f9808caSOliver Upton "unexpected system counter value: %"PRIu64" expected range: [%"PRIu64", %"PRIu64"]", 813f9808caSOliver Upton obs, start, end); 823f9808caSOliver Upton 833f9808caSOliver Upton pr_info("system counter value: %"PRIu64" expected range [%"PRIu64", %"PRIu64"]\n", 843f9808caSOliver Upton obs, start, end); 853f9808caSOliver Upton } 863f9808caSOliver Upton 873f9808caSOliver Upton static void handle_abort(struct ucall *uc) 883f9808caSOliver Upton { 893f9808caSOliver Upton TEST_FAIL("%s at %s:%ld", (const char *)uc->args[0], 903f9808caSOliver Upton __FILE__, uc->args[1]); 913f9808caSOliver Upton } 923f9808caSOliver Upton 93*10f0b222SSean Christopherson static void enter_guest(struct kvm_vcpu *vcpu) 943f9808caSOliver Upton { 953f9808caSOliver Upton uint64_t start, end; 963f9808caSOliver Upton struct ucall uc; 973f9808caSOliver Upton int i; 983f9808caSOliver Upton 993f9808caSOliver Upton for (i = 0; i < ARRAY_SIZE(test_cases); i++) { 1003f9808caSOliver Upton struct test_case *test = &test_cases[i]; 1013f9808caSOliver Upton 102*10f0b222SSean Christopherson setup_system_counter(vcpu, test); 1033f9808caSOliver Upton start = host_read_guest_system_counter(test); 104*10f0b222SSean Christopherson vcpu_run(vcpu->vm, vcpu->id); 1053f9808caSOliver Upton end = host_read_guest_system_counter(test); 1063f9808caSOliver Upton 107*10f0b222SSean Christopherson switch (get_ucall(vcpu->vm, vcpu->id, &uc)) { 1083f9808caSOliver Upton case UCALL_SYNC: 1093f9808caSOliver Upton handle_sync(&uc, start, end); 1103f9808caSOliver Upton break; 1113f9808caSOliver Upton case UCALL_ABORT: 1123f9808caSOliver Upton handle_abort(&uc); 1133f9808caSOliver Upton return; 1143f9808caSOliver Upton default: 1153f9808caSOliver Upton TEST_ASSERT(0, "unhandled ucall %ld\n", 116*10f0b222SSean Christopherson get_ucall(vcpu->vm, vcpu->id, &uc)); 1173f9808caSOliver Upton } 1183f9808caSOliver Upton } 1193f9808caSOliver Upton } 1203f9808caSOliver Upton 1213f9808caSOliver Upton int main(void) 1223f9808caSOliver Upton { 123*10f0b222SSean Christopherson struct kvm_vcpu *vcpu; 1243f9808caSOliver Upton struct kvm_vm *vm; 1253f9808caSOliver Upton 126*10f0b222SSean Christopherson vm = vm_create_with_one_vcpu(&vcpu, guest_main); 127*10f0b222SSean Christopherson check_preconditions(vcpu); 1283f9808caSOliver Upton ucall_init(vm, NULL); 1293f9808caSOliver Upton 130*10f0b222SSean Christopherson enter_guest(vcpu); 1313f9808caSOliver Upton kvm_vm_free(vm); 1323f9808caSOliver Upton } 133