[PATCH v2] ARM: document arm_setup_stack() pitfalls
Uwe Kleine-König
u.kleine-koenig at pengutronix.de
Thu Sep 16 03:48:48 PDT 2021
On Thu, Sep 16, 2021 at 11:37:53AM +0200, Ahmad Fatoum wrote:
> Many arm32 board entry points use arm_setup_stack() to set up
> the stack from C code. This necessitates using __naked, which
> probably has been our most frequent cause of misscompiled C code.
>
> GCC is quite clear that:
>
> Only basic asm statements can safely be included in naked functions
> While using extended asm or a mixture of basic asm and C code may
> appear to work, they cannot be depended upon to work reliably and
> are not supported.
>
> But some boards use it anyway, because it's nice to avoid writing
> assembly. Reading generated assembly to spot compiler miscompilation
> isn't that nice though, so add some documentation, comments
> and compiler diagnostics to hopefully reduce future porting effort.
>
> Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
> ---
> v1 -> v2:
> - fix commit message title
>
> Cc: Jules Maselbas <jmaselbas at kalray.eu>
> ---
> Documentation/devel/porting.rst | 21 +++++++++++++++++++++
> arch/arm/include/asm/common.h | 22 ++++++++++++++++++++++
> 2 files changed, 43 insertions(+)
>
> diff --git a/Documentation/devel/porting.rst b/Documentation/devel/porting.rst
> index 97b787327c9a..699badbec672 100644
> --- a/Documentation/devel/porting.rst
> +++ b/Documentation/devel/porting.rst
> @@ -169,6 +169,27 @@ Looking at other boards you might see some different patterns:
> needs to be done at start. If a board similar to yours does this, you probably
> want to do likewise.
>
> + - ``__naked``: All functions called before stack is correctly initialized must be
> + marked with this attribute. Otherwise, function prologue and epilogue may access
> + the uninitialized stack. If the compiler for the target architecture doesn't
> + support the attribute, stack must be set up in non-inline assembly:
> + either a barebox assembly entry point or in earlier firmware.
s/either/Either/
> + The compiler may still spill excess local C variables used in a naked function
> + to the stack before it was initialized.
> + A naked function should thus preferably only contain inline assembly, set up a
> + stack and jump directly after to a ``noinline`` non naked function where the
> + stack is then normally usable.
> +
> + - ``noinline``: Compiler code inlining is oblivious to stack modification.
> + If you want to ensure a new function has its own stack frame (e.g. after setting
> + up the stack in a ``__naked`` function), you must jump to a ``__noreturn noinline``
> + function.
> +
> + - ``arm_setup_stack``: For 32-bit ARM, ``arm_setup_stack`` initialized the stack
s/initialized/initializes/
> + top when called from a naked C function, which allows to write the entry point
> + directly in C. The stack pointer will be decremented before pushing values.
> + Avoid interleaving with C-code. See ``__naked`` above for more details.
> +
> - ``__dtb_z_my_board_start[];``: Because the PBL normally doesn't parse anything out
> of the device tree blob, boards can benefit from keeping the device tree blob
> compressed and only unpack it in barebox proper. Such LZO-compressed device trees
> diff --git a/arch/arm/include/asm/common.h b/arch/arm/include/asm/common.h
> index d03ee6273fe5..88e2991c9324 100644
> --- a/arch/arm/include/asm/common.h
> +++ b/arch/arm/include/asm/common.h
> @@ -1,6 +1,8 @@
> #ifndef __ASM_ARM_COMMON_H
> #define __ASM_ARM_COMMON_H
>
> +#include <linux/compiler.h>
> +
> static inline unsigned long get_pc(void)
> {
> unsigned long pc;
> @@ -46,8 +48,28 @@ static inline unsigned long get_sp(void)
> return sp;
> }
>
> +extern void __compiletime_error(
> + "arm_setup_stack() called outside of naked function. On ARM64, "
> + "stack should be setup in non-inline assembly before branching to C entry point."
> +) __unsafe_stack_setup(void);
> +
> +/*
> + * Sets up new stack growing down from top within a naked C function.
> + * The first stack word will be top - sizeof(word).
> + *
> + * Avoid interleaving with C code as much as possible and and jump
s/and and/and/
> + * ASAP to a noinline function.
> + */
> static inline void arm_setup_stack(unsigned long top)
> {
> + if (IS_ENABLED(CONFIG_CPU_V8)) {
For configs that have CONFIG_CPU_V8 and CONFIG_CPU_V7 it might be legal
to call arm_setup_stack when running on a v7 SoC. Not sure how relevant
this is though, maybe just add a comment?
> + /*
> + * There are no naked functions on ARM64 and thus it's never
> + * safe to call arm_setup_stack().
> + */
> + __unsafe_stack_setup();
> + }
> +
Best regards
Uwe
--
Pengutronix e.K. | Uwe Kleine-König |
Industrial Linux Solutions | https://www.pengutronix.de/ |
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 488 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/barebox/attachments/20210916/5bc6b240/attachment-0001.sig>
More information about the barebox
mailing list