summaryrefslogtreecommitdiffstats
path: root/arch/arm/include
diff options
context:
space:
mode:
authorAhmad Fatoum <a.fatoum@pengutronix.de>2022-01-14 09:42:25 +0100
committerSascha Hauer <s.hauer@pengutronix.de>2022-01-17 08:10:10 +0100
commit880c9803b95a08520359c49285f57af874ee109f (patch)
tree26dfeb600a37a4be14fe0150870e153d4809dabf /arch/arm/include
parentdaafe431e65e65d98f388f77673810bed93b58f8 (diff)
downloadbarebox-880c9803b95a08520359c49285f57af874ee109f.tar.gz
barebox-880c9803b95a08520359c49285f57af874ee109f.tar.xz
ARM: implement ENTRY_FUNCTION_WITHSTACK
The point of ENTRY_FUNCTION is to write the entry point in C. Due to lack of __naked on ARM64, the start of the entry point will have prologue using stack and it's not possible to set up the stack safely without branching into non-inline assembly[0]. On ARM32, where we got __naked, we have the potential for a different problem: If BootROM sets up stack for us and we branch to a naked function, which doesn't set up its own stack, compiler may decide to spill local variables overwriting instructions it had already run[1]. For code reuse between ARM and ARM64, it would be nice to use the same entry point structure for both. Currently, the only way is to write it in non-inline assembly using the ENTRY_PROC macro. This introduces another way: the ARM64 barebox header has enough space for 8 instructions of which 5 are unused (2 instructions compiler prologue + 1 instruction to jump after the header), we could place a stack setup routine there to avoid having to write a separate assembly file. For ARM32, we just call arm_setup_stack and branch out directly after, freeing board porters of the burden of getting it right. Add a new ENTRY_FUNCTION_WITHSTACK to realize this. [0]: 76bced6fe146 ("ARM: document arm_setup_stack() pitfalls"), [1]: b51b15ba1738 ("RISC-V: board-dt-2nd: move low level init into nonnaked function") Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de> Link: https://lore.barebox.org/20220114084227.308804-1-a.fatoum@pengutronix.de Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Diffstat (limited to 'arch/arm/include')
-rw-r--r--arch/arm/include/asm/barebox-arm-head.h6
-rw-r--r--arch/arm/include/asm/barebox-arm.h47
2 files changed, 48 insertions, 5 deletions
diff --git a/arch/arm/include/asm/barebox-arm-head.h b/arch/arm/include/asm/barebox-arm-head.h
index 187d12c9fc..3e8da0da7c 100644
--- a/arch/arm/include/asm/barebox-arm-head.h
+++ b/arch/arm/include/asm/barebox-arm-head.h
@@ -44,14 +44,10 @@ static inline void __barebox_arm_head(void)
"1: b 1b\n"
#endif
#else
+ /* 5 instructions added by ENTRY_FUNCTION */
/* two instruction long function prologue */
/* only use if stack is initialized! */
"b 2f\n"
- "nop\n"
- "nop\n"
- "nop\n"
- "nop\n"
- "nop\n"
#endif
".asciz \"barebox\"\n"
#ifdef CONFIG_CPU_32
diff --git a/arch/arm/include/asm/barebox-arm.h b/arch/arm/include/asm/barebox-arm.h
index cfb5943f33..2fbdaaa356 100644
--- a/arch/arm/include/asm/barebox-arm.h
+++ b/arch/arm/include/asm/barebox-arm.h
@@ -18,6 +18,7 @@
#include <linux/types.h>
#include <linux/compiler.h>
#include <asm/barebox-arm-head.h>
+#include <asm/common.h>
#include <asm/sections.h>
/*
@@ -161,6 +162,51 @@ static inline unsigned long arm_mem_barebox_image(unsigned long membase,
}
}
+#ifdef CONFIG_CPU_64
+
+#define ____emit_entry_prologue(instr, ...) do { \
+ static __attribute__ ((unused,section(".text_head_prologue"))) \
+ const u32 __entry_prologue[] = {(instr), ##__VA_ARGS__}; \
+ barrier_data(__entry_prologue); \
+} while(0)
+
+#define __emit_entry_prologue(instr1, instr2, instr3, instr4, instr5) \
+ ____emit_entry_prologue(instr1, instr2, instr3, instr4, instr5)
+
+#define __ARM_SETUP_STACK(stack_top) \
+ __emit_entry_prologue(0x14000002 /* b pc+0x8 */, \
+ stack_top /* 32-bit literal */, \
+ 0x18ffffe9 /* ldr w9, top */, \
+ 0xb4000049 /* cbz x9, pc+0x8 */, \
+ 0x9100013f /* mov sp, x9 */)
+#else
+#define __ARM_SETUP_STACK(stack_top) if (stack_top) arm_setup_stack(stack_top)
+#endif
+
+/*
+ * Unlike ENTRY_FUNCTION, this can be used to setup stack for a C entry
+ * point on both ARM32 and ARM64. ENTRY_FUNCTION on ARM64 can only be used
+ * if preceding boot stage has initialized the stack pointer.
+ *
+ * Stack top of 0 means stack is already set up. In that case, the follow-up
+ * code block will not be inlined and may spill to stack right away.
+ */
+#define ENTRY_FUNCTION_WITHSTACK(name, stack_top, arg0, arg1, arg2) \
+ void name(ulong r0, ulong r1, ulong r2); \
+ \
+ static void __##name(ulong, ulong, ulong); \
+ \
+ void NAKED __section(.text_head_entry_##name) name \
+ (ulong r0, ulong r1, ulong r2) \
+ { \
+ __barebox_arm_head(); \
+ __ARM_SETUP_STACK(stack_top); \
+ __##name(r0, r1, r2); \
+ } \
+ static void noinline __##name \
+ (ulong arg0, ulong arg1, ulong arg2)
+
+
#define ENTRY_FUNCTION(name, arg0, arg1, arg2) \
void name(ulong r0, ulong r1, ulong r2); \
\
@@ -170,6 +216,7 @@ static inline unsigned long arm_mem_barebox_image(unsigned long membase,
(ulong r0, ulong r1, ulong r2) \
{ \
__barebox_arm_head(); \
+ __ARM_SETUP_STACK(0); \
__##name(r0, r1, r2); \
} \
static void NAKED noinline __##name \