1 | /* Copyright (C) 1996-2022 Free Software Foundation, Inc. |
2 | This file is part of the GNU C Library. |
3 | |
4 | The GNU C Library is free software; you can redistribute it and/or |
5 | modify it under the terms of the GNU Lesser General Public |
6 | License as published by the Free Software Foundation; either |
7 | version 2.1 of the License, or (at your option) any later version. |
8 | |
9 | The GNU C Library is distributed in the hope that it will be useful, |
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
12 | Lesser General Public License for more details. |
13 | |
14 | You should have received a copy of the GNU Lesser General Public |
15 | License along with the GNU C Library. If not, see |
16 | <https://www.gnu.org/licenses/>. */ |
17 | |
18 | /* clone() is even more special than fork() as it mucks with stacks |
19 | and invokes a function in the right context after its all over. */ |
20 | |
21 | #include <sysdep.h> |
22 | #define _ERRNO_H 1 |
23 | #include <bits/errno.h> |
24 | #include <tcb-offsets.h> |
25 | |
26 | /* Non-thread code calls __clone with the following parameters: |
27 | int clone(int (*fn)(void *arg), |
28 | void *child_stack, |
29 | int flags, |
30 | void *arg) |
31 | |
32 | NPTL Code will call __clone with the following parameters: |
33 | int clone(int (*fn)(void *arg), |
34 | void *child_stack, |
35 | int flags, |
36 | void *arg, |
37 | int *parent_tidptr, |
38 | struct user_desc *newtls, |
39 | int *child_pidptr) |
40 | |
41 | The code should not mangle the extra input registers. |
42 | Syscall expects: Input to __clone: |
43 | 4(r25) - function pointer (r26, arg0) |
44 | 0(r25) - argument (r23, arg3) |
45 | r26 - clone flags. (r24, arg2) |
46 | r25+64 - user stack pointer. (r25, arg1) |
47 | r24 - parent tid pointer. (stack - 52) |
48 | r23 - struct user_desc newtls pointer. (stack - 56) |
49 | r22 - child tid pointer. (stack - 60) |
50 | r20 - clone syscall number (constant) |
51 | |
52 | Return: |
53 | |
54 | On success the thread ID of the child process is returend in |
55 | the callers context. |
56 | On error return -1, and set errno to the value returned by |
57 | the syscall. |
58 | */ |
59 | |
60 | .text |
61 | ENTRY(__clone) |
62 | /* Prologue */ |
63 | stwm %r4, 64(%sp) |
64 | .cfi_def_cfa_offset -64 |
65 | .cfi_offset 4, 0 |
66 | stw %sp, -4(%sp) |
67 | #ifdef PIC |
68 | stw %r19, -32(%sp) |
69 | .cfi_offset 19, 32 |
70 | #endif |
71 | |
72 | /* Sanity check arguments. */ |
73 | comib,=,n 0,%arg0,.LerrorSanity /* no NULL function pointers */ |
74 | comib,=,n 0,%arg1,.LerrorSanity /* no NULL stack pointers */ |
75 | |
76 | /* Ensure stack argument is 8-byte aligned. */ |
77 | ldo 7(%r25),%r25 |
78 | depi 0,31,3,%r25 |
79 | |
80 | /* Save the function pointer, arg, and flags on the new stack. */ |
81 | stwm %r26, 64(%r25) |
82 | stw %r23, -60(%r25) |
83 | stw %r24, -56(%r25) |
84 | |
85 | /* Clone arguments are (int flags, void * child_stack) */ |
86 | copy %r24, %r26 /* flags are first */ |
87 | /* User stack pointer is in the correct register already */ |
88 | |
89 | /* Load args from stack... */ |
90 | ldw -116(%sp), %r24 /* Load parent_tidptr */ |
91 | ldw -120(%sp), %r23 /* Load newtls */ |
92 | ldw -124(%sp), %r22 /* Load child_tidptr */ |
93 | |
94 | /* Save the PIC register. */ |
95 | #ifdef PIC |
96 | copy %r19, %r4 /* parent */ |
97 | #endif |
98 | |
99 | /* Do the system call */ |
100 | ble 0x100(%sr2, %r0) |
101 | ldi __NR_clone, %r20 |
102 | |
103 | ldi -4096, %r1 |
104 | comclr,>>= %r1, %ret0, %r0 /* Note: unsigned compare. */ |
105 | b,n .LerrorRest |
106 | |
107 | /* Restore the PIC register. */ |
108 | #ifdef PIC |
109 | copy %r4, %r19 /* parent */ |
110 | #endif |
111 | |
112 | comib,=,n 0, %ret0, .LthreadStart |
113 | |
114 | /* Successful return from the parent |
115 | No need to restore the PIC register, |
116 | since we return immediately. */ |
117 | |
118 | ldw -84(%sp), %rp |
119 | bv %r0(%rp) |
120 | ldwm -64(%sp), %r4 |
121 | |
122 | .LerrorRest: |
123 | /* Something bad happened -- no child created */ |
124 | bl __syscall_error, %rp |
125 | sub %r0, %ret0, %arg0 |
126 | ldw -84(%sp), %rp |
127 | /* Return after setting errno, ret0 is set to -1 by __syscall_error. */ |
128 | bv %r0(%rp) |
129 | ldwm -64(%sp), %r4 |
130 | |
131 | .LerrorSanity: |
132 | /* Sanity checks failed, return -1, and set errno to EINVAL. */ |
133 | bl __syscall_error, %rp |
134 | ldi EINVAL, %arg0 |
135 | ldw -84(%sp), %rp |
136 | bv %r0(%rp) |
137 | ldwm -64(%sp), %r4 |
138 | |
139 | .LthreadStart: |
140 | /* Load up the arguments. */ |
141 | ldw -60(%sp), %arg0 |
142 | ldw -64(%sp), %r22 |
143 | |
144 | /* $$dyncall fixes child's PIC register */ |
145 | |
146 | /* Call the user's function */ |
147 | #ifdef PIC |
148 | copy %r19, %r4 |
149 | #endif |
150 | bl $$dyncall, %r31 |
151 | copy %r31, %rp |
152 | #ifdef PIC |
153 | copy %r4, %r19 |
154 | #endif |
155 | copy %r28, %r26 |
156 | ble 0x100(%sr2, %r0) |
157 | ldi __NR_exit, %r20 |
158 | |
159 | /* We should not return from exit. |
160 | We do not restore r4, or the stack state. */ |
161 | iitlbp %r0, (%sr0, %r0) |
162 | |
163 | PSEUDO_END(__clone) |
164 | |
165 | libc_hidden_def (__clone) |
166 | weak_alias (__clone, clone) |
167 | |