aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHarry Moulton <harry.moulton@arm.com>2025-01-23 12:40:05 +0000
committerAndrew Turner <andrew@FreeBSD.org>2025-02-04 11:24:41 +0000
commit32111003c3087389cc5e50949ee3a26c4e7b26c4 (patch)
tree9b9d629dc356c34f64408a3c24ca1adb15691760
parent078e8b34b13d6d0663661542eeac9007806fccdc (diff)
arm64/vmm: save and restore HCRX_EL2 register
With the addition of the Extended Hypervisor Configuration Register (HCRX_EL2), this change ensures that it is both set to 0 before entering a vm, and that it is properly saved/restored. Reviewed by: andrew Sponsored by: Arm Ltd Differential Revision: https://reviews.freebsd.org/D48584 Signed-off-by: Harry Moulton <harry.moulton@arm.com>
-rw-r--r--sys/arm64/vmm/arm64.h1
-rw-r--r--sys/arm64/vmm/vmm_hyp.c15
-rw-r--r--sys/arm64/vmm/vmm_reset.c2
3 files changed, 18 insertions, 0 deletions
diff --git a/sys/arm64/vmm/arm64.h b/sys/arm64/vmm/arm64.h
index 8cfe77dcde6f..6a0c4c78e568 100644
--- a/sys/arm64/vmm/arm64.h
+++ b/sys/arm64/vmm/arm64.h
@@ -94,6 +94,7 @@ struct hypctx {
/* EL2 control registers */
uint64_t cptr_el2; /* Architectural Feature Trap Register */
uint64_t hcr_el2; /* Hypervisor Configuration Register */
+ uint64_t hcrx_el2; /* Extended Hypervisor Configuration Register */
uint64_t mdcr_el2; /* Monitor Debug Configuration Register */
uint64_t vpidr_el2; /* Virtualization Processor ID Register */
uint64_t vmpidr_el2; /* Virtualization Multiprocessor ID Register */
diff --git a/sys/arm64/vmm/vmm_hyp.c b/sys/arm64/vmm/vmm_hyp.c
index bd119c80139b..d61885c15871 100644
--- a/sys/arm64/vmm/vmm_hyp.c
+++ b/sys/arm64/vmm/vmm_hyp.c
@@ -259,6 +259,14 @@ 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
@@ -268,6 +276,13 @@ 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);
+ }
+ }
isb();
WRITE_SPECIALREG(sp_el0, hypctx->sp_el0);
diff --git a/sys/arm64/vmm/vmm_reset.c b/sys/arm64/vmm/vmm_reset.c
index 8ccb83e7a0ea..79d022cf33e8 100644
--- a/sys/arm64/vmm/vmm_reset.c
+++ b/sys/arm64/vmm/vmm_reset.c
@@ -140,6 +140,8 @@ reset_vm_el2_regs(void *vcpu)
el2ctx->hcr_el2 |= HCR_E2H;
}
+ /* Set the Extended Hypervisor Configuration Register */
+ el2ctx->hcrx_el2 = 0;
/* TODO: Trap all extensions we don't support */
el2ctx->mdcr_el2 = 0;
/* PMCR_EL0.N is read from MDCR_EL2.HPMN */