Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 23 Sep 2025 17:09:32 GMT
From:      Andrew Turner <andrew@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org
Subject:   git: 0f455824d0ab - main - arm64/vmm: Add a feature flag and use it for HCRX
Message-ID:  <202509231709.58NH9WAd077214@gitrepo.freebsd.org>

next in thread | raw e-mail | index | archive | help
The branch main has been updated by andrew:

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

commit 0f455824d0abdcf09d2e96cf97f99c542bbde877
Author:     Andrew Turner <andrew@FreeBSD.org>
AuthorDate: 2025-09-22 17:07:57 +0000
Commit:     Andrew Turner <andrew@FreeBSD.org>
CommitDate: 2025-09-23 17:08:36 +0000

    arm64/vmm: Add a feature flag and use it for HCRX
    
    Add a field to hold the features the hardware supports that need to be
    handled when switching to a guest and use it to handle FEAT_HCX that
    adds the HRX_EL2 register.
    
    This reduces the number of times we read ID registers in guest
    switching which may be trapped when running under nested virtualisation.
    
    Sponsored by:   Arm Ltd
    Differential Revision:  https://reviews.freebsd.org/D51816
---
 sys/arm64/vmm/arm64.h     |  2 ++
 sys/arm64/vmm/vmm_arm64.c |  6 ++++++
 sys/arm64/vmm/vmm_hyp.c   | 28 +++++++++++++++-------------
 3 files changed, 23 insertions(+), 13 deletions(-)

diff --git a/sys/arm64/vmm/arm64.h b/sys/arm64/vmm/arm64.h
index 6a0c4c78e568..0bd5a933bee1 100644
--- a/sys/arm64/vmm/arm64.h
+++ b/sys/arm64/vmm/arm64.h
@@ -125,6 +125,8 @@ struct hyp {
 	uint64_t	vmid_generation;
 	uint64_t	vttbr_el2;
 	uint64_t	el2_addr;	/* The address of this in el2 space */
+	uint64_t	feats;		/* Which features are enabled */
+#define	HYP_FEAT_HCX		(0x1ul << 0)
 	bool		vgic_attached;
 	struct vgic_v3	*vgic;
 	struct hypctx	*ctx[];
diff --git a/sys/arm64/vmm/vmm_arm64.c b/sys/arm64/vmm/vmm_arm64.c
index e293c99a6646..70bb914d68c6 100644
--- a/sys/arm64/vmm/vmm_arm64.c
+++ b/sys/arm64/vmm/vmm_arm64.c
@@ -517,6 +517,7 @@ vmmops_init(struct vm *vm, pmap_t pmap)
 {
 	struct hyp *hyp;
 	vm_size_t size;
+	uint64_t idreg;
 
 	size = el2_hyp_size(vm);
 	hyp = malloc_aligned(size, PAGE_SIZE, M_HYP, M_WAITOK | M_ZERO);
@@ -524,6 +525,11 @@ vmmops_init(struct vm *vm, pmap_t pmap)
 	hyp->vm = vm;
 	hyp->vgic_attached = false;
 
+	if (get_kernel_reg(ID_AA64MMFR1_EL1, &idreg)) {
+		if (ID_AA64MMFR1_HCX_VAL(idreg) >= ID_AA64MMFR1_HCX_IMPL)
+			hyp->feats |= HYP_FEAT_HCX;
+	}
+
 	vtimer_vminit(hyp);
 	vgic_vminit(hyp);
 
diff --git a/sys/arm64/vmm/vmm_hyp.c b/sys/arm64/vmm/vmm_hyp.c
index d61885c15871..475ad79f63cc 100644
--- a/sys/arm64/vmm/vmm_hyp.c
+++ b/sys/arm64/vmm/vmm_hyp.c
@@ -259,14 +259,6 @@ vmm_hyp_reg_store(struct hypctx *hypctx, struct hyp *hyp, bool guest)
 	hypctx->hcr_el2 = READ_SPECIALREG(hcr_el2);
 	hypctx->vpidr_el2 = READ_SPECIALREG(vpidr_el2);
 	hypctx->vmpidr_el2 = READ_SPECIALREG(vmpidr_el2);
-
-#ifndef VMM_VHE
-	/* hcrx_el2 depends on feat_hcx */
-	uint64_t mmfr1 = READ_SPECIALREG(id_aa64mmfr1_el1);
-	if (ID_AA64MMFR1_HCX_VAL(mmfr1) >> ID_AA64MMFR1_HCX_SHIFT) {
-		hypctx->hcrx_el2 = READ_SPECIALREG(MRS_REG_ALT_NAME(HCRX_EL2));
-	}
-#endif
 }
 
 static void
@@ -277,11 +269,9 @@ vmm_hyp_reg_restore(struct hypctx *hypctx, struct hyp *hyp, bool guest)
 	/* Restore the special registers */
 	WRITE_SPECIALREG(hcr_el2, hypctx->hcr_el2);
 
-	if (guest_or_nonvhe(guest)) {
-		uint64_t mmfr1 = READ_SPECIALREG(id_aa64mmfr1_el1);
-		if (ID_AA64MMFR1_HCX_VAL(mmfr1) >> ID_AA64MMFR1_HCX_SHIFT) {
-			WRITE_SPECIALREG(MRS_REG_ALT_NAME(HCRX_EL2), hypctx->hcrx_el2);
-		}
+	if (guest) {
+		if ((hyp->feats & HYP_FEAT_HCX) != 0)
+			WRITE_SPECIALREG(HCRX_EL2_REG, hypctx->hcrx_el2);
 	}
 	isb();
 
@@ -502,11 +492,18 @@ vmm_hyp_call_guest(struct hyp *hyp, struct hypctx *hypctx)
 	struct hypctx host_hypctx;
 	uint64_t cntvoff_el2;
 	uint64_t ich_hcr_el2, ich_vmcr_el2, cnthctl_el2, cntkctl_el1;
+#ifndef VMM_VHE
+	uint64_t hcrx_el2;
+#endif
 	uint64_t ret;
 	uint64_t s1e1r, hpfar_el2;
 	bool hpfar_valid;
 
 	vmm_hyp_reg_store(&host_hypctx, NULL, false);
+#ifndef VMM_VHE
+	if ((hyp->feats & HYP_FEAT_HCX) != 0)
+		hcrx_el2 = READ_SPECIALREG(MRS_REG_ALT_NAME(HCRX_EL2));
+#endif
 
 	/* Save the host special registers */
 	cnthctl_el2 = READ_SPECIALREG(cnthctl_el2);
@@ -584,6 +581,11 @@ vmm_hyp_call_guest(struct hyp *hyp, struct hypctx *hypctx)
 
 	vmm_hyp_reg_restore(&host_hypctx, NULL, false);
 
+#ifndef VMM_VHE
+	if ((hyp->feats & HYP_FEAT_HCX) != 0)
+		WRITE_SPECIALREG(MRS_REG_ALT_NAME(HCRX_EL2), hcrx_el2);
+#endif
+
 	/* Restore the host special registers */
 	WRITE_SPECIALREG(ich_hcr_el2, ich_hcr_el2);
 	WRITE_SPECIALREG(ich_vmcr_el2, ich_vmcr_el2);



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202509231709.58NH9WAd077214>