git: f4c3458ab3ce - main - arm64/vmm: Move vttbr_el2 & vtimer into struct hypctx

From: Andrew Turner <andrew_at_FreeBSD.org>
Date: Mon, 06 Jul 2026 15:24:42 UTC
The branch main has been updated by andrew:

URL: https://cgit.FreeBSD.org/src/commit/?id=f4c3458ab3ce52ba9b234bee7711d0cb9a0745ac

commit f4c3458ab3ce52ba9b234bee7711d0cb9a0745ac
Author:     Kajetan Puchalski <kajetan.puchalski@arm.com>
AuthorDate: 2026-07-06 14:17:58 +0000
Commit:     Andrew Turner <andrew@FreeBSD.org>
CommitDate: 2026-07-06 15:18:30 +0000

    arm64/vmm: Move vttbr_el2 & vtimer into struct hypctx
    
    Move vttbr_el2 & vtimer from struct hyp into struct hypctx to streamline
    the logic and handle them in the same way as other *_el2 registers are
    already being handled.
    
    Signed-off-by:  Kajetan Puchalski <kajetan.puchalski@arm.com>
    Reviewed by:    andrew
    Sponsored by:   Arm Ltd
    Differential Revision:  https://reviews.freebsd.org/D56554
---
 sys/arm64/vmm/arm64.h     |  6 ++-
 sys/arm64/vmm/io/vtimer.c | 99 ++++++++++++++++++++---------------------------
 sys/arm64/vmm/io/vtimer.h |  1 -
 sys/arm64/vmm/vmm_arm64.c |  4 +-
 sys/arm64/vmm/vmm_hyp.c   | 21 +++++-----
 5 files changed, 56 insertions(+), 75 deletions(-)

diff --git a/sys/arm64/vmm/arm64.h b/sys/arm64/vmm/arm64.h
index 2b69f86da321..c43034454808 100644
--- a/sys/arm64/vmm/arm64.h
+++ b/sys/arm64/vmm/arm64.h
@@ -229,6 +229,8 @@ struct hypctx {
 	uint64_t	hfgrtr2_el2;
 	uint64_t	hfgwtr2_el2;
 
+	uint64_t	vttbr_el2;
+
 	/* Storage for *host* timer registers */
 	struct {
 		uint64_t cnthctl_el2;
@@ -242,6 +244,7 @@ struct hypctx {
 		uint64_t	hpfar_el2;	/* Hypervisor IPA Fault Address Register */
 	} exit_info;
 
+	struct vtimer	vtimer;
 	struct vtimer_cpu 	vtimer_cpu;
 
 	uint64_t		setcaps;	/* Currently enabled capabilities. */
@@ -307,9 +310,8 @@ hypctx_read_sys_reg(struct hypctx *hypctx, enum hypctx_sysreg reg)
 
 struct hyp {
 	struct vm	*vm;
-	struct vtimer	vtimer;
 	uint64_t	vmid_generation;
-	uint64_t	vttbr_el2;
+	uint64_t	cntvoff_el2;    /* VM-wide virtual timer offset */
 	uint64_t	el2_addr;	/* The address of this in el2 space */
 	uint64_t	feats;		/* Which features are enabled */
 #define	HYP_FEAT_HCX		(0x1ul << 0)
diff --git a/sys/arm64/vmm/io/vtimer.c b/sys/arm64/vmm/io/vtimer.c
index d1c489463882..ff29a06751e0 100644
--- a/sys/arm64/vmm/io/vtimer.c
+++ b/sys/arm64/vmm/io/vtimer.c
@@ -97,7 +97,7 @@ vtimer_virtual_timer_intr(void *arg)
 	}
 
 	cntpct_el0 = READ_SPECIALREG(cntpct_el0) -
-	    hypctx->hyp->vtimer.cntvoff_el2;
+	    hypctx->vtimer.cntvoff_el2;
 	if (hypctx->vtimer_cpu.virt_timer.cntx_cval_el0 < cntpct_el0)
 		vgic_inject_irq(hypctx->hyp, vcpu_vcpuid(hypctx->vcpu),
 		    GT_VIRT_IRQ, true);
@@ -133,14 +133,35 @@ vtimer_init(void)
 }
 
 void
-vtimer_vminit(struct hyp *hyp)
+vtimer_cpuinit(struct hypctx *hypctx)
 {
-	uint64_t now;
+	struct vtimer_cpu *vtimer_cpu;
 	bool ecv_poff;
 
+	vtimer_cpu = &hypctx->vtimer_cpu;
+	/*
+	 * Configure physical timer interrupts for the VCPU.
+	 *
+	 * CNTP_CTL_IMASK: mask interrupts
+	 * ~CNTP_CTL_ENABLE: disable the timer
+	 */
+	vtimer_cpu->phys_timer.cntx_ctl_el0 = CNTP_CTL_IMASK & ~CNTP_CTL_ENABLE;
+
+	mtx_init(&vtimer_cpu->phys_timer.mtx, "vtimer phys callout mutex", NULL,
+	    MTX_DEF);
+	callout_init_mtx(&vtimer_cpu->phys_timer.callout,
+	    &vtimer_cpu->phys_timer.mtx, 0);
+	vtimer_cpu->phys_timer.irqid = GT_PHYS_NS_IRQ;
+
+	mtx_init(&vtimer_cpu->virt_timer.mtx, "vtimer virt callout mutex", NULL,
+	    MTX_DEF);
+	callout_init_mtx(&vtimer_cpu->virt_timer.callout,
+	    &vtimer_cpu->virt_timer.mtx, 0);
+	vtimer_cpu->virt_timer.irqid = GT_VIRT_IRQ;
+
 	ecv_poff = false;
 
-	if (allow_ecv_phys && (hyp->feats & HYP_FEAT_ECV_POFF) != 0)
+	if (allow_ecv_phys && (hypctx->hyp->feats & HYP_FEAT_ECV_POFF) != 0)
 		ecv_poff = true;
 
 	/*
@@ -165,17 +186,17 @@ vtimer_vminit(struct hyp *hyp)
 		 *
 		 * TODO: Don't trap when FEAT_ECV is present
 		 */
-		hyp->vtimer.cnthctl_el2 =
+		hypctx->vtimer.cnthctl_el2 =
 		    CNTHCTL_E2H_EL0VCTEN_NOTRAP |
 		    CNTHCTL_E2H_EL0VTEN_NOTRAP;
 		if (ecv_poff) {
-			hyp->vtimer.cnthctl_el2 |=
+			hypctx->vtimer.cnthctl_el2 |=
 			    CNTHCTL_E2H_EL0PCTEN_NOTRAP |
 			    CNTHCTL_E2H_EL0PTEN_NOTRAP |
 			    CNTHCTL_E2H_EL1PCTEN_NOTRAP |
 			    CNTHCTL_E2H_EL1PTEN_NOTRAP;
 		} else {
-			hyp->vtimer.cnthctl_el2 |=
+			hypctx->vtimer.cnthctl_el2 |=
 			    CNTHCTL_E2H_EL0PCTEN_TRAP |
 			    CNTHCTL_E2H_EL0PTEN_TRAP |
 			    CNTHCTL_E2H_EL1PCTEN_TRAP |
@@ -188,50 +209,20 @@ vtimer_vminit(struct hyp *hyp)
 		 * CNTHCTL_EL1PCTEN: trap access to CNTPCT_EL0
 		 */
 		if (ecv_poff) {
-			hyp->vtimer.cnthctl_el2 =
+			hypctx->vtimer.cnthctl_el2 =
 			    CNTHCTL_EL1PCTEN_NOTRAP |
 			    CNTHCTL_EL1PCEN_NOTRAP;
 		} else {
-			hyp->vtimer.cnthctl_el2 =
+			hypctx->vtimer.cnthctl_el2 =
 			    CNTHCTL_EL1PCTEN_TRAP |
 			    CNTHCTL_EL1PCEN_TRAP;
 		}
 	}
 
 	if (ecv_poff)
-		hyp->vtimer.cnthctl_el2 |= CNTHCTL_ECV_EN;
-
-	now = READ_SPECIALREG(cntpct_el0);
-	hyp->vtimer.cntvoff_el2 = now;
+		hypctx->vtimer.cnthctl_el2 |= CNTHCTL_ECV_EN;
 
-	return;
-}
-
-void
-vtimer_cpuinit(struct hypctx *hypctx)
-{
-	struct vtimer_cpu *vtimer_cpu;
-
-	vtimer_cpu = &hypctx->vtimer_cpu;
-	/*
-	 * Configure physical timer interrupts for the VCPU.
-	 *
-	 * CNTP_CTL_IMASK: mask interrupts
-	 * ~CNTP_CTL_ENABLE: disable the timer
-	 */
-	vtimer_cpu->phys_timer.cntx_ctl_el0 = CNTP_CTL_IMASK & ~CNTP_CTL_ENABLE;
-
-	mtx_init(&vtimer_cpu->phys_timer.mtx, "vtimer phys callout mutex", NULL,
-	    MTX_DEF);
-	callout_init_mtx(&vtimer_cpu->phys_timer.callout,
-	    &vtimer_cpu->phys_timer.mtx, 0);
-	vtimer_cpu->phys_timer.irqid = GT_PHYS_NS_IRQ;
-
-	mtx_init(&vtimer_cpu->virt_timer.mtx, "vtimer virt callout mutex", NULL,
-	    MTX_DEF);
-	callout_init_mtx(&vtimer_cpu->virt_timer.callout,
-	    &vtimer_cpu->virt_timer.mtx, 0);
-	vtimer_cpu->virt_timer.irqid = GT_VIRT_IRQ;
+	hypctx->vtimer.cntvoff_el2 = hypctx->hyp->cntvoff_el2;
 }
 
 void
@@ -289,10 +280,10 @@ vtimer_sync_hwstate(struct hypctx *hypctx)
 	uint64_t cntpct_el0;
 
 	cntpct_el0 = READ_SPECIALREG(cntpct_el0) -
-	    hypctx->hyp->vtimer.cntvoff_el2;
+	    hypctx->vtimer.cntvoff_el2;
 	vtime_sync_timer(hypctx, &hypctx->vtimer_cpu.virt_timer, cntpct_el0);
 	/* If FEAT_ECV_POFF is in use then we need to sync the physical timer */
-	if ((hypctx->hyp->vtimer.cnthctl_el2 & CNTHCTL_ECV_EN) != 0) {
+	if ((hypctx->vtimer.cnthctl_el2 & CNTHCTL_ECV_EN) != 0) {
 		vtime_sync_timer(hypctx, &hypctx->vtimer_cpu.phys_timer,
 		    cntpct_el0);
 	}
@@ -331,7 +322,7 @@ vtimer_schedule_irq(struct hypctx *hypctx, bool phys)
 	else
 		timer = &hypctx->vtimer_cpu.virt_timer;
 	cntpct_el0 = READ_SPECIALREG(cntpct_el0) -
-	    hypctx->hyp->vtimer.cntvoff_el2;
+	    hypctx->vtimer.cntvoff_el2;
 	if (timer->cntx_cval_el0 < cntpct_el0) {
 		/* Timer set in the past, trigger interrupt */
 		vgic_inject_irq(hypctx->hyp, vcpu_vcpuid(hypctx->vcpu),
@@ -381,16 +372,14 @@ vtimer_remove_irq(struct hypctx *hypctx, struct vcpu *vcpu)
 int
 vtimer_phys_ctl_read(struct vcpu *vcpu, uint64_t *rval, void *arg)
 {
-	struct hyp *hyp;
 	struct hypctx *hypctx;
 	struct vtimer_cpu *vtimer_cpu;
 	uint64_t cntpct_el0;
 
 	hypctx = vcpu_get_cookie(vcpu);
-	hyp = hypctx->hyp;
 	vtimer_cpu = &hypctx->vtimer_cpu;
 
-	cntpct_el0 = READ_SPECIALREG(cntpct_el0) - hyp->vtimer.cntvoff_el2;
+	cntpct_el0 = READ_SPECIALREG(cntpct_el0) - hypctx->vtimer.cntvoff_el2;
 	if (vtimer_cpu->phys_timer.cntx_cval_el0 < cntpct_el0)
 		/* Timer condition met */
 		*rval = vtimer_cpu->phys_timer.cntx_ctl_el0 | CNTP_CTL_ISTATUS;
@@ -430,12 +419,10 @@ vtimer_phys_ctl_write(struct vcpu *vcpu, uint64_t wval, void *arg)
 int
 vtimer_phys_cnt_read(struct vcpu *vcpu, uint64_t *rval, void *arg)
 {
-	struct vm *vm;
-	struct hyp *hyp;
+	struct hypctx *hypctx;
 
-	vm = vcpu_vm(vcpu);
-	hyp = vm_get_cookie(vm);
-	*rval = READ_SPECIALREG(cntpct_el0) - hyp->vtimer.cntvoff_el2;
+	hypctx = vcpu_get_cookie(vcpu);
+	*rval = READ_SPECIALREG(cntpct_el0) - hypctx->vtimer.cntvoff_el2;
 	return (0);
 }
 
@@ -481,13 +468,11 @@ vtimer_phys_cval_write(struct vcpu *vcpu, uint64_t wval, void *arg)
 int
 vtimer_phys_tval_read(struct vcpu *vcpu, uint64_t *rval, void *arg)
 {
-	struct hyp *hyp;
 	struct hypctx *hypctx;
 	struct vtimer_cpu *vtimer_cpu;
 	uint32_t cntpct_el0;
 
 	hypctx = vcpu_get_cookie(vcpu);
-	hyp = hypctx->hyp;
 	vtimer_cpu = &hypctx->vtimer_cpu;
 
 	if (!(vtimer_cpu->phys_timer.cntx_ctl_el0 & CNTP_CTL_ENABLE)) {
@@ -500,7 +485,7 @@ vtimer_phys_tval_read(struct vcpu *vcpu, uint64_t *rval, void *arg)
 		*rval = (uint32_t)RES1;
 	} else {
 		cntpct_el0 = READ_SPECIALREG(cntpct_el0) -
-		    hyp->vtimer.cntvoff_el2;
+		    hypctx->vtimer.cntvoff_el2;
 		*rval = vtimer_cpu->phys_timer.cntx_cval_el0 - cntpct_el0;
 	}
 
@@ -510,16 +495,14 @@ vtimer_phys_tval_read(struct vcpu *vcpu, uint64_t *rval, void *arg)
 int
 vtimer_phys_tval_write(struct vcpu *vcpu, uint64_t wval, void *arg)
 {
-	struct hyp *hyp;
 	struct hypctx *hypctx;
 	struct vtimer_cpu *vtimer_cpu;
 	uint64_t cntpct_el0;
 
 	hypctx = vcpu_get_cookie(vcpu);
-	hyp = hypctx->hyp;
 	vtimer_cpu = &hypctx->vtimer_cpu;
 
-	cntpct_el0 = READ_SPECIALREG(cntpct_el0) - hyp->vtimer.cntvoff_el2;
+	cntpct_el0 = READ_SPECIALREG(cntpct_el0) - hypctx->vtimer.cntvoff_el2;
 	vtimer_cpu->phys_timer.cntx_cval_el0 = (int32_t)wval + cntpct_el0;
 
 	vtimer_remove_irq(hypctx, vcpu);
diff --git a/sys/arm64/vmm/io/vtimer.h b/sys/arm64/vmm/io/vtimer.h
index 92ce025968d2..d415afa47acc 100644
--- a/sys/arm64/vmm/io/vtimer.h
+++ b/sys/arm64/vmm/io/vtimer.h
@@ -67,7 +67,6 @@ struct vtimer_cpu {
 };
 
 int 	vtimer_init(void);
-void 	vtimer_vminit(struct hyp *);
 void 	vtimer_cpuinit(struct hypctx *);
 void 	vtimer_cpucleanup(struct hypctx *);
 void	vtimer_vmcleanup(struct hyp *);
diff --git a/sys/arm64/vmm/vmm_arm64.c b/sys/arm64/vmm/vmm_arm64.c
index 3615d2da66cc..43f45dc596c9 100644
--- a/sys/arm64/vmm/vmm_arm64.c
+++ b/sys/arm64/vmm/vmm_arm64.c
@@ -542,7 +542,7 @@ vmmops_init(struct vm *vm, pmap_t pmap)
 	if (ID_AA64MMFR1_HCX_VAL(idreg) >= ID_AA64MMFR1_HCX_IMPL)
 		hyp->feats |= HYP_FEAT_HCX;
 
-	vtimer_vminit(hyp);
+	hyp->cntvoff_el2 = READ_SPECIALREG(cntpct_el0);
 	vgic_vminit(hyp);
 
 	if (!in_vhe())
@@ -1170,7 +1170,7 @@ vmmops_run(void *vcpui, register_t pc, pmap_t pmap, struct vm_eventinfo *evinfo)
 
 		/* Activate the stage2 pmap so the vmid is valid */
 		pmap_activate_vm(pmap);
-		hyp->vttbr_el2 = pmap_to_ttbr0(pmap);
+		hypctx->vttbr_el2 = pmap_to_ttbr0(pmap);
 
 		/*
 		 * TODO: What happens if a timer interrupt is asserted exactly
diff --git a/sys/arm64/vmm/vmm_hyp.c b/sys/arm64/vmm/vmm_hyp.c
index 25b04d14dca8..070142199c44 100644
--- a/sys/arm64/vmm/vmm_hyp.c
+++ b/sys/arm64/vmm/vmm_hyp.c
@@ -241,13 +241,13 @@ vmm_hyp_reg_store_timer(struct hypctx *hypctx, struct hyp *hyp, bool guest)
 	} else {
 		hypctx->vtimer_cpu.cntkctl_el1 =
 		    READ_SPECIALREG(cntkctl_el1);
-		hypctx->host_timer_regs.cnthctl_el2 =
+		hypctx->vtimer.cnthctl_el2 =
 		    READ_SPECIALREG(cnthctl_el2);
-		hypctx->host_timer_regs.cntvoff_el2 =
+		hypctx->vtimer.cntvoff_el2 =
 		    READ_SPECIALREG(cntvoff_el2);
 	}
 
-	ecv_poff = (hyp->vtimer.cnthctl_el2 & CNTHCTL_ECV_EN) != 0;
+	ecv_poff = (hypctx->vtimer.cnthctl_el2 & CNTHCTL_ECV_EN) != 0;
 
 	if (guest_or_nonvhe(guest) && ecv_poff) {
 		/*
@@ -565,11 +565,12 @@ static void
 vmm_hyp_reg_restore_timer(struct hypctx *hypctx, struct hyp *hyp, bool guest)
 {
 	bool ecv_poff;
-	ecv_poff = (hyp->vtimer.cnthctl_el2 & CNTHCTL_ECV_EN) != 0;
+	ecv_poff = (hypctx->vtimer.cnthctl_el2 & CNTHCTL_ECV_EN) != 0;
+
+	WRITE_SPECIALREG(cnthctl_el2, hypctx->vtimer.cnthctl_el2);
+	WRITE_SPECIALREG(cntvoff_el2, hypctx->vtimer.cntvoff_el2);
 
 	if (guest) {
-		WRITE_SPECIALREG(cnthctl_el2, hyp->vtimer.cnthctl_el2);
-		WRITE_SPECIALREG(cntvoff_el2, hyp->vtimer.cntvoff_el2);
 		WRITE_SPECIALREG(EL1_REG(CNTKCTL),
 		    hypctx->vtimer_cpu.cntkctl_el1);
 		WRITE_SPECIALREG(EL0_REG(CNTV_CVAL),
@@ -583,14 +584,10 @@ vmm_hyp_reg_restore_timer(struct hypctx *hypctx, struct hyp *hyp, bool guest)
 			 * to keep in sync.
 			 */
 			WRITE_SPECIALREG(CNTPOFF_EL2_REG,
-			    hyp->vtimer.cntvoff_el2);
+			    hypctx->vtimer.cntvoff_el2);
 			isb();
 		}
 	} else {
-		WRITE_SPECIALREG(cnthctl_el2,
-		    hypctx->host_timer_regs.cnthctl_el2);
-		WRITE_SPECIALREG(cntvoff_el2,
-		    hypctx->host_timer_regs.cntvoff_el2);
 		WRITE_SPECIALREG(cntkctl_el1, hypctx->vtimer_cpu.cntkctl_el1);
 	}
 	if (guest_or_nonvhe(guest) && ecv_poff) {
@@ -736,7 +733,7 @@ static uint64_t
 __vmm_hyp_call_guest(struct hypctx *hypctx, struct hypctx *host_hypctx)
 {
 	uint64_t ret;
-	WRITE_SPECIALREG(vttbr_el2, hypctx->hyp->vttbr_el2);
+	WRITE_SPECIALREG(vttbr_el2, hypctx->vttbr_el2);
 	WRITE_SPECIALREG(mdcr_el2, hypctx->mdcr_el2);
 	/* Call into the guest */
 	ret = VMM_HYP_FUNC(do_call_guest)(hypctx);