diff --git a/sys/arm64/arm64/locore.S b/sys/arm64/arm64/locore.S --- a/sys/arm64/arm64/locore.S +++ b/sys/arm64/arm64/locore.S @@ -262,8 +262,12 @@ #endif /* - * If we are started in EL2, configure the required hypervisor - * registers and drop to EL1. + * Enter the exception level the kernel will use: + * + * - If in EL1 continue in EL1 + * - If the HCR_E2H field is stuck continue in EL2 + * - Configure EL2 to support running the kernel at EL1 and call ERET to + * continue in EL1 */ LENTRY(enter_kernel_el) mrs x23, CurrentEL @@ -283,6 +287,9 @@ msr sctlr_el2, x2 isb + /* Set the counter offset to a known value */ + msr cntvoff_el2, xzr + /* Configure the Hypervisor */ ldr x2, =(HCR_RW | HCR_APK | HCR_API) msr hcr_el2, x2 @@ -291,6 +298,21 @@ isb mrs x4, hcr_el2 + /* If HCR_EL2.E2H is stuck then continue in EL2 */ + tst x4, HCR_E2H + b.eq 2f + + /* + * The kernel will be running in EL2, route exceptions here rather + * than EL1. + */ + orr x4, x4, #(HCR_TGE) + msr hcr_el2, x4 + isb + + ret +2: + /* Load the Virtualization Process ID Register */ mrs x2, midr_el1 msr vpidr_el2, x2 @@ -303,15 +325,7 @@ ldr x2, .Lsctlr_res1 msr sctlr_el1, x2 - /* - * On some hardware, e.g., Apple M1, we can't clear E2H, so make sure we - * don't trap to EL2 for SIMD register usage to have at least a - * minimally usable system. - */ - tst x4, #HCR_E2H mov x3, #CPTR_RES1 /* HCR_E2H == 0 */ - mov x5, #CPTR_FPEN /* HCR_E2H == 1 */ - csel x2, x3, x5, eq msr cptr_el2, x2 /* Don't trap to EL2 for CP15 traps */ @@ -322,9 +336,6 @@ orr x2, x2, #(CNTHCTL_EL1PCTEN | CNTHCTL_EL1PCEN) msr cnthctl_el2, x2 - /* Set the counter offset to a known value */ - msr cntvoff_el2, xzr - /* Hypervisor trap functions */ adrp x2, hyp_stub_vectors add x2, x2, :lo12:hyp_stub_vectors @@ -342,13 +353,13 @@ ubfx x2, x2, #ID_AA64PFR0_GIC_SHIFT, #ID_AA64PFR0_GIC_BITS /* GIC[3:0] == 0001 - GIC CPU interface via special regs. supported */ cmp x2, #(ID_AA64PFR0_GIC_CPUIF_EN >> ID_AA64PFR0_GIC_SHIFT) - b.ne 2f + b.ne 3f mrs x2, icc_sre_el2 orr x2, x2, #ICC_SRE_EL2_EN /* Enable access from insecure EL1 */ orr x2, x2, #ICC_SRE_EL2_SRE /* Enable system registers */ msr icc_sre_el2, x2 -2: +3: /* Set the address to return to our return address */ msr elr_el2, x30 diff --git a/sys/arm64/arm64/machdep.c b/sys/arm64/arm64/machdep.c --- a/sys/arm64/arm64/machdep.c +++ b/sys/arm64/arm64/machdep.c @@ -207,12 +207,7 @@ bool has_hyp(void) { - - /* - * XXX The E2H check is wrong, but it's close enough for now. Needs to - * be re-evaluated once we're running regularly in EL2. - */ - return (boot_el == 2 && (hcr_el2 & HCR_E2H) == 0); + return (boot_el == 2); } bool