[PATCH v2 07/12] selftests: KVM: Introduce system counter offset test

Andrew Jones drjones at redhat.com
Wed Jul 21 08:17:33 PDT 2021


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 <oupton at google.com>
> ---
>  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
> kvmarm at lists.cs.columbia.edu
> https://lists.cs.columbia.edu/mailman/listinfo/kvmarm
>

Reviewed-by: Andrew Jones <drjones at redhat.com>




More information about the linux-arm-kernel mailing list