Just enough GIC to trigger timer interrupts.
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
tests/tcg/aarch64/system/lib/gicv3.h | 56 +++++++++++++++++
tests/tcg/aarch64/system/lib/gicv3.c | 77 +++++++++++++++++++++++
tests/tcg/aarch64/Makefile.softmmu-target | 7 ++-
3 files changed, 138 insertions(+), 2 deletions(-)
create mode 100644 tests/tcg/aarch64/system/lib/gicv3.h
create mode 100644 tests/tcg/aarch64/system/lib/gicv3.c
diff --git a/tests/tcg/aarch64/system/lib/gicv3.h b/tests/tcg/aarch64/system/lib/gicv3.h
new file mode 100644
index 00000000000..9a1268937c6
--- /dev/null
+++ b/tests/tcg/aarch64/system/lib/gicv3.h
@@ -0,0 +1,56 @@
+/*
+ * GICv3 Helper Library
+ *
+ * Copyright (c) 2024 Linaro Ltd
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef GICV3_H
+#define GICV3_H
+
+#include <stdint.h>
+
+/* Virt machine GICv3 base addresses */
+#define GICD_BASE 0x08000000 /* c.f. VIRT_GIC_DIST */
+#define GICR_BASE 0x080a0000 /* c.f. VIRT_GIC_REDIST */
+
+/* Distributor registers */
+#define GICD_CTLR (GICD_BASE + 0x0000)
+#define GICD_TYPER (GICD_BASE + 0x0004)
+#define GICD_IIDR (GICD_BASE + 0x0008)
+
+/* Redistributor registers (per-CPU) */
+#define GICR_SGI_OFFSET 0x00010000
+
+#define GICR_CTLR 0x0000
+#define GICR_WAKER 0x0014
+#define GICR_IGROUPR0 (GICR_SGI_OFFSET + 0x0080)
+#define GICR_ISENABLER0 (GICR_SGI_OFFSET + 0x0100)
+#define GICR_IPRIORITYR0 (GICR_SGI_OFFSET + 0x0400)
+
+/* GICD_CTLR bits */
+#define GICD_CTLR_ARE_NS (1U << 4)
+#define GICD_CTLR_ENA_G1NS (1U << 1)
+#define GICD_CTLR_ENA_G0 (1U << 0)
+
+/* GICR_WAKER bits */
+#define GICR_WAKER_ChildrenAsleep (1U << 2)
+#define GICR_WAKER_ProcessorSleep (1U << 1)
+
+/**
+ * gicv3_init:
+ *
+ * Initialize GICv3 distributor and the redistributor for the current CPU.
+ */
+void gicv3_init(void);
+
+/**
+ * gicv3_enable_irq:
+ * @irq: The IRQ number to enable
+ *
+ * Enable the specified IRQ (SPI or PPI).
+ */
+void gicv3_enable_irq(unsigned int irq);
+
+#endif /* GICV3_H */
diff --git a/tests/tcg/aarch64/system/lib/gicv3.c b/tests/tcg/aarch64/system/lib/gicv3.c
new file mode 100644
index 00000000000..a09a0e430e6
--- /dev/null
+++ b/tests/tcg/aarch64/system/lib/gicv3.c
@@ -0,0 +1,77 @@
+/*
+ * GICv3 Helper Library Implementation
+ *
+ * Copyright (c) 2024 Linaro Ltd
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "gicv3.h"
+
+#define write_sysreg(r, v) do { \
+ uint64_t __val = (uint64_t)(v); \
+ asm volatile("msr " #r ", %x0" \
+ : : "rZ" (__val)); \
+} while (0)
+
+#define isb() asm volatile("isb" : : : "memory")
+
+static inline void write_reg(uintptr_t addr, uint32_t val)
+{
+ *(volatile uint32_t *)addr = val;
+}
+
+static inline uint32_t read_reg(uintptr_t addr)
+{
+ return *(volatile uint32_t *)addr;
+}
+
+void gicv3_init(void)
+{
+ uint32_t val;
+
+ /* 1. Enable Distributor ARE and Group 1 NS */
+ val = read_reg(GICD_CTLR);
+ val |= GICD_CTLR_ARE_NS | GICD_CTLR_ENA_G1NS;
+ write_reg(GICD_CTLR, val);
+
+ /* 2. Wake up Redistributor 0 */
+ /* Clear ProcessorSleep */
+ val = read_reg(GICR_BASE + GICR_WAKER);
+ val &= ~GICR_WAKER_ProcessorSleep;
+ write_reg(GICR_BASE + GICR_WAKER, val);
+
+ /* Wait for ChildrenAsleep to be cleared */
+ while (read_reg(GICR_BASE + GICR_WAKER) & GICR_WAKER_ChildrenAsleep) {
+ /* spin */
+ }
+
+ /* 3. Enable CPU interface */
+ /* Set Priority Mask to allow all interrupts */
+ write_sysreg(ICC_PMR_EL1, 0xff);
+ /* Enable Group 1 Non-Secure interrupts */
+ write_sysreg(ICC_IGRPEN1_EL1, 1);
+ isb();
+}
+
+void gicv3_enable_irq(unsigned int irq)
+{
+ if (irq < 32) {
+ /* PPI: use GICR_ISENABLER0 */
+ uintptr_t addr;
+
+ /* Set Group 1 */
+ addr = GICR_BASE + GICR_IGROUPR0;
+ write_reg(addr, read_reg(addr) | (1U << irq));
+
+ /* Set priority (0xa0) */
+ addr = GICR_BASE + GICR_IPRIORITYR0 + irq;
+ *(volatile uint8_t *)addr = 0xa0;
+
+ /* Enable it */
+ addr = GICR_BASE + GICR_ISENABLER0;
+ write_reg(addr, 1U << irq);
+ } else {
+ /* SPI: not implemented yet */
+ }
+}
diff --git a/tests/tcg/aarch64/Makefile.softmmu-target b/tests/tcg/aarch64/Makefile.softmmu-target
index f7a7d2b800f..c0939a0eeca 100644
--- a/tests/tcg/aarch64/Makefile.softmmu-target
+++ b/tests/tcg/aarch64/Makefile.softmmu-target
@@ -4,8 +4,9 @@
AARCH64_SRC=$(SRC_PATH)/tests/tcg/aarch64
AARCH64_SYSTEM_SRC=$(AARCH64_SRC)/system
+AARCH64_SYSTEM_LIB_SRC=$(AARCH64_SYSTEM_SRC)/lib
-VPATH+=$(AARCH64_SYSTEM_SRC)
+VPATH+=$(AARCH64_SYSTEM_SRC) $(AARCH64_SYSTEM_LIB_SRC)
# These objects provide the basic boot code and helper functions for all tests
CRT_OBJS=boot.o
@@ -24,7 +25,7 @@ LINK_SCRIPT=$(AARCH64_SYSTEM_SRC)/kernel.ld
LDFLAGS=-Wl,-T$(LINK_SCRIPT)
TESTS+=$(AARCH64_TESTS) $(MULTIARCH_TESTS)
EXTRA_RUNS+=$(MULTIARCH_RUNS)
-CFLAGS+=-nostdlib -ggdb -O0 $(MINILIB_INC)
+CFLAGS+=-nostdlib -ggdb -O0 $(MINILIB_INC) -I$(AARCH64_SYSTEM_LIB_SRC)
LDFLAGS+=-static -nostdlib $(CRT_OBJS) $(MINILIB_OBJS) -lgcc
config-cc.mak: Makefile
@@ -102,6 +103,8 @@ run-pauth-3:
$(call skip-test, "RUN of pauth-3", "not built")
endif
+gicv3.o: gicv3.c gicv3.h
+ $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -c $< -o $@
ifneq ($(CROSS_CC_HAS_ARMV8_MTE),)
QEMU_MTE_ENABLED_MACHINE=-M virt,mte=on -cpu max -display none
QEMU_OPTS_WITH_MTE_ON = $(QEMU_MTE_ENABLED_MACHINE) $(QEMU_BASE_ARGS) -kernel
--
2.47.3