162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * arch/arm/lib/call_with_stack.S
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2011 ARM Ltd.
662306a36Sopenharmony_ci * Written by Will Deacon <will.deacon@arm.com>
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <linux/linkage.h>
1062306a36Sopenharmony_ci#include <asm/assembler.h>
1162306a36Sopenharmony_ci#include <asm/unwind.h>
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci/*
1462306a36Sopenharmony_ci * void call_with_stack(void (*fn)(void *), void *arg, void *sp)
1562306a36Sopenharmony_ci *
1662306a36Sopenharmony_ci * Change the stack to that pointed at by sp, then invoke fn(arg) with
1762306a36Sopenharmony_ci * the new stack.
1862306a36Sopenharmony_ci *
1962306a36Sopenharmony_ci * The sequence below follows the APCS frame convention for frame pointer
2062306a36Sopenharmony_ci * unwinding, and implements the unwinder annotations needed by the EABI
2162306a36Sopenharmony_ci * unwinder.
2262306a36Sopenharmony_ci */
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ciENTRY(call_with_stack)
2562306a36Sopenharmony_ci#if defined(CONFIG_UNWINDER_FRAME_POINTER) && defined(CONFIG_CC_IS_GCC)
2662306a36Sopenharmony_ci	mov	ip, sp
2762306a36Sopenharmony_ci	push	{fp, ip, lr, pc}
2862306a36Sopenharmony_ci	sub	fp, ip, #4
2962306a36Sopenharmony_ci#else
3062306a36Sopenharmony_ciUNWIND( .fnstart		)
3162306a36Sopenharmony_ciUNWIND( .save	{fpreg, lr}	)
3262306a36Sopenharmony_ci	push	{fpreg, lr}
3362306a36Sopenharmony_ciUNWIND( .setfp	fpreg, sp	)
3462306a36Sopenharmony_ci	mov	fpreg, sp
3562306a36Sopenharmony_ci#endif
3662306a36Sopenharmony_ci	mov	sp, r2
3762306a36Sopenharmony_ci	mov	r2, r0
3862306a36Sopenharmony_ci	mov	r0, r1
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci	bl_r	r2
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci#if defined(CONFIG_UNWINDER_FRAME_POINTER) && defined(CONFIG_CC_IS_GCC)
4362306a36Sopenharmony_ci	ldmdb	fp, {fp, sp, pc}
4462306a36Sopenharmony_ci#else
4562306a36Sopenharmony_ci	mov	sp, fpreg
4662306a36Sopenharmony_ci	pop	{fpreg, pc}
4762306a36Sopenharmony_ciUNWIND( .fnend			)
4862306a36Sopenharmony_ci#endif
4962306a36Sopenharmony_ci	.globl call_with_stack_end
5062306a36Sopenharmony_cicall_with_stack_end:
5162306a36Sopenharmony_ciENDPROC(call_with_stack)
52