Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 19 Sep 2025 10:30:10 GMT
From:      Andrew Turner <andrew@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org
Subject:   git: 0706d3464f4e - main - arm64: Set the endian without a memory access
Message-ID:  <202509191030.58JAUACK005592@gitrepo.freebsd.org>

next in thread | raw e-mail | index | archive | help
The branch main has been updated by andrew:

URL: https://cgit.FreeBSD.org/src/commit/?id=0706d3464f4ef375fc31ecc7fa0733a13eca9d19

commit 0706d3464f4ef375fc31ecc7fa0733a13eca9d19
Author:     Andrew Turner <andrew@FreeBSD.org>
AuthorDate: 2025-09-19 10:05:47 +0000
Commit:     Andrew Turner <andrew@FreeBSD.org>
CommitDate: 2025-09-19 10:05:47 +0000

    arm64: Set the endian without a memory access
    
    Early in the kernel we set the endian through the sctlr_el1 and
    sctlr_el2 registers. To get the value to put into these registers we
    load them from memory. As this will depend on the endian to get the
    fields in the correct order then it will fail if the endian is not
    what the kernel expects.
    
    Add a macro to load a 64-bit value into a register without a memory
    access and use this to set the register. As instructions are not
    affected by the endian set in sctlr this is safe.
    
    It is unlikely this will be hit as UEFI requires the processor to be
    in little endian mode, however when booting using the Linux ABI the
    kernel may start in big-endian, and secondary CPUs could be big-endian.
    
    Reviewed by:    emaste
    Sponsored by:   Arm Ltd
    Differential Revision:  https://reviews.freebsd.org/D51012
---
 sys/arm64/arm64/locore.S | 41 +++++++++++++++++++++++++++++++++++++----
 1 file changed, 37 insertions(+), 4 deletions(-)

diff --git a/sys/arm64/arm64/locore.S b/sys/arm64/arm64/locore.S
index 4a10a2b4f2d3..50a3eda846da 100644
--- a/sys/arm64/arm64/locore.S
+++ b/sys/arm64/arm64/locore.S
@@ -39,6 +39,23 @@
 
 #define	VIRT_BITS	48
 
+/*
+ * Loads a 64-bit value into reg using 1 to 4 mov/movk instructions.
+ * This can be used early on when we don't know the CPUs endianness.
+ */
+.macro	mov_q reg, val
+	mov	\reg, :abs_g0_nc:\val
+.if (\val >> 16) & 0xffff != 0
+	movk	\reg, :abs_g1_nc:\val
+.endif
+.if (\val >> 32) & 0xffff != 0
+	movk	\reg, :abs_g2_nc:\val
+.endif
+.if (\val >> 48) & 0xffff != 0
+	movk	\reg, :abs_g3:\val
+.endif
+.endm
+
 #if PAGE_SIZE == PAGE_SIZE_16K
 /*
  * The number of level 3 tables to create. 32 will allow for 1G of address
@@ -324,15 +341,23 @@ LENTRY(enter_kernel_el)
 	cmp	x23, #(CURRENTEL_EL_EL2)
 	b.eq	1f
 
-	ldr	x2, =SCTLR_MMU_OFF
+	/*
+	 * Ensure there are no memory operations here. If the boot loader
+	 * enters the kernel in big-endian mode then loading sctlr will
+	 * be incorrect. As instructions are the same in both endians it is
+	 * safe to use mov instructions.
+	 */
+	mov_q	x2, SCTLR_MMU_OFF
 	msr	sctlr_el1, x2
-	/* SCTLR_EOS is set so eret is a context synchronizing event so we
+	/*
+	 * SCTLR_EOS is set to make eret a context synchronizing event. 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
+	/*
+	 * Ensure SPSR_EL1 and pstate are in sync. The only way to set the
 	 * latter is to set the former and return from an exception with eret.
 	 */
 	mov	x2, #(PSR_DAIF | PSR_M_EL1h)
@@ -346,11 +371,19 @@ LENTRY(enter_kernel_el)
 	 * 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.
+	 *
+	 * As with sctlr_el1 above use mov instructions to ensure there are
+	 * no memory operations.
 	 */
-	ldr	x2, =(SCTLR_EL2_RES1 | SCTLR_EL2_EIS | SCTLR_EL2_EOS)
+	mov_q	x2, (SCTLR_EL2_RES1 | SCTLR_EL2_EIS | SCTLR_EL2_EOS)
 	msr	sctlr_el2, x2
 	isb
 
+	/*
+	 * The hardware is now in little-endian mode so memory operations
+	 * are safe.
+	 */
+
 	/* Configure the Hypervisor */
 	ldr	x2, =(HCR_RW | HCR_APK | HCR_API)
 	msr	hcr_el2, x2



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202509191030.58JAUACK005592>