diff options
author | Harry Moulton <harry.moulton@arm.com> | 2025-01-23 12:40:05 +0000 |
---|---|---|
committer | Andrew Turner <andrew@FreeBSD.org> | 2025-02-04 11:24:41 +0000 |
commit | 32111003c3087389cc5e50949ee3a26c4e7b26c4 (patch) | |
tree | 9b9d629dc356c34f64408a3c24ca1adb15691760 | |
parent | 078e8b34b13d6d0663661542eeac9007806fccdc (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.h | 1 | ||||
-rw-r--r-- | sys/arm64/vmm/vmm_hyp.c | 15 | ||||
-rw-r--r-- | sys/arm64/vmm/vmm_reset.c | 2 |
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 */ |