1/* Save current context and jump to a new context.
2   Copyright (C) 2005-2022 Free Software Foundation, Inc.
3   This file is part of the GNU C Library.
4
5   The GNU C Library is free software; you can redistribute it and/or
6   modify it under the terms of the GNU Lesser General Public
7   License as published by the Free Software Foundation; either
8   version 2.1 of the License, or (at your option) any later version.
9
10   The GNU C Library is distributed in the hope that it will be useful,
11   but WITHOUT ANY WARRANTY; without even the implied warranty of
12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13   Lesser General Public License for more details.
14
15   You should have received a copy of the GNU Lesser General Public
16   License along with the GNU C Library; if not, see
17   <https://www.gnu.org/licenses/>.  */
18
19/* This is the common implementation of setcontext for powerpc32.
20   It not complete in itself should be included in to a framework that
21   defines:
22     __CONTEXT_FUNC_NAME
23   and if appropriate:
24     __CONTEXT_ENABLE_FPRS
25     __CONTEXT_ENABLE_VRS
26   Any architecture that implements the Vector unit is assumed to also
27   implement the floating unit.  */
28
29/* Stack frame offsets.  */
30#define _FRAME_BACKCHAIN	0
31#define _FRAME_LR_SAVE		4
32#define _FRAME_PARM_SAVE1	8
33#define _FRAME_PARM_SAVE2	12
34#define _FRAME_PARM_SAVE3	16
35#define _FRAME_PARM_SAVE4	20
36
37#ifdef __CONTEXT_ENABLE_VRS
38	.machine	"altivec"
39#endif
40ENTRY(__CONTEXT_FUNC_NAME)
41	stwu	r1,-16(r1)
42	cfi_adjust_cfa_offset (16)
43/* Insure that the _UC_REGS start on a quadword boundary.  */
44	stw	r3,_FRAME_PARM_SAVE1(r1)
45	addi	r3,r3,_UC_REG_SPACE+12
46	stw	r4,_FRAME_PARM_SAVE2(r1)	/* new context pointer */
47	clrrwi  r3,r3,4
48
49/* Save the general purpose registers */
50	stw	r0,_UC_GREGS+(PT_R0*4)(r3)
51	mflr	r0
52	stw	r2,_UC_GREGS+(PT_R2*4)(r3)
53	stw	r4,_UC_GREGS+(PT_R4*4)(r3)
54/* Set the callers LR_SAVE, and the ucontext LR and NIP to the callers
55   return address.  */
56	stw	r0,_UC_GREGS+(PT_LNK*4)(r3)
57	stw	r0,_UC_GREGS+(PT_NIP*4)(r3)
58	stw	r0,_FRAME_LR_SAVE+16(r1)
59	cfi_offset (lr, _FRAME_LR_SAVE)
60	stw	r5,_UC_GREGS+(PT_R5*4)(r3)
61	stw	r6,_UC_GREGS+(PT_R6*4)(r3)
62	stw	r7,_UC_GREGS+(PT_R7*4)(r3)
63	stw	r8,_UC_GREGS+(PT_R8*4)(r3)
64	stw	r9,_UC_GREGS+(PT_R9*4)(r3)
65	stw	r10,_UC_GREGS+(PT_R10*4)(r3)
66	stw	r11,_UC_GREGS+(PT_R11*4)(r3)
67	stw	r12,_UC_GREGS+(PT_R12*4)(r3)
68	stw	r13,_UC_GREGS+(PT_R13*4)(r3)
69	stw	r14,_UC_GREGS+(PT_R14*4)(r3)
70	stw	r15,_UC_GREGS+(PT_R15*4)(r3)
71	stw	r16,_UC_GREGS+(PT_R16*4)(r3)
72	stw	r17,_UC_GREGS+(PT_R17*4)(r3)
73	stw	r18,_UC_GREGS+(PT_R18*4)(r3)
74	stw	r19,_UC_GREGS+(PT_R19*4)(r3)
75	stw	r20,_UC_GREGS+(PT_R20*4)(r3)
76	stw	r21,_UC_GREGS+(PT_R21*4)(r3)
77	stw	r22,_UC_GREGS+(PT_R22*4)(r3)
78	stw	r23,_UC_GREGS+(PT_R23*4)(r3)
79	stw	r24,_UC_GREGS+(PT_R24*4)(r3)
80	stw	r25,_UC_GREGS+(PT_R25*4)(r3)
81	stw	r26,_UC_GREGS+(PT_R26*4)(r3)
82	stw	r27,_UC_GREGS+(PT_R27*4)(r3)
83	stw	r28,_UC_GREGS+(PT_R28*4)(r3)
84	stw	r29,_UC_GREGS+(PT_R29*4)(r3)
85	stw	r30,_UC_GREGS+(PT_R30*4)(r3)
86	stw	r31,_UC_GREGS+(PT_R31*4)(r3)
87
88/* Save the value of R1.  We had to push the stack before we
89   had the address of uc_reg_space.  So compute the address of
90   the callers stack pointer and save it as R1.  */
91	addi	r8,r1,16
92	li	r0,0
93/* Save the count, exception and condition registers.  */
94	mfctr	r11
95	mfxer	r10
96	mfcr	r9
97	stw	r8,_UC_GREGS+(PT_R1*4)(r3)
98	stw	r11,_UC_GREGS+(PT_CTR*4)(r3)
99	stw	r10,_UC_GREGS+(PT_XER*4)(r3)
100	stw	r9,_UC_GREGS+(PT_CCR*4)(r3)
101/* Set the return value of getcontext to "success".  R3 is the only
102   register whose value is not preserved in the saved context.  */
103	stw	r0,_UC_GREGS+(PT_R3*4)(r3)
104
105	/* Zero fill fields that can't be set in user state. */
106	stw	r0,_UC_GREGS+(PT_MSR*4)(r3)
107	stw	r0,_UC_GREGS+(PT_MQ*4)(r3)
108
109#ifdef __CONTEXT_ENABLE_FPRS
110	/* Save the floating-point registers */
111	stfd	fp0,_UC_FREGS+(0*8)(r3)
112	stfd	fp1,_UC_FREGS+(1*8)(r3)
113	stfd	fp2,_UC_FREGS+(2*8)(r3)
114	stfd	fp3,_UC_FREGS+(3*8)(r3)
115	stfd	fp4,_UC_FREGS+(4*8)(r3)
116	stfd	fp5,_UC_FREGS+(5*8)(r3)
117	stfd	fp6,_UC_FREGS+(6*8)(r3)
118	stfd	fp7,_UC_FREGS+(7*8)(r3)
119	stfd	fp8,_UC_FREGS+(8*8)(r3)
120	stfd	fp9,_UC_FREGS+(9*8)(r3)
121	stfd	fp10,_UC_FREGS+(10*8)(r3)
122	stfd	fp11,_UC_FREGS+(11*8)(r3)
123	stfd	fp12,_UC_FREGS+(12*8)(r3)
124	stfd	fp13,_UC_FREGS+(13*8)(r3)
125	stfd	fp14,_UC_FREGS+(14*8)(r3)
126	stfd	fp15,_UC_FREGS+(15*8)(r3)
127	stfd	fp16,_UC_FREGS+(16*8)(r3)
128	stfd	fp17,_UC_FREGS+(17*8)(r3)
129	stfd	fp18,_UC_FREGS+(18*8)(r3)
130	stfd	fp19,_UC_FREGS+(19*8)(r3)
131	stfd	fp20,_UC_FREGS+(20*8)(r3)
132	stfd	fp21,_UC_FREGS+(21*8)(r3)
133	stfd	fp22,_UC_FREGS+(22*8)(r3)
134	stfd	fp23,_UC_FREGS+(23*8)(r3)
135	stfd	fp24,_UC_FREGS+(24*8)(r3)
136	stfd	fp25,_UC_FREGS+(25*8)(r3)
137	stfd	fp26,_UC_FREGS+(26*8)(r3)
138	stfd	fp27,_UC_FREGS+(27*8)(r3)
139	stfd	fp28,_UC_FREGS+(28*8)(r3)
140	stfd	fp29,_UC_FREGS+(29*8)(r3)
141	mffs	fp0
142	stfd	fp30,_UC_FREGS+(30*8)(r3)
143	stfd	fp31,_UC_FREGS+(31*8)(r3)
144	stfd	fp0,_UC_FREGS+(32*8)(r3)
145
146# ifdef PIC
147	mflr    r8
148#  define got_label GENERATE_GOT_LABEL (__CONTEXT_FUNC_NAME)
149	SETUP_GOT_ACCESS(r7,got_label)
150	addis	r7,r7,_GLOBAL_OFFSET_TABLE_-got_label@ha
151	addi	r7,r7,_GLOBAL_OFFSET_TABLE_-got_label@l
152#  ifdef SHARED
153	lwz     r7,_rtld_global_ro@got(r7)
154	mtlr    r8
155	lwz     r7,RTLD_GLOBAL_RO_DL_HWCAP_OFFSET+LOWORD(r7)
156#  else
157	lwz     r7,_dl_hwcap@got(r7)
158	mtlr    r8
159	lwz     r7,LOWORD(r7)
160#  endif
161# else
162	lis	r7,(_dl_hwcap+LOWORD)@ha
163	lwz     r7,(_dl_hwcap+LOWORD)@l(r7)
164# endif
165
166# ifdef __CONTEXT_ENABLE_VRS
167	andis.	r6,r7,(PPC_FEATURE_HAS_ALTIVEC >> 16)
168
169	la	r10,(_UC_VREGS)(r3)
170	la	r9,(_UC_VREGS+16)(r3)
171
172/*	beq	L(no_vec)*/
173	beq	2f
174/* address of the combined VSCR/VSAVE quadword.  */
175	la	r8,(_UC_VREGS+512)(r3)
176
177/* Save the vector registers */
178	stvx  v0,0,r10
179	stvx  v1,0,r9
180	addi  r10,r10,32
181	addi  r9,r9,32
182/* We need to get the Vector Status and Control Register early to avoid
183   store order problems later with the VSAVE register that shares the
184   same quadword.  */
185	mfvscr	v0
186
187	stvx  v2,0,r10
188	stvx  v3,0,r9
189	addi  r10,r10,32
190	addi  r9,r9,32
191
192	stvx	v0,0,r8
193
194	stvx  v4,0,r10
195	stvx  v5,0,r9
196	addi  r10,r10,32
197	addi  r9,r9,32
198
199	stvx  v6,0,r10
200	stvx  v7,0,r9
201	addi  r10,r10,32
202	addi  r9,r9,32
203
204	stvx  v8,0,r10
205	stvx  v9,0,r9
206	addi  r10,r10,32
207	addi  r9,r9,32
208
209	stvx  v10,0,r10
210	stvx  v11,0,r9
211	addi  r10,r10,32
212	addi  r9,r9,32
213
214	stvx  v12,0,r10
215	stvx  v13,0,r9
216	addi  r10,r10,32
217	addi  r9,r9,32
218
219	stvx  v14,0,r10
220	stvx  v15,0,r9
221	addi  r10,r10,32
222	addi  r9,r9,32
223
224	stvx  v16,0,r10
225	stvx  v17,0,r9
226	addi  r10,r10,32
227	addi  r9,r9,32
228
229	stvx  v18,0,r10
230	stvx  v19,0,r9
231	addi  r10,r10,32
232	addi  r9,r9,32
233
234	stvx  v20,0,r10
235	stvx  v21,0,r9
236	addi  r10,r10,32
237	addi  r9,r9,32
238
239	stvx  v22,0,r10
240	stvx  v23,0,r9
241	addi  r10,r10,32
242	addi  r9,r9,32
243
244	stvx  v24,0,r10
245	stvx  v25,0,r9
246	addi  r10,r10,32
247	addi  r9,r9,32
248
249	stvx  v26,0,r10
250	stvx  v27,0,r9
251	addi  r10,r10,32
252	addi  r9,r9,32
253
254	stvx  v28,0,r10
255	stvx  v29,0,r9
256	addi  r10,r10,32
257	addi  r9,r9,32
258
259	mfvscr	v0
260	stvx  v30,0,r10
261	stvx  v31,0,r9
262 	stw	r0,0(r8)
263
2642: /*L(no_vec):*/
265# endif /* __CONTEXT_ENABLE_VRS */
266#endif /* __CONTEXT_ENABLE_FPRS */
267
268/* Restore ucontext (parm1) from stack.  */
269	lwz	r12,_FRAME_PARM_SAVE1(r1)
270	lwz	r4,_FRAME_PARM_SAVE2(r1)
271	addi	r4,r4,_UC_SIGMASK
272	stw	r3,_UC_REGS_PTR(r12)
273	addi	r5,r12,_UC_SIGMASK
274	li	r3,SIG_SETMASK
275	bl	__sigprocmask@local
276	cmpwi	r3,0
277	bne	3f	/* L(error_exit) */
278
279	lwz	r4,_FRAME_PARM_SAVE2(r1)
280	lwz	r31,_UC_REGS_PTR(r4)
281
282#ifdef __CONTEXT_ENABLE_FPRS
283# ifdef __CONTEXT_ENABLE_VRS
284
285#  ifdef PIC
286	mflr    r8
287	SETUP_GOT_ACCESS(r7,got_label)
288	addis	r7,r7,_GLOBAL_OFFSET_TABLE_-got_label@ha
289	addi	r7,r7,_GLOBAL_OFFSET_TABLE_-got_label@l
290	mtlr    r8
291#   ifdef SHARED
292	lwz     r7,_rtld_global_ro@got(r7)
293	lwz     r7,RTLD_GLOBAL_RO_DL_HWCAP_OFFSET+LOWORD(r7)
294#   else
295	lwz     r7,_dl_hwcap@got(r7)
296	lwz     r7,LOWORD(r7)
297#   endif
298#  else
299	lis	r7,(_dl_hwcap+LOWORD)@ha
300	lwz     r7,(_dl_hwcap+LOWORD)@l(r7)
301#  endif
302	andis.	r7,r7,(PPC_FEATURE_HAS_ALTIVEC >> 16)
303	la	r10,(_UC_VREGS)(r31)
304	beq	6f	/* L(has_no_vec) */
305
306	lwz   r0,(32*16)(r10)
307	li    r9,(32*16)
308	cmpwi r0,0
309	mtspr VRSAVE,r0
310	beq	6f	/* L(has_no_vec) */
311
312	lvx   v19,r9,r10
313	la    r9,(16)(r10)
314
315	lvx   v0,0,r10
316	lvx   v1,0,r9
317	addi  r10,r10,32
318	addi  r9,r9,32
319
320	mtvscr  v19
321	lvx   v2,0,r10
322	lvx   v3,0,r9
323	addi  r10,r10,32
324	addi  r9,r9,32
325
326	lvx   v4,0,r10
327	lvx   v5,0,r9
328	addi  r10,r10,32
329	addi  r9,r9,32
330
331	lvx   v6,0,r10
332	lvx   v7,0,r9
333	addi  r10,r10,32
334	addi  r9,r9,32
335
336	lvx   v8,0,r10
337	lvx   v9,0,r9
338	addi  r10,r10,32
339	addi  r9,r9,32
340
341	lvx   v10,0,r10
342	lvx   v11,0,r9
343	addi  r10,r10,32
344	addi  r9,r9,32
345
346	lvx   v12,0,r10
347	lvx   v13,0,r9
348	addi  r10,r10,32
349	addi  r9,r9,32
350
351	lvx   v14,0,r10
352	lvx   v15,0,r9
353	addi  r10,r10,32
354	addi  r9,r9,32
355
356	lvx   v16,0,r10
357	lvx   v17,0,r9
358	addi  r10,r10,32
359	addi  r9,r9,32
360
361	lvx   v18,0,r10
362	lvx   v19,0,r9
363	addi  r10,r10,32
364	addi  r9,r9,32
365
366	lvx   v20,0,r10
367	lvx   v21,0,r9
368	addi  r10,r10,32
369	addi  r9,r9,32
370
371	lvx   v22,0,r10
372	lvx   v23,0,r9
373	addi  r10,r10,32
374	addi  r9,r9,32
375
376	lvx   v24,0,r10
377	lvx   v25,0,r9
378	addi  r10,r10,32
379	addi  r9,r9,32
380
381	lvx   v26,0,r10
382	lvx   v27,0,r9
383	addi  r10,r10,32
384	addi  r9,r9,32
385
386	lvx   v28,0,r10
387	lvx   v29,0,r9
388	addi  r10,r10,32
389	addi  r9,r9,32
390
391	lvx   v30,0,r10
392	lvx   v31,0,r9
393	addi  r10,r10,32
394	addi  r9,r9,32
395
396	lvx   v10,0,r10
397	lvx   v11,0,r9
398
3996: /* L(has_no_vec): */
400# endif /* __CONTEXT_ENABLE_VRS */
401	/* Restore the floating-point registers */
402	lfd	fp31,_UC_FREGS+(32*8)(r31)
403	lfd	fp0,_UC_FREGS+(0*8)(r31)
404# ifdef _ARCH_PWR6
405	/* Use the extended four-operand version of the mtfsf insn.  */
406	mtfsf	0xff,fp31,1,0
407# else
408	.machine push
409	.machine "power6"
410	/* Availability of DFP indicates a 64-bit FPSCR.  */
411	andi.	r6,r7,PPC_FEATURE_HAS_DFP
412	beq	7f
413	/* Use the extended four-operand version of the mtfsf insn.  */
414	mtfsf	0xff,fp31,1,0
415	b	8f
416	/* Continue to operate on the FPSCR as if it were 32-bits.  */
4177:	mtfsf	0xff,fp31
4188:	.machine pop
419#endif /* _ARCH_PWR6 */
420	lfd	fp1,_UC_FREGS+(1*8)(r31)
421	lfd	fp2,_UC_FREGS+(2*8)(r31)
422	lfd	fp3,_UC_FREGS+(3*8)(r31)
423	lfd	fp4,_UC_FREGS+(4*8)(r31)
424	lfd	fp5,_UC_FREGS+(5*8)(r31)
425	lfd	fp6,_UC_FREGS+(6*8)(r31)
426	lfd	fp7,_UC_FREGS+(7*8)(r31)
427	lfd	fp8,_UC_FREGS+(8*8)(r31)
428	lfd	fp9,_UC_FREGS+(9*8)(r31)
429	lfd	fp10,_UC_FREGS+(10*8)(r31)
430	lfd	fp11,_UC_FREGS+(11*8)(r31)
431	lfd	fp12,_UC_FREGS+(12*8)(r31)
432	lfd	fp13,_UC_FREGS+(13*8)(r31)
433	lfd	fp14,_UC_FREGS+(14*8)(r31)
434	lfd	fp15,_UC_FREGS+(15*8)(r31)
435	lfd	fp16,_UC_FREGS+(16*8)(r31)
436	lfd	fp17,_UC_FREGS+(17*8)(r31)
437	lfd	fp18,_UC_FREGS+(18*8)(r31)
438	lfd	fp19,_UC_FREGS+(19*8)(r31)
439	lfd	fp20,_UC_FREGS+(20*8)(r31)
440	lfd	fp21,_UC_FREGS+(21*8)(r31)
441	lfd	fp22,_UC_FREGS+(22*8)(r31)
442	lfd	fp23,_UC_FREGS+(23*8)(r31)
443	lfd	fp24,_UC_FREGS+(24*8)(r31)
444	lfd	fp25,_UC_FREGS+(25*8)(r31)
445	lfd	fp26,_UC_FREGS+(26*8)(r31)
446	lfd	fp27,_UC_FREGS+(27*8)(r31)
447	lfd	fp28,_UC_FREGS+(28*8)(r31)
448	lfd	fp29,_UC_FREGS+(29*8)(r31)
449	lfd	fp30,_UC_FREGS+(30*8)(r31)
450	lfd	fp31,_UC_FREGS+(31*8)(r31)
451#endif /* __CONTEXT_ENABLE_FPRS */
452
453	/* Restore LR and CCR, and set CTR to the NIP value */
454	lwz	r3,_UC_GREGS+(PT_LNK*4)(r31)
455	lwz	r4,_UC_GREGS+(PT_NIP*4)(r31)
456	lwz	r5,_UC_GREGS+(PT_CCR*4)(r31)
457	mtlr	r3
458	mtctr	r4
459	mtcr	r5
460
461	/* Restore the general registers */
462	lwz	r3,_UC_GREGS+(PT_R3*4)(r31)
463	lwz	r4,_UC_GREGS+(PT_R4*4)(r31)
464	lwz	r5,_UC_GREGS+(PT_R5*4)(r31)
465	lwz	r6,_UC_GREGS+(PT_R6*4)(r31)
466	lwz	r7,_UC_GREGS+(PT_R7*4)(r31)
467	lwz	r8,_UC_GREGS+(PT_R8*4)(r31)
468	lwz	r9,_UC_GREGS+(PT_R9*4)(r31)
469	lwz	r10,_UC_GREGS+(PT_R10*4)(r31)
470	lwz	r11,_UC_GREGS+(PT_R11*4)(r31)
471	lwz	r12,_UC_GREGS+(PT_R12*4)(r31)
472	lwz	r13,_UC_GREGS+(PT_R13*4)(r31)
473	lwz	r14,_UC_GREGS+(PT_R14*4)(r31)
474	lwz	r15,_UC_GREGS+(PT_R15*4)(r31)
475	lwz	r16,_UC_GREGS+(PT_R16*4)(r31)
476	lwz	r17,_UC_GREGS+(PT_R17*4)(r31)
477	lwz	r18,_UC_GREGS+(PT_R18*4)(r31)
478	lwz	r19,_UC_GREGS+(PT_R19*4)(r31)
479	lwz	r20,_UC_GREGS+(PT_R20*4)(r31)
480	lwz	r21,_UC_GREGS+(PT_R21*4)(r31)
481	lwz	r22,_UC_GREGS+(PT_R22*4)(r31)
482	lwz	r23,_UC_GREGS+(PT_R23*4)(r31)
483	lwz	r24,_UC_GREGS+(PT_R24*4)(r31)
484	lwz	r25,_UC_GREGS+(PT_R25*4)(r31)
485	lwz	r26,_UC_GREGS+(PT_R26*4)(r31)
486	lwz	r27,_UC_GREGS+(PT_R27*4)(r31)
487	lwz	r28,_UC_GREGS+(PT_R28*4)(r31)
488	lwz	r29,_UC_GREGS+(PT_R29*4)(r31)
489	lwz	r30,_UC_GREGS+(PT_R30*4)(r31)
490	lwz	r1,_UC_GREGS+(PT_R1*4)(r31)
491	lwz	r31,_UC_GREGS+(PT_R31*4)(r31)
492
493	bctr
494
4953:/*L(error_exit):*/
496	lwz	r0,_FRAME_LR_SAVE+16(r1)
497	addi	r1,r1,16
498	mtlr	r0
499	blr
500
501END(__CONTEXT_FUNC_NAME)
502