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);



Reply via email to