1 | /* Create new context. |
2 | Copyright (C) 2002-2024 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 | |
21 | #define __ASSEMBLY__ |
22 | #include <asm/ptrace.h> |
23 | #include "ucontext_i.h" |
24 | #include <asm/errno.h> |
25 | |
26 | ENTRY (__makecontext) |
27 | CALL_MCOUNT 3 |
28 | /* Save parameters into the parameter save area of callers frame. */ |
29 | std r3,FRAME_PARM_SAVE+0(r1) /* ucontext_t *ucp */ |
30 | std r4,FRAME_PARM_SAVE+8(r1) /* void (*func)(void) */ |
31 | std r5,FRAME_PARM_SAVE+16(r1) /* int argc */ |
32 | std r6,FRAME_PARM_SAVE+24(r1) /* ... */ |
33 | std r7,FRAME_PARM_SAVE+32(r1) |
34 | std r8,FRAME_PARM_SAVE+40(r1) |
35 | std r9,FRAME_PARM_SAVE+48(r1) |
36 | std r10,FRAME_PARM_SAVE+56(r1) |
37 | mflr r0 |
38 | /* Get the address of the target functions first parameter. */ |
39 | addi r6,r1,FRAME_PARM_SAVE+24 |
40 | std r0,FRAME_LR_SAVE(r1) |
41 | cfi_offset (lr, FRAME_LR_SAVE) |
42 | stdu r1,-128(r1) |
43 | cfi_adjust_cfa_offset (128) |
44 | |
45 | /* Get the ucontexts stack pointer and size. Compute the top of stack |
46 | and round down to a quadword boundary. Then stack a dummy frame |
47 | with a null back chain. We store the context pointer in the frames |
48 | "compiler double word" field so we can recover if is the function |
49 | returns. Finally save the callers link register and TOC pointer |
50 | into this frame so the debugger can display a backtrace. |
51 | */ |
52 | ld r7,UCONTEXT_STACK_SP(r3) |
53 | ld r0,UCONTEXT_STACK_SIZE(r3) |
54 | add r7,r7,r0 |
55 | clrrdi r7,r7,4 |
56 | li r0,0 |
57 | stdu r0,-64(r7) |
58 | std r3,FRAME_PARM_SAVE(r7) /* Store context in dummy parm1. */ |
59 | mflr r0 |
60 | std r2,FRAME_TOC_SAVE(r7) /* Store the TOC pointer for later. */ |
61 | std r0,FRAME_LR_SAVE(r7) |
62 | |
63 | /* Now we need to stack another frame to hold the parameter save area |
64 | for the function. We need to allocate a frame with the minimum 48 |
65 | byte header and 8 parameter register. However if there are more |
66 | than 8 parameters addition space is need to hold all the parameters. |
67 | The total size it rounded up to a quadword multiple then a frame is |
68 | stacked. This address is stored in the ucontext as GPR 1. */ |
69 | |
70 | cmpdi cr1,r5,8 |
71 | sldi r8,r5,3 |
72 | bgt cr1,L(gt8) |
73 | li r8,64 |
74 | L(gt8): |
75 | addi r8,r8,FRAME_PARM_SAVE+8 /* Add header plus rounding factor. */ |
76 | clrrdi r8,r8,4 /* Round down to quadword. */ |
77 | |
78 | subf r8,r8,r7 |
79 | std r7,0(r8) /* Stack the frame. */ |
80 | std r8,(SIGCONTEXT_GP_REGS+(PT_R1*8))(r3) |
81 | |
82 | /* Now we need to copy the target functions parameters. The functions |
83 | parameters are saved in the parameter save area. We skip over the |
84 | first three parameters and copy up to 8 double word into the |
85 | SIGCONTEXT_GP_REGS starting with R3. If there are more than 8 |
86 | parameters then doublewords 8-N are copied into the parameter |
87 | save area of the context frame. */ |
88 | cmpdi r5,0 |
89 | beq L(noparms) |
90 | mr r0,r5 |
91 | ble cr1,L(le8) |
92 | li r0,8 |
93 | L(le8): |
94 | mtctr r0 |
95 | addi r7,r6,-8 |
96 | addi r9,r3,(SIGCONTEXT_GP_REGS+(PT_R3*8)-8) |
97 | L(parmloop2): |
98 | ldu r0,8(r7) |
99 | stdu r0,8(r9) |
100 | bdnz L(parmloop2) |
101 | |
102 | addi r0,r5,-8 |
103 | ble cr1,L(noparms) |
104 | mtctr r0 |
105 | addi r9,r8,FRAME_PARM_SAVE+64-8 |
106 | L(parmloop): |
107 | ldu r0,8(r7) |
108 | stdu r0,8(r9) |
109 | bdnz L(parmloop) |
110 | |
111 | L(noparms): |
112 | |
113 | #if _CALL_ELF != 2 |
114 | /* Load the function address and TOC from the function descriptor |
115 | and store them in the ucontext as NIP and r2. Store the 3rd |
116 | field of the function descriptor into the ucontext as r11 in case |
117 | the calling language needs the "environment pointer". */ |
118 | ld r0,0(r4) |
119 | ld r10,8(r4); |
120 | ld r9,16(r4); |
121 | std r0,(SIGCONTEXT_GP_REGS+(PT_NIP*8))(r3) |
122 | std r10,(SIGCONTEXT_GP_REGS+(PT_R2*8))(r3) |
123 | std r9,(SIGCONTEXT_GP_REGS+(PT_R11*8))(r3) |
124 | #else |
125 | /* In the ELFv2 ABI, the function pointer is already the address. |
126 | Store it as NIP and r12 as required by the ABI. */ |
127 | std r4,(SIGCONTEXT_GP_REGS+(PT_NIP*8))(r3) |
128 | std r4,(SIGCONTEXT_GP_REGS+(PT_R12*8))(r3) |
129 | #endif |
130 | |
131 | /* If the target function returns we need to do some cleanup. We use a |
132 | code trick to get the address of our cleanup function into the link |
133 | register. Do not add any code between here and L(exitcode). |
134 | Use this conditional form of branch and link to avoid destroying |
135 | the cpu link stack used to predict blr return addresses. */ |
136 | bcl 20,31,L(gotexitcodeaddr); |
137 | |
138 | /* End FDE now, because while executing on the context's stack |
139 | the unwind info would be wrong otherwise. */ |
140 | cfi_endproc |
141 | |
142 | /* This is the helper code which gets called if a function which |
143 | is registered with 'makecontext' returns. In this case we |
144 | have to install the context listed in the uc_link element of |
145 | the context 'makecontext' manipulated at the time of the |
146 | 'makecontext' call. If the pointer is NULL the process must |
147 | terminate. */ |
148 | L(exitcode): |
149 | /* Recover the ucontext and TOC from the dummy frame. */ |
150 | ld r1,FRAME_BACKCHAIN(r1) /* Unstack the parameter save area frame. */ |
151 | ld r3,FRAME_PARM_SAVE(r1) |
152 | ld r2,FRAME_TOC_SAVE(r1) |
153 | ld r3,UCONTEXT_LINK(r3) /* Load the resume context. */ |
154 | cmpdi r3,0 |
155 | beq L(do_exit) |
156 | bl JUMPTARGET(__setcontext) |
157 | nop |
158 | /* If setcontext returns (which can happen if the syscall fails) we will |
159 | exit the program with error status (-1). */ |
160 | li r3,-1 |
161 | L(do_exit): |
162 | #ifdef SHARED |
163 | b JUMPTARGET (NOTOC (__GI_exit)); |
164 | #else |
165 | b JUMPTARGET(exit); |
166 | nop |
167 | #endif |
168 | b L(do_exit) |
169 | |
170 | /* Re-establish FDE for the rest of the actual makecontext routine. */ |
171 | cfi_startproc |
172 | cfi_offset (lr, FRAME_LR_SAVE) |
173 | cfi_adjust_cfa_offset (128) |
174 | |
175 | /* The address of the exit code is in the link register. Store the lr |
176 | in the ucontext as LNK so the target function will return to our |
177 | exit code. */ |
178 | L(gotexitcodeaddr): |
179 | mflr r0 |
180 | std r0,(SIGCONTEXT_GP_REGS+(PT_LNK*8))(r3) |
181 | ld r0,128+FRAME_LR_SAVE(r1) |
182 | addi r1,r1,128 |
183 | mtlr r0 |
184 | blr |
185 | END(__makecontext) |
186 | |
187 | weak_alias (__makecontext, makecontext) |
188 | |