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/* ANSI concatenation macros.  */
37#define CONCAT(a, b)  CONCAT2(a, b)
38#define CONCAT2(a, b) a##b
39
40#ifndef __USER_LABEL_PREFIX__
41#error  __USER_LABEL_PREFIX__ not defined
42#endif
43
44#define SYM(x) CONCAT (__USER_LABEL_PREFIX__, x)
45
46#ifdef __ELF__
47#define TYPE(x) .type SYM(x),function
48#define SIZE(x) .size SYM(x), . - SYM(x)
49#else
50#define TYPE(x)
51#define SIZE(x)
52#endif
53
54/* Arm/Thumb interworking support:
55
56   The interworking scheme expects functions to use a BX instruction
57   to return control to their parent.  Since we need this code to work
58   in both interworked and non-interworked environments as well as with
59   older processors which do not have the BX instruction we do the
60   following:
61	Test the return address.
62	If the bottom bit is clear perform an "old style" function exit.
63	(We know that we are in ARM mode and returning to an ARM mode caller).
64	Otherwise use the BX instruction to perform the function exit.
65
66   We know that we will never attempt to perform the BX instruction on
67   an older processor, because that kind of processor will never be
68   interworked, and a return address with the bottom bit set will never
69   be generated.
70
71   In addition, we do not actually assemble the BX instruction as this would
72   require us to tell the assembler that the processor is an ARM7TDMI and
73   it would store this information in the binary.  We want this binary to be
74   able to be linked with binaries compiled for older processors however, so
75   we do not want such information stored there.
76
77   If we are running using the APCS-26 convention however, then we never
78   test the bottom bit, because this is part of the processor status.
79   Instead we just do a normal return, since we know that we cannot be
80   returning to a Thumb caller - the Thumb does not support APCS-26.
81
82   Function entry is much simpler.  If we are compiling for the Thumb we
83   just switch into ARM mode and then drop through into the rest of the
84   function.  The function exit code will take care of the restore to
85   Thumb mode.
86
87   For Thumb-2 do everything in Thumb mode.  */
88
89#if defined(__ARM_ARCH_6M__)
90/* ARMv6-M has to be implemented in Thumb mode.  */
91
92.thumb
93.thumb_func
94	.globl SYM (setjmp)
95	TYPE (setjmp)
96SYM (setjmp):
97	/* Save registers in jump buffer.  */
98	stmia	r0!, {r4, r5, r6, r7}
99	mov	r1, r8
100	mov	r2, r9
101	mov	r3, r10
102	mov	r4, fp
103	mov	r5, sp
104	mov	r6, lr
105	stmia	r0!, {r1, r2, r3, r4, r5, r6}
106	sub	r0, r0, #40
107	/* Restore callee-saved low regs.  */
108	ldmia	r0!, {r4, r5, r6, r7}
109	/* Return zero.  */
110	mov	r0, #0
111	bx lr
112
113.thumb_func
114	.globl SYM (longjmp)
115	TYPE (longjmp)
116SYM (longjmp):
117	/* Restore High regs.  */
118	add	r0, r0, #16
119	ldmia	r0!, {r2, r3, r4, r5, r6}
120	mov	r8, r2
121	mov	r9, r3
122	mov	r10, r4
123	mov	fp, r5
124	mov	sp, r6
125	ldmia	r0!, {r3} /* lr */
126	/* Restore low regs.  */
127	sub	r0, r0, #40
128	ldmia	r0!, {r4, r5, r6, r7}
129	/* Return the result argument, or 1 if it is zero.  */
130	mov	r0, r1
131	bne	1f
132	mov	r0, #1
1331:
134	bx	r3
135
136#else
137
138#ifdef __APCS_26__
139#define RET	movs		pc, lr
140#elif defined(__thumb2__)
141#define RET	bx lr
142#else
143#define RET	tst		lr, #1; \
144	        moveq		pc, lr ; \
145.word           0xe12fff1e	/* bx lr */
146#endif
147
148#ifdef __thumb2__
149.macro COND where when
150	i\where	\when
151.endm
152#else
153.macro COND where when
154.endm
155#endif
156
157#if defined(__thumb2__)
158.syntax unified
159.macro MODE
160	.thumb
161	.thumb_func
162.endm
163.macro PROLOGUE name
164.endm
165
166#elif defined(__thumb__)
167#define	MODE		.thumb_func
168.macro PROLOGUE name
169	.code 16
170	bx	pc
171	nop
172	.code 32
173SYM (.arm_start_of.\name):
174.endm
175#else /* Arm */
176#define	MODE		.code 32
177.macro PROLOGUE name
178.endm
179#endif
180
181.macro FUNC_START name
182	.text
183	.align 2
184	MODE
185	.globl SYM (\name)
186	TYPE (\name)
187SYM (\name):
188	PROLOGUE \name
189.endm
190
191.macro FUNC_END name
192	RET
193	SIZE (\name)
194.endm
195
196/* --------------------------------------------------------------------
197                 int setjmp (jmp_buf);
198   -------------------------------------------------------------------- */
199
200	FUNC_START setjmp
201
202	/* Save all the callee-preserved registers into the jump buffer.  */
203#ifdef __thumb2__
204	mov		ip, sp
205	stmea		a1!, { v1-v7, fp, ip, lr }
206#else
207	stmea		a1!, { v1-v7, fp, ip}
208	str 		sp, [a1], #4
209	str 		lr, [a1], #4
210#endif
211
212#if 0	/* Simulator does not cope with FP instructions yet.  */
213#ifndef __SOFTFP__
214	/* Save the floating point registers.  */
215	sfmea		f4, 4, [a1]
216#endif
217#endif
218
219#ifdef CFG_FTRACE_SUPPORT
220	stmdb		sp!, { lr }
221	/*
222	 * As ftrace is supported in ARM mode only, so hardcode jmp_buf
223	 * offset used to save ftrace return index.
224	 */
225	add		a1, a1, #48
226	bl		ftrace_setjmp
227	ldmia		sp!, { lr }
228#endif
229
230	/* When setting up the jump buffer return 0.  */
231	mov		a1, #0
232
233	FUNC_END setjmp
234
235/* --------------------------------------------------------------------
236		volatile void longjmp (jmp_buf, int);
237   -------------------------------------------------------------------- */
238
239	FUNC_START longjmp
240
241	/* If we have stack extension code it ought to be handled here.  */
242
243#ifdef CFG_FTRACE_SUPPORT
244	stmdb		sp!, { a1, a2, lr }
245	/*
246	 * As ftrace is supported in ARM mode only, so hardcode jmp_buf
247	 * offset used to restore ftrace return stack.
248	 */
249	add		a1, a1, #92
250	bl		ftrace_longjmp
251	ldmia		sp!, { a1, a2, lr }
252#endif
253
254	/* Restore the registers, retrieving the state when setjmp() was called.  */
255#ifdef __thumb2__
256	ldmfd		a1!, { v1-v7, fp, ip, lr }
257	mov		sp, ip
258#else
259	ldmfd		a1!, { v1-v7, fp, ip }
260	ldr		sp, [a1], #4
261	ldr 		lr, [a1], #4
262#endif
263
264#if 0	/* Simulator does not cope with FP instructions yet.  */
265#ifndef __SOFTFP__
266	/* Restore floating point registers as well.  */
267	lfmfd		f4, 4, [a1]
268#endif
269#endif
270	/* Put the return value into the integer result register.
271	   But if it is zero then return 1 instead.  */
272	movs		a1, a2
273#ifdef __thumb2__
274	it		eq
275#endif
276	moveq		a1, #1
277
278	FUNC_END longjmp
279#endif
280