Index | Thread | Search

From:
Mark Kettenis <mark.kettenis@xs4all.nl>
Subject:
Re: [PATCH 3/4] Pick the correct timer interrupt for the running EL
To:
Marc Zyngier <maz@kernel.org>
Cc:
tech@openbsd.org, jsg@openbsd.org, patrick@openbsd.org, mail@patrick-wildt.de
Date:
Sun, 26 Apr 2026 12:22:19 +0200

Download raw body.

Thread
Hi Marc,

> When running at EL2, the kernel is using the virtual EL2 timer,
> and therefore uses a different interrupt from the one driven by
> the virtual EL0 timer which gets used when running at EL1.
>
> Pick the correct interrupt depending on the EL the kernel runs at.

Thanks again for the diff.  I've reworked your diff a bit to use
READ_SPECIALREG() and bits in <machine/armreg.h> which is the usual
way we deal with system registers in OpenBSD.

Tested this on one of my Apple systems.  There it will pick a
different interrupt now.  Worried a bit about that until I realized
that the way timer interrupts are FIQs and handled by looking directly
at the generic timer registers means that the actual interrupt
descriptor that we use on that platform doesn't matter...

To my fellow OpenBSD developers: ok?


Index: arch/arm64/include/armreg.h
===================================================================
RCS file: /cvs/src/sys/arch/arm64/include/armreg.h,v
diff -u -p -r1.44 armreg.h
--- arch/arm64/include/armreg.h	22 Jul 2025 09:20:41 -0000	1.44
+++ arch/arm64/include/armreg.h	26 Apr 2026 09:56:36 -0000
@@ -119,6 +119,14 @@
 #define	CTR_ILINE_MASK		(0xf << CTR_ILINE_SHIFT)
 #define	CTR_ILINE_SIZE(reg)	(((reg) & CTR_ILINE_MASK) >> CTR_ILINE_SHIFT)
 
+/* CurrentEL - Current Exception Level */
+#define	CURRENTEL_EL_SHIFT	2
+#define	CURRENTEL_EL_MASK	(0x3 << CURRENTEL_EL_SHIFT)
+#define	 CURRENTEL_EL_EL0	(0x0 << CURRENTEL_EL_SHIFT)
+#define	 CURRENTEL_EL_EL1	(0x1 << CURRENTEL_EL_SHIFT)
+#define	 CURRENTEL_EL_EL2	(0x2 << CURRENTEL_EL_SHIFT)
+#define	 CURRENTEL_EL_EL3	(0x3 << CURRENTEL_EL_SHIFT)
+
 /* MPIDR_EL1 - Multiprocessor Affinity Register */
 #define MPIDR_AFF3		(0xFFULL << 32)
 #define MPIDR_AFF2		(0xFFULL << 16)
Index: arch/arm64/dev/agtimer.c
===================================================================
RCS file: /cvs/src/sys/arch/arm64/dev/agtimer.c,v
diff -u -p -r1.29 agtimer.c
--- arch/arm64/dev/agtimer.c	31 Jan 2025 16:46:41 -0000	1.29
+++ arch/arm64/dev/agtimer.c	26 Apr 2026 09:56:36 -0000
@@ -289,7 +289,9 @@ agtimer_set_clockrate(int32_t new_freque
 void
 agtimer_cpu_initclocks(void)
 {
-	struct agtimer_softc	*sc = agtimer_cd.cd_devs[0];
+	struct agtimer_softc *sc = agtimer_cd.cd_devs[0];
+	uint64_t el;
+	int idx;
 
 	stathz = hz;
 	profhz = stathz * 10;
@@ -299,8 +301,20 @@ agtimer_cpu_initclocks(void)
 		agtimer_set_clockrate(agtimer_frequency);
 	}
 
+	/* Pick the correct PPI depending on the running EL. */
+	el = READ_SPECIALREG(CurrentEL) & CURRENTEL_EL_MASK;
+	if (el == CURRENTEL_EL_EL2) {
+		idx = OF_getindex(sc->sc_node, "hyp-virt", "interrupt-names");
+		if (idx == -1)
+			idx = 4;
+	} else {
+		idx = OF_getindex(sc->sc_node, "virt", "interrupt-names");
+		if (idx == -1)
+			idx = 2;
+	}
+
 	/* configure virtual timer interrupt */
-	sc->sc_ih = arm_intr_establish_fdt_idx(sc->sc_node, 2,
+	sc->sc_ih = arm_intr_establish_fdt_idx(sc->sc_node, idx,
 	    IPL_CLOCK|IPL_MPSAFE, agtimer_intr, NULL, "tick");
 }