[PATCH v2 2/3] [NOT-FOR-UPSTREAM] lib: utils: irqchip: add QEMU virt test for APLIC wired IRQs
Raymond Mao
raymondmaoca at gmail.com
Mon May 4 10:13:41 PDT 2026
From: Raymond Mao <raymond.mao at riscstar.com>
Add a QEMU virt specific test hook for validating APLIC wired external
interrupt handling.
When APLIC_QEMU_WIRED_TEST is enabled, keep the test path limited to
hwirq 10 and only register it when the current APLIC instance is the
M-mode direct-mode provider and that interrupt is not delegated to a
child domain.
This keeps the test path compatible with the generic APLIC changes
while still allowing a DT overlay to expose an M-mode wired IRQ on
QEMU virt.
Signed-off-by: Raymond Mao <raymond.mao at riscstar.com>
---
Makefile | 3 ++
lib/utils/irqchip/aplic.c | 62 +++++++++++++++++++++++++++++++++++++++
2 files changed, 65 insertions(+)
diff --git a/Makefile b/Makefile
index 46541063..418ee1aa 100644
--- a/Makefile
+++ b/Makefile
@@ -399,6 +399,9 @@ CFLAGS += $(GENFLAGS)
CFLAGS += $(platform-cflags-y)
CFLAGS += -fPIE -pie
CFLAGS += $(firmware-cflags-y)
+ifeq ($(APLIC_QEMU_WIRED_TEST),y)
+CFLAGS += -DAPLIC_QEMU_WIRED_TEST
+endif
CPPFLAGS += $(GENFLAGS)
CPPFLAGS += $(platform-cppflags-y)
diff --git a/lib/utils/irqchip/aplic.c b/lib/utils/irqchip/aplic.c
index 3f4991b5..82efdb71 100644
--- a/lib/utils/irqchip/aplic.c
+++ b/lib/utils/irqchip/aplic.c
@@ -112,6 +112,7 @@
#define APLIC_DEFAULT_PRIORITY 1
#define APLIC_DISABLE_IDELIVERY 0
#define APLIC_ENABLE_IDELIVERY 1
+#define APLIC_QEMU_TEST_HWIRQ 10
#define APLIC_DISABLE_ITHRESHOLD 1
#define APLIC_ENABLE_ITHRESHOLD 0
@@ -119,6 +120,41 @@ static SBI_LIST_HEAD(aplic_list);
static void aplic_writel_msicfg(struct aplic_msicfg_data *msicfg,
void *msicfgaddr, void *msicfgaddrH);
+#ifdef APLIC_QEMU_WIRED_TEST
+
+#define UART_QEMU_MMIO 0x10000000UL
+
+static void aplic_test_uart_handler(void)
+{
+ volatile u8 *uart = (volatile u8 *)UART_QEMU_MMIO;
+
+ /* Drain RX FIFO to clear the interrupt source */
+ while (uart[0x05] & 0x01) { /* LSR.DR */
+ u8 ch = uart[0x00]; /* RBR */
+
+ sbi_printf("[APLIC TEST] UART got '%c'(0x%02x)\n",
+ (ch >= 32 && ch < 127) ? ch : '.', ch);
+ }
+
+ /* (Optional) read IIR to acknowledge on some models */
+ (void)uart[0x02]; /* IIR is at offset 2 when DLAB=0; */
+}
+
+static void aplic_hwirq_test_run(unsigned long aplic_addr)
+{
+ volatile u8 *uart = (volatile u8 *)UART_QEMU_MMIO;
+
+ /* UART: enable RX interrupt */
+ uart[0x02] = 0x07; /* FCR enable+clear */
+ uart[0x04] |= (1 << 3); /* MCR.OUT2 */
+ uart[0x01] |= 0x01; /* IER.ERBFI */
+ while (uart[0x05] & 0x01) /* drain */
+ (void)uart[0x00];
+
+ sbi_printf("[APLIC TEST] Setup done. Type keys now.\n");
+}
+#endif
+
static void aplic_init(struct aplic_data *aplic)
{
struct aplic_delegate_data *deleg;
@@ -245,6 +281,20 @@ static int aplic_check_msicfg(struct aplic_msicfg_data *msicfg)
return 0;
}
+#ifdef APLIC_QEMU_WIRED_TEST
+static int aplic_hwirq_handler(u32 hwirq, void *opaque)
+{
+ (void)opaque;
+
+ sbi_printf("[APLIC] Enter registered hwirq %u raw handler callback\n",
+ hwirq);
+
+ if (hwirq == 10)
+ aplic_test_uart_handler();
+
+ return SBI_OK;
+}
+#endif
static inline void *aplic_idc_base(unsigned long aplic_addr, u32 idc_index)
{
return (void *)(aplic_addr + APLIC_IDC_BASE +
@@ -541,6 +591,18 @@ int aplic_cold_irqchip_init(struct aplic_data *aplic)
/* Attach to the aplic list */
sbi_list_add_tail(&aplic->node, &aplic_list);
+#ifdef APLIC_QEMU_WIRED_TEST
+ if (aplic_mmode_direct(aplic) &&
+ !aplic_hwirq_delegated(aplic, APLIC_QEMU_TEST_HWIRQ)) {
+ rc = sbi_irqchip_register_handler(&aplic->irqchip,
+ APLIC_QEMU_TEST_HWIRQ, 1,
+ aplic_hwirq_handler, NULL);
+ if (rc)
+ return rc;
+ /* Enable test in M-mode before jumping to any payload */
+ aplic_hwirq_test_run(aplic->addr);
+ }
+#endif
return 0;
}
--
2.25.1
More information about the opensbi
mailing list