Hi Daniel, Apologies for the delayed reply; I overlooked your email. Thanks for catching the non-KVM build issue. I missed updating kvm-stub.c.
Stefan's patchset also covers hosts that support only 63 guest interrupt identities and includes the corresponding non-KVM stub changes. We are coordinating on his series, and I have already provided review feedback. I may follow up with additional changes on top of his series to allow configuring more than 255 MSI IDs when the host supports it. Best regards, Qingwei Hu > On Sep 26, 2026, at 03:38, Daniel Henrique Barboza > <[email protected]> wrote: > > Hello, > > If we try to build this patch in a non-KVM enviroment we'll have this error: > > FAILED: libstubs_riscv.a.p/target_riscv_kvm_kvm-stub.c.o > cc -m64 -Ilibstubs_riscv.a.p -I. -I.. -I../common-user/host/x86_64 > -I../linux-user/include/host/x86_64 -I../linux-user/include -Itarget/riscv > -I../target/riscv -Iqapi -Itrace -Iui -Iui/shader -I/usr/include/glib-2.0 > -I/usr/lib/x86_64-linux-gnu/glib-2.0/include -fdiagnostics-color=auto -Wall > -Winvalid-pch -Werror -std=gnu11 -O0 -g -mcx16 -msse2 -D_GNU_SOURCE > -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -fno-strict-aliasing -fno-common > -fwrapv -ftrivial-auto-var-init=zero -fzero-call-used-regs=used-gpr > -fstack-protector-strong -Wempty-body -Wendif-labels -Wexpansion-to-defined > -Wformat-overflow=2 -Wformat-security -Wformat-y2k -Wignored-qualifiers > -Wimplicit-fallthrough=2 -Winit-self -Wmissing-format-attribute > -Wmissing-prototypes -Wnested-externs -Wold-style-declaration > -Wold-style-definition -Wredundant-decls -Wshadow=local -Wstrict-prototypes > -Wtype-limits -Wundef -Wvla -Wwrite-strings -Wno-missing-include-dirs > -Wno-psabi -Wno-shift-negative-value -isystem > /local/mnt/workspace/qemu/linux-headers -isystem linux-headers -iquote . > -iquote /local/mnt/workspace/qemu -iquote /local/mnt/workspace/qemu/include > -iquote /local/mnt/workspace/qemu/host/include/x86_64 -iquote > /local/mnt/workspace/qemu/host/include/generic -iquote > /local/mnt/workspace/qemu/tcg/x86_64 -pthread -fPIE -DCPU_DEFS_H > -DCOMPILING_SYSTEM_VS_USER -DCONFIG_SOFTMMU -MD -MQ > libstubs_riscv.a.p/target_riscv_kvm_kvm-stub.c.o -MF > libstubs_riscv.a.p/target_riscv_kvm_kvm-stub.c.o.d -o > libstubs_riscv.a.p/target_riscv_kvm_kvm-stub.c.o -c > ../target/riscv/kvm/kvm-stub.c > ../target/riscv/kvm/kvm-stub.c:12:6: error: conflicting types for > ‘kvm_riscv_aia_create’; have ‘void(MachineState *, uint64_t, uint64_t, > uint64_t, uint64_t, uint64_t, uint64_t)’ {aka ‘void(MachineState *, long > unsigned int, long unsigned int, long unsigned int, long unsigned int, > long unsigned int, long unsigned int)’} > 12 | void kvm_riscv_aia_create(MachineState *machine, uint64_t group_shift, > | ^~~~~~~~~~~~~~~~~~~~ > In file included from ../target/riscv/kvm/kvm-stub.c:10: > /local/mnt/workspace/qemu/target/riscv/kvm/kvm_riscv.h:26:5: note: previous > declaration of ‘kvm_riscv_aia_create’ with type > int(uint64_t, uint32_t *)’ {aka ‘int(long unsigned int, unsigned int *)’} > 26 | int kvm_riscv_aia_create(uint64_t aia_irq_num, uint32_t *aia_msi_num); > | ^~~~~~~~~~~~~~~~~~~~ > [1958/3154] Compiling C object > libqemu-riscv64-softmmu.a.p/target_riscv_tcg_debug.c.o > > > The reason is, down there ... > > > On 9/22/2026 9:22 AM, Qingwei Hu wrote: >> KVM initializes CONFIG_IDS to the number of guest MSI IDs supported by >> the host. The virt machine currently overwrites it with the fixed >> VIRT_IRQCHIP_NUM_MSIS value of 255, which can be inconsistent with the >> host-supported guest MSI ID count. >> Create the KVM AIA device before realizing the per-socket IMSICs and >> read the host-provided CONFIG_IDS value. Use it to configure the QEMU >> IMSIC devices and the guest-visible DT and ACPI descriptions. Complete >> the remaining KVM AIA setup after all vCPUs have been created, as the >> IMSIC address configuration depends on them. >> Keep VIRT_IRQCHIP_NUM_MSIS as the default for non-KVM machines. >> Fixes: 9634ef7eda5f ("target/riscv: Create an KVM AIA irqchip") >> Signed-off-by: Qingwei Hu <[email protected]> >> --- >> hw/riscv/virt-acpi-build.c | 4 +-- >> hw/riscv/virt.c | 28 ++++++++++++----- >> include/hw/riscv/virt.h | 1 + >> target/riscv/kvm/kvm-cpu.c | 59 +++++++++++++++++++++++------------- >> target/riscv/kvm/kvm_riscv.h | 9 +++--- >> 5 files changed, 66 insertions(+), 35 deletions(-) >> diff --git a/hw/riscv/virt-acpi-build.c b/hw/riscv/virt-acpi-build.c >> index 8e516ec114..0ebfa10a02 100644 >> --- a/hw/riscv/virt-acpi-build.c >> +++ b/hw/riscv/virt-acpi-build.c >> @@ -576,9 +576,9 @@ static void build_madt(GArray *table_data, >> build_append_int_noprefix(table_data, 0, 1); /* Reserved */ >> build_append_int_noprefix(table_data, 0, 4); /* Flags */ >> /* Number of supervisor mode Interrupt Identities */ >> - build_append_int_noprefix(table_data, VIRT_IRQCHIP_NUM_MSIS, 2); >> + build_append_int_noprefix(table_data, s->num_msis, 2); >> /* Number of guest mode Interrupt Identities */ >> - build_append_int_noprefix(table_data, VIRT_IRQCHIP_NUM_MSIS, 2); >> + build_append_int_noprefix(table_data, s->num_msis, 2); >> /* Guest Index Bits */ >> build_append_int_noprefix(table_data, guest_index_bits, 1); >> /* Hart Index Bits */ >> diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c >> index d4b501802f..ba0e74ce83 100644 >> --- a/hw/riscv/virt.c >> +++ b/hw/riscv/virt.c >> @@ -277,7 +277,7 @@ static void create_fdt_sockets(RISCVVirtState *s, >> .imsic_m_base = !kvm_enabled() ? s->memmap[VIRT_IMSIC_M].base : >> 0, >> .imsic_s_base = s->memmap[VIRT_IMSIC_S].base, >> .imsic_group_max_size = VIRT_IMSIC_GROUP_MAX_SIZE, >> - .irqchip_num_msis = VIRT_IRQCHIP_NUM_MSIS, >> + .irqchip_num_msis = s->num_msis, >> .aia_guests = s->aia_guests >> }; >> @@ -718,6 +718,7 @@ static void virt_machine_init(MachineState *machine) >> DeviceState *mmio_irqchip, *virtio_irqchip, *pcie_irqchip; >> int i, base_hartid, hart_count; >> int socket_count = riscv_socket_count(machine); >> + int aia_fd = -1; >> s->memmap = virt_memmap; >> @@ -733,6 +734,16 @@ static void virt_machine_init(MachineState *machine) >> exit(1); >> } >> + /* >> + * Create the KVM AIA device and query the host MSI ID count before >> + * realizing the per-socket IMSICs. Complete AIA initialization after >> + * all vCPUs have been created. >> + */ >> + if (kvm_enabled() && virt_use_kvm_aia_aplic_imsic(s->aia_type)) { >> + aia_fd = kvm_riscv_aia_create(VIRT_IRQCHIP_NUM_SOURCES, >> + &s->num_msis); >> + } >> + >> /* Initialize sockets */ >> mmio_irqchip = virtio_irqchip = pcie_irqchip = NULL; >> for (i = 0; i < socket_count; i++) { >> @@ -826,7 +837,7 @@ static void virt_machine_init(MachineState *machine) >> &s->memmap[VIRT_IMSIC_M], >> &s->memmap[VIRT_IMSIC_S], >> i, base_hartid, hart_count, >> - VIRT_IRQCHIP_NUM_MSIS, >> + s->num_msis, >> VIRT_IRQCHIP_NUM_PRIO_BITS); >> } >> @@ -845,12 +856,12 @@ static void virt_machine_init(MachineState *machine) >> } >> } >> - if (kvm_enabled() && virt_use_kvm_aia_aplic_imsic(s->aia_type)) { >> - kvm_riscv_aia_create(machine, IMSIC_MMIO_GROUP_MIN_SHIFT, >> - VIRT_IRQCHIP_NUM_SOURCES, >> VIRT_IRQCHIP_NUM_MSIS, >> - s->memmap[VIRT_APLIC_S].base, >> - s->memmap[VIRT_IMSIC_S].base, >> - s->aia_guests); > > This call of kvm_riscv_aia_create(), even when guarded with a kvm_enabled(), > needs to be > visible to the compiler in a TCG only build. We have a kvm-stub.c file that > declares it > like so: > > void kvm_riscv_aia_create(MachineState *machine, uint64_t group_shift, > uint64_t aia_irq_num, uint64_t aia_msi_num, > uint64_t aplic_base, uint64_t imsic_base, > uint64_t guest_num) > { > g_assert_not_reached(); > } > > Thus changing kvm_riscv_aia_create() requires a change in its kvm-stub as > well. > >> + if (aia_fd >= 0) { >> + kvm_riscv_aia_init(machine, aia_fd, IMSIC_MMIO_GROUP_MIN_SHIFT, >> + VIRT_IRQCHIP_NUM_SOURCES, >> + s->memmap[VIRT_APLIC_S].base, >> + s->memmap[VIRT_IMSIC_S].base, >> + s->aia_guests); >> } > > And a similar thing is needed here for kvm_riscv_aia_init(). We need a > kvm-stub entry and it > needs to be guarded with kvm_enabled() as well. > > We need something like this diff: > > $ git diff > diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c > index ba0e74ce83..4df8d7d441 100644 > --- a/hw/riscv/virt.c > +++ b/hw/riscv/virt.c > @@ -856,7 +856,7 @@ static void virt_machine_init(MachineState *machine) > } > } > > - if (aia_fd >= 0) { > + if (kvm_enabled() && aia_fd >= 0) { > kvm_riscv_aia_init(machine, aia_fd, IMSIC_MMIO_GROUP_MIN_SHIFT, > VIRT_IRQCHIP_NUM_SOURCES, > s->memmap[VIRT_APLIC_S].base, > diff --git a/target/riscv/kvm/kvm-stub.c b/target/riscv/kvm/kvm-stub.c > index 64e39c96d8..b7e6504f5f 100644 > --- a/target/riscv/kvm/kvm-stub.c > +++ b/target/riscv/kvm/kvm-stub.c > @@ -9,10 +9,15 @@ > #include "qemu/osdep.h" > #include "target/riscv/kvm/kvm_riscv.h" > > -void kvm_riscv_aia_create(MachineState *machine, uint64_t group_shift, > - uint64_t aia_irq_num, uint64_t aia_msi_num, > - uint64_t aplic_base, uint64_t imsic_base, > - uint64_t guest_num) > +int kvm_riscv_aia_create(uint64_t aia_irq_num, uint32_t *aia_msi_num) > +{ > + g_assert_not_reached(); > +} > + > +void kvm_riscv_aia_init(MachineState *machine, int aia_fd, > + uint64_t group_shift, uint64_t aia_irq_num, > + uint64_t aplic_base, uint64_t imsic_base, > + uint64_t guest_num) > { > g_assert_not_reached(); > } > > > Code LGTM otherwise. Booted a KVM aia guest and play with it a little bit > without any hicups. > > > Thanks, > Daniel > > >> if (riscv_is_32bit(&s->soc[0])) { >> @@ -972,6 +983,7 @@ static void virt_machine_instance_init(Object *obj) >> s->acpi = ON_OFF_AUTO_AUTO; >> s->iommu_sys = ON_OFF_AUTO_AUTO; >> s->num_sources = VIRT_IRQCHIP_NUM_SOURCES; >> + s->num_msis = VIRT_IRQCHIP_NUM_MSIS; >> } >> static char *virt_get_aia_guests(Object *obj, Error **errp) >> diff --git a/include/hw/riscv/virt.h b/include/hw/riscv/virt.h >> index e516898f9a..f64a2a3448 100644 >> --- a/include/hw/riscv/virt.h >> +++ b/include/hw/riscv/virt.h >> @@ -66,6 +66,7 @@ struct RISCVVirtState { >> OnOffAuto iommu_sys; >> uint16_t pci_iommu_bdf; >> uint16_t num_sources; >> + uint32_t num_msis; >> }; >> enum { >> diff --git a/target/riscv/kvm/kvm-cpu.c b/target/riscv/kvm/kvm-cpu.c >> index 68e1501b21..02af4e7723 100644 >> --- a/target/riscv/kvm/kvm-cpu.c >> +++ b/target/riscv/kvm/kvm-cpu.c >> @@ -1859,19 +1859,11 @@ void kvm_arch_accel_class_init(ObjectClass *oc) >> "auto"); >> } >> -void kvm_riscv_aia_create(MachineState *machine, uint64_t group_shift, >> - uint64_t aia_irq_num, uint64_t aia_msi_num, >> - uint64_t aplic_base, uint64_t imsic_base, >> - uint64_t guest_num) >> +int kvm_riscv_aia_create(uint64_t aia_irq_num, uint32_t *aia_msi_num) >> { >> - int ret, i; >> - int aia_fd = -1; >> + int ret; >> + int aia_fd; >> uint64_t default_aia_mode; >> - uint64_t socket_count = riscv_socket_count(machine); >> - uint64_t max_hart_per_socket = 0; >> - uint64_t socket, base_hart, hart_count, socket_imsic_base, imsic_addr; >> - uint64_t socket_bits, hart_bits, guest_bits; >> - uint64_t max_group_id; >> aia_fd = kvm_create_device(kvm_state, KVM_DEV_TYPE_RISCV_AIA, false); >> @@ -1903,6 +1895,41 @@ void kvm_riscv_aia_create(MachineState *machine, >> uint64_t group_shift, >> } >> } >> + /* >> + * Get the maximum MSI ID supported by the host from the CONFIG_IDS >> + * attribute and use it for the guest-visible interrupt controller >> + * configuration. >> + */ >> + ret = kvm_device_access(aia_fd, KVM_DEV_RISCV_AIA_GRP_CONFIG, >> + KVM_DEV_RISCV_AIA_CONFIG_IDS, >> + aia_msi_num, false, NULL); >> + if (ret < 0) { >> + error_report("KVM AIA: failed to get number of MSI IDs"); >> + exit(1); >> + } >> + >> + if (!kvm_kernel_irqchip_split() && *aia_msi_num < aia_irq_num) { >> + error_report("KVM AIA: host supports only %" PRIu32 " MSI IDs, " >> + "but the virt machine requires at least %" PRIu64, >> + *aia_msi_num, aia_irq_num); >> + exit(1); >> + } >> + >> + return aia_fd; >> +} >> + >> +void kvm_riscv_aia_init(MachineState *machine, int aia_fd, >> + uint64_t group_shift, uint64_t aia_irq_num, >> + uint64_t aplic_base, uint64_t imsic_base, >> + uint64_t guest_num) >> +{ >> + int ret, i; >> + uint64_t socket_count = riscv_socket_count(machine); >> + uint64_t max_hart_per_socket = 0; >> + uint64_t socket, base_hart, hart_count, socket_imsic_base, imsic_addr; >> + uint64_t socket_bits, hart_bits, guest_bits; >> + uint64_t max_group_id; >> + >> /* >> * Skip APLIC creation in KVM if we're running split mode. >> * This is done by leaving KVM_DEV_RISCV_AIA_CONFIG_SRCS >> @@ -1927,15 +1954,6 @@ void kvm_riscv_aia_create(MachineState *machine, >> uint64_t group_shift, >> } >> } >> - ret = kvm_device_access(aia_fd, KVM_DEV_RISCV_AIA_GRP_CONFIG, >> - KVM_DEV_RISCV_AIA_CONFIG_IDS, >> - &aia_msi_num, true, NULL); >> - if (ret < 0) { >> - error_report("KVM AIA: failed to set number of msi"); >> - exit(1); >> - } >> - >> - >> if (socket_count > 1) { >> max_group_id = socket_count - 1; >> socket_bits = find_last_bit(&max_group_id, BITS_PER_LONG) + 1; >> @@ -1987,7 +2005,6 @@ void kvm_riscv_aia_create(MachineState *machine, >> uint64_t group_shift, >> } >> } >> - >> if (max_hart_per_socket > 1) { >> max_hart_per_socket--; >> hart_bits = find_last_bit(&max_hart_per_socket, BITS_PER_LONG) + 1; >> diff --git a/target/riscv/kvm/kvm_riscv.h b/target/riscv/kvm/kvm_riscv.h >> index 61eaa12443..1499fb4487 100644 >> --- a/target/riscv/kvm/kvm_riscv.h >> +++ b/target/riscv/kvm/kvm_riscv.h >> @@ -23,10 +23,11 @@ >> void kvm_riscv_reset_vcpu(RISCVCPU *cpu); >> void kvm_riscv_set_irq(RISCVCPU *cpu, int irq, int level); >> -void kvm_riscv_aia_create(MachineState *machine, uint64_t group_shift, >> - uint64_t aia_irq_num, uint64_t aia_msi_num, >> - uint64_t aplic_base, uint64_t imsic_base, >> - uint64_t guest_num); >> +int kvm_riscv_aia_create(uint64_t aia_irq_num, uint32_t *aia_msi_num); >> +void kvm_riscv_aia_init(MachineState *machine, int aia_fd, >> + uint64_t group_shift, uint64_t aia_irq_num, >> + uint64_t aplic_base, uint64_t imsic_base, >> + uint64_t guest_num); >> void riscv_kvm_aplic_request(void *opaque, int irq, int level); >> bool kvm_riscv_has_mp_state(void); >> void riscv_kvm_cpu_finalize_features(RISCVCPU *cpu, Error **errp);
