1/* Switch to context.
2   Copyright (C) 2002-2021 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#include <sysdep.h>
20#include <rtld-global-offsets.h>
21#include <shlib-compat.h>
22
23#define __ASSEMBLY__
24#include <asm/ptrace.h>
25#include "ucontext_i.h"
26#include <asm/errno.h>
27
28	.section	".toc","aw"
29.LC__dl_hwcap:
30#ifdef SHARED
31	.tc _rtld_global_ro[TC],_rtld_global_ro
32#else
33	.tc _dl_hwcap[TC],_dl_hwcap
34#endif
35	.section ".text"
36
37#if SHLIB_COMPAT (libc, GLIBC_2_3, GLIBC_2_3_4)
38ENTRY(__novec_setcontext)
39	CALL_MCOUNT 1
40  mflr  r0
41  std   r31,-8(1)
42  cfi_offset(r31,-8)
43  std   r0,FRAME_LR_SAVE(r1)
44  cfi_offset (lr, FRAME_LR_SAVE)
45  stdu  r1,-128(r1)
46  cfi_adjust_cfa_offset (128)
47  mr    r31,r3
48
49  li    r5,0
50  addi  r4,r3,UCONTEXT_SIGMASK
51  li    r3,SIG_SETMASK
52  bl    JUMPTARGET(__sigprocmask)
53  nop
54  cmpdi r3,0
55  bne   L(nv_error_exit)
56
57# ifdef SHARED
58/* Load _rtld-global._dl_hwcap.  */
59  ld    r5,RTLD_GLOBAL_RO_DL_HWCAP_OFFSET(r5)
60# else
61  ld    r5,0(r5) /* Load extern _dl_hwcap.  */
62# endif
63
64  lfd  fp0,(SIGCONTEXT_FP_REGS+(32*8))(r31)
65  lfd  fp31,(SIGCONTEXT_FP_REGS+(PT_R31*8))(r31)
66  lfd  fp30,(SIGCONTEXT_FP_REGS+(PT_R30*8))(r31)
67
68# ifdef _ARCH_PWR6
69  /* Use the extended four-operand version of the mtfsf insn.  */
70  .machine push
71  .machine "power6"
72
73  mtfsf  0xff,fp0,1,0
74
75  .machine pop
76# else
77  /* Availability of DFP indicates a 64-bit FPSCR.  */
78  andi.  r6,r5,PPC_FEATURE_HAS_DFP
79  beq    5f
80  /* Use the extended four-operand version of the mtfsf insn.  */
81  .machine push
82  .machine "power6"
83
84  mtfsf  0xff,fp0,1,0
85
86  .machine pop
87
88  b      6f
89  /* Continue to operate on the FPSCR as if it were 32-bits.  */
905:
91  mtfsf  0xff,fp0
926:
93# endif /* _ARCH_PWR6 */
94
95  lfd  fp29,(SIGCONTEXT_FP_REGS+(PT_R29*8))(r31)
96  lfd  fp28,(SIGCONTEXT_FP_REGS+(PT_R28*8))(r31)
97  lfd  fp27,(SIGCONTEXT_FP_REGS+(PT_R27*8))(r31)
98  lfd  fp26,(SIGCONTEXT_FP_REGS+(PT_R26*8))(r31)
99  lfd  fp25,(SIGCONTEXT_FP_REGS+(PT_R25*8))(r31)
100  lfd  fp24,(SIGCONTEXT_FP_REGS+(PT_R24*8))(r31)
101  lfd  fp23,(SIGCONTEXT_FP_REGS+(PT_R23*8))(r31)
102  lfd  fp22,(SIGCONTEXT_FP_REGS+(PT_R22*8))(r31)
103  lfd  fp21,(SIGCONTEXT_FP_REGS+(PT_R21*8))(r31)
104  lfd  fp20,(SIGCONTEXT_FP_REGS+(PT_R20*8))(r31)
105  lfd  fp19,(SIGCONTEXT_FP_REGS+(PT_R19*8))(r31)
106  lfd  fp18,(SIGCONTEXT_FP_REGS+(PT_R18*8))(r31)
107  lfd  fp17,(SIGCONTEXT_FP_REGS+(PT_R17*8))(r31)
108  lfd  fp16,(SIGCONTEXT_FP_REGS+(PT_R16*8))(r31)
109  lfd  fp15,(SIGCONTEXT_FP_REGS+(PT_R15*8))(r31)
110  lfd  fp14,(SIGCONTEXT_FP_REGS+(PT_R14*8))(r31)
111  lfd  fp13,(SIGCONTEXT_FP_REGS+(PT_R13*8))(r31)
112  lfd  fp12,(SIGCONTEXT_FP_REGS+(PT_R12*8))(r31)
113  lfd  fp11,(SIGCONTEXT_FP_REGS+(PT_R11*8))(r31)
114  lfd  fp10,(SIGCONTEXT_FP_REGS+(PT_R10*8))(r31)
115  lfd  fp9,(SIGCONTEXT_FP_REGS+(PT_R9*8))(r31)
116  lfd  fp8,(SIGCONTEXT_FP_REGS+(PT_R8*8))(r31)
117  lfd  fp7,(SIGCONTEXT_FP_REGS+(PT_R7*8))(r31)
118  lfd  fp6,(SIGCONTEXT_FP_REGS+(PT_R6*8))(r31)
119  lfd  fp5,(SIGCONTEXT_FP_REGS+(PT_R5*8))(r31)
120  lfd  fp4,(SIGCONTEXT_FP_REGS+(PT_R4*8))(r31)
121  lfd  fp3,(SIGCONTEXT_FP_REGS+(PT_R3*8))(r31)
122  lfd  fp2,(SIGCONTEXT_FP_REGS+(PT_R2*8))(r31)
123  lfd  fp1,(SIGCONTEXT_FP_REGS+(PT_R1*8))(r31)
124  lfd  fp0,(SIGCONTEXT_FP_REGS+(PT_R0*8))(r31)
125
126  /* End FDE now, because the unwind info would be wrong while
127     we're reloading registers to switch to the new context.  */
128  cfi_endproc
129
130  ld   r0,(SIGCONTEXT_GP_REGS+(PT_LNK*8))(r31)
131  ld   r1,(SIGCONTEXT_GP_REGS+(PT_R1*8))(r31)
132  mtlr r0
133  ld   r2,(SIGCONTEXT_GP_REGS+(PT_R2*8))(r31)
134  ld   r0,(SIGCONTEXT_GP_REGS+(PT_XER*8))(r31)
135  ld   r3,(SIGCONTEXT_GP_REGS+(PT_R3*8))(r31)
136  mtxer r0
137  ld   r4,(SIGCONTEXT_GP_REGS+(PT_R4*8))(r31)
138  ld   r0,(SIGCONTEXT_GP_REGS+(PT_CCR*8))(r31)
139  ld   r5,(SIGCONTEXT_GP_REGS+(PT_R5*8))(r31)
140  mtcr r0
141  ld   r6,(SIGCONTEXT_GP_REGS+(PT_R6*8))(r31)
142  ld   r7,(SIGCONTEXT_GP_REGS+(PT_R7*8))(r31)
143  ld   r8,(SIGCONTEXT_GP_REGS+(PT_R8*8))(r31)
144  ld   r9,(SIGCONTEXT_GP_REGS+(PT_R9*8))(r31)
145  ld   r10,(SIGCONTEXT_GP_REGS+(PT_R10*8))(r31)
146  ld   r11,(SIGCONTEXT_GP_REGS+(PT_R11*8))(r31)
147  ld   r12,(SIGCONTEXT_GP_REGS+(PT_R12*8))(r31)
148  /* Don't reload the thread ID or TLS pointer (r13).  */
149  ld   r14,(SIGCONTEXT_GP_REGS+(PT_R14*8))(r31)
150  ld   r15,(SIGCONTEXT_GP_REGS+(PT_R15*8))(r31)
151  ld   r16,(SIGCONTEXT_GP_REGS+(PT_R16*8))(r31)
152  ld   r17,(SIGCONTEXT_GP_REGS+(PT_R17*8))(r31)
153  ld   r18,(SIGCONTEXT_GP_REGS+(PT_R18*8))(r31)
154  ld   r19,(SIGCONTEXT_GP_REGS+(PT_R19*8))(r31)
155  ld   r20,(SIGCONTEXT_GP_REGS+(PT_R20*8))(r31)
156  ld   r21,(SIGCONTEXT_GP_REGS+(PT_R21*8))(r31)
157  ld   r22,(SIGCONTEXT_GP_REGS+(PT_R22*8))(r31)
158  ld   r23,(SIGCONTEXT_GP_REGS+(PT_R23*8))(r31)
159  ld   r24,(SIGCONTEXT_GP_REGS+(PT_R24*8))(r31)
160  ld   r25,(SIGCONTEXT_GP_REGS+(PT_R25*8))(r31)
161  ld   r26,(SIGCONTEXT_GP_REGS+(PT_R26*8))(r31)
162  ld   r27,(SIGCONTEXT_GP_REGS+(PT_R27*8))(r31)
163  ld   r28,(SIGCONTEXT_GP_REGS+(PT_R28*8))(r31)
164  ld   r29,(SIGCONTEXT_GP_REGS+(PT_R29*8))(r31)
165  ld   r30,(SIGCONTEXT_GP_REGS+(PT_R30*8))(r31)
166
167  /* Now we branch to the "Next Instruction Pointer" from the saved
168     context.  With the powerpc64 instruction set there is no good way to
169     do this (from user state) without clobbering either the LR or CTR.
170     The makecontext and swapcontext functions depend on the callers
171     LR being preserved so we use the CTR.  */
172  ld   r0,(SIGCONTEXT_GP_REGS+(PT_NIP*8))(r31)
173  mtctr r0
174  ld   r0,(SIGCONTEXT_GP_REGS+(PT_R0*8))(r31)
175  ld   r31,(SIGCONTEXT_GP_REGS+(PT_R31*8))(r31)
176  bctr
177
178  /* Re-establish FDE for the rest of the actual setcontext routine.  */
179  cfi_startproc
180  cfi_offset (lr, FRAME_LR_SAVE)
181  cfi_adjust_cfa_offset (128)
182
183L(nv_error_exit):
184  ld   r0,128+FRAME_LR_SAVE(r1)
185  addi r1,r1,128
186  mtlr r0
187	ld   r31,-8(r1)
188  blr
189PSEUDO_END(__novec_setcontext)
190
191compat_symbol (libc, __novec_setcontext, setcontext, GLIBC_2_3)
192
193#endif
194
195	.section ".text"
196	.machine	"altivec"
197ENTRY(__setcontext)
198	CALL_MCOUNT 1
199  mflr  r0
200  std   r31,-8(1)
201  cfi_offset(r31,-8)
202  std   r0,FRAME_LR_SAVE(r1)
203  cfi_offset (lr, FRAME_LR_SAVE)
204  stdu  r1,-128(r1)
205  cfi_adjust_cfa_offset (128)
206  mr    r31,r3
207
208  li    r5,0
209  addi  r4,r3,UCONTEXT_SIGMASK
210  li    r3,SIG_SETMASK
211  bl    JUMPTARGET(__sigprocmask)
212  nop
213  cmpdi r3,0
214  bne   L(error_exit)
215
216  ld    r5,.LC__dl_hwcap@toc(r2)
217  ld    r10,(SIGCONTEXT_V_REGS_PTR)(r31)
218# ifdef SHARED
219/* Load _rtld-global._dl_hwcap.  */
220  ld    r5,RTLD_GLOBAL_RO_DL_HWCAP_OFFSET(r5)
221# else
222  ld    r5,0(r5) /* Load extern _dl_hwcap.  */
223# endif
224  andis.  r6,r5,(PPC_FEATURE_HAS_ALTIVEC >> 16)
225  beq   L(has_no_vec)
226
227  cmpdi r10,0
228  beq   L(has_no_vec)
229  lwz   r0,(33*16)(r10)
230
231  li    r9,(16*32)
232  mtspr VRSAVE,r0
233  cmpwi r0,0
234  beq   L(has_no_vec)
235
236  lvx   v19,r9,r10
237  la    r9,(16)(r10)
238
239  lvx   v0,0,r10
240  lvx   v1,0,r9
241  addi  r10,r10,32
242  addi  r9,r9,32
243
244  mtvscr  v19
245  lvx   v2,0,r10
246  lvx   v3,0,r9
247  addi  r10,r10,32
248  addi  r9,r9,32
249
250  lvx   v4,0,r10
251  lvx   v5,0,r9
252  addi  r10,r10,32
253  addi  r9,r9,32
254
255  lvx   v6,0,r10
256  lvx   v7,0,r9
257  addi  r10,r10,32
258  addi  r9,r9,32
259
260  lvx   v8,0,r10
261  lvx   v9,0,r9
262  addi  r10,r10,32
263  addi  r9,r9,32
264
265  lvx   v10,0,r10
266  lvx   v11,0,r9
267  addi  r10,r10,32
268  addi  r9,r9,32
269
270  lvx   v12,0,r10
271  lvx   v13,0,r9
272  addi  r10,r10,32
273  addi  r9,r9,32
274
275  lvx   v14,0,r10
276  lvx   v15,0,r9
277  addi  r10,r10,32
278  addi  r9,r9,32
279
280  lvx   v16,0,r10
281  lvx   v17,0,r9
282  addi  r10,r10,32
283  addi  r9,r9,32
284
285  lvx   v18,0,r10
286  lvx   v19,0,r9
287  addi  r10,r10,32
288  addi  r9,r9,32
289
290  lvx   v20,0,r10
291  lvx   v21,0,r9
292  addi  r10,r10,32
293  addi  r9,r9,32
294
295  lvx   v22,0,r10
296  lvx   v23,0,r9
297  addi  r10,r10,32
298  addi  r9,r9,32
299
300  lvx   v24,0,r10
301  lvx   v25,0,r9
302  addi  r10,r10,32
303  addi  r9,r9,32
304
305  lvx   v26,0,r10
306  lvx   v27,0,r9
307  addi  r10,r10,32
308  addi  r9,r9,32
309
310  lvx   v28,0,r10
311  lvx   v29,0,r9
312  addi  r10,r10,32
313  addi  r9,r9,32
314
315  lvx   v30,0,r10
316  lvx   v31,0,r9
317  addi  r10,r10,32
318  addi  r9,r9,32
319
320  lvx   v10,0,r10
321  lvx   v11,0,r9
322  addi  r10,r10,32
323  addi  r9,r9,32
324
325L(has_no_vec):
326  lfd  fp0,(SIGCONTEXT_FP_REGS+(32*8))(r31)
327  lfd  fp31,(SIGCONTEXT_FP_REGS+(PT_R31*8))(r31)
328  lfd  fp30,(SIGCONTEXT_FP_REGS+(PT_R30*8))(r31)
329
330# ifdef _ARCH_PWR6
331  /* Use the extended four-operand version of the mtfsf insn.  */
332  .machine push
333  .machine "power6"
334
335  mtfsf  0xff,fp0,1,0
336
337  .machine pop
338# else
339  /* Availability of DFP indicates a 64-bit FPSCR.  */
340  andi.  r6,r5,PPC_FEATURE_HAS_DFP
341  beq    7f
342  /* Use the extended four-operand version of the mtfsf insn.  */
343  .machine push
344  .machine "power6"
345
346  mtfsf  0xff,fp0,1,0
347
348  .machine pop
349
350  b      8f
351  /* Continue to operate on the FPSCR as if it were 32-bits.  */
3527:
353  mtfsf  0xff,fp0
3548:
355# endif /* _ARCH_PWR6 */
356
357  lfd  fp29,(SIGCONTEXT_FP_REGS+(PT_R29*8))(r31)
358  lfd  fp28,(SIGCONTEXT_FP_REGS+(PT_R28*8))(r31)
359  lfd  fp27,(SIGCONTEXT_FP_REGS+(PT_R27*8))(r31)
360  lfd  fp26,(SIGCONTEXT_FP_REGS+(PT_R26*8))(r31)
361  lfd  fp25,(SIGCONTEXT_FP_REGS+(PT_R25*8))(r31)
362  lfd  fp24,(SIGCONTEXT_FP_REGS+(PT_R24*8))(r31)
363  lfd  fp23,(SIGCONTEXT_FP_REGS+(PT_R23*8))(r31)
364  lfd  fp22,(SIGCONTEXT_FP_REGS+(PT_R22*8))(r31)
365  lfd  fp21,(SIGCONTEXT_FP_REGS+(PT_R21*8))(r31)
366  lfd  fp20,(SIGCONTEXT_FP_REGS+(PT_R20*8))(r31)
367  lfd  fp19,(SIGCONTEXT_FP_REGS+(PT_R19*8))(r31)
368  lfd  fp18,(SIGCONTEXT_FP_REGS+(PT_R18*8))(r31)
369  lfd  fp17,(SIGCONTEXT_FP_REGS+(PT_R17*8))(r31)
370  lfd  fp16,(SIGCONTEXT_FP_REGS+(PT_R16*8))(r31)
371  lfd  fp15,(SIGCONTEXT_FP_REGS+(PT_R15*8))(r31)
372  lfd  fp14,(SIGCONTEXT_FP_REGS+(PT_R14*8))(r31)
373  lfd  fp13,(SIGCONTEXT_FP_REGS+(PT_R13*8))(r31)
374  lfd  fp12,(SIGCONTEXT_FP_REGS+(PT_R12*8))(r31)
375  lfd  fp11,(SIGCONTEXT_FP_REGS+(PT_R11*8))(r31)
376  lfd  fp10,(SIGCONTEXT_FP_REGS+(PT_R10*8))(r31)
377  lfd  fp9,(SIGCONTEXT_FP_REGS+(PT_R9*8))(r31)
378  lfd  fp8,(SIGCONTEXT_FP_REGS+(PT_R8*8))(r31)
379  lfd  fp7,(SIGCONTEXT_FP_REGS+(PT_R7*8))(r31)
380  lfd  fp6,(SIGCONTEXT_FP_REGS+(PT_R6*8))(r31)
381  lfd  fp5,(SIGCONTEXT_FP_REGS+(PT_R5*8))(r31)
382  lfd  fp4,(SIGCONTEXT_FP_REGS+(PT_R4*8))(r31)
383  lfd  fp3,(SIGCONTEXT_FP_REGS+(PT_R3*8))(r31)
384  lfd  fp2,(SIGCONTEXT_FP_REGS+(PT_R2*8))(r31)
385  lfd  fp1,(SIGCONTEXT_FP_REGS+(PT_R1*8))(r31)
386  lfd  fp0,(SIGCONTEXT_FP_REGS+(PT_R0*8))(r31)
387
388  /* End FDE now, because the unwind info would be wrong while
389     we're reloading registers to switch to the new context.  */
390  cfi_endproc
391
392  ld   r0,(SIGCONTEXT_GP_REGS+(PT_LNK*8))(r31)
393  ld   r1,(SIGCONTEXT_GP_REGS+(PT_R1*8))(r31)
394  mtlr r0
395  ld   r2,(SIGCONTEXT_GP_REGS+(PT_R2*8))(r31)
396  ld   r0,(SIGCONTEXT_GP_REGS+(PT_XER*8))(r31)
397  ld   r3,(SIGCONTEXT_GP_REGS+(PT_R3*8))(r31)
398  mtxer r0
399  ld   r4,(SIGCONTEXT_GP_REGS+(PT_R4*8))(r31)
400  ld   r0,(SIGCONTEXT_GP_REGS+(PT_CCR*8))(r31)
401  ld   r5,(SIGCONTEXT_GP_REGS+(PT_R5*8))(r31)
402  ld   r6,(SIGCONTEXT_GP_REGS+(PT_R6*8))(r31)
403  ld   r7,(SIGCONTEXT_GP_REGS+(PT_R7*8))(r31)
404  ld   r8,(SIGCONTEXT_GP_REGS+(PT_R8*8))(r31)
405  ld   r9,(SIGCONTEXT_GP_REGS+(PT_R9*8))(r31)
406  mtcr r0
407  ld   r10,(SIGCONTEXT_GP_REGS+(PT_R10*8))(r31)
408  ld   r11,(SIGCONTEXT_GP_REGS+(PT_R11*8))(r31)
409  ld   r12,(SIGCONTEXT_GP_REGS+(PT_R12*8))(r31)
410  /* Don't reload the thread ID or TLS pointer (r13).  */
411  ld   r14,(SIGCONTEXT_GP_REGS+(PT_R14*8))(r31)
412  ld   r15,(SIGCONTEXT_GP_REGS+(PT_R15*8))(r31)
413  ld   r16,(SIGCONTEXT_GP_REGS+(PT_R16*8))(r31)
414  ld   r17,(SIGCONTEXT_GP_REGS+(PT_R17*8))(r31)
415  ld   r18,(SIGCONTEXT_GP_REGS+(PT_R18*8))(r31)
416  ld   r19,(SIGCONTEXT_GP_REGS+(PT_R19*8))(r31)
417  ld   r20,(SIGCONTEXT_GP_REGS+(PT_R20*8))(r31)
418  ld   r21,(SIGCONTEXT_GP_REGS+(PT_R21*8))(r31)
419  ld   r22,(SIGCONTEXT_GP_REGS+(PT_R22*8))(r31)
420  ld   r23,(SIGCONTEXT_GP_REGS+(PT_R23*8))(r31)
421  ld   r24,(SIGCONTEXT_GP_REGS+(PT_R24*8))(r31)
422  ld   r25,(SIGCONTEXT_GP_REGS+(PT_R25*8))(r31)
423  ld   r26,(SIGCONTEXT_GP_REGS+(PT_R26*8))(r31)
424  ld   r27,(SIGCONTEXT_GP_REGS+(PT_R27*8))(r31)
425  ld   r28,(SIGCONTEXT_GP_REGS+(PT_R28*8))(r31)
426  ld   r29,(SIGCONTEXT_GP_REGS+(PT_R29*8))(r31)
427  ld   r30,(SIGCONTEXT_GP_REGS+(PT_R30*8))(r31)
428
429  /* Now we branch to the "Next Instruction Pointer" from the saved
430     context.  With the powerpc64 instruction set there is no good way to
431     do this (from user state) without clobbering either the LR or CTR.
432     The makecontext and swapcontext functions depend on the callers
433     LR being preserved so we use the CTR.  */
434  ld   r0,(SIGCONTEXT_GP_REGS+(PT_NIP*8))(r31)
435  mtctr r0
436  ld   r0,(SIGCONTEXT_GP_REGS+(PT_R0*8))(r31)
437  ld   r31,(SIGCONTEXT_GP_REGS+(PT_R31*8))(r31)
438  bctr
439
440  /* Re-establish FDE for the rest of the actual setcontext routine.  */
441  cfi_startproc
442  cfi_offset (lr, FRAME_LR_SAVE)
443  cfi_adjust_cfa_offset (128)
444
445L(error_exit):
446  ld   r0,128+FRAME_LR_SAVE(r1)
447  addi r1,r1,128
448  mtlr r0
449	ld   r31,-8(r1)
450  blr
451
452PSEUDO_END(__setcontext)
453
454versioned_symbol (libc, __setcontext, setcontext, GLIBC_2_3_4)
455