[PATCH 2/3] hw/sparc/sun4m: Use qdev GPIOs rather than qemu_allocate_irqs()

Peter Maydell posted 3 patches 1 month ago
Maintainers: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>, Artyom Tarasenko <atar4qemu@gmail.com>
[PATCH 2/3] hw/sparc/sun4m: Use qdev GPIOs rather than qemu_allocate_irqs()
Posted by Peter Maydell 1 month ago
In the sun4m machine creation code, we currently use qemu_allocate_irqs()
to set up the IRQ lines that act as the inbound IRQ lines to the CPUs.
This results in a memory leak:

Direct leak of 128 byte(s) in 1 object(s) allocated from:
    #0 0x5a23c1281ec3 in malloc (/home/pm215/qemu/build/sparc-san/qemu-system-sparc+0xdf1ec3) (BuildId: e6aa10be01feb5524656dd083997bc82b85e3e93)
    #1 0x79e8f78f0ac9 in g_malloc (/lib/x86_64-linux-gnu/libglib-2.0.so.0+0x62ac9) (BuildId: 116e142b9b52c8a4dfd403e759e71ab8f95d8bb3)
    #2 0x5a23c1a94e54 in qemu_extend_irqs /home/pm215/qemu/build/sparc-san/../../hw/core/irq.c:77:51
    #3 0x5a23c1a39e03 in cpu_devinit /home/pm215/qemu/build/sparc-san/../../hw/sparc/sun4m.c:802:17
    #4 0x5a23c1a39e03 in sun4m_hw_init /home/pm215/qemu/build/sparc-san/../../hw/sparc/sun4m.c:838:9

The leak is unimportant as it is a "once at startup" leak, but
fixing it helps in getting a clean leak-sanitizer test run.

Switch the sun4m code to handle CPU interrupt lines in the same way
as the leon3 machine does: the machine init code uses
qdev_init_gpio_in to create GPIO lines on the CPU objects.  This is a
little bit odd as ideally the CPU would do that itself, but for these
32-bit SPARC machines the machine and the CPU are very closely
coupled already (the functions handling the IRQ lines modify data
fields inside the CPU).

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 hw/sparc/sun4m.c | 23 ++++++++++++++---------
 1 file changed, 14 insertions(+), 9 deletions(-)

diff --git a/hw/sparc/sun4m.c b/hw/sparc/sun4m.c
index 29bc26ebcb..b9f8236be5 100644
--- a/hw/sparc/sun4m.c
+++ b/hw/sparc/sun4m.c
@@ -341,7 +341,7 @@ static void *sparc32_dma_init(hwaddr dma_base,
 static DeviceState *slavio_intctl_init(hwaddr addr,
                                        hwaddr addrg,
                                        unsigned int smp_cpus,
-                                       qemu_irq **parent_irq)
+                                       DeviceState **cpus)
 {
     DeviceState *dev;
     SysBusDevice *s;
@@ -354,7 +354,8 @@ static DeviceState *slavio_intctl_init(hwaddr addr,
 
     for (i = 0; i < smp_cpus; i++) {
         for (j = 0; j < MAX_PILS; j++) {
-            sysbus_connect_irq(s, i * MAX_PILS + j, parent_irq[i][j]);
+            sysbus_connect_irq(s, i * MAX_PILS + j,
+                               qdev_get_gpio_in_named(cpus[i], "pil", j));
         }
     }
     sysbus_mmio_map(s, 0, addrg);
@@ -785,22 +786,25 @@ static const TypeInfo ram_info = {
     .class_init    = ram_class_init,
 };
 
-static void cpu_devinit(const char *cpu_type, unsigned int id,
-                        uint64_t prom_addr, qemu_irq **cpu_irqs)
+static DeviceState *cpu_devinit(const char *cpu_type, unsigned int id,
+                                uint64_t prom_addr)
 {
     SPARCCPU *cpu;
     CPUSPARCState *env;
+    DeviceState *cpudev;
 
     cpu = SPARC_CPU(object_new(cpu_type));
     env = &cpu->env;
+    cpudev = DEVICE(cpu);
 
     qemu_register_reset(sun4m_cpu_reset, cpu);
     object_property_set_bool(OBJECT(cpu), "start-powered-off", id != 0,
                              &error_abort);
-    qdev_realize_and_unref(DEVICE(cpu), NULL, &error_fatal);
+    qdev_init_gpio_in_named(cpudev, cpu_set_irq, "pil", MAX_PILS);
+    qdev_realize_and_unref(cpudev, NULL, &error_fatal);
     cpu_sparc_set_id(env, id);
-    *cpu_irqs = qemu_allocate_irqs(cpu_set_irq, cpu, MAX_PILS);
     env->prom_addr = prom_addr;
+    return cpudev;
 }
 
 static void dummy_fdc_tc(void *opaque, int irq, int level)
@@ -813,13 +817,14 @@ static void sun4m_hw_init(MachineState *machine)
     DeviceState *slavio_intctl;
     unsigned int i;
     Nvram *nvram;
-    qemu_irq *cpu_irqs[MAX_CPUS], slavio_irq[32], slavio_cpu_irq[MAX_CPUS];
+    qemu_irq slavio_irq[32], slavio_cpu_irq[MAX_CPUS];
     qemu_irq fdc_tc;
     unsigned long kernel_size;
     uint32_t initrd_size;
     DriveInfo *fd[MAX_FD];
     FWCfgState *fw_cfg;
     DeviceState *dev, *ms_kb_orgate, *serial_orgate;
+    DeviceState *cpus[MAX_CPUS];
     SysBusDevice *s;
     unsigned int smp_cpus = machine->smp.cpus;
     unsigned int max_cpus = machine->smp.max_cpus;
@@ -835,7 +840,7 @@ static void sun4m_hw_init(MachineState *machine)
 
     /* init CPUs */
     for(i = 0; i < smp_cpus; i++) {
-        cpu_devinit(machine->cpu_type, i, hwdef->slavio_base, &cpu_irqs[i]);
+        cpus[i] = cpu_devinit(machine->cpu_type, i, hwdef->slavio_base);
     }
 
     /* Create and map RAM frontend */
@@ -855,7 +860,7 @@ static void sun4m_hw_init(MachineState *machine)
     slavio_intctl = slavio_intctl_init(hwdef->intctl_base,
                                        hwdef->intctl_base + 0x10000ULL,
                                        smp_cpus,
-                                       cpu_irqs);
+                                       cpus);
 
     for (i = 0; i < 32; i++) {
         slavio_irq[i] = qdev_get_gpio_in(slavio_intctl, i);
-- 
2.43.0
Re: [PATCH 2/3] hw/sparc/sun4m: Use qdev GPIOs rather than qemu_allocate_irqs()
Posted by Mark Cave-Ayland 1 month ago
On 07/03/2026 11:29, Peter Maydell wrote:

> In the sun4m machine creation code, we currently use qemu_allocate_irqs()
> to set up the IRQ lines that act as the inbound IRQ lines to the CPUs.
> This results in a memory leak:
> 
> Direct leak of 128 byte(s) in 1 object(s) allocated from:
>      #0 0x5a23c1281ec3 in malloc (/home/pm215/qemu/build/sparc-san/qemu-system-sparc+0xdf1ec3) (BuildId: e6aa10be01feb5524656dd083997bc82b85e3e93)
>      #1 0x79e8f78f0ac9 in g_malloc (/lib/x86_64-linux-gnu/libglib-2.0.so.0+0x62ac9) (BuildId: 116e142b9b52c8a4dfd403e759e71ab8f95d8bb3)
>      #2 0x5a23c1a94e54 in qemu_extend_irqs /home/pm215/qemu/build/sparc-san/../../hw/core/irq.c:77:51
>      #3 0x5a23c1a39e03 in cpu_devinit /home/pm215/qemu/build/sparc-san/../../hw/sparc/sun4m.c:802:17
>      #4 0x5a23c1a39e03 in sun4m_hw_init /home/pm215/qemu/build/sparc-san/../../hw/sparc/sun4m.c:838:9
> 
> The leak is unimportant as it is a "once at startup" leak, but
> fixing it helps in getting a clean leak-sanitizer test run.
> 
> Switch the sun4m code to handle CPU interrupt lines in the same way
> as the leon3 machine does: the machine init code uses
> qdev_init_gpio_in to create GPIO lines on the CPU objects.  This is a
> little bit odd as ideally the CPU would do that itself, but for these
> 32-bit SPARC machines the machine and the CPU are very closely
> coupled already (the functions handling the IRQ lines modify data
> fields inside the CPU).
> 
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> ---
>   hw/sparc/sun4m.c | 23 ++++++++++++++---------
>   1 file changed, 14 insertions(+), 9 deletions(-)
> 
> diff --git a/hw/sparc/sun4m.c b/hw/sparc/sun4m.c
> index 29bc26ebcb..b9f8236be5 100644
> --- a/hw/sparc/sun4m.c
> +++ b/hw/sparc/sun4m.c
> @@ -341,7 +341,7 @@ static void *sparc32_dma_init(hwaddr dma_base,
>   static DeviceState *slavio_intctl_init(hwaddr addr,
>                                          hwaddr addrg,
>                                          unsigned int smp_cpus,
> -                                       qemu_irq **parent_irq)
> +                                       DeviceState **cpus)
>   {
>       DeviceState *dev;
>       SysBusDevice *s;
> @@ -354,7 +354,8 @@ static DeviceState *slavio_intctl_init(hwaddr addr,
>   
>       for (i = 0; i < smp_cpus; i++) {
>           for (j = 0; j < MAX_PILS; j++) {
> -            sysbus_connect_irq(s, i * MAX_PILS + j, parent_irq[i][j]);
> +            sysbus_connect_irq(s, i * MAX_PILS + j,
> +                               qdev_get_gpio_in_named(cpus[i], "pil", j));
>           }
>       }
>       sysbus_mmio_map(s, 0, addrg);
> @@ -785,22 +786,25 @@ static const TypeInfo ram_info = {
>       .class_init    = ram_class_init,
>   };
>   
> -static void cpu_devinit(const char *cpu_type, unsigned int id,
> -                        uint64_t prom_addr, qemu_irq **cpu_irqs)
> +static DeviceState *cpu_devinit(const char *cpu_type, unsigned int id,
> +                                uint64_t prom_addr)
>   {
>       SPARCCPU *cpu;
>       CPUSPARCState *env;
> +    DeviceState *cpudev;
>   
>       cpu = SPARC_CPU(object_new(cpu_type));
>       env = &cpu->env;
> +    cpudev = DEVICE(cpu);
>   
>       qemu_register_reset(sun4m_cpu_reset, cpu);
>       object_property_set_bool(OBJECT(cpu), "start-powered-off", id != 0,
>                                &error_abort);
> -    qdev_realize_and_unref(DEVICE(cpu), NULL, &error_fatal);
> +    qdev_init_gpio_in_named(cpudev, cpu_set_irq, "pil", MAX_PILS);
> +    qdev_realize_and_unref(cpudev, NULL, &error_fatal);
>       cpu_sparc_set_id(env, id);
> -    *cpu_irqs = qemu_allocate_irqs(cpu_set_irq, cpu, MAX_PILS);
>       env->prom_addr = prom_addr;
> +    return cpudev;
>   }
>   
>   static void dummy_fdc_tc(void *opaque, int irq, int level)
> @@ -813,13 +817,14 @@ static void sun4m_hw_init(MachineState *machine)
>       DeviceState *slavio_intctl;
>       unsigned int i;
>       Nvram *nvram;
> -    qemu_irq *cpu_irqs[MAX_CPUS], slavio_irq[32], slavio_cpu_irq[MAX_CPUS];
> +    qemu_irq slavio_irq[32], slavio_cpu_irq[MAX_CPUS];
>       qemu_irq fdc_tc;
>       unsigned long kernel_size;
>       uint32_t initrd_size;
>       DriveInfo *fd[MAX_FD];
>       FWCfgState *fw_cfg;
>       DeviceState *dev, *ms_kb_orgate, *serial_orgate;
> +    DeviceState *cpus[MAX_CPUS];
>       SysBusDevice *s;
>       unsigned int smp_cpus = machine->smp.cpus;
>       unsigned int max_cpus = machine->smp.max_cpus;
> @@ -835,7 +840,7 @@ static void sun4m_hw_init(MachineState *machine)
>   
>       /* init CPUs */
>       for(i = 0; i < smp_cpus; i++) {
> -        cpu_devinit(machine->cpu_type, i, hwdef->slavio_base, &cpu_irqs[i]);
> +        cpus[i] = cpu_devinit(machine->cpu_type, i, hwdef->slavio_base);
>       }
>   
>       /* Create and map RAM frontend */
> @@ -855,7 +860,7 @@ static void sun4m_hw_init(MachineState *machine)
>       slavio_intctl = slavio_intctl_init(hwdef->intctl_base,
>                                          hwdef->intctl_base + 0x10000ULL,
>                                          smp_cpus,
> -                                       cpu_irqs);
> +                                       cpus);
>   
>       for (i = 0; i < 32; i++) {
>           slavio_irq[i] = qdev_get_gpio_in(slavio_intctl, i);

Reviewed-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>


ATB,

Mark.