hw/intc/arm_gicv5: Make gicv5_set_* update SPI state
The GIC CD* insns that update interrupt state also work for SPIs. Instead of ignoring the GICV5_SPI type in gicv5_set_priority() and friends, update the state in our SPI state array. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Message-id: 20260327111700.795099-25-peter.maydell@linaro.org
Peter Maydell committed
Mar 27, 2026 at 11:16 UTC
5beb48ab53d57c0378c19c04941ccab2d2ab925e
2 files changed
+104
hw/intc/arm_gicv5.c
+64
@@ -490,6 +490,19 @@ void gicv5_set_priority(GICv5Common *cs, uint32_t id, uint8_t priority,
490
put_l2_iste(cs, cfg, &h);
491
break;
492
}
493
+ case GICV5_SPI:
494
+ {
495
+ GICv5SPIState *spi = gicv5_spi_state(cs, id, domain);
496
+
497
+ if (!spi) {
498
+ qemu_log_mask(LOG_GUEST_ERROR, "gicv5_set_priority: tried to set "
499
+ "priority of unreachable SPI %d\n", id);
500
+ return;
501
+ }
502
+
503
+ spi->priority = priority;
504
+ break;
505
+ }
506
default:
507
qemu_log_mask(LOG_GUEST_ERROR, "gicv5_set_priority: tried to set "
508
"priority of bad interrupt type %d\n", type);
@@ -524,6 +537,19 @@ void gicv5_set_enabled(GICv5Common *cs, uint32_t id, bool enabled,
537
put_l2_iste(cs, cfg, &h);
538
break;
539
}
540
+ case GICV5_SPI:
541
+ {
542
+ GICv5SPIState *spi = gicv5_spi_state(cs, id, domain);
543
+
544
+ if (!spi) {
545
+ qemu_log_mask(LOG_GUEST_ERROR, "gicv5_set_enabled: tried to set "
546
+ "enable state of unreachable SPI %d\n", id);
547
+ return;
548
+ }
549
+
550
+ spi->enabled = true;
551
+ break;
552
+ }
553
default:
554
qemu_log_mask(LOG_GUEST_ERROR, "gicv5_set_enabled: tried to set "
555
"enable state of bad interrupt type %d\n", type);
@@ -558,6 +584,19 @@ void gicv5_set_pending(GICv5Common *cs, uint32_t id, bool pending,
584
put_l2_iste(cs, cfg, &h);
585
break;
586
}
587
+ case GICV5_SPI:
588
+ {
589
+ GICv5SPIState *spi = gicv5_spi_state(cs, id, domain);
590
+
591
+ if (!spi) {
592
+ qemu_log_mask(LOG_GUEST_ERROR, "gicv5_set_pending: tried to set "
593
+ "pending state of unreachable SPI %d\n", id);
594
+ return;
595
+ }
596
+
597
+ spi->pending = true;
598
+ break;
599
+ }
600
default:
601
qemu_log_mask(LOG_GUEST_ERROR, "gicv5_set_pending: tried to set "
602
"pending state of bad interrupt type %d\n", type);
@@ -593,6 +632,18 @@ void gicv5_set_handling(GICv5Common *cs, uint32_t id,
632
put_l2_iste(cs, cfg, &h);
633
break;
634
}
635
+ case GICV5_SPI:
636
+ {
637
+ GICv5SPIState *spi = gicv5_spi_state(cs, id, domain);
638
+
639
+ if (!spi) {
640
+ qemu_log_mask(LOG_GUEST_ERROR, "gicv5_set_handling: tried to set "
641
+ "priority of unreachable SPI %d\n", id);
642
+ }
643
+
644
+ spi->hm = handling;
645
+ break;
646
+ }
647
default:
648
qemu_log_mask(LOG_GUEST_ERROR, "gicv5_set_handling: tried to set "
649
"handling mode of bad interrupt type %d\n", type);
@@ -642,6 +693,19 @@ void gicv5_set_target(GICv5Common *cs, uint32_t id, uint32_t iaffid,
693
put_l2_iste(cs, cfg, &h);
694
break;
695
}
696
+ case GICV5_SPI:
697
+ {
698
+ GICv5SPIState *spi = gicv5_spi_state(cs, id, domain);
699
+
700
+ if (!spi) {
701
+ qemu_log_mask(LOG_GUEST_ERROR, "gicv5_set_target: tried to set "
702
+ "target of unreachable SPI %d\n", id);
703
+ return;
704
+ }
705
+
706
+ spi->iaffid = iaffid;
707
+ break;
708
+ }
709
default:
710
qemu_log_mask(LOG_GUEST_ERROR, "gicv5_set_target: tried to set "
711
"target of bad interrupt type %d\n", type);
include/hw/intc/arm_gicv5_common.h
+40
@@ -200,4 +200,44 @@ static inline const char *gicv5_class_name(void)
200
return "arm-gicv5";
201
}
202
203
+/**
204
+ * gicv5_raw_spi_state
205
+ * @cs: GIC object
206
+ * @id: INTID of SPI to look up
207
+ *
208
+ * Return pointer to the GICv5SPIState for this SPI, or NULL if the
209
+ * interrupt ID is out of range. This does not do a check that the SPI
210
+ * is assigned to the right domain: generally you should call it via
211
+ * some other wrapper that performs an appropriate further check.
212
+ */
213
+static inline GICv5SPIState *gicv5_raw_spi_state(GICv5Common *cs, uint32_t id)
214
+{
215
+ if (id < cs->spi_base || id >= cs->spi_base + cs->spi_irs_range) {
216
+ return NULL;
217
+ }
218
+
219
+ return cs->spi + (id - cs->spi_base);
220
+}
221
+
222
+/**
223
+ * gicv5_spi_state:
224
+ * @cs: GIC object
225
+ * @id: INTID of SPI to look up
226
+ * @domain: domain to check
227
+ *
228
+ * Return pointer to the GICv5SPIState for this SPI, or NULL if the
229
+ * interrupt is unreachable (which can be because the INTID is out of
230
+ * range, or because the SPI is configured for a different domain).
231
+ */
232
+static inline GICv5SPIState *gicv5_spi_state(GICv5Common *cs, uint32_t id,
233
+ GICv5Domain domain)
234
+{
235
+ GICv5SPIState *spi = gicv5_raw_spi_state(cs, id);
236
+
237
+ if (!spi || spi->domain != domain) {
238
+ return NULL;
239
+ }
240
+ return spi;
241
+}
242
+
243
#endif