1
0
mirror of https://git.FreeBSD.org/src.git synced 2024-10-19 02:29:40 +00:00

arm64: Ensure sctlr and pstate are in known states

Before entering the kernel exception level ensure sctlr_el2 and
sctlr_el1 are in a known state. The EOS flag needs to be set to ensure
an eret instruction is a context synchronization event.

Set spcr_el1 when entering the kernel from EL1 and use an eret
instruction to return to the caller. This ensures the CPU pstate is
consistent with the value in spcr_el1 as it is the only way to set it
directly.

Sponsored by:	Arm Ltd
Differential Revision:	https://reviews.freebsd.org/D45528
This commit is contained in:
Andrew Turner 2024-07-23 10:18:24 +01:00
parent 57ef7935eb
commit 034c83fd7d
2 changed files with 32 additions and 26 deletions

View File

@ -67,19 +67,6 @@ ENTRY(_start)
/* Enter the kernel exception level */
bl enter_kernel_el
/*
* Disable the MMU. We may have entered the kernel with it on and
* will need to update the tables later. If this has been set up
* with anything other than a VA == PA map then this will fail,
* but in this case the code to find where we are running from
* would have also failed.
*/
dsb sy
mrs x2, sctlr_el1
bic x2, x2, SCTLR_M
msr sctlr_el1, x2
isb
/* Set the context id */
msr contextidr_el1, xzr
@ -314,19 +301,37 @@ LEND(mpentry_common)
* registers and drop to EL1.
*/
LENTRY(enter_kernel_el)
#define INIT_SCTLR_EL1 (SCTLR_LSMAOE | SCTLR_nTLSMD | SCTLR_EIS | \
SCTLR_TSCXT | SCTLR_EOS)
mrs x23, CurrentEL
and x23, x23, #(CURRENTEL_EL_MASK)
cmp x23, #(CURRENTEL_EL_EL2)
b.eq 1f
ret
1:
/*
* Disable the MMU. If the HCR_EL2.E2H field is set we will clear it
* which may break address translation.
ldr x2, =INIT_SCTLR_EL1
msr sctlr_el1, x2
/* SCTLR_EOS is set so eret is a context synchronizing event so we
* need an isb here to ensure it's observed by later instructions,
* but don't need it in the eret below.
*/
isb
/* Ensure SPSR_EL1 and pstate are in sync. The only wat to set the
* latter is to set the former and return from an exception with eret.
*/
mov x2, #(PSR_DAIF | PSR_M_EL1h)
msr spsr_el1, x2
msr elr_el1, lr
eret
1:
dsb sy
mrs x2, sctlr_el2
bic x2, x2, SCTLR_M
/*
* Set just the reserved bits in sctlr_el2. This will disable the
* MMU which may have broken the kernel if we enter the kernel in
* EL2, e.g. when using VHE.
*/
ldr x2, =(SCTLR_EL2_RES1 | SCTLR_EL2_EIS | SCTLR_EL2_EOS)
msr sctlr_el2, x2
isb
@ -346,8 +351,8 @@ LENTRY(enter_kernel_el)
mrs x2, mpidr_el1
msr vmpidr_el2, x2
/* Set the bits that need to be 1 in sctlr_el1 */
ldr x2, .Lsctlr_res1
/* Set the initial sctlr_el1 */
ldr x2, =INIT_SCTLR_EL1
msr sctlr_el1, x2
/*
@ -403,10 +408,7 @@ LENTRY(enter_kernel_el)
isb
eret
.align 3
.Lsctlr_res1:
.quad SCTLR_RES1
#undef INIT_SCTLR_EL1
LEND(enter_kernel_el)
/*

View File

@ -148,10 +148,14 @@
#define SCTLR_EL2_C (0x1UL << SCTLR_EL2_C_SHIFT)
#define SCTLR_EL2_SA_SHIFT 3
#define SCTLR_EL2_SA (0x1UL << SCTLR_EL2_SA_SHIFT)
#define SCTLR_EL2_EOS_SHIFT 11
#define SCTLR_EL2_EOS (0x1UL << SCTLR_EL2_EOS_SHIFT)
#define SCTLR_EL2_I_SHIFT 12
#define SCTLR_EL2_I (0x1UL << SCTLR_EL2_I_SHIFT)
#define SCTLR_EL2_WXN_SHIFT 19
#define SCTLR_EL2_WXN (0x1UL << SCTLR_EL2_WXN_SHIFT)
#define SCTLR_EL2_EIS_SHIFT 22
#define SCTLR_EL2_EIS (0x1UL << SCTLR_EL2_EIS_SHIFT)
#define SCTLR_EL2_EE_SHIFT 25
#define SCTLR_EL2_EE (0x1UL << SCTLR_EL2_EE_SHIFT)