xref: /optee_os/lib/libutils/isoc/arch/arm/setjmp_a32.S (revision 7749dda24cf2b1f0a04d1de529cde03b6ca79867)
11bb92983SJerome Forissier/* SPDX-License-Identifier: BSD-3-Clause */
20c81fcd6SJens Wiklander/*
30c81fcd6SJens Wiklander * Copyright (c) 1994-2009  Red Hat, Inc.
40c81fcd6SJens Wiklander * All rights reserved.
50c81fcd6SJens Wiklander *
60c81fcd6SJens Wiklander * Redistribution and use in source and binary forms, with or without
70c81fcd6SJens Wiklander * modification, are permitted provided that the following conditions are met:
80c81fcd6SJens Wiklander *
90c81fcd6SJens Wiklander * 1. Redistributions of source code must retain the above copyright notice,
100c81fcd6SJens Wiklander * this list of conditions and the following disclaimer.
110c81fcd6SJens Wiklander *
120c81fcd6SJens Wiklander * 2. Redistributions in binary form must reproduce the above copyright notice,
130c81fcd6SJens Wiklander * this list of conditions and the following disclaimer in the documentation
140c81fcd6SJens Wiklander * and/or other materials provided with the distribution.
150c81fcd6SJens Wiklander *
160c81fcd6SJens Wiklander * 3. Neither the name of the copyright holder nor the names of its
170c81fcd6SJens Wiklander * contributors may be used to endorse or promote products derived from this
180c81fcd6SJens Wiklander * software without specific prior written permission.
190c81fcd6SJens Wiklander *
200c81fcd6SJens Wiklander * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
210c81fcd6SJens Wiklander * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
220c81fcd6SJens Wiklander * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
230c81fcd6SJens Wiklander * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
240c81fcd6SJens Wiklander * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
250c81fcd6SJens Wiklander * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
260c81fcd6SJens Wiklander * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
270c81fcd6SJens Wiklander * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
280c81fcd6SJens Wiklander * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
290c81fcd6SJens Wiklander * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
300c81fcd6SJens Wiklander * POSSIBILITY OF SUCH DAMAGE.
310c81fcd6SJens Wiklander */
320c81fcd6SJens Wiklander/* This is a simple version of setjmp and longjmp.
330c81fcd6SJens Wiklander
340c81fcd6SJens Wiklander   Nick Clifton, Cygnus Solutions, 13 June 1997.  */
350c81fcd6SJens Wiklander
360c81fcd6SJens Wiklander/* ANSI concatenation macros.  */
370c81fcd6SJens Wiklander#define CONCAT(a, b)  CONCAT2(a, b)
380c81fcd6SJens Wiklander#define CONCAT2(a, b) a##b
390c81fcd6SJens Wiklander
400c81fcd6SJens Wiklander#ifndef __USER_LABEL_PREFIX__
410c81fcd6SJens Wiklander#error  __USER_LABEL_PREFIX__ not defined
420c81fcd6SJens Wiklander#endif
430c81fcd6SJens Wiklander
440c81fcd6SJens Wiklander#define SYM(x) CONCAT (__USER_LABEL_PREFIX__, x)
450c81fcd6SJens Wiklander
460c81fcd6SJens Wiklander#ifdef __ELF__
470c81fcd6SJens Wiklander#define TYPE(x) .type SYM(x),function
480c81fcd6SJens Wiklander#define SIZE(x) .size SYM(x), . - SYM(x)
490c81fcd6SJens Wiklander#else
500c81fcd6SJens Wiklander#define TYPE(x)
510c81fcd6SJens Wiklander#define SIZE(x)
520c81fcd6SJens Wiklander#endif
530c81fcd6SJens Wiklander
54d9925536SJerome Forissier	.section .note.GNU-stack,"",%progbits
55d9925536SJerome Forissier
560c81fcd6SJens Wiklander/* Arm/Thumb interworking support:
570c81fcd6SJens Wiklander
580c81fcd6SJens Wiklander   The interworking scheme expects functions to use a BX instruction
590c81fcd6SJens Wiklander   to return control to their parent.  Since we need this code to work
600c81fcd6SJens Wiklander   in both interworked and non-interworked environments as well as with
610c81fcd6SJens Wiklander   older processors which do not have the BX instruction we do the
620c81fcd6SJens Wiklander   following:
630c81fcd6SJens Wiklander	Test the return address.
640c81fcd6SJens Wiklander	If the bottom bit is clear perform an "old style" function exit.
650c81fcd6SJens Wiklander	(We know that we are in ARM mode and returning to an ARM mode caller).
660c81fcd6SJens Wiklander	Otherwise use the BX instruction to perform the function exit.
670c81fcd6SJens Wiklander
680c81fcd6SJens Wiklander   We know that we will never attempt to perform the BX instruction on
690c81fcd6SJens Wiklander   an older processor, because that kind of processor will never be
700c81fcd6SJens Wiklander   interworked, and a return address with the bottom bit set will never
710c81fcd6SJens Wiklander   be generated.
720c81fcd6SJens Wiklander
730c81fcd6SJens Wiklander   In addition, we do not actually assemble the BX instruction as this would
740c81fcd6SJens Wiklander   require us to tell the assembler that the processor is an ARM7TDMI and
750c81fcd6SJens Wiklander   it would store this information in the binary.  We want this binary to be
760c81fcd6SJens Wiklander   able to be linked with binaries compiled for older processors however, so
770c81fcd6SJens Wiklander   we do not want such information stored there.
780c81fcd6SJens Wiklander
790c81fcd6SJens Wiklander   If we are running using the APCS-26 convention however, then we never
800c81fcd6SJens Wiklander   test the bottom bit, because this is part of the processor status.
810c81fcd6SJens Wiklander   Instead we just do a normal return, since we know that we cannot be
820c81fcd6SJens Wiklander   returning to a Thumb caller - the Thumb does not support APCS-26.
830c81fcd6SJens Wiklander
840c81fcd6SJens Wiklander   Function entry is much simpler.  If we are compiling for the Thumb we
850c81fcd6SJens Wiklander   just switch into ARM mode and then drop through into the rest of the
860c81fcd6SJens Wiklander   function.  The function exit code will take care of the restore to
870c81fcd6SJens Wiklander   Thumb mode.
880c81fcd6SJens Wiklander
890c81fcd6SJens Wiklander   For Thumb-2 do everything in Thumb mode.  */
900c81fcd6SJens Wiklander
910c81fcd6SJens Wiklander#if defined(__ARM_ARCH_6M__)
920c81fcd6SJens Wiklander/* ARMv6-M has to be implemented in Thumb mode.  */
930c81fcd6SJens Wiklander
940c81fcd6SJens Wiklander.thumb
950c81fcd6SJens Wiklander.thumb_func
960c81fcd6SJens Wiklander	.globl SYM (setjmp)
970c81fcd6SJens Wiklander	TYPE (setjmp)
980c81fcd6SJens WiklanderSYM (setjmp):
990c81fcd6SJens Wiklander	/* Save registers in jump buffer.  */
1000c81fcd6SJens Wiklander	stmia	r0!, {r4, r5, r6, r7}
1010c81fcd6SJens Wiklander	mov	r1, r8
1020c81fcd6SJens Wiklander	mov	r2, r9
1030c81fcd6SJens Wiklander	mov	r3, r10
1040c81fcd6SJens Wiklander	mov	r4, fp
1050c81fcd6SJens Wiklander	mov	r5, sp
1060c81fcd6SJens Wiklander	mov	r6, lr
1070c81fcd6SJens Wiklander	stmia	r0!, {r1, r2, r3, r4, r5, r6}
1080c81fcd6SJens Wiklander	sub	r0, r0, #40
1090c81fcd6SJens Wiklander	/* Restore callee-saved low regs.  */
1100c81fcd6SJens Wiklander	ldmia	r0!, {r4, r5, r6, r7}
1110c81fcd6SJens Wiklander	/* Return zero.  */
1120c81fcd6SJens Wiklander	mov	r0, #0
1130c81fcd6SJens Wiklander	bx lr
1140c81fcd6SJens Wiklander
1150c81fcd6SJens Wiklander.thumb_func
1160c81fcd6SJens Wiklander	.globl SYM (longjmp)
1170c81fcd6SJens Wiklander	TYPE (longjmp)
1180c81fcd6SJens WiklanderSYM (longjmp):
1190c81fcd6SJens Wiklander	/* Restore High regs.  */
1200c81fcd6SJens Wiklander	add	r0, r0, #16
1210c81fcd6SJens Wiklander	ldmia	r0!, {r2, r3, r4, r5, r6}
1220c81fcd6SJens Wiklander	mov	r8, r2
1230c81fcd6SJens Wiklander	mov	r9, r3
1240c81fcd6SJens Wiklander	mov	r10, r4
1250c81fcd6SJens Wiklander	mov	fp, r5
1260c81fcd6SJens Wiklander	mov	sp, r6
1270c81fcd6SJens Wiklander	ldmia	r0!, {r3} /* lr */
1280c81fcd6SJens Wiklander	/* Restore low regs.  */
1290c81fcd6SJens Wiklander	sub	r0, r0, #40
1300c81fcd6SJens Wiklander	ldmia	r0!, {r4, r5, r6, r7}
1310c81fcd6SJens Wiklander	/* Return the result argument, or 1 if it is zero.  */
1320c81fcd6SJens Wiklander	mov	r0, r1
1330c81fcd6SJens Wiklander	bne	1f
1340c81fcd6SJens Wiklander	mov	r0, #1
1350c81fcd6SJens Wiklander1:
1360c81fcd6SJens Wiklander	bx	r3
1370c81fcd6SJens Wiklander
1380c81fcd6SJens Wiklander#else
1390c81fcd6SJens Wiklander
1400c81fcd6SJens Wiklander#ifdef __APCS_26__
1410c81fcd6SJens Wiklander#define RET	movs		pc, lr
1420c81fcd6SJens Wiklander#elif defined(__thumb2__)
1430c81fcd6SJens Wiklander#define RET	bx lr
1440c81fcd6SJens Wiklander#else
1450c81fcd6SJens Wiklander#define RET	tst		lr, #1; \
1460c81fcd6SJens Wiklander	        moveq		pc, lr ; \
1470c81fcd6SJens Wiklander.word           0xe12fff1e	/* bx lr */
1480c81fcd6SJens Wiklander#endif
1490c81fcd6SJens Wiklander
1500c81fcd6SJens Wiklander#ifdef __thumb2__
1510c81fcd6SJens Wiklander.macro COND where when
1520c81fcd6SJens Wiklander	i\where	\when
1530c81fcd6SJens Wiklander.endm
1540c81fcd6SJens Wiklander#else
1550c81fcd6SJens Wiklander.macro COND where when
1560c81fcd6SJens Wiklander.endm
1570c81fcd6SJens Wiklander#endif
1580c81fcd6SJens Wiklander
1590c81fcd6SJens Wiklander#if defined(__thumb2__)
1600c81fcd6SJens Wiklander.syntax unified
1610c81fcd6SJens Wiklander.macro MODE
1620c81fcd6SJens Wiklander	.thumb
1630c81fcd6SJens Wiklander	.thumb_func
1640c81fcd6SJens Wiklander.endm
1650c81fcd6SJens Wiklander.macro PROLOGUE name
1660c81fcd6SJens Wiklander.endm
1670c81fcd6SJens Wiklander
1680c81fcd6SJens Wiklander#elif defined(__thumb__)
1690c81fcd6SJens Wiklander#define	MODE		.thumb_func
1700c81fcd6SJens Wiklander.macro PROLOGUE name
1710c81fcd6SJens Wiklander	.code 16
1720c81fcd6SJens Wiklander	bx	pc
1730c81fcd6SJens Wiklander	nop
1740c81fcd6SJens Wiklander	.code 32
1750c81fcd6SJens WiklanderSYM (.arm_start_of.\name):
1760c81fcd6SJens Wiklander.endm
1770c81fcd6SJens Wiklander#else /* Arm */
1780c81fcd6SJens Wiklander#define	MODE		.code 32
1790c81fcd6SJens Wiklander.macro PROLOGUE name
1800c81fcd6SJens Wiklander.endm
1810c81fcd6SJens Wiklander#endif
1820c81fcd6SJens Wiklander
1830c81fcd6SJens Wiklander.macro FUNC_START name
1840c81fcd6SJens Wiklander	.text
1850c81fcd6SJens Wiklander	.align 2
1860c81fcd6SJens Wiklander	MODE
1870c81fcd6SJens Wiklander	.globl SYM (\name)
1880c81fcd6SJens Wiklander	TYPE (\name)
1890c81fcd6SJens WiklanderSYM (\name):
1900c81fcd6SJens Wiklander	PROLOGUE \name
1910c81fcd6SJens Wiklander.endm
1920c81fcd6SJens Wiklander
1930c81fcd6SJens Wiklander.macro FUNC_END name
1940c81fcd6SJens Wiklander	RET
1950c81fcd6SJens Wiklander	SIZE (\name)
1960c81fcd6SJens Wiklander.endm
1970c81fcd6SJens Wiklander
1980c81fcd6SJens Wiklander/* --------------------------------------------------------------------
1990c81fcd6SJens Wiklander                 int setjmp (jmp_buf);
2000c81fcd6SJens Wiklander   -------------------------------------------------------------------- */
2010c81fcd6SJens Wiklander
2020c81fcd6SJens Wiklander	FUNC_START setjmp
2030c81fcd6SJens Wiklander
2040c81fcd6SJens Wiklander	/* Save all the callee-preserved registers into the jump buffer.  */
2050c81fcd6SJens Wiklander#ifdef __thumb2__
2060c81fcd6SJens Wiklander	mov		ip, sp
2070c81fcd6SJens Wiklander	stmea		a1!, { v1-v7, fp, ip, lr }
2080c81fcd6SJens Wiklander#else
2099de8272eSJerome Forissier	stmea		a1!, { v1-v7, fp, ip}
2109de8272eSJerome Forissier	str 		sp, [a1], #4
2119de8272eSJerome Forissier	str 		lr, [a1], #4
2120c81fcd6SJens Wiklander#endif
2130c81fcd6SJens Wiklander
2140c81fcd6SJens Wiklander#if 0	/* Simulator does not cope with FP instructions yet.  */
2150c81fcd6SJens Wiklander#ifndef __SOFTFP__
2160c81fcd6SJens Wiklander	/* Save the floating point registers.  */
2170c81fcd6SJens Wiklander	sfmea		f4, 4, [a1]
2180c81fcd6SJens Wiklander#endif
2190c81fcd6SJens Wiklander#endif
220c96d7091SSumit Garg
221099918f6SSumit Garg#ifdef CFG_FTRACE_SUPPORT
222c96d7091SSumit Garg	stmdb		sp!, { lr }
223c96d7091SSumit Garg	/*
224c96d7091SSumit Garg	 * As ftrace is supported in ARM mode only, so hardcode jmp_buf
225c96d7091SSumit Garg	 * offset used to save ftrace return index.
226c96d7091SSumit Garg	 */
227c96d7091SSumit Garg	add		a1, a1, #48
228c96d7091SSumit Garg	bl		ftrace_setjmp
229c96d7091SSumit Garg	ldmia		sp!, { lr }
230c96d7091SSumit Garg#endif
231c96d7091SSumit Garg
2320c81fcd6SJens Wiklander	/* When setting up the jump buffer return 0.  */
2330c81fcd6SJens Wiklander	mov		a1, #0
2340c81fcd6SJens Wiklander
2350c81fcd6SJens Wiklander	FUNC_END setjmp
2360c81fcd6SJens Wiklander
2370c81fcd6SJens Wiklander/* --------------------------------------------------------------------
2380c81fcd6SJens Wiklander		volatile void longjmp (jmp_buf, int);
2390c81fcd6SJens Wiklander   -------------------------------------------------------------------- */
2400c81fcd6SJens Wiklander
2410c81fcd6SJens Wiklander	FUNC_START longjmp
2420c81fcd6SJens Wiklander
2430c81fcd6SJens Wiklander	/* If we have stack extension code it ought to be handled here.  */
2440c81fcd6SJens Wiklander
245099918f6SSumit Garg#ifdef CFG_FTRACE_SUPPORT
246c96d7091SSumit Garg	stmdb		sp!, { a1, a2, lr }
247c96d7091SSumit Garg	/*
248c96d7091SSumit Garg	 * As ftrace is supported in ARM mode only, so hardcode jmp_buf
249c96d7091SSumit Garg	 * offset used to restore ftrace return stack.
250c96d7091SSumit Garg	 */
251c96d7091SSumit Garg	add		a1, a1, #92
252c96d7091SSumit Garg	bl		ftrace_longjmp
253c96d7091SSumit Garg	ldmia		sp!, { a1, a2, lr }
254c96d7091SSumit Garg#endif
255*7749dda2SAleksandr Iashchenko#if defined(__KERNEL__) && defined(CFG_CORE_SANITIZE_KADDRESS) && \
256*7749dda2SAleksandr Iashchenko    !defined(CFG_DYN_CONFIG)
257*7749dda2SAleksandr Iashchenko	stmdb		sp!, { a1, a2, a3, lr }
258*7749dda2SAleksandr Iashchenko
259*7749dda2SAleksandr Iashchenko#ifdef __thumb2__
260*7749dda2SAleksandr Iashchenko	ldr		a1, [a1, #32]
261*7749dda2SAleksandr Iashchenko#else
262*7749dda2SAleksandr Iashchenko	ldr		a1, [a1, #36]
263*7749dda2SAleksandr Iashchenko#endif
264*7749dda2SAleksandr Iashchenko	bl		asan_handle_longjmp
265*7749dda2SAleksandr Iashchenko	ldmia		sp!, { a1, a2, a3, lr }
266*7749dda2SAleksandr Iashchenko#endif
267c96d7091SSumit Garg
2680c81fcd6SJens Wiklander	/* Restore the registers, retrieving the state when setjmp() was called.  */
2690c81fcd6SJens Wiklander#ifdef __thumb2__
2700c81fcd6SJens Wiklander	ldmfd		a1!, { v1-v7, fp, ip, lr }
2710c81fcd6SJens Wiklander	mov		sp, ip
2720c81fcd6SJens Wiklander#else
2739de8272eSJerome Forissier	ldmfd		a1!, { v1-v7, fp, ip }
2749de8272eSJerome Forissier	ldr		sp, [a1], #4
2759de8272eSJerome Forissier	ldr 		lr, [a1], #4
2760c81fcd6SJens Wiklander#endif
2770c81fcd6SJens Wiklander
2780c81fcd6SJens Wiklander#if 0	/* Simulator does not cope with FP instructions yet.  */
2790c81fcd6SJens Wiklander#ifndef __SOFTFP__
2800c81fcd6SJens Wiklander	/* Restore floating point registers as well.  */
2810c81fcd6SJens Wiklander	lfmfd		f4, 4, [a1]
2820c81fcd6SJens Wiklander#endif
2830c81fcd6SJens Wiklander#endif
2840c81fcd6SJens Wiklander	/* Put the return value into the integer result register.
2850c81fcd6SJens Wiklander	   But if it is zero then return 1 instead.  */
2860c81fcd6SJens Wiklander	movs		a1, a2
2870c81fcd6SJens Wiklander#ifdef __thumb2__
2880c81fcd6SJens Wiklander	it		eq
2890c81fcd6SJens Wiklander#endif
2900c81fcd6SJens Wiklander	moveq		a1, #1
2910c81fcd6SJens Wiklander
2920c81fcd6SJens Wiklander	FUNC_END longjmp
2930c81fcd6SJens Wiklander#endif
294