]> www.infradead.org Git - users/hch/misc.git/commitdiff
KVM: arm64: selftests: Create a VGICv3 for 'default' VMs
authorOliver Upton <oliver.upton@linux.dev>
Wed, 17 Sep 2025 21:20:35 +0000 (14:20 -0700)
committerMarc Zyngier <maz@kernel.org>
Wed, 24 Sep 2025 18:23:32 +0000 (19:23 +0100)
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>
19 files changed:
tools/testing/selftests/kvm/arm64/arch_timer.c
tools/testing/selftests/kvm/arm64/arch_timer_edge_cases.c
tools/testing/selftests/kvm/arm64/no-vgic-v3.c
tools/testing/selftests/kvm/arm64/psci_test.c
tools/testing/selftests/kvm/arm64/set_id_regs.c
tools/testing/selftests/kvm/arm64/smccc_filter.c
tools/testing/selftests/kvm/arm64/vgic_init.c
tools/testing/selftests/kvm/arm64/vgic_irq.c
tools/testing/selftests/kvm/arm64/vgic_lpi_stress.c
tools/testing/selftests/kvm/arm64/vpmu_counter_access.c
tools/testing/selftests/kvm/dirty_log_perf_test.c
tools/testing/selftests/kvm/dirty_log_test.c
tools/testing/selftests/kvm/include/arm64/kvm_util_arch.h
tools/testing/selftests/kvm/include/arm64/processor.h
tools/testing/selftests/kvm/include/kvm_util.h
tools/testing/selftests/kvm/lib/arm64/processor.c
tools/testing/selftests/kvm/lib/kvm_util.c
tools/testing/selftests/kvm/lib/x86/processor.c
tools/testing/selftests/kvm/s390/cmma_test.c

index aaf4285f832adf84c34e5c63012275602313ddea..c753013319bc67eb00d76c9cfcd3f4dd03e549b7 100644 (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);
 }
index d349d80d8418221f2b2e87819a974da482ac8009..5c60262f4c2e8780a17aefb1a78796829450ab06 100644 (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);
 }
 
index f222538e608418065d745c6df07378269486550b..152c34776981afdfc354d30fd8d3ef9919967227 100644 (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),
index ab491ee9e5f756c2f149185032554841cd511f2b..cf208390fd0e6f4e6652669d9988f9bdb80bba5d 100644 (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;
 }
 
index a2d367a2c93c48757b8ce4cd0066ba6e2937f128..77718628facfc14f772351547d9d45d0ea9ee811 100644 (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));
index 2d189f3da228cdb74b8a8976c0736abde18ce9b5..eb5551d21dbefac6fba1c709200803e28f167218 100644 (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;
 }
 
index a8e0f46bc0abb15f76d7f850fde1e5f49b2b9b7e..8d6d3a4ae4dbd64c8b0faba00e65513270e8a773 100644 (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;
 
index 9fc9e8e44ecdcbc677518104de056b6ce2312407..6338f5bbdb705bb1c0c17d2f19b07702aa609a36 100644 (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) {
index cc2b21d374af8fe2a4cc755cf212649dd353102e..87922a89b1345631e669eb790a3a2947977431f8 100644 (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);
 }
index 01f61657de45497472b5a4aba52a3c163d282360..4a7e8e85a1b84cdf0ab5888bdaf7cde6f27cf11e 100644 (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);
 }
 
index e79817bd0e29e31fd530480cfba9acbae023fb1c..0a1ea1d1e2d8f48896888b0cbe02802876b7b554 100644 (file)
 #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);
 }
 
index 23593d9eeba9af0fb2e7c9474d36a625313630ec..d58a641b0e6a79df38703aa8dccb24286f33aecb 100644 (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;
 }
 
index e43a57d99b56cc3f541d7718b868eb92b4a46e10..b973bb2c64a65fed878aa11a899359063ee09554 100644 (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
index 8370fc94041df3ca2fc7ccd2799a4be885860ad6..8c066ba1deb5bc51b4562145331ab1f528440ee7 100644 (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 */
index 23a506d7eca3dedeec83e535edc8135f25c802ba..3ab1fffbc3f286fb42ce6204c141b319bd7b12c0 100644 (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);
 
index caed1998c7b38809b77fee598af9e696f0d63772..de77d9a7e0cd34ffe006e51e080d82bd3846cc5e 100644 (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);
 }
index c3f5142b0a5415673815cb308a97ad7ea5b87656..67f32d41a59c732a1b724e04e38901d5c2ae3fa5 100644 (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)
 {
 }
 
index d4c19ac885a95a92da2816d62ee4dcf26a983308..bff75aa341bf3ee948651974a838961d23de2b7d 100644 (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;
 
index 85cc8c18d6e70e4c8a5c4d296cb90d2bad8474bd..e39a724fe860e3c10a51a19fb43fd3dcbe857e5d 100644 (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)