/* Switch to context. Copyright (C) 2002 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The GNU C Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with the GNU C Library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ #include #define __ASSEMBLY__ #include #include "ucontext_i.h" ENTRY(__setcontext) mflr r0 std r31,-8(1) std r0,FRAME_LR_SAVE(r1) stdu r1,-128(r1) mr r31,r3 /* * If this ucontext refers to the point where we were interrupted * by a signal, we have to use the rt_sigreturn system call to * return to the context so we get both LR and CTR restored. * * Otherwise, the context we are restoring is either just after * a procedure call (getcontext/swapcontext) or at the beginning * of a procedure call (makecontext), so we don't need to restore * msr and ctr. We don't restore r13 since it will be used as * the TLS pointer. */ lwz r0,(SIGCONTEXT_GP_REGS+(PT_MSR*8))(r31) cmpdi r0,0 bne L(do_sigret) li r5,0 addi r4,r3,UCONTEXT_SIGMASK li r3,SIG_SETMASK bl .sigprocmask nop cmpdi r3,0 bne L(error_exit) lfd fp0,(SIGCONTEXT_FP_REGS+(32*8))(r31) lfd fp31,(SIGCONTEXT_FP_REGS+(PT_R31*8))(r31) lfd fp30,(SIGCONTEXT_FP_REGS+(PT_R30*8))(r31) mtfsf 0xff,fp0 lfd fp29,(SIGCONTEXT_FP_REGS+(PT_R29*8))(r31) lfd fp28,(SIGCONTEXT_FP_REGS+(PT_R28*8))(r31) lfd fp27,(SIGCONTEXT_FP_REGS+(PT_R27*8))(r31) lfd fp26,(SIGCONTEXT_FP_REGS+(PT_R26*8))(r31) lfd fp25,(SIGCONTEXT_FP_REGS+(PT_R25*8))(r31) lfd fp24,(SIGCONTEXT_FP_REGS+(PT_R24*8))(r31) lfd fp23,(SIGCONTEXT_FP_REGS+(PT_R23*8))(r31) lfd fp22,(SIGCONTEXT_FP_REGS+(PT_R22*8))(r31) lfd fp21,(SIGCONTEXT_FP_REGS+(PT_R21*8))(r31) lfd fp20,(SIGCONTEXT_FP_REGS+(PT_R20*8))(r31) lfd fp19,(SIGCONTEXT_FP_REGS+(PT_R19*8))(r31) lfd fp18,(SIGCONTEXT_FP_REGS+(PT_R18*8))(r31) lfd fp17,(SIGCONTEXT_FP_REGS+(PT_R17*8))(r31) lfd fp16,(SIGCONTEXT_FP_REGS+(PT_R16*8))(r31) lfd fp15,(SIGCONTEXT_FP_REGS+(PT_R15*8))(r31) lfd fp14,(SIGCONTEXT_FP_REGS+(PT_R14*8))(r31) lfd fp13,(SIGCONTEXT_FP_REGS+(PT_R13*8))(r31) lfd fp12,(SIGCONTEXT_FP_REGS+(PT_R12*8))(r31) lfd fp11,(SIGCONTEXT_FP_REGS+(PT_R11*8))(r31) lfd fp10,(SIGCONTEXT_FP_REGS+(PT_R10*8))(r31) lfd fp9,(SIGCONTEXT_FP_REGS+(PT_R9*8))(r31) lfd fp8,(SIGCONTEXT_FP_REGS+(PT_R8*8))(r31) lfd fp7,(SIGCONTEXT_FP_REGS+(PT_R7*8))(r31) lfd fp6,(SIGCONTEXT_FP_REGS+(PT_R6*8))(r31) lfd fp5,(SIGCONTEXT_FP_REGS+(PT_R5*8))(r31) lfd fp4,(SIGCONTEXT_FP_REGS+(PT_R4*8))(r31) lfd fp3,(SIGCONTEXT_FP_REGS+(PT_R3*8))(r31) lfd fp2,(SIGCONTEXT_FP_REGS+(PT_R2*8))(r31) lfd fp1,(SIGCONTEXT_FP_REGS+(PT_R1*8))(r31) lfd fp0,(SIGCONTEXT_FP_REGS+(PT_R0*8))(r31) ld r0,(SIGCONTEXT_GP_REGS+(PT_LNK*8))(r31) ld r1,(SIGCONTEXT_GP_REGS+(PT_R1*8))(r31) mtlr r0 ld r2,(SIGCONTEXT_GP_REGS+(PT_R2*8))(r31) ld r0,(SIGCONTEXT_GP_REGS+(PT_XER*8))(r31) ld r3,(SIGCONTEXT_GP_REGS+(PT_R3*8))(r31) mtxer r0 ld r4,(SIGCONTEXT_GP_REGS+(PT_R4*8))(r31) ld r0,(SIGCONTEXT_GP_REGS+(PT_CCR*8))(r31) ld r5,(SIGCONTEXT_GP_REGS+(PT_R5*8))(r31) mfcr r0 ld r6,(SIGCONTEXT_GP_REGS+(PT_R6*8))(r31) ld r7,(SIGCONTEXT_GP_REGS+(PT_R7*8))(r31) ld r8,(SIGCONTEXT_GP_REGS+(PT_R8*8))(r31) ld r9,(SIGCONTEXT_GP_REGS+(PT_R9*8))(r31) ld r10,(SIGCONTEXT_GP_REGS+(PT_R10*8))(r31) ld r11,(SIGCONTEXT_GP_REGS+(PT_R11*8))(r31) ld r12,(SIGCONTEXT_GP_REGS+(PT_R12*8))(r31) /* Don't reload the thread ID or TLS pointer (r13). */ ld r14,(SIGCONTEXT_GP_REGS+(PT_R14*8))(r31) ld r15,(SIGCONTEXT_GP_REGS+(PT_R15*8))(r31) ld r16,(SIGCONTEXT_GP_REGS+(PT_R16*8))(r31) ld r17,(SIGCONTEXT_GP_REGS+(PT_R17*8))(r31) ld r18,(SIGCONTEXT_GP_REGS+(PT_R18*8))(r31) ld r19,(SIGCONTEXT_GP_REGS+(PT_R19*8))(r31) ld r20,(SIGCONTEXT_GP_REGS+(PT_R20*8))(r31) ld r21,(SIGCONTEXT_GP_REGS+(PT_R21*8))(r31) ld r22,(SIGCONTEXT_GP_REGS+(PT_R22*8))(r31) ld r23,(SIGCONTEXT_GP_REGS+(PT_R23*8))(r31) ld r24,(SIGCONTEXT_GP_REGS+(PT_R24*8))(r31) ld r25,(SIGCONTEXT_GP_REGS+(PT_R25*8))(r31) ld r26,(SIGCONTEXT_GP_REGS+(PT_R26*8))(r31) ld r27,(SIGCONTEXT_GP_REGS+(PT_R27*8))(r31) ld r28,(SIGCONTEXT_GP_REGS+(PT_R28*8))(r31) ld r29,(SIGCONTEXT_GP_REGS+(PT_R29*8))(r31) ld r30,(SIGCONTEXT_GP_REGS+(PT_R30*8))(r31) /* Now we branch to the "Next Instruction Pointer" from the saved context. With the powerpc64 instruction set there is no good way to do this (from user state) without clobbering either the LR or CTR. The makecontext and swapcontext functions depend on the callers LR being preserved so we use the CTR. */ ld r0,(SIGCONTEXT_GP_REGS+(PT_NIP*8))(r31) mtctr r0 ld r0,(SIGCONTEXT_GP_REGS+(PT_R0*8))(r31) ld r31,(SIGCONTEXT_GP_REGS+(PT_R31*8))(r31) bctr L(error_exit): ld r0,128+FRAME_LR_SAVE(r1) addi r1,r1,128 mtlr r0 ld r31,-8(r1) blr /* At this point we assume that the ucontext was created by a rt_signal and we should use rt_sigreturn to restore the original state. As of the 2.4.21 kernel the ucontext is the first thing (offset 0) in the rt_signal frame and rt_sigreturn expects the ucontext address in R1. Normally the rt-signal trampoline handles this by popping dummy frame before the rt_signal syscall. In our case the stack may not be in its original (signal handler return with R1 pointing at the dummy frame) state. We do have the ucontext address in R3, so simply copy R3 to R1 before the syscall. */ L(do_sigret): mr r1,r3, li r0,SYS_ify(rt_sigreturn) sc /* No return. */ PSEUDO_END(__setcontext) weak_alias(__setcontext, setcontext)