@samitouri / QOSamiQemu / commits / aa82039d7d

hw/arm/virt: Create and connect GICv5

In this commit we create and connect up the GICv5. We do not advertise it in the ACPI tables or DTB; that will be done in a following commit. The user-facing gic-version property still only documents and permits in its setter function the existing set of possible values; we won't permit the user to select a GICv5 until all the code to handle it is in place. Although we currently implement only the IRS, and only for EL1, we reserve space in the virt board's memory map now for all the register frames that the GICv5 may use. Each interrupt domain has: * one IRS config register frame * one ITS config register frame * one ITS translate register frame and each of these frames is 64K in size and 64K aligned and must be at a unique address (that is, it is not permitted to have all the IRS config register frames at the same physical address in the different S/NS/etc physical address spaces). The addresses and layout of these frames are entirely up to the implementation: software will be passed their addresses via firmware data structures (ACPI or DTB). Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Message-id: 20260327111700.795099-61-peter.maydell@linaro.org

Peter Maydell committed Mar 27, 2026 at 11:16 UTC aa82039d7d8a62f4de983baf81b0db0c4e02d635
2 files changed +115
hw/arm/virt.c
+101
@@ -68,6 +68,7 @@
68 #include "hw/intc/arm_gic.h"
69 #include "hw/intc/arm_gicv3_common.h"
70 #include "hw/intc/arm_gicv3_its_common.h"
71 +#include "hw/intc/arm_gicv5_common.h"
72 #include "hw/core/irq.h"
73 #include "kvm_arm.h"
74 #include "whpx_arm.h"
@@ -184,6 +185,19 @@ static const MemMapEntry base_memmap[] = {
185 [VIRT_GIC_ITS] = { 0x08080000, 0x00020000 },
186 /* This redistributor space allows up to 2*64kB*123 CPUs */
187 [VIRT_GIC_REDIST] = { 0x080A0000, 0x00F60000 },
188 + /* The GICv5 uses this address range differently from GICv2/v3/v4 */
189 + [VIRT_GICV5_IRS_S] = { 0x08000000, 0x00010000 },
190 + [VIRT_GICV5_IRS_NS] = { 0x08010000, 0x00010000 },
191 + [VIRT_GICV5_IRS_EL3] = { 0x08020000, 0x00010000 },
192 + [VIRT_GICV5_IRS_REALM] = { 0x08030000, 0x00010000 },
193 + [VIRT_GICV5_ITS_S] = { 0x08040000, 0x00010000 },
194 + [VIRT_GICV5_ITS_NS] = { 0x08050000, 0x00010000 },
195 + [VIRT_GICV5_ITS_EL3] = { 0x08060000, 0x00010000 },
196 + [VIRT_GICV5_ITS_REALM] = { 0x08070000, 0x00010000 },
197 + [VIRT_GICV5_ITS_TR_S] = { 0x08080000, 0x00010000 },
198 + [VIRT_GICV5_ITS_TR_NS] = { 0x08090000, 0x00010000 },
199 + [VIRT_GICV5_ITS_TR_EL3] = { 0x080A0000, 0x00010000 },
200 + [VIRT_GICV5_ITS_TR_REALM] = { 0x080B0000, 0x00010000 },
201 [VIRT_UART0] = { 0x09000000, 0x00001000 },
202 [VIRT_RTC] = { 0x09010000, 0x00001000 },
203 [VIRT_FW_CFG] = { 0x09020000, 0x00000018 },
@@ -1106,6 +1120,49 @@ static void create_v2m(VirtMachineState *vms)
1120 vms->msi_controller = VIRT_MSI_CTRL_GICV2M;
1121 }
1122
1123 +static void create_gicv5(VirtMachineState *vms, MemoryRegion *mem)
1124 +{
1125 + MachineState *ms = MACHINE(vms);
1126 + SysBusDevice *gicbusdev;
1127 + const char *gictype = gicv5_class_name();
1128 + QList *cpulist = qlist_new(), *iaffidlist = qlist_new();
1129 +
1130 + vms->gic = qdev_new(gictype);
1131 + qdev_prop_set_uint32(vms->gic, "spi-range", NUM_IRQS);
1132 +
1133 + object_property_set_link(OBJECT(vms->gic), "sysmem", OBJECT(mem),
1134 + &error_fatal);
1135 +
1136 + for (int i = 0; i < ms->smp.cpus; i++) {
1137 + qlist_append_link(cpulist, OBJECT(qemu_get_cpu(i)));
1138 + /*
1139 + * GICv5 IAFFIDs must be system-wide unique across all GICs.
1140 + * For virt we make them the same as the CPU index.
1141 + */
1142 + qlist_append_int(iaffidlist, i);
1143 + }
1144 + qdev_prop_set_array(vms->gic, "cpus", cpulist);
1145 + qdev_prop_set_array(vms->gic, "cpu-iaffids", iaffidlist);
1146 +
1147 + gicbusdev = SYS_BUS_DEVICE(vms->gic);
1148 + sysbus_realize_and_unref(gicbusdev, &error_fatal);
1149 +
1150 + /*
1151 + * Map the IRS config frames for the interrupt domains.
1152 + * At the moment we implement only the NS domain, so this is simple.
1153 + */
1154 + sysbus_mmio_map(gicbusdev, GICV5_ID_NS,
1155 + vms->memmap[VIRT_GICV5_IRS_NS].base);
1156 +
1157 + /*
1158 + * The GICv5 does not need to wire up CPU timer IRQ outputs to the GIC
1159 + * because for the GICv5 those PPIs are entirely internal to the CPU.
1160 + * Nor do we need to wire up GIC IRQ/FIQ signals to the CPUs, because
1161 + * that information is communicated directly between a GICv5 IRS and
1162 + * the GICv5 CPU interface via our equivalent of the stream protocol.
1163 + */
1164 +}
1165 +
1166 /*
1167 * If the CPU has FEAT_NMI, then turn on the NMI support in the GICv3 too.
1168 * It's permitted to have a configuration with NMI in the CPU (and thus the
@@ -1319,6 +1376,9 @@ static void create_gic(VirtMachineState *vms, MemoryRegion *mem)
1376 case VIRT_GIC_VERSION_4:
1377 create_gicv3(vms, mem);
1378 break;
1379 + case VIRT_GIC_VERSION_5:
1380 + create_gicv5(vms, mem);
1381 + break;
1382 default:
1383 g_assert_not_reached();
1384 }
@@ -2254,6 +2314,11 @@ static uint64_t virt_cpu_mp_affinity(VirtMachineState *vms, int idx)
2314 /*
2315 * Adjust MPIDR to make TCG consistent (with 64-bit KVM hosts)
2316 * and to improve SGI efficiency.
2317 + * - GICv2 only supports 8 CPUs anyway
2318 + * - GICv3 wants 16 CPUs per Aff0 because of an ICC_SGIxR
2319 + * register limitation
2320 + * - GICv5 has no restrictions, so we retain the GICv3 16-per-Aff0
2321 + * layout because that's what KVM does
2322 */
2323 if (vms->gic_version == VIRT_GIC_VERSION_2) {
2324 clustersz = GIC_TARGETLIST_BITS;
@@ -2399,6 +2464,11 @@ static VirtGICType finalize_gic_version_do(const char *accel_name,
2464 return finalize_gic_version_do(accel_name, VIRT_GIC_VERSION_MAX,
2465 gics_supported, max_cpus);
2466 case VIRT_GIC_VERSION_MAX:
2467 + /*
2468 + * We don't (currently) make 'max' select GICv5 as it is not
2469 + * backwards compatible for system software with GICv3/v4 and
2470 + * at time of writing not widely supported in guest kernels.
2471 + */
2472 if (gics_supported & VIRT_GIC_VERSION_4_MASK) {
2473 gic_version = VIRT_GIC_VERSION_4;
2474 } else if (gics_supported & VIRT_GIC_VERSION_3_MASK) {
@@ -2427,6 +2497,7 @@ static VirtGICType finalize_gic_version_do(const char *accel_name,
2497 case VIRT_GIC_VERSION_2:
2498 case VIRT_GIC_VERSION_3:
2499 case VIRT_GIC_VERSION_4:
2500 + case VIRT_GIC_VERSION_5:
2501 break;
2502 }
2503
@@ -2451,6 +2522,12 @@ static VirtGICType finalize_gic_version_do(const char *accel_name,
2522 exit(1);
2523 }
2524 break;
2525 + case VIRT_GIC_VERSION_5:
2526 + if (!(gics_supported & VIRT_GIC_VERSION_5_MASK)) {
2527 + error_report("%s does not support GICv5 emulation", accel_name);
2528 + exit(1);
2529 + }
2530 + break;
2531 default:
2532 error_report("logic error in finalize_gic_version");
2533 exit(1);
@@ -2510,6 +2587,10 @@ static void finalize_gic_version(VirtMachineState *vms)
2587 gics_supported |= VIRT_GIC_VERSION_4_MASK;
2588 }
2589 }
2590 + if (!hvf_enabled() && module_object_class_by_name("arm-gicv5")) {
2591 + /* HVF doesn't have GICv5 support */
2592 + gics_supported |= VIRT_GIC_VERSION_5_MASK;
2593 + }
2594 } else {
2595 error_report("Unsupported accelerator, can not determine GIC support");
2596 exit(1);
@@ -2545,6 +2626,9 @@ static void finalize_msi_controller(VirtMachineState *vms)
2626 vms->msi_controller = VIRT_MSI_CTRL_GICV2M;
2627 } else if (hvf_enabled() && hvf_irqchip_in_kernel()) {
2628 vms->msi_controller = VIRT_MSI_CTRL_GICV2M;
2629 + } else if (vms->gic_version == VIRT_GIC_VERSION_5) {
2630 + /* GICv5 ITS is not yet implemented */
2631 + vms->msi_controller = VIRT_MSI_CTRL_NONE;
2632 } else {
2633 vms->msi_controller = VIRT_MSI_CTRL_ITS;
2634 }
@@ -2560,6 +2644,10 @@ static void finalize_msi_controller(VirtMachineState *vms)
2644 error_report("GICv2 + ITS is an invalid configuration.");
2645 exit(1);
2646 }
2647 + if (vms->gic_version == VIRT_GIC_VERSION_5) {
2648 + error_report("GICv5 + ITS is not yet implemented.");
2649 + exit(1);
2650 + }
2651 if (whpx_enabled()) {
2652 error_report("ITS not supported on WHPX.");
2653 exit(1);
@@ -2736,6 +2824,13 @@ static void machvirt_init(MachineState *machine)
2824 */
2825 if (vms->gic_version == VIRT_GIC_VERSION_2) {
2826 virt_max_cpus = GIC_NCPU;
2827 + } else if (vms->gic_version == VIRT_GIC_VERSION_5) {
2828 + /*
2829 + * GICv5 imposes no CPU limit beyond the 16-bit IAFFID field.
2830 + * The maximum number of CPUs will be limited not by this, but
2831 + * by the MachineClass::max_cpus value we set earlier.
2832 + */
2833 + virt_max_cpus = 1 << QEMU_GICV5_IAFFID_BITS;
2834 } else {
2835 virt_max_cpus = virt_redist_capacity(vms, VIRT_GIC_REDIST);
2836 if (vms->highmem_redists) {
@@ -2782,6 +2877,12 @@ static void machvirt_init(MachineState *machine)
2877 exit(1);
2878 }
2879
2880 + if ((vms->virt || vms->secure) &&
2881 + vms->gic_version == VIRT_GIC_VERSION_5) {
2882 + error_report("mach-virt: GICv5 currently supports EL1 only");
2883 + exit(1);
2884 + }
2885 +
2886 create_fdt(vms);
2887
2888 assert(possible_cpus->len == max_cpus);
include/hw/arm/virt.h
+14
@@ -66,6 +66,18 @@ enum {
66 VIRT_GIC_VCPU,
67 VIRT_GIC_ITS,
68 VIRT_GIC_REDIST,
69 + VIRT_GICV5_IRS_S,
70 + VIRT_GICV5_IRS_NS,
71 + VIRT_GICV5_IRS_EL3,
72 + VIRT_GICV5_IRS_REALM,
73 + VIRT_GICV5_ITS_S,
74 + VIRT_GICV5_ITS_NS,
75 + VIRT_GICV5_ITS_EL3,
76 + VIRT_GICV5_ITS_REALM,
77 + VIRT_GICV5_ITS_TR_S,
78 + VIRT_GICV5_ITS_TR_NS,
79 + VIRT_GICV5_ITS_TR_EL3,
80 + VIRT_GICV5_ITS_TR_REALM,
81 VIRT_SMMU,
82 VIRT_UART0,
83 VIRT_MMIO,
@@ -119,12 +131,14 @@ typedef enum VirtGICType {
131 VIRT_GIC_VERSION_2 = 2,
132 VIRT_GIC_VERSION_3 = 3,
133 VIRT_GIC_VERSION_4 = 4,
134 + VIRT_GIC_VERSION_5 = 5,
135 VIRT_GIC_VERSION_NOSEL,
136 } VirtGICType;
137
138 #define VIRT_GIC_VERSION_2_MASK BIT(VIRT_GIC_VERSION_2)
139 #define VIRT_GIC_VERSION_3_MASK BIT(VIRT_GIC_VERSION_3)
140 #define VIRT_GIC_VERSION_4_MASK BIT(VIRT_GIC_VERSION_4)
141 +#define VIRT_GIC_VERSION_5_MASK BIT(VIRT_GIC_VERSION_5)
142
143 struct VirtMachineClass {
144 MachineClass parent;