Commit 0b78f2e9 authored by Ard Biesheuvel's avatar Ard Biesheuvel
Browse files

ARM: call_with_stack: add unwind support



Restructure the code and add the unwind annotations so that both the
frame pointer unwinder as well as the EHABI unwind info based unwinder
will be able to follow the call stack through call_with_stack().

Since GCC and Clang use different formats for the stack frame, two
methods are implemented: a GCC version that pushes fp, sp, lr and pc for
compatibility with the frame pointer unwinder, and a second version that
works with Clang, as well as with the EHABI unwinder both in ARM and
Thumb2 modes.

Signed-off-by: default avatarArd Biesheuvel <ardb@kernel.org>
Acked-by: default avatarLinus Walleij <linus.walleij@linaro.org>
Tested-by: default avatarKeith Packard <keithpac@amazon.com>
Reviewed-by: default avatarNick Desaulniers <ndesaulniers@google.com>
Tested-by: default avatarMarc Zyngier <maz@kernel.org>
Tested-by: Vladimir Murzin <vladimir.murzin@arm.com> # ARMv7M
parent d4664b6c
Loading
Loading
Loading
Loading
+25 −8
Original line number Diff line number Diff line
@@ -8,25 +8,42 @@

#include <linux/linkage.h>
#include <asm/assembler.h>
#include <asm/unwind.h>

/*
 * void call_with_stack(void (*fn)(void *), void *arg, void *sp)
 *
 * Change the stack to that pointed at by sp, then invoke fn(arg) with
 * the new stack.
 *
 * The sequence below follows the APCS frame convention for frame pointer
 * unwinding, and implements the unwinder annotations needed by the EABI
 * unwinder.
 */
ENTRY(call_with_stack)
	str	sp, [r2, #-4]!
	str	lr, [r2, #-4]!

ENTRY(call_with_stack)
#if defined(CONFIG_UNWINDER_FRAME_POINTER) && defined(CONFIG_CC_IS_GCC)
	mov	ip, sp
	push	{fp, ip, lr, pc}
	sub	fp, ip, #4
#else
UNWIND( .fnstart		)
UNWIND( .save	{fpreg, lr}	)
	push	{fpreg, lr}
UNWIND( .setfp	fpreg, sp	)
	mov	fpreg, sp
#endif
	mov	sp, r2
	mov	r2, r0
	mov	r0, r1

	badr	lr, 1f
	ret	r2
	bl_r	r2

1:	ldr	lr, [sp]
	ldr	sp, [sp, #4]
	ret	lr
#if defined(CONFIG_UNWINDER_FRAME_POINTER) && defined(CONFIG_CC_IS_GCC)
	ldmdb	fp, {fp, sp, pc}
#else
	mov	sp, fpreg
	pop	{fpreg, pc}
UNWIND( .fnend			)
#endif
ENDPROC(call_with_stack)