On Fri, Jul 16, 2021 at 09:26:24PM +0000, Oliver Upton wrote:
> Introduce a KVM selftest to verify that userspace manipulation of the
> TSC (via the new vCPU attribute) results in the correct behavior within
> the guest.
> 
> Signed-off-by: Oliver Upton <[email protected]>
> ---
>  tools/testing/selftests/kvm/.gitignore        |   1 +
>  tools/testing/selftests/kvm/Makefile          |   1 +
>  .../kvm/system_counter_offset_test.c          | 133 ++++++++++++++++++
>  3 files changed, 135 insertions(+)
>  create mode 100644 tools/testing/selftests/kvm/system_counter_offset_test.c
> 
> diff --git a/tools/testing/selftests/kvm/.gitignore 
> b/tools/testing/selftests/kvm/.gitignore
> index d0877d01e771..2752813d5090 100644
> --- a/tools/testing/selftests/kvm/.gitignore
> +++ b/tools/testing/selftests/kvm/.gitignore
> @@ -50,3 +50,4 @@
>  /set_memory_region_test
>  /steal_time
>  /kvm_binary_stats_test
> +/system_counter_offset_test
> diff --git a/tools/testing/selftests/kvm/Makefile 
> b/tools/testing/selftests/kvm/Makefile
> index f7e24f334c6e..7bf2e5fb1d5a 100644
> --- a/tools/testing/selftests/kvm/Makefile
> +++ b/tools/testing/selftests/kvm/Makefile
> @@ -83,6 +83,7 @@ TEST_GEN_PROGS_x86_64 += memslot_perf_test
>  TEST_GEN_PROGS_x86_64 += set_memory_region_test
>  TEST_GEN_PROGS_x86_64 += steal_time
>  TEST_GEN_PROGS_x86_64 += kvm_binary_stats_test
> +TEST_GEN_PROGS_x86_64 += system_counter_offset_test
>  
>  TEST_GEN_PROGS_aarch64 += aarch64/debug-exceptions
>  TEST_GEN_PROGS_aarch64 += aarch64/get-reg-list
> diff --git a/tools/testing/selftests/kvm/system_counter_offset_test.c 
> b/tools/testing/selftests/kvm/system_counter_offset_test.c
> new file mode 100644
> index 000000000000..7e9015770759
> --- /dev/null
> +++ b/tools/testing/selftests/kvm/system_counter_offset_test.c
> @@ -0,0 +1,133 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (C) 2021, Google LLC.
> + *
> + * Tests for adjusting the system counter from userspace
> + */
> +#include <asm/kvm_para.h>
> +#include <stdint.h>
> +#include <string.h>
> +#include <sys/stat.h>
> +#include <time.h>
> +
> +#include "test_util.h"
> +#include "kvm_util.h"
> +#include "processor.h"
> +
> +#define VCPU_ID 0
> +
> +#ifdef __x86_64__
> +
> +struct test_case {
> +     uint64_t tsc_offset;
> +};
> +
> +static struct test_case test_cases[] = {
> +     { 0 },
> +     { 180 * NSEC_PER_SEC },
> +     { -180 * NSEC_PER_SEC },
> +};
> +
> +static void check_preconditions(struct kvm_vm *vm)
> +{
> +     if (!_vcpu_has_device_attr(vm, VCPU_ID, KVM_VCPU_TSC_CTRL, 
> KVM_VCPU_TSC_OFFSET))
> +             return;
> +
> +     print_skip("KVM_VCPU_TSC_OFFSET not supported; skipping test");
> +     exit(KSFT_SKIP);
> +}
> +
> +static void setup_system_counter(struct kvm_vm *vm, struct test_case *test)
> +{
> +     vcpu_access_device_attr(vm, VCPU_ID, KVM_VCPU_TSC_CTRL,
> +                             KVM_VCPU_TSC_OFFSET, &test->tsc_offset, true);
> +}
> +
> +static uint64_t guest_read_system_counter(struct test_case *test)
> +{
> +     return rdtsc();
> +}
> +
> +static uint64_t host_read_guest_system_counter(struct test_case *test)
> +{
> +     return rdtsc() + test->tsc_offset;
> +}
> +
> +#else /* __x86_64__ */
> +
> +#error test not implemented for this architecture!
> +
> +#endif
> +
> +#define GUEST_SYNC_CLOCK(__stage, __val)                     \
> +             GUEST_SYNC_ARGS(__stage, __val, 0, 0, 0)
> +
> +static void guest_main(void)
> +{
> +     int i;
> +
> +     for (i = 0; i < ARRAY_SIZE(test_cases); i++) {
> +             struct test_case *test = &test_cases[i];
> +
> +             GUEST_SYNC_CLOCK(i, guest_read_system_counter(test));
> +     }
> +
> +     GUEST_DONE();
> +}
> +
> +static void handle_sync(struct ucall *uc, uint64_t start, uint64_t end)
> +{
> +     uint64_t obs = uc->args[2];
> +
> +     TEST_ASSERT(start <= obs && obs <= end,
> +                 "unexpected system counter value: %"PRIu64" expected range: 
> [%"PRIu64", %"PRIu64"]",
> +                 obs, start, end);
> +
> +     pr_info("system counter value: %"PRIu64" expected range [%"PRIu64", 
> %"PRIu64"]\n",
> +             obs, start, end);
> +}
> +
> +static void handle_abort(struct ucall *uc)
> +{
> +     TEST_FAIL("%s at %s:%ld", (const char *)uc->args[0],
> +               __FILE__, uc->args[1]);
> +}
> +
> +static void enter_guest(struct kvm_vm *vm)
> +{
> +     uint64_t start, end;
> +     struct ucall uc;
> +     int i;
> +
> +     for (i = 0; i < ARRAY_SIZE(test_cases); i++) {
> +             struct test_case *test = &test_cases[i];
> +
> +             setup_system_counter(vm, test);
> +             start = host_read_guest_system_counter(test);
> +             vcpu_run(vm, VCPU_ID);
> +             end = host_read_guest_system_counter(test);
> +
> +             switch (get_ucall(vm, VCPU_ID, &uc)) {
> +             case UCALL_SYNC:
> +                     handle_sync(&uc, start, end);
> +                     break;
> +             case UCALL_ABORT:
> +                     handle_abort(&uc);
> +                     return;
> +             case UCALL_DONE:
> +                     return;
> +             }
> +     }
> +}
> +
> +int main(void)
> +{
> +     struct kvm_vm *vm;
> +
> +     vm = vm_create_default(VCPU_ID, 0, guest_main);
> +     check_preconditions(vm);
> +     ucall_init(vm, NULL);
> +
> +     enter_guest(vm);
> +     kvm_vm_free(vm);
> +}
> -- 
> 2.32.0.402.g57bb445576-goog
> 
> _______________________________________________
> kvmarm mailing list
> [email protected]
> https://lists.cs.columbia.edu/mailman/listinfo/kvmarm
>

Reviewed-by: Andrew Jones <[email protected]>

_______________________________________________
kvmarm mailing list
[email protected]
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

Reply via email to