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