1/* This is a simple version of setjmp and longjmp.
2
3   Nick Clifton, Cygnus Solutions, 13 June 1997.  */
4
5#include "acle-compat.h"
6
7/* ANSI concatenation macros.  */
8#define CONCAT(a, b)  CONCAT2(a, b)
9#define CONCAT2(a, b) a##b
10
11#ifndef __USER_LABEL_PREFIX__
12#error  __USER_LABEL_PREFIX__ not defined
13#endif
14
15#define SYM(x) CONCAT (__USER_LABEL_PREFIX__, x)
16
17#ifdef __ELF__
18#define TYPE(x) .type SYM(x),function
19#define SIZE(x) .size SYM(x), . - SYM(x)
20#else
21#define TYPE(x)
22#define SIZE(x)
23#endif
24
25/* Arm/Thumb interworking support:
26
27   The interworking scheme expects functions to use a BX instruction
28   to return control to their parent.  Since we need this code to work
29   in both interworked and non-interworked environments as well as with
30   older processors which do not have the BX instruction we do the
31   following:
32	Test the return address.
33	If the bottom bit is clear perform an "old style" function exit.
34	(We know that we are in ARM mode and returning to an ARM mode caller).
35	Otherwise use the BX instruction to perform the function exit.
36
37   We know that we will never attempt to perform the BX instruction on
38   an older processor, because that kind of processor will never be
39   interworked, and a return address with the bottom bit set will never
40   be generated.
41
42   In addition, we do not actually assemble the BX instruction as this would
43   require us to tell the assembler that the processor is an ARM7TDMI and
44   it would store this information in the binary.  We want this binary to be
45   able to be linked with binaries compiled for older processors however, so
46   we do not want such information stored there.
47
48   If we are running using the APCS-26 convention however, then we never
49   test the bottom bit, because this is part of the processor status.
50   Instead we just do a normal return, since we know that we cannot be
51   returning to a Thumb caller - the Thumb does not support APCS-26.
52
53   Function entry is much simpler.  If we are compiling for the Thumb we
54   just switch into ARM mode and then drop through into the rest of the
55   function.  The function exit code will take care of the restore to
56   Thumb mode.
57
58   For Thumb-2 do everything in Thumb mode.  */
59
60#if __ARM_ARCH_ISA_THUMB == 1 && !__ARM_ARCH_ISA_ARM
61/* ARMv6-M-like has to be implemented in Thumb mode.  */
62
63.thumb
64.thumb_func
65	.globl SYM (setjmp)
66	TYPE (setjmp)
67SYM (setjmp):
68	/* Save registers in jump buffer.  */
69	stmia	r0!, {r4, r5, r6, r7}
70	mov	r1, r8
71	mov	r2, r9
72	mov	r3, r10
73	mov	r4, fp
74	mov	r5, sp
75	mov	r6, lr
76	stmia	r0!, {r1, r2, r3, r4, r5, r6}
77	sub	r0, r0, #40
78	/* Restore callee-saved low regs.  */
79	ldmia	r0!, {r4, r5, r6, r7}
80	/* Return zero.  */
81	mov	r0, #0
82	bx lr
83
84.thumb_func
85	.globl SYM (longjmp)
86	TYPE (longjmp)
87SYM (longjmp):
88	/* Restore High regs.  */
89	add	r0, r0, #16
90	ldmia	r0!, {r2, r3, r4, r5, r6}
91	mov	r8, r2
92	mov	r9, r3
93	mov	r10, r4
94	mov	fp, r5
95	mov	sp, r6
96	ldmia	r0!, {r3} /* lr */
97	/* Restore low regs.  */
98	sub	r0, r0, #40
99	ldmia	r0!, {r4, r5, r6, r7}
100	/* Return the result argument, or 1 if it is zero.  */
101	mov	r0, r1
102	bne	1f
103	mov	r0, #1
1041:
105	bx	r3
106
107#else
108
109#ifdef __APCS_26__
110#define RET	movs		pc, lr
111#elif defined(__thumb2__)
112#define RET	bx lr
113#else
114#define RET	tst		lr, #1; \
115	        moveq		pc, lr ; \
116.word           0xe12fff1e	/* bx lr */
117#endif
118
119#ifdef __thumb2__
120.macro COND where when
121	i\where	\when
122.endm
123#else
124.macro COND where when
125.endm
126#endif
127
128#if defined(__thumb2__)
129.syntax unified
130.macro MODE
131	.thumb
132	.thumb_func
133.endm
134.macro PROLOGUE name
135.endm
136
137#elif defined(__thumb__)
138#define	MODE		.thumb_func
139.macro PROLOGUE name
140	.code 16
141	bx	pc
142	nop
143	.code 32
144SYM (.arm_start_of.\name):
145.endm
146#else /* Arm */
147#define	MODE		.code 32
148.macro PROLOGUE name
149.endm
150#endif
151
152.macro FUNC_START name
153	.text
154	.align 2
155	MODE
156	.globl SYM (\name)
157	TYPE (\name)
158SYM (\name):
159	PROLOGUE \name
160.endm
161
162.macro FUNC_END name
163	RET
164	SIZE (\name)
165.endm
166
167/* --------------------------------------------------------------------
168                 int setjmp (jmp_buf);
169   -------------------------------------------------------------------- */
170
171	FUNC_START setjmp
172
173	/* Save all the callee-preserved registers into the jump buffer.  */
174#ifdef __thumb2__
175	mov		ip, sp
176	stmea		a1!, { v1-v7, fp, ip, lr }
177#else
178	stmea		a1!, { v1-v7, fp, ip, sp, lr }
179#endif
180
181#if 0	/* Simulator does not cope with FP instructions yet.  */
182#ifndef __SOFTFP__
183	/* Save the floating point registers.  */
184	sfmea		f4, 4, [a1]
185#endif
186#endif
187	/* When setting up the jump buffer return 0.  */
188	mov		a1, #0
189
190	FUNC_END setjmp
191
192/* --------------------------------------------------------------------
193		volatile void longjmp (jmp_buf, int);
194   -------------------------------------------------------------------- */
195
196	FUNC_START longjmp
197
198	/* If we have stack extension code it ought to be handled here.  */
199
200	/* Restore the registers, retrieving the state when setjmp() was called.  */
201#ifdef __thumb2__
202	ldmfd		a1!, { v1-v7, fp, ip, lr }
203	mov		sp, ip
204#else
205	ldmfd		a1!, { v1-v7, fp, ip, sp, lr }
206#endif
207
208#if 0	/* Simulator does not cope with FP instructions yet.  */
209#ifndef __SOFTFP__
210	/* Restore floating point registers as well.  */
211	lfmfd		f4, 4, [a1]
212#endif
213#endif
214	/* Put the return value into the integer result register.
215	   But if it is zero then return 1 instead.  */
216	movs		a1, a2
217#ifdef __thumb2__
218	it		eq
219#endif
220	moveq		a1, #1
221
222	FUNC_END longjmp
223#endif
224