KVM: arm64: selftests: Create a VGICv3 for 'default' VMs

Start creating a VGICv3 by default unless explicitly opted-out by the
test. While having an interrupt controller is nice, the real benefit
here is clearing a hurdle for EL2 VMs which mandate the presence of a
VGIC.

Signed-off-by: Oliver Upton <oliver.upton@linux.dev>
Signed-off-by: Marc Zyngier <maz@kernel.org>
This commit is contained in:
Oliver Upton 2025-09-17 14:20:35 -07:00 committed by Marc Zyngier
parent b8daa7ceac
commit 8911c7dbc6
19 changed files with 60 additions and 56 deletions

View File

@ -176,8 +176,6 @@ static void test_init_timer_irq(struct kvm_vm *vm)
pr_debug("ptimer_irq: %d; vtimer_irq: %d\n", ptimer_irq, vtimer_irq);
}
static int gic_fd;
struct kvm_vm *test_vm_create(void)
{
struct kvm_vm *vm;
@ -206,7 +204,6 @@ struct kvm_vm *test_vm_create(void)
vcpu_init_descriptor_tables(vcpus[i]);
test_init_timer_irq(vm);
gic_fd = vgic_v3_setup(vm, nr_vcpus, 64);
/* Make all the test's cmdline args visible to the guest */
sync_global_to_guest(vm, test_args);
@ -216,6 +213,5 @@ struct kvm_vm *test_vm_create(void)
void test_vm_cleanup(struct kvm_vm *vm)
{
close(gic_fd);
kvm_vm_free(vm);
}

View File

@ -935,8 +935,6 @@ static void test_init_timer_irq(struct kvm_vm *vm, struct kvm_vcpu *vcpu)
pr_debug("ptimer_irq: %d; vtimer_irq: %d\n", ptimer_irq, vtimer_irq);
}
static int gic_fd;
static void test_vm_create(struct kvm_vm **vm, struct kvm_vcpu **vcpu,
enum arch_timer timer)
{
@ -951,7 +949,6 @@ static void test_vm_create(struct kvm_vm **vm, struct kvm_vcpu **vcpu,
vcpu_args_set(*vcpu, 1, timer);
test_init_timer_irq(*vm, *vcpu);
gic_fd = vgic_v3_setup(*vm, 1, 64);
sync_global_to_guest(*vm, test_args);
sync_global_to_guest(*vm, CVAL_MAX);
@ -960,7 +957,6 @@ static void test_vm_create(struct kvm_vm **vm, struct kvm_vcpu **vcpu,
static void test_vm_cleanup(struct kvm_vm *vm)
{
close(gic_fd);
kvm_vm_free(vm);
}

View File

@ -163,6 +163,8 @@ int main(int argc, char *argv[])
struct kvm_vm *vm;
uint64_t pfr0;
test_disable_default_vgic();
vm = vm_create_with_one_vcpu(&vcpu, NULL);
pfr0 = vcpu_get_reg(vcpu, KVM_ARM64_SYS_REG(SYS_ID_AA64PFR0_EL1));
__TEST_REQUIRE(FIELD_GET(ID_AA64PFR0_EL1_GIC, pfr0),

View File

@ -95,6 +95,7 @@ static struct kvm_vm *setup_vm(void *guest_code, struct kvm_vcpu **source,
*source = aarch64_vcpu_add(vm, 0, &init, guest_code);
*target = aarch64_vcpu_add(vm, 1, &init, guest_code);
kvm_arch_vm_finalize_vcpus(vm);
return vm;
}

View File

@ -763,6 +763,7 @@ int main(void)
vm = vm_create(1);
vm_enable_cap(vm, KVM_CAP_ARM_WRITABLE_IMP_ID_REGS, 0);
vcpu = vm_vcpu_add(vm, 0, guest_code);
kvm_arch_vm_finalize_vcpus(vm);
/* Check for AARCH64 only system */
val = vcpu_get_reg(vcpu, KVM_ARM64_SYS_REG(SYS_ID_AA64PFR0_EL1));

View File

@ -73,6 +73,7 @@ static struct kvm_vm *setup_vm(struct kvm_vcpu **vcpu)
init.features[0] |= (1 << KVM_ARM_VCPU_PSCI_0_2);
*vcpu = aarch64_vcpu_add(vm, 0, &init, guest_main);
kvm_arch_vm_finalize_vcpus(vm);
return vm;
}

View File

@ -994,6 +994,8 @@ int main(int ac, char **av)
int pa_bits;
int cnt_impl = 0;
test_disable_default_vgic();
pa_bits = vm_guest_mode_params[VM_MODE_DEFAULT].pa_bits;
max_phys_size = 1ULL << pa_bits;

View File

@ -802,6 +802,7 @@ int main(int argc, char **argv)
bool eoi_split = false;
TEST_REQUIRE(kvm_supports_vgic_v3());
test_disable_default_vgic();
while ((opt = getopt(argc, argv, "hn:e:l:")) != -1) {
switch (opt) {

View File

@ -27,7 +27,7 @@ static vm_paddr_t gpa_base;
static struct kvm_vm *vm;
static struct kvm_vcpu **vcpus;
static int gic_fd, its_fd;
static int its_fd;
static struct test_data {
bool request_vcpus_stop;
@ -214,7 +214,6 @@ static void setup_test_data(void)
static void setup_gic(void)
{
gic_fd = vgic_v3_setup(vm, test_data.nr_cpus, 64);
its_fd = vgic_its_setup(vm);
}
@ -353,7 +352,6 @@ static void setup_vm(void)
static void destroy_vm(void)
{
close(its_fd);
close(gic_fd);
kvm_vm_free(vm);
free(vcpus);
}

View File

@ -28,7 +28,6 @@
struct vpmu_vm {
struct kvm_vm *vm;
struct kvm_vcpu *vcpu;
int gic_fd;
};
static struct vpmu_vm vpmu_vm;
@ -435,7 +434,8 @@ static void create_vpmu_vm(void *guest_code)
init.features[0] |= (1 << KVM_ARM_VCPU_PMU_V3);
vpmu_vm.vcpu = aarch64_vcpu_add(vpmu_vm.vm, 0, &init, guest_code);
vcpu_init_descriptor_tables(vpmu_vm.vcpu);
vpmu_vm.gic_fd = vgic_v3_setup(vpmu_vm.vm, 1, 64);
kvm_arch_vm_finalize_vcpus(vpmu_vm.vm);
/* Make sure that PMUv3 support is indicated in the ID register */
dfr0 = vcpu_get_reg(vpmu_vm.vcpu, KVM_ARM64_SYS_REG(SYS_ID_AA64DFR0_EL1));
@ -451,7 +451,6 @@ static void create_vpmu_vm(void *guest_code)
static void destroy_vpmu_vm(void)
{
close(vpmu_vm.gic_fd);
kvm_vm_free(vpmu_vm.vm);
}

View File

@ -20,38 +20,6 @@
#include "guest_modes.h"
#include "ucall_common.h"
#ifdef __aarch64__
#include "arm64/vgic.h"
static int gic_fd;
static void arch_setup_vm(struct kvm_vm *vm, unsigned int nr_vcpus)
{
/*
* The test can still run even if hardware does not support GICv3, as it
* is only an optimization to reduce guest exits.
*/
gic_fd = vgic_v3_setup(vm, nr_vcpus, 64);
}
static void arch_cleanup_vm(struct kvm_vm *vm)
{
if (gic_fd > 0)
close(gic_fd);
}
#else /* __aarch64__ */
static void arch_setup_vm(struct kvm_vm *vm, unsigned int nr_vcpus)
{
}
static void arch_cleanup_vm(struct kvm_vm *vm)
{
}
#endif
/* How many host loops to run by default (one KVM_GET_DIRTY_LOG for each loop)*/
#define TEST_HOST_LOOP_N 2UL
@ -166,8 +134,6 @@ static void run_test(enum vm_guest_mode mode, void *arg)
vm_enable_cap(vm, KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2,
dirty_log_manual_caps);
arch_setup_vm(vm, nr_vcpus);
/* Start the iterations */
iteration = 0;
host_quit = false;
@ -285,7 +251,6 @@ static void run_test(enum vm_guest_mode mode, void *arg)
}
memstress_free_bitmaps(bitmaps, p->slots);
arch_cleanup_vm(vm);
memstress_destroy_vm(vm);
}

View File

@ -585,6 +585,7 @@ static struct kvm_vm *create_vm(enum vm_guest_mode mode, struct kvm_vcpu **vcpu,
log_mode_create_vm_done(vm);
*vcpu = vm_vcpu_add(vm, 0, guest_code);
kvm_arch_vm_finalize_vcpus(vm);
return vm;
}

View File

@ -2,6 +2,9 @@
#ifndef SELFTEST_KVM_UTIL_ARCH_H
#define SELFTEST_KVM_UTIL_ARCH_H
struct kvm_vm_arch {};
struct kvm_vm_arch {
bool has_gic;
int gic_fd;
};
#endif // SELFTEST_KVM_UTIL_ARCH_H

View File

@ -301,5 +301,6 @@ void smccc_smc(uint32_t function_id, uint64_t arg0, uint64_t arg1,
void wfi(void);
void test_wants_mte(void);
void test_disable_default_vgic(void);
#endif /* SELFTEST_KVM_PROCESSOR_H */

View File

@ -1257,7 +1257,9 @@ static inline int __vm_disable_nx_huge_pages(struct kvm_vm *vm)
*/
void kvm_selftest_arch_init(void);
void kvm_arch_vm_post_create(struct kvm_vm *vm);
void kvm_arch_vm_post_create(struct kvm_vm *vm, unsigned int nr_vcpus);
void kvm_arch_vm_finalize_vcpus(struct kvm_vm *vm);
void kvm_arch_vm_release(struct kvm_vm *vm);
bool vm_is_gpa_protected(struct kvm_vm *vm, vm_paddr_t paddr);

View File

@ -12,6 +12,7 @@
#include "kvm_util.h"
#include "processor.h"
#include "ucall_common.h"
#include "vgic.h"
#include <linux/bitfield.h>
#include <linux/sizes.h>
@ -655,14 +656,37 @@ void wfi(void)
}
static bool request_mte;
static bool request_vgic = true;
void test_wants_mte(void)
{
request_mte = true;
}
void kvm_arch_vm_post_create(struct kvm_vm *vm)
void test_disable_default_vgic(void)
{
request_vgic = false;
}
void kvm_arch_vm_post_create(struct kvm_vm *vm, unsigned int nr_vcpus)
{
if (request_mte && vm_check_cap(vm, KVM_CAP_ARM_MTE))
vm_enable_cap(vm, KVM_CAP_ARM_MTE, 0);
if (request_vgic && kvm_supports_vgic_v3()) {
vm->arch.gic_fd = __vgic_v3_setup(vm, nr_vcpus, 64);
vm->arch.has_gic = true;
}
}
void kvm_arch_vm_finalize_vcpus(struct kvm_vm *vm)
{
if (vm->arch.has_gic)
__vgic_v3_init(vm->arch.gic_fd);
}
void kvm_arch_vm_release(struct kvm_vm *vm)
{
if (vm->arch.has_gic)
close(vm->arch.gic_fd);
}

View File

@ -517,7 +517,7 @@ struct kvm_vm *__vm_create(struct vm_shape shape, uint32_t nr_runnable_vcpus,
guest_rng = new_guest_random_state(guest_random_seed);
sync_global_to_guest(vm, guest_rng);
kvm_arch_vm_post_create(vm);
kvm_arch_vm_post_create(vm, nr_runnable_vcpus);
return vm;
}
@ -555,6 +555,7 @@ struct kvm_vm *__vm_create_with_vcpus(struct vm_shape shape, uint32_t nr_vcpus,
for (i = 0; i < nr_vcpus; ++i)
vcpus[i] = vm_vcpu_add(vm, i, guest_code);
kvm_arch_vm_finalize_vcpus(vm);
return vm;
}
@ -805,6 +806,8 @@ void kvm_vm_release(struct kvm_vm *vmp)
/* Free cached stats metadata and close FD */
kvm_stats_release(&vmp->stats);
kvm_arch_vm_release(vmp);
}
static void __vm_mem_region_delete(struct kvm_vm *vm,
@ -2330,7 +2333,15 @@ void kvm_get_stat(struct kvm_binary_stats *stats, const char *name,
TEST_FAIL("Unable to find stat '%s'", name);
}
__weak void kvm_arch_vm_post_create(struct kvm_vm *vm)
__weak void kvm_arch_vm_post_create(struct kvm_vm *vm, unsigned int nr_vcpus)
{
}
__weak void kvm_arch_vm_finalize_vcpus(struct kvm_vm *vm)
{
}
__weak void kvm_arch_vm_release(struct kvm_vm *vm)
{
}

View File

@ -625,7 +625,7 @@ void assert_on_unhandled_exception(struct kvm_vcpu *vcpu)
REPORT_GUEST_ASSERT(uc);
}
void kvm_arch_vm_post_create(struct kvm_vm *vm)
void kvm_arch_vm_post_create(struct kvm_vm *vm, unsigned int nr_vcpus)
{
int r;

View File

@ -145,7 +145,7 @@ static void finish_vm_setup(struct kvm_vm *vm)
slot0 = memslot2region(vm, 0);
ucall_init(vm, slot0->region.guest_phys_addr + slot0->region.memory_size);
kvm_arch_vm_post_create(vm);
kvm_arch_vm_post_create(vm, 0);
}
static struct kvm_vm *create_vm_two_memslots(void)