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