The branch stable/15 has been updated by andrew:

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

commit 09ea88fde992cfe52ac9e03e36e0088a98ebd44c
Author:     Andrew Turner <[email protected]>
AuthorDate: 2025-09-22 17:07:57 +0000
Commit:     Andrew Turner <[email protected]>
CommitDate: 2026-01-13 14:06:18 +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
    
    (cherry picked from commit 0f455824d0abdcf09d2e96cf97f99c542bbde877)
---
 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 20cb3c312df5..c0bcbe822ec0 100644
--- a/sys/arm64/vmm/arm64.h
+++ b/sys/arm64/vmm/arm64.h
@@ -128,6 +128,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 e4deb052d396..8e3d8d5220ec 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 636247c48080..eb066e23363b 100644
--- a/sys/arm64/vmm/vmm_hyp.c
+++ b/sys/arm64/vmm/vmm_hyp.c
@@ -264,14 +264,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
@@ -282,11 +274,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();
 
@@ -513,11 +503,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);
@@ -595,6 +592,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);

Reply via email to