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 <sys/asm.h> |
22 | #include <sysdep.h> |
23 | #define _ERRNO_H 1 |
24 | #include <bits/errno.h> |
25 | #include <tls.h> |
26 | |
27 | /* int clone(int (*fn)(void *arg), void *child_stack, int flags, void *arg, |
28 | void *parent_tidptr, void *tls, void *child_tidptr) */ |
29 | |
30 | .text |
31 | .set nomips16 |
32 | #if _MIPS_SIM == _ABIO32 |
33 | # define 1 |
34 | #else |
35 | # define EXTRA_LOCALS 0 |
36 | #endif |
37 | LOCALSZ= 4 |
38 | FRAMESZ= (((NARGSAVE+LOCALSZ)*SZREG)+ALSZ)&ALMASK |
39 | GPOFF= FRAMESZ-(1*SZREG) |
40 | NESTED(__clone,4*SZREG,sp) |
41 | #ifdef __PIC__ |
42 | SETUP_GP |
43 | #endif |
44 | PTR_SUBU sp, FRAMESZ |
45 | cfi_adjust_cfa_offset (FRAMESZ) |
46 | SETUP_GP64_STACK (GPOFF, __clone) |
47 | #ifdef __PIC__ |
48 | SAVE_GP (GPOFF) |
49 | #endif |
50 | #ifdef PROF |
51 | .set noat |
52 | move $1,ra |
53 | jal _mcount |
54 | .set at |
55 | #endif |
56 | |
57 | /* Align stack to 8/16 bytes per the ABI. */ |
58 | #if _MIPS_SIM == _ABIO32 |
59 | li t0,-8 |
60 | #else |
61 | li t0,-16 |
62 | #endif |
63 | and a1,a1,t0 |
64 | |
65 | /* Sanity check arguments. */ |
66 | li v0,EINVAL |
67 | beqz a0,L(error) /* No NULL function pointers. */ |
68 | beqz a1,L(error) /* No NULL stack pointers. */ |
69 | |
70 | PTR_SUBU a1,32 /* Reserve argument save space. */ |
71 | PTR_S a0,0(a1) /* Save function pointer. */ |
72 | PTR_S a3,PTRSIZE(a1) /* Save argument pointer. */ |
73 | LONG_S a2,(PTRSIZE*2)(a1) /* Save clone flags. */ |
74 | |
75 | move a0,a2 |
76 | |
77 | /* Shuffle in the last three arguments - arguments 5, 6, and 7 to |
78 | this function, but arguments 3, 4, and 5 to the syscall. */ |
79 | #if _MIPS_SIM == _ABIO32 |
80 | PTR_L a2,(FRAMESZ+PTRSIZE+PTRSIZE+16)(sp) |
81 | PTR_S a2,16(sp) |
82 | PTR_L a2,(FRAMESZ+16)(sp) |
83 | PTR_L a3,(FRAMESZ+PTRSIZE+16)(sp) |
84 | #else |
85 | move a2,a4 |
86 | move a3,a5 |
87 | move a4,a6 |
88 | #endif |
89 | |
90 | /* Do the system call */ |
91 | li v0,__NR_clone |
92 | cfi_endproc |
93 | syscall |
94 | |
95 | bnez a3,L(error) |
96 | beqz v0,L(thread_start) |
97 | |
98 | /* Successful return from the parent */ |
99 | cfi_startproc |
100 | cfi_adjust_cfa_offset (FRAMESZ) |
101 | SETUP_GP64_STACK_CFI (GPOFF) |
102 | cfi_remember_state |
103 | RESTORE_GP64_STACK |
104 | PTR_ADDU sp, FRAMESZ |
105 | cfi_adjust_cfa_offset (-FRAMESZ) |
106 | ret |
107 | |
108 | /* Something bad happened -- no child created */ |
109 | L(error): |
110 | cfi_restore_state |
111 | #ifdef __PIC__ |
112 | PTR_LA t9,__syscall_error |
113 | RESTORE_GP64_STACK |
114 | PTR_ADDU sp, FRAMESZ |
115 | cfi_adjust_cfa_offset (-FRAMESZ) |
116 | jr t9 |
117 | #else |
118 | RESTORE_GP64_STACK |
119 | PTR_ADDU sp, FRAMESZ |
120 | cfi_adjust_cfa_offset (-FRAMESZ) |
121 | j __syscall_error |
122 | #endif |
123 | END(__clone) |
124 | |
125 | /* Load up the arguments to the function. Put this block of code in |
126 | its own function so that we can terminate the stack trace with our |
127 | debug info. */ |
128 | |
129 | ENTRY(__thread_start) |
130 | L(thread_start): |
131 | cfi_undefined ($31) |
132 | /* cp is already loaded. */ |
133 | SAVE_GP (GPOFF) |
134 | /* The stackframe has been created on entry of clone(). */ |
135 | |
136 | /* Restore the arg for user's function. */ |
137 | PTR_L t9,0(sp) /* Function pointer. */ |
138 | PTR_L a0,PTRSIZE(sp) /* Argument pointer. */ |
139 | |
140 | /* Call the user's function. */ |
141 | jal t9 |
142 | |
143 | move a0,v0 |
144 | li v0,__NR_exit |
145 | syscall |
146 | |
147 | END(__thread_start) |
148 | |
149 | libc_hidden_def (__clone) |
150 | weak_alias (__clone, clone) |
151 | |