xref: /optee_os/lib/libutils/isoc/arch/arm/setjmp_a32.S (revision bc679ca5079e11f0f5a3cf1788fb2e5e4d861d14)
1/* SPDX-License-Identifier: BSD-3-Clause */
2/*
3 * Copyright (c) 1994-2009  Red Hat, Inc.
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright notice,
10 * this list of conditions and the following disclaimer.
11 *
12 * 2. Redistributions in binary form must reproduce the above copyright notice,
13 * this list of conditions and the following disclaimer in the documentation
14 * and/or other materials provided with the distribution.
15 *
16 * 3. Neither the name of the copyright holder nor the names of its
17 * contributors may be used to endorse or promote products derived from this
18 * software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
24 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
31 */
32/* This is a simple version of setjmp and longjmp.
33
34   Nick Clifton, Cygnus Solutions, 13 June 1997.  */
35
36#include <asan.h>
37
38/* ANSI concatenation macros.  */
39#define CONCAT(a, b)  CONCAT2(a, b)
40#define CONCAT2(a, b) a##b
41
42#ifndef __USER_LABEL_PREFIX__
43#error  __USER_LABEL_PREFIX__ not defined
44#endif
45
46#define SYM(x) CONCAT (__USER_LABEL_PREFIX__, x)
47
48#ifdef __ELF__
49#define TYPE(x) .type SYM(x),function
50#define SIZE(x) .size SYM(x), . - SYM(x)
51#else
52#define TYPE(x)
53#define SIZE(x)
54#endif
55
56	.section .note.GNU-stack,"",%progbits
57
58/* Arm/Thumb interworking support:
59
60   The interworking scheme expects functions to use a BX instruction
61   to return control to their parent.  Since we need this code to work
62   in both interworked and non-interworked environments as well as with
63   older processors which do not have the BX instruction we do the
64   following:
65	Test the return address.
66	If the bottom bit is clear perform an "old style" function exit.
67	(We know that we are in ARM mode and returning to an ARM mode caller).
68	Otherwise use the BX instruction to perform the function exit.
69
70   We know that we will never attempt to perform the BX instruction on
71   an older processor, because that kind of processor will never be
72   interworked, and a return address with the bottom bit set will never
73   be generated.
74
75   In addition, we do not actually assemble the BX instruction as this would
76   require us to tell the assembler that the processor is an ARM7TDMI and
77   it would store this information in the binary.  We want this binary to be
78   able to be linked with binaries compiled for older processors however, so
79   we do not want such information stored there.
80
81   If we are running using the APCS-26 convention however, then we never
82   test the bottom bit, because this is part of the processor status.
83   Instead we just do a normal return, since we know that we cannot be
84   returning to a Thumb caller - the Thumb does not support APCS-26.
85
86   Function entry is much simpler.  If we are compiling for the Thumb we
87   just switch into ARM mode and then drop through into the rest of the
88   function.  The function exit code will take care of the restore to
89   Thumb mode.
90
91   For Thumb-2 do everything in Thumb mode.  */
92
93#if defined(__ARM_ARCH_6M__)
94/* ARMv6-M has to be implemented in Thumb mode.  */
95
96.thumb
97.thumb_func
98	.globl SYM (setjmp)
99	TYPE (setjmp)
100SYM (setjmp):
101	/* Save registers in jump buffer.  */
102	stmia	r0!, {r4, r5, r6, r7}
103	mov	r1, r8
104	mov	r2, r9
105	mov	r3, r10
106	mov	r4, fp
107	mov	r5, sp
108	mov	r6, lr
109	stmia	r0!, {r1, r2, r3, r4, r5, r6}
110	sub	r0, r0, #40
111	/* Restore callee-saved low regs.  */
112	ldmia	r0!, {r4, r5, r6, r7}
113	/* Return zero.  */
114	mov	r0, #0
115	bx lr
116
117.thumb_func
118	.globl SYM (longjmp)
119	TYPE (longjmp)
120SYM (longjmp):
121	/* Restore High regs.  */
122	add	r0, r0, #16
123	ldmia	r0!, {r2, r3, r4, r5, r6}
124	mov	r8, r2
125	mov	r9, r3
126	mov	r10, r4
127	mov	fp, r5
128	mov	sp, r6
129	ldmia	r0!, {r3} /* lr */
130	/* Restore low regs.  */
131	sub	r0, r0, #40
132	ldmia	r0!, {r4, r5, r6, r7}
133	/* Return the result argument, or 1 if it is zero.  */
134	mov	r0, r1
135	bne	1f
136	mov	r0, #1
1371:
138	bx	r3
139
140#else
141
142#ifdef __APCS_26__
143#define RET	movs		pc, lr
144#elif defined(__thumb2__)
145#define RET	bx lr
146#else
147#define RET	tst		lr, #1; \
148	        moveq		pc, lr ; \
149.word           0xe12fff1e	/* bx lr */
150#endif
151
152#ifdef __thumb2__
153.macro COND where when
154	i\where	\when
155.endm
156#else
157.macro COND where when
158.endm
159#endif
160
161#if defined(__thumb2__)
162.syntax unified
163.macro MODE
164	.thumb
165	.thumb_func
166.endm
167.macro PROLOGUE name
168.endm
169
170#elif defined(__thumb__)
171#define	MODE		.thumb_func
172.macro PROLOGUE name
173	.code 16
174	bx	pc
175	nop
176	.code 32
177SYM (.arm_start_of.\name):
178.endm
179#else /* Arm */
180#define	MODE		.code 32
181.macro PROLOGUE name
182.endm
183#endif
184
185.macro FUNC_START name
186	.text
187	.align 2
188	MODE
189	.globl SYM (\name)
190	TYPE (\name)
191SYM (\name):
192	PROLOGUE \name
193.endm
194
195.macro FUNC_END name
196	RET
197	SIZE (\name)
198.endm
199
200/* --------------------------------------------------------------------
201                 int setjmp (jmp_buf);
202   -------------------------------------------------------------------- */
203
204	FUNC_START setjmp
205
206	/* Save all the callee-preserved registers into the jump buffer.  */
207#ifdef __thumb2__
208	mov		ip, sp
209	stmea		a1!, { v1-v7, fp, ip, lr }
210#else
211	stmea		a1!, { v1-v7, fp, ip}
212	str 		sp, [a1], #4
213	str 		lr, [a1], #4
214#endif
215
216#if 0	/* Simulator does not cope with FP instructions yet.  */
217#ifndef __SOFTFP__
218	/* Save the floating point registers.  */
219	sfmea		f4, 4, [a1]
220#endif
221#endif
222
223#ifdef CFG_FTRACE_SUPPORT
224	stmdb		sp!, { lr }
225	/*
226	 * As ftrace is supported in ARM mode only, so hardcode jmp_buf
227	 * offset used to save ftrace return index.
228	 */
229	add		a1, a1, #48
230	bl		ftrace_setjmp
231	ldmia		sp!, { lr }
232#endif
233
234	/* When setting up the jump buffer return 0.  */
235	mov		a1, #0
236
237	FUNC_END setjmp
238
239/* --------------------------------------------------------------------
240		volatile void longjmp (jmp_buf, int);
241   -------------------------------------------------------------------- */
242
243	FUNC_START longjmp
244
245	/* If we have stack extension code it ought to be handled here.  */
246
247#ifdef CFG_FTRACE_SUPPORT
248	stmdb		sp!, { a1, a2, lr }
249	/*
250	 * As ftrace is supported in ARM mode only, so hardcode jmp_buf
251	 * offset used to restore ftrace return stack.
252	 */
253	add		a1, a1, #92
254	bl		ftrace_longjmp
255	ldmia		sp!, { a1, a2, lr }
256#endif
257
258#if ASAN_IS_ENABLED && (!defined(__KERNEL__) || !defined(CFG_DYN_CONFIG))
259	stmdb		sp!, { a1, a2, a3, lr }
260
261#ifdef __thumb2__
262	ldr		a1, [a1, #32]
263#else
264	ldr		a1, [a1, #36]
265#endif
266	bl		asan_handle_longjmp
267	ldmia		sp!, { a1, a2, a3, lr }
268#endif
269
270	/* Restore the registers, retrieving the state when setjmp() was called.  */
271#ifdef __thumb2__
272	ldmfd		a1!, { v1-v7, fp, ip, lr }
273	mov		sp, ip
274#else
275	ldmfd		a1!, { v1-v7, fp, ip }
276	ldr		sp, [a1], #4
277	ldr 		lr, [a1], #4
278#endif
279
280#if 0	/* Simulator does not cope with FP instructions yet.  */
281#ifndef __SOFTFP__
282	/* Restore floating point registers as well.  */
283	lfmfd		f4, 4, [a1]
284#endif
285#endif
286	/* Put the return value into the integer result register.
287	   But if it is zero then return 1 instead.  */
288	movs		a1, a2
289#ifdef __thumb2__
290	it		eq
291#endif
292	moveq		a1, #1
293
294	FUNC_END longjmp
295#endif
296