1/*
2Copyright (c) 1990 The Regents of the University of California.
3All rights reserved.
4
5Redistribution and use in source and binary forms are permitted
6provided that the above copyright notice and this paragraph are
7duplicated in all such forms and that any documentation,
8and/or other materials related to such
9distribution and use acknowledge that the software was developed
10by the University of California, Berkeley.  The name of the
11University may not be used to endorse or promote products derived
12from this software without specific prior written permission.
13THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16 */
17/* This is a simple version of setjmp and longjmp for the PowerPC.
18   Ian Lance Taylor, Cygnus Support, 9 Feb 1994.
19   Modified by Jeff Johnston, Red Hat Inc. 2 Oct 2001.
20   Modified by Sebastian Huber, embedded brains GmbH. 22 Sep 2022.  */
21
22#include "ppc-asm.h"
23
24FUNC_START(setjmp)
25#ifdef __ALTIVEC__
26	addi	3,3,15		# align Altivec to 16 byte boundary
27#if __powerpc64__
28	clrrdi	3,3,4
29#else
30	rlwinm	3,3,0,0,27
31#endif
32#else
33	addi	3,3,7		# align to 8 byte boundary
34#if __powerpc64__
35	clrrdi	3,3,3
36#else
37	rlwinm	3,3,0,0,28
38#endif
39#endif
40#if __SPE__
41	/* If we are E500, then save 64-bit registers.  */
42	evstdd	1,0(3)		# offset 0
43	evstdd	2,8(3)		# offset 8
44	evstdd	13,16(3)	# offset 16
45	evstdd	14,24(3)	# offset 24
46	evstdd	15,32(3)	# offset 32
47	evstdd	16,40(3)	# offset 40
48	evstdd	17,48(3)	# offset 48
49	evstdd	18,56(3)	# offset 56
50	evstdd	19,64(3)	# offset 64
51	evstdd	20,72(3)	# offset 72
52	evstdd	21,80(3)	# offset 80
53	evstdd	22,88(3)	# offset 88
54	evstdd	23,96(3)	# offset 96
55	evstdd	24,104(3)	# offset 104
56	evstdd	25,112(3)	# offset 112
57	evstdd	26,120(3)	# offset 120
58	evstdd	27,128(3)	# offset 128
59	evstdd	28,136(3)	# offset 136
60	evstdd	29,144(3)	# offset 144
61	evstdd	30,152(3)	# offset 152
62	evstdd	31,160(3)	# offset 160
63
64	/* Add 164 to r3 to account for the amount of data we just
65	   stored.  Note that we are not adding 168 because the next
66	   store instruction uses an offset of 4.  */
67	addi	3,3,164
68#elif __powerpc64__
69	/* In the first store, add 8 to r3 so that the subsequent floating
70	   point stores are aligned on an 8 byte boundary and the Altivec
71	   stores are aligned on a 16 byte boundary.  */
72	stdu	1,8(3)		# offset 8
73	stdu	2,8(3)		# offset 16
74	stdu	13,8(3)		# offset 24
75	stdu	14,8(3)		# offset 32
76	stdu	15,8(3)		# offset 40
77	stdu	16,8(3)		# offset 48
78	stdu	17,8(3)		# offset 56
79	stdu	18,8(3)		# offset 64
80	stdu	19,8(3)		# offset 72
81	stdu	20,8(3)		# offset 80
82	stdu	21,8(3)		# offset 88
83	stdu	22,8(3)		# offset 96
84	stdu	23,8(3)		# offset 104
85	stdu	24,8(3)		# offset 112
86	stdu	25,8(3)		# offset 120
87	stdu	26,8(3)		# offset 128
88	stdu	27,8(3)		# offset 136
89	stdu	28,8(3)		# offset 144
90	stdu	29,8(3)		# offset 152
91	stdu	30,8(3)		# offset 160
92	stdu	31,8(3)		# offset 168
93	mflr	4
94	stdu	4,8(3)		# offset 176
95	mfcr	4
96	stwu	4,8(3)		# offset 184
97#else
98	stw	1,0(3)		# offset 0
99	stwu	2,4(3)		# offset 4
100	stwu	13,4(3)		# offset 8
101	stwu	14,4(3)		# offset 12
102	stwu	15,4(3)		# offset 16
103	stwu	16,4(3)		# offset 20
104	stwu	17,4(3)		# offset 24
105	stwu	18,4(3)		# offset 28
106	stwu	19,4(3)		# offset 32
107	stwu	20,4(3)		# offset 36
108	stwu	21,4(3)		# offset 40
109	stwu	22,4(3)		# offset 44
110	stwu	23,4(3)		# offset 48
111	stwu	24,4(3)		# offset 52
112	stwu	25,4(3)		# offset 56
113	stwu	26,4(3)		# offset 60
114	stwu	27,4(3)		# offset 64
115	stwu	28,4(3)		# offset 68
116	stwu	29,4(3)		# offset 72
117	stwu	30,4(3)		# offset 76
118	stwu	31,4(3)		# offset 80
119#endif
120
121#if !__powerpc64__
122	/* If __SPE__, then add 84 to the offset shown from this point on until
123	   the end of this function.  This difference comes from the fact that
124	   we save 21 64-bit registers instead of 21 32-bit registers above.  */
125	mflr	4
126	stwu	4,4(3)		# offset 84
127	mfcr	4
128	stwu	4,4(3)		# offset 88
129				# one word pad to get floating point aligned on 8 byte boundary
130#endif
131
132	/* Check whether we need to save FPRs.  Checking __NO_FPRS__
133	   on its own would be enough for GCC 4.1 and above, but older
134	   compilers only define _SOFT_FLOAT, so check both.  */
135#if !defined (__NO_FPRS__) && !defined (_SOFT_FLOAT)
136#if defined (__rtems__) && !defined (__PPC_CPU_E6500__)
137	/* For some RTEMS multilibs, the FPU and Altivec units are disabled
138	   during interrupt handling.  Do not save and restore the
139	   corresponding registers in this case.  */
140	mfmsr	5
141	andi.	5,5,0x2000
142	beq	1f
143#endif
144
145	/* If __powerpc64__, then add 96 to the offset shown from this point on until
146	   the end of this function.  This difference comes from the fact that
147	   we save 23 64-bit registers instead of 23 32-bit registers above and
148	   we take alignement requirements of floating point and Altivec stores
149	   into account.  */
150
151	stfdu	14,8(3)		# offset 96
152	stfdu	15,8(3)		# offset 104
153	stfdu	16,8(3)		# offset 112
154	stfdu	17,8(3)		# offset 120
155	stfdu	18,8(3)		# offset 128
156	stfdu	19,8(3)		# offset 136
157	stfdu	20,8(3)		# offset 144
158	stfdu	21,8(3)		# offset 152
159	stfdu	22,8(3)		# offset 160
160	stfdu	23,8(3)		# offset 168
161	stfdu	24,8(3)		# offset 176
162	stfdu	25,8(3)		# offset 184
163	stfdu	26,8(3)		# offset 192
164	stfdu	27,8(3)		# offset 200
165	stfdu	28,8(3)		# offset 208
166	stfdu	29,8(3)		# offset 216
167	stfdu	30,8(3)		# offset 224
168	stfdu	31,8(3)		# offset 232
1691:
170#endif
171
172	/* This requires a total of 21 * 4 + 18 * 8 + 4 + 4 + 4
173	   bytes == 60 * 4 bytes == 240 bytes.  */
174
175#ifdef __ALTIVEC__
176#if defined (__rtems__) && !defined (__PPC_CPU_E6500__)
177	mfmsr	5
178	andis.	5,5,0x200
179	beq	1f
180#endif
181	/* save Altivec vrsave and vr20-vr31 registers */
182	mfspr	4,256		# vrsave register
183	stwu	4,16(3)		# offset 248
184	addi	3,3,8
185	stvx	20,0,3		# offset 256
186	addi	3,3,16
187	stvx	21,0,3		# offset 272
188	addi	3,3,16
189	stvx	22,0,3		# offset 288
190	addi	3,3,16
191	stvx	23,0,3		# offset 304
192	addi	3,3,16
193	stvx	24,0,3		# offset 320
194	addi	3,3,16
195	stvx	25,0,3		# offset 336
196	addi	3,3,16
197	stvx	26,0,3		# offset 352
198	addi	3,3,16
199	stvx	27,0,3		# offset 368
200	addi	3,3,16
201	stvx	28,0,3		# offset 384
202	addi	3,3,16
203	stvx	29,0,3		# offset 400
204	addi	3,3,16
205	stvx	30,0,3		# offset 416
206	addi	3,3,16
207	stvx	31,0,3		# offset 432
2081:
209
210	/* This requires a total of 240 + 8 + 8 + 12 * 16 == 448 bytes. */
211#endif
212	li	3,0
213	blr
214FUNC_END(setjmp)
215
216
217FUNC_START(longjmp)
218#ifdef __ALTIVEC__
219	addi	3,3,15		# align Altivec to 16 byte boundary
220#if __powerpc64__
221	clrrdi	3,3,4
222#else
223	rlwinm	3,3,0,0,27
224#endif
225#else
226	addi	3,3,7		# align to 8 byte boundary
227#if __powerpc64__
228	clrrdi	3,3,3
229#else
230	rlwinm	3,3,0,0,28
231#endif
232#endif
233#if __SPE__
234	/* If we are E500, then restore 64-bit registers.  */
235	evldd	1,0(3)		# offset 0
236	evldd	2,8(3)		# offset 8
237	evldd	13,16(3)	# offset 16
238	evldd	14,24(3)	# offset 24
239	evldd	15,32(3)	# offset 32
240	evldd	16,40(3)	# offset 40
241	evldd	17,48(3)	# offset 48
242	evldd	18,56(3)	# offset 56
243	evldd	19,64(3)	# offset 64
244	evldd	20,72(3)	# offset 72
245	evldd	21,80(3)	# offset 80
246	evldd	22,88(3)	# offset 88
247	evldd	23,96(3)	# offset 96
248	evldd	24,104(3)	# offset 104
249	evldd	25,112(3)	# offset 112
250	evldd	26,120(3)	# offset 120
251	evldd	27,128(3)	# offset 128
252	evldd	28,136(3)	# offset 136
253	evldd	29,144(3)	# offset 144
254	evldd	30,152(3)	# offset 152
255	evldd	31,160(3)	# offset 160
256
257	/* Add 164 to r3 to account for the amount of data we just
258	   loaded.  Note that we are not adding 168 because the next
259	   load instruction uses an offset of 4.  */
260	addi	3,3,164
261#elif __powerpc64__
262	/* In the first load, add 8 to r3 so that the subsequent floating
263	   point loades are aligned on an 8 byte boundary and the Altivec
264	   loads are aligned on a 16 byte boundary.  */
265	ldu	1,8(3)		# offset 8
266	ldu	2,8(3)		# offset 16
267	ldu	13,8(3)		# offset 24
268	ldu	14,8(3)		# offset 32
269	ldu	15,8(3)		# offset 40
270	ldu	16,8(3)		# offset 48
271	ldu	17,8(3)		# offset 56
272	ldu	18,8(3)		# offset 64
273	ldu	19,8(3)		# offset 72
274	ldu	20,8(3)		# offset 80
275	ldu	21,8(3)		# offset 88
276	ldu	22,8(3)		# offset 96
277	ldu	23,8(3)		# offset 104
278	ldu	24,8(3)		# offset 112
279	ldu	25,8(3)		# offset 120
280	ldu	26,8(3)		# offset 128
281	ldu	27,8(3)		# offset 136
282	ldu	28,8(3)		# offset 144
283	ldu	29,8(3)		# offset 152
284	ldu	30,8(3)		# offset 160
285	ldu	31,8(3)		# offset 168
286	ldu	5,8(3)		# offset 176
287	mtlr	5
288	lwzu	5,8(3)		# offset 184
289	mtcrf	255,5
290#else
291	lwz	1,0(3)		# offset 0
292	lwzu	2,4(3)		# offset 4
293	lwzu	13,4(3)		# offset 8
294	lwzu	14,4(3)		# offset 12
295	lwzu	15,4(3)		# offset 16
296	lwzu	16,4(3)		# offset 20
297	lwzu	17,4(3)		# offset 24
298	lwzu	18,4(3)		# offset 28
299	lwzu	19,4(3)		# offset 32
300	lwzu	20,4(3)		# offset 36
301	lwzu	21,4(3)		# offset 40
302	lwzu	22,4(3)		# offset 44
303	lwzu	23,4(3)		# offset 48
304	lwzu	24,4(3)		# offset 52
305	lwzu	25,4(3)		# offset 56
306	lwzu	26,4(3)		# offset 60
307	lwzu	27,4(3)		# offset 64
308	lwzu	28,4(3)		# offset 68
309	lwzu	29,4(3)		# offset 72
310	lwzu	30,4(3)		# offset 76
311	lwzu	31,4(3)		# offset 80
312#endif
313	/* If __SPE__, then add 84 to the offset shown from this point on until
314	   the end of this function.  This difference comes from the fact that
315	   we restore 22 64-bit registers instead of 22 32-bit registers above.  */
316
317#if !__powerpc64__
318	lwzu	5,4(3)		# offset 84
319	mtlr	5
320	lwzu	5,4(3)		# offset 88
321	mtcrf	255,5
322				# one word pad to get floating point aligned on 8 byte boundary
323#endif
324
325	/* Check whether we need to restore FPRs.  Checking
326	   __NO_FPRS__ on its own would be enough for GCC 4.1 and
327	   above, but older compilers only define _SOFT_FLOAT, so
328	   check both.  */
329#if !defined (__NO_FPRS__) && !defined (_SOFT_FLOAT)
330#if defined (__rtems__) && !defined (__PPC_CPU_E6500__)
331	mfmsr	5
332	andi.	5,5,0x2000
333	beq	1f
334#endif
335
336	/* If __powerpc64__, then add 96 to the offset shown from this point on until
337	   the end of this function.  This difference comes from the fact that
338	   we restore 23 64-bit registers instead of 23 32-bit registers above and
339	   we take alignement requirements of floating point and Altivec loads
340	   into account.  */
341
342	lfdu	14,8(3)         # offset 96
343	lfdu	15,8(3)         # offset 104
344	lfdu	16,8(3)         # offset 112
345	lfdu	17,8(3)         # offset 120
346	lfdu	18,8(3)         # offset 128
347	lfdu	19,8(3)         # offset 136
348	lfdu	20,8(3)         # offset 144
349	lfdu	21,8(3)         # offset 152
350	lfdu	22,8(3)         # offset 160
351	lfdu	23,8(3)         # offset 168
352	lfdu	24,8(3)         # offset 176
353	lfdu	25,8(3)         # offset 184
354	lfdu	26,8(3)         # offset 192
355	lfdu	27,8(3)         # offset 200
356	lfdu	28,8(3)         # offset 208
357	lfdu	29,8(3)         # offset 216
358	lfdu	30,8(3)         # offset 224
359	lfdu	31,8(3)         # offset 232
3601:
361#endif
362
363#ifdef __ALTIVEC__
364#if defined (__rtems__) && !defined (__PPC_CPU_E6500__)
365	mfmsr	5
366	andis.	5,5,0x200
367	beq	1f
368#endif
369	/* restore Altivec vrsave and v20-v31 registers */
370	lwzu	5,16(3)		# offset 248
371	mtspr	256,5		# vrsave
372	addi	3,3,8
373	lvx	20,0,3		# offset 256
374	addi	3,3,16
375	lvx	21,0,3		# offset 272
376	addi	3,3,16
377	lvx	22,0,3		# offset 288
378	addi	3,3,16
379	lvx	23,0,3		# offset 304
380	addi	3,3,16
381	lvx	24,0,3		# offset 320
382	addi	3,3,16
383	lvx	25,0,3		# offset 336
384	addi	3,3,16
385	lvx	26,0,3		# offset 352
386	addi	3,3,16
387	lvx	27,0,3		# offset 368
388	addi	3,3,16
389	lvx	28,0,3		# offset 384
390	addi	3,3,16
391	lvx	29,0,3		# offset 400
392	addi	3,3,16
393	lvx	30,0,3		# offset 416
394	addi	3,3,16
395	lvx	31,0,3		# offset 432
3961:
397#endif
398
399	mr.	3,4
400	bclr+	4,2
401	li	3,1
402	blr
403FUNC_END(longjmp)
404