- Define _GNU_SOURCE for all selftests to fix a warning that was introduced by a change to kselftest_harness.h late in the 6.9 cycle, and because forcing every test to #define _GNU_SOURCE is painful. - Provide a global psuedo-RNG instance for all tests, so that library code can generate random, but determinstic numbers. - Use the global pRNG to randomly force emulation of select writes from guest code on x86, e.g. to help validate KVM's emulation of locked accesses. - Rename kvm_util_base.h back to kvm_util.h, as the weird layer of indirection was added purely to avoid manually #including ucall_common.h in a handful of locations. - Allocate and initialize x86's GDT, IDT, TSS, segments, and default exception handlers at VM creation, instead of forcing tests to manually trigger the related setup. -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEKTobbabEP7vbhhN9OlYIJqCjN/0FAmY+qhoACgkQOlYIJqCj N/2coRAAicA2485dlMjLbRazrb58dFiT8XheKKTHQwWRZPhxUMI8Rqo9Hp74t2tc hU1+VXIupzTH4hXxTmqrTtsJsulhdgbQMzxeefK9U8WxS2jsHnC5Ltx9hmGWQG92 FeUhkDka1zc52bhMGOY43A5rNxCfQ0GYCWdHnILw2tqWQhqAvEuma7CwVYm85zTe gl6Bfe1sokjnx1EIdwC4SyfDAh9DXIah02b7GvbTvkrNcLBpxnRp19mZlmSqSg9L 5VVPup2oSeKZAhXYP3dWgUGGJtT96tpz60QwkmVxcNIqvL41CsmW7wB9ODzYlihQ uBmlchx9NIR9+ICL2DaZi5UfmrfeRW2sYVH9K0NewDswV8N36/pMabN+gWCKjZ7m 5K99nY6xtVmTkxdgJEQ1n4+oa2VTD68H52/hwvO5e6Kd1yab+SKoBf4LKxXu6gO7 P2hcM+FGwJlSU6gmI7B4+2RNFPurplVgC5MN7cJuEivKXhTXL8GzbOCxsRhCynIk z+L+nnrSRiXAD45uYon1UIXLszANYfjizx7/fL5hC2mtpARP9S35zIDCCzEBNWWt VI30/O0GAH/d6p1Rows/DzPmFJKbc+YVHoW9Ck8OP9axQHZuFoj6Qdy8BSwb8O+u B0rJXUyVFh2jwZ2zkMPDnDS5FOhqmTXxZSNj+i5tX/BZus7Iews= =vsRz -----END PGP SIGNATURE----- Merge tag 'kvm-x86-selftests_utils-6.10' of https://github.com/kvm-x86/linux into HEAD KVM selftests treewide updates for 6.10: - Define _GNU_SOURCE for all selftests to fix a warning that was introduced by a change to kselftest_harness.h late in the 6.9 cycle, and because forcing every test to #define _GNU_SOURCE is painful. - Provide a global psuedo-RNG instance for all tests, so that library code can generate random, but determinstic numbers. - Use the global pRNG to randomly force emulation of select writes from guest code on x86, e.g. to help validate KVM's emulation of locked accesses. - Rename kvm_util_base.h back to kvm_util.h, as the weird layer of indirection was added purely to avoid manually #including ucall_common.h in a handful of locations. - Allocate and initialize x86's GDT, IDT, TSS, segments, and default exception handlers at VM creation, instead of forcing tests to manually trigger the related setup.
109 lines
2.9 KiB
C
109 lines
2.9 KiB
C
// SPDX-License-Identifier: GPL-2.0-only
|
|
/*
|
|
* arch_timer.c - Tests the riscv64 sstc timer IRQ functionality
|
|
*
|
|
* The test validates the sstc timer IRQs using vstimecmp registers.
|
|
* It's ported from the aarch64 arch_timer test.
|
|
*
|
|
* Copyright (c) 2024, Intel Corporation.
|
|
*/
|
|
#include "arch_timer.h"
|
|
#include "kvm_util.h"
|
|
#include "processor.h"
|
|
#include "timer_test.h"
|
|
#include "ucall_common.h"
|
|
|
|
static int timer_irq = IRQ_S_TIMER;
|
|
|
|
static void guest_irq_handler(struct ex_regs *regs)
|
|
{
|
|
uint64_t xcnt, xcnt_diff_us, cmp;
|
|
unsigned int intid = regs->cause & ~CAUSE_IRQ_FLAG;
|
|
uint32_t cpu = guest_get_vcpuid();
|
|
struct test_vcpu_shared_data *shared_data = &vcpu_shared_data[cpu];
|
|
|
|
timer_irq_disable();
|
|
|
|
xcnt = timer_get_cycles();
|
|
cmp = timer_get_cmp();
|
|
xcnt_diff_us = cycles_to_usec(xcnt - shared_data->xcnt);
|
|
|
|
/* Make sure we are dealing with the correct timer IRQ */
|
|
GUEST_ASSERT_EQ(intid, timer_irq);
|
|
|
|
__GUEST_ASSERT(xcnt >= cmp,
|
|
"xcnt = 0x%"PRIx64", cmp = 0x%"PRIx64", xcnt_diff_us = 0x%" PRIx64,
|
|
xcnt, cmp, xcnt_diff_us);
|
|
|
|
WRITE_ONCE(shared_data->nr_iter, shared_data->nr_iter + 1);
|
|
}
|
|
|
|
static void guest_run(struct test_vcpu_shared_data *shared_data)
|
|
{
|
|
uint32_t irq_iter, config_iter;
|
|
|
|
shared_data->nr_iter = 0;
|
|
shared_data->guest_stage = 0;
|
|
|
|
for (config_iter = 0; config_iter < test_args.nr_iter; config_iter++) {
|
|
/* Setup the next interrupt */
|
|
timer_set_next_cmp_ms(test_args.timer_period_ms);
|
|
shared_data->xcnt = timer_get_cycles();
|
|
timer_irq_enable();
|
|
|
|
/* Setup a timeout for the interrupt to arrive */
|
|
udelay(msecs_to_usecs(test_args.timer_period_ms) +
|
|
test_args.timer_err_margin_us);
|
|
|
|
irq_iter = READ_ONCE(shared_data->nr_iter);
|
|
__GUEST_ASSERT(config_iter + 1 == irq_iter,
|
|
"config_iter + 1 = 0x%x, irq_iter = 0x%x.\n"
|
|
" Guest timer interrupt was not triggered within the specified\n"
|
|
" interval, try to increase the error margin by [-e] option.\n",
|
|
config_iter + 1, irq_iter);
|
|
}
|
|
}
|
|
|
|
static void guest_code(void)
|
|
{
|
|
uint32_t cpu = guest_get_vcpuid();
|
|
struct test_vcpu_shared_data *shared_data = &vcpu_shared_data[cpu];
|
|
|
|
timer_irq_disable();
|
|
local_irq_enable();
|
|
|
|
guest_run(shared_data);
|
|
|
|
GUEST_DONE();
|
|
}
|
|
|
|
struct kvm_vm *test_vm_create(void)
|
|
{
|
|
struct kvm_vm *vm;
|
|
int nr_vcpus = test_args.nr_vcpus;
|
|
|
|
vm = vm_create_with_vcpus(nr_vcpus, guest_code, vcpus);
|
|
__TEST_REQUIRE(__vcpu_has_isa_ext(vcpus[0], KVM_RISCV_ISA_EXT_SSTC),
|
|
"SSTC not available, skipping test\n");
|
|
|
|
vm_init_vector_tables(vm);
|
|
vm_install_interrupt_handler(vm, guest_irq_handler);
|
|
|
|
for (int i = 0; i < nr_vcpus; i++)
|
|
vcpu_init_vector_tables(vcpus[i]);
|
|
|
|
/* Initialize guest timer frequency. */
|
|
vcpu_get_reg(vcpus[0], RISCV_TIMER_REG(frequency), &timer_freq);
|
|
sync_global_to_guest(vm, timer_freq);
|
|
pr_debug("timer_freq: %lu\n", timer_freq);
|
|
|
|
/* Make all the test's cmdline args visible to the guest */
|
|
sync_global_to_guest(vm, test_args);
|
|
|
|
return vm;
|
|
}
|
|
|
|
void test_vm_cleanup(struct kvm_vm *vm)
|
|
{
|
|
kvm_vm_free(vm);
|
|
}
|