aboutsummaryrefslogtreecommitdiff
path: root/sys/arm
diff options
context:
space:
mode:
authorAndrew Turner <andrew@FreeBSD.org>2024-01-11 17:13:12 +0000
committerAndrew Turner <andrew@FreeBSD.org>2024-05-17 16:07:16 +0000
commite72c41772352e1165711900c4f8df6b15b842ba8 (patch)
treef38086c5f61326a308683c695b5ad4086aabac84 /sys/arm
parentf715e95461c9264913a65e2dc93c291b7e318d2e (diff)
downloadsrc-e72c41772352e1165711900c4f8df6b15b842ba8.tar.gz
src-e72c41772352e1165711900c4f8df6b15b842ba8.zip
arm: Use the correct irq when in the hypervisor
When booting in the hypervisor state we need to use the hypervisor interrupt in the generic timer. In this case the registers we access in the kernel are remapped to the EL2 versions, however this causes an unexpected interrupt to trigger. Sponsored by: Arm Ltd Differential Revision: https://reviews.freebsd.org/D43975
Diffstat (limited to 'sys/arm')
-rw-r--r--sys/arm/arm/generic_timer.c25
1 files changed, 18 insertions, 7 deletions
diff --git a/sys/arm/arm/generic_timer.c b/sys/arm/arm/generic_timer.c
index bad0939b6ab9..d3e264527a7f 100644
--- a/sys/arm/arm/generic_timer.c
+++ b/sys/arm/arm/generic_timer.c
@@ -171,12 +171,14 @@ static struct timecounter arm_tmr_timecount = {
#define set_el0(x, val) cp15_## x ##_set(val)
#define set_el1(x, val) cp15_## x ##_set(val)
#define HAS_PHYS true
+#define IN_VHE false
#else /* __aarch64__ */
#define get_el0(x) READ_SPECIALREG(x ##_el0)
#define get_el1(x) READ_SPECIALREG(x ##_el1)
#define set_el0(x, val) WRITE_SPECIALREG(x ##_el0, val)
#define set_el1(x, val) WRITE_SPECIALREG(x ##_el1, val)
#define HAS_PHYS has_hyp()
+#define IN_VHE in_vhe()
#endif
static int
@@ -678,13 +680,22 @@ arm_tmr_attach(device_t dev)
#endif
#ifdef __aarch64__
- /*
- * Use the virtual timer when we can't use the hypervisor.
- * A hypervisor guest may change the virtual timer registers while
- * executing so any use of the virtual timer interrupt needs to be
- * coordinated with the virtual machine manager.
- */
- if (!HAS_PHYS) {
+ if (IN_VHE) {
+ /*
+ * The kernel is running at EL2. The EL0 timer registers are
+ * re-mapped to the EL2 version. Because of this we need to
+ * use the EL2 interrupt.
+ */
+ sc->physical_sys = true;
+ first_timer = GT_HYP_PHYS;
+ last_timer = GT_HYP_PHYS;
+ } else if (!HAS_PHYS) {
+ /*
+ * Use the virtual timer when we can't use the hypervisor.
+ * A hypervisor guest may change the virtual timer registers
+ * while executing so any use of the virtual timer interrupt
+ * needs to be coordinated with the virtual machine manager.
+ */
sc->physical_sys = false;
first_timer = GT_VIRT;
last_timer = GT_VIRT;