]> git.ipfire.org Git - thirdparty/glibc.git/blob - sysdeps/unix/sysv/linux/powerpc/powerpc32/swapcontext-common.S
77e47a712ee5d020ac243a0294c64c2bb91b2e9b
[thirdparty/glibc.git] / sysdeps / unix / sysv / linux / powerpc / powerpc32 / swapcontext-common.S
1 /* Save current context and jump to a new context.
2 Copyright (C) 2005-2013 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 <http://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 archecture 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
40 ENTRY(__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+4(r7)
156 # else
157 lwz r7,_dl_hwcap@got(r7)
158 mtlr r8
159 lwz r7,4(r7)
160 # endif
161 # else
162 lis r7,(_dl_hwcap+4)@ha
163 lwz r7,(_dl_hwcap+4)@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
264 2: /*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 li r4,0
271 stw r3,_UC_REGS_PTR(r12)
272 addi r5,r12,_UC_SIGMASK
273 li r3,SIG_SETMASK
274 bl __sigprocmask@local
275 cmpwi r3,0
276 bne 3f /* L(error_exit) */
277
278 /*
279 * If the new ucontext refers to the point where we were interrupted
280 * by a signal, we have to use the rt_sigreturn system call to
281 * return to the context so we get both LR and CTR restored.
282 *
283 * Otherwise, the context we are restoring is either just after
284 * a procedure call (getcontext/swapcontext) or at the beginning
285 * of a procedure call (makecontext), so we don't need to restore
286 * r0, xer, ctr. We don't restore r2 since it will be used as
287 * the TLS pointer.
288 */
289 lwz r4,_FRAME_PARM_SAVE2(r1)
290 lwz r31,_UC_REGS_PTR(r4)
291 lwz r0,_UC_GREGS+(PT_MSR*4)(r31)
292 cmpwi r0,0
293 bne 4f /* L(do_sigret) */
294
295 #ifdef __CONTEXT_ENABLE_FPRS
296 # ifdef __CONTEXT_ENABLE_VRS
297
298 # ifdef PIC
299 mflr r8
300 # ifdef HAVE_ASM_PPC_REL16
301 SETUP_GOT_ACCESS(r7,got_label)
302 addis r7,r7,_GLOBAL_OFFSET_TABLE_-got_label@ha
303 addi r7,r7,_GLOBAL_OFFSET_TABLE_-got_label@l
304 # else
305 bl _GLOBAL_OFFSET_TABLE_@local-4
306 mflr r7
307 # endif
308 mtlr r8
309 # ifdef SHARED
310 lwz r7,_rtld_global_ro@got(r7)
311 lwz r7,RTLD_GLOBAL_RO_DL_HWCAP_OFFSET+4(r7)
312 # else
313 lwz r7,_dl_hwcap@got(r7)
314 lwz r7,4(r7)
315 # endif
316 # else
317 lis r7,(_dl_hwcap+4)@ha
318 lwz r7,(_dl_hwcap+4)@l(r7)
319 # endif
320 andis. r7,r7,(PPC_FEATURE_HAS_ALTIVEC >> 16)
321 la r10,(_UC_VREGS)(r31)
322 beq 6f /* L(has_no_vec) */
323
324 lwz r0,(32*16)(r10)
325 li r9,(32*16)
326 cmpwi r0,0
327 mtspr VRSAVE,r0
328 beq 6f /* L(has_no_vec) */
329
330 lvx v19,r9,r10
331 la r9,(16)(r10)
332
333 lvx v0,0,r10
334 lvx v1,0,r9
335 addi r10,r10,32
336 addi r9,r9,32
337
338 mtvscr v19
339 lvx v2,0,r10
340 lvx v3,0,r9
341 addi r10,r10,32
342 addi r9,r9,32
343
344 lvx v4,0,r10
345 lvx v5,0,r9
346 addi r10,r10,32
347 addi r9,r9,32
348
349 lvx v6,0,r10
350 lvx v7,0,r9
351 addi r10,r10,32
352 addi r9,r9,32
353
354 lvx v8,0,r10
355 lvx v9,0,r9
356 addi r10,r10,32
357 addi r9,r9,32
358
359 lvx v10,0,r10
360 lvx v11,0,r9
361 addi r10,r10,32
362 addi r9,r9,32
363
364 lvx v12,0,r10
365 lvx v13,0,r9
366 addi r10,r10,32
367 addi r9,r9,32
368
369 lvx v14,0,r10
370 lvx v15,0,r9
371 addi r10,r10,32
372 addi r9,r9,32
373
374 lvx v16,0,r10
375 lvx v17,0,r9
376 addi r10,r10,32
377 addi r9,r9,32
378
379 lvx v18,0,r10
380 lvx v19,0,r9
381 addi r10,r10,32
382 addi r9,r9,32
383
384 lvx v20,0,r10
385 lvx v21,0,r9
386 addi r10,r10,32
387 addi r9,r9,32
388
389 lvx v22,0,r10
390 lvx v23,0,r9
391 addi r10,r10,32
392 addi r9,r9,32
393
394 lvx v24,0,r10
395 lvx v25,0,r9
396 addi r10,r10,32
397 addi r9,r9,32
398
399 lvx v26,0,r10
400 lvx v27,0,r9
401 addi r10,r10,32
402 addi r9,r9,32
403
404 lvx v28,0,r10
405 lvx v29,0,r9
406 addi r10,r10,32
407 addi r9,r9,32
408
409 lvx v30,0,r10
410 lvx v31,0,r9
411 addi r10,r10,32
412 addi r9,r9,32
413
414 lvx v10,0,r10
415 lvx v11,0,r9
416
417 6: /* L(has_no_vec): */
418 # endif /* __CONTEXT_ENABLE_VRS */
419 /* Restore the floating-point registers */
420 lfd fp31,_UC_FREGS+(32*8)(r31)
421 lfd fp0,_UC_FREGS+(0*8)(r31)
422 # ifdef _ARCH_PWR6
423 /* Use the extended four-operand version of the mtfsf insn. */
424 mtfsf 0xff,fp31,1,0
425 # else
426 .machine push
427 .machine "power6"
428 /* Availability of DFP indicates a 64-bit FPSCR. */
429 andi. r6,r7,PPC_FEATURE_HAS_DFP
430 beq 7f
431 /* Use the extended four-operand version of the mtfsf insn. */
432 mtfsf 0xff,fp31,1,0
433 b 8f
434 /* Continue to operate on the FPSCR as if it were 32-bits. */
435 7: mtfsf 0xff,fp31
436 8: .machine pop
437 #endif /* _ARCH_PWR6 */
438 lfd fp1,_UC_FREGS+(1*8)(r31)
439 lfd fp2,_UC_FREGS+(2*8)(r31)
440 lfd fp3,_UC_FREGS+(3*8)(r31)
441 lfd fp4,_UC_FREGS+(4*8)(r31)
442 lfd fp5,_UC_FREGS+(5*8)(r31)
443 lfd fp6,_UC_FREGS+(6*8)(r31)
444 lfd fp7,_UC_FREGS+(7*8)(r31)
445 lfd fp8,_UC_FREGS+(8*8)(r31)
446 lfd fp9,_UC_FREGS+(9*8)(r31)
447 lfd fp10,_UC_FREGS+(10*8)(r31)
448 lfd fp11,_UC_FREGS+(11*8)(r31)
449 lfd fp12,_UC_FREGS+(12*8)(r31)
450 lfd fp13,_UC_FREGS+(13*8)(r31)
451 lfd fp14,_UC_FREGS+(14*8)(r31)
452 lfd fp15,_UC_FREGS+(15*8)(r31)
453 lfd fp16,_UC_FREGS+(16*8)(r31)
454 lfd fp17,_UC_FREGS+(17*8)(r31)
455 lfd fp18,_UC_FREGS+(18*8)(r31)
456 lfd fp19,_UC_FREGS+(19*8)(r31)
457 lfd fp20,_UC_FREGS+(20*8)(r31)
458 lfd fp21,_UC_FREGS+(21*8)(r31)
459 lfd fp22,_UC_FREGS+(22*8)(r31)
460 lfd fp23,_UC_FREGS+(23*8)(r31)
461 lfd fp24,_UC_FREGS+(24*8)(r31)
462 lfd fp25,_UC_FREGS+(25*8)(r31)
463 lfd fp26,_UC_FREGS+(26*8)(r31)
464 lfd fp27,_UC_FREGS+(27*8)(r31)
465 lfd fp28,_UC_FREGS+(28*8)(r31)
466 lfd fp29,_UC_FREGS+(29*8)(r31)
467 lfd fp30,_UC_FREGS+(30*8)(r31)
468 lfd fp31,_UC_FREGS+(31*8)(r31)
469 #endif /* __CONTEXT_ENABLE_FPRS */
470
471 /* Restore LR and CCR, and set CTR to the NIP value */
472 lwz r3,_UC_GREGS+(PT_LNK*4)(r31)
473 lwz r4,_UC_GREGS+(PT_NIP*4)(r31)
474 lwz r5,_UC_GREGS+(PT_CCR*4)(r31)
475 mtlr r3
476 mtctr r4
477 mtcr r5
478
479 /* Restore the general registers */
480 lwz r3,_UC_GREGS+(PT_R3*4)(r31)
481 lwz r4,_UC_GREGS+(PT_R4*4)(r31)
482 lwz r5,_UC_GREGS+(PT_R5*4)(r31)
483 lwz r6,_UC_GREGS+(PT_R6*4)(r31)
484 lwz r7,_UC_GREGS+(PT_R7*4)(r31)
485 lwz r8,_UC_GREGS+(PT_R8*4)(r31)
486 lwz r9,_UC_GREGS+(PT_R9*4)(r31)
487 lwz r10,_UC_GREGS+(PT_R10*4)(r31)
488 lwz r11,_UC_GREGS+(PT_R11*4)(r31)
489 lwz r12,_UC_GREGS+(PT_R12*4)(r31)
490 lwz r13,_UC_GREGS+(PT_R13*4)(r31)
491 lwz r14,_UC_GREGS+(PT_R14*4)(r31)
492 lwz r15,_UC_GREGS+(PT_R15*4)(r31)
493 lwz r16,_UC_GREGS+(PT_R16*4)(r31)
494 lwz r17,_UC_GREGS+(PT_R17*4)(r31)
495 lwz r18,_UC_GREGS+(PT_R18*4)(r31)
496 lwz r19,_UC_GREGS+(PT_R19*4)(r31)
497 lwz r20,_UC_GREGS+(PT_R20*4)(r31)
498 lwz r21,_UC_GREGS+(PT_R21*4)(r31)
499 lwz r22,_UC_GREGS+(PT_R22*4)(r31)
500 lwz r23,_UC_GREGS+(PT_R23*4)(r31)
501 lwz r24,_UC_GREGS+(PT_R24*4)(r31)
502 lwz r25,_UC_GREGS+(PT_R25*4)(r31)
503 lwz r26,_UC_GREGS+(PT_R26*4)(r31)
504 lwz r27,_UC_GREGS+(PT_R27*4)(r31)
505 lwz r28,_UC_GREGS+(PT_R28*4)(r31)
506 lwz r29,_UC_GREGS+(PT_R29*4)(r31)
507 lwz r30,_UC_GREGS+(PT_R30*4)(r31)
508 lwz r1,_UC_GREGS+(PT_R1*4)(r31)
509 lwz r31,_UC_GREGS+(PT_R31*4)(r31)
510
511 bctr
512
513 3:/*L(error_exit):*/
514 lwz r0,_FRAME_LR_SAVE+16(r1)
515 addi r1,r1,16
516 mtlr r0
517 blr
518
519 4:/*L(do_sigret):*/
520 addi r1,r4,-0xd0
521 li r0,SYS_ify(rt_sigreturn)
522 sc
523 /* NOTREACHED */
524
525 END(__CONTEXT_FUNC_NAME)