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@xxxxxxxxxxxxxx> --- v1 -> v2: - add __ARM_SETUP_STACK(0) to normal ENTRY_FUNCTION. On ARM32, it's a no-op, but on ARM64, it ensures the header isn't shifted --- arch/arm/include/asm/barebox-arm-head.h | 6 +--- arch/arm/include/asm/barebox-arm.h | 46 +++++++++++++++++++++++++ arch/arm/lib/pbl.lds.S | 1 + 3 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 fcb7e31d8531..099e1bef3cb8 100644 --- a/arch/arm/include/asm/barebox-arm-head.h +++ b/arch/arm/include/asm/barebox-arm-head.h @@ -46,14 +46,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 cfb5943f33d6..5018b3e2f57a 100644 --- a/arch/arm/include/asm/barebox-arm.h +++ b/arch/arm/include/asm/barebox-arm.h @@ -161,6 +161,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 +215,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 \ diff --git a/arch/arm/lib/pbl.lds.S b/arch/arm/lib/pbl.lds.S index 0a0fb8b5ac13..e77b3220fcb0 100644 --- a/arch/arm/lib/pbl.lds.S +++ b/arch/arm/lib/pbl.lds.S @@ -31,6 +31,7 @@ SECTIONS .text : { _stext = .; + *(.text_head_prologue*) *(.text_head_entry*) __bare_init_start = .; *(.text_bare_init*) -- 2.30.2 _______________________________________________ barebox mailing list barebox@xxxxxxxxxxxxxxxxxxx http://lists.infradead.org/mailman/listinfo/barebox