]>
Commit | Line | Data |
---|---|---|
f850220b | 1 | /* Copyright (C) 1996, 1997, 2000, 2003, 2005 Free Software Foundation, Inc. |
a334319f UD |
2 | This file is part of the GNU C Library. |
3 | Contributed by Ralf Baechle <ralf@linux-mips.org>, 1996. | |
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, write to the Free | |
17 | Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA | |
18 | 02111-1307 USA. */ | |
19 | ||
20 | /* clone() is even more special than fork() as it mucks with stacks | |
21 | and invokes a function in the right context after its all over. */ | |
22 | ||
23 | #include <sys/asm.h> | |
24 | #include <sysdep.h> | |
25 | #define _ERRNO_H 1 | |
26 | #include <bits/errno.h> | |
f850220b AJ |
27 | #ifdef RESET_PID |
28 | #include <tls.h> | |
29 | #endif | |
30 | ||
31 | #define CLONE_VM 0x00000100 | |
32 | #define CLONE_THREAD 0x00010000 | |
a334319f | 33 | |
f850220b AJ |
34 | /* int clone(int (*fn)(void *arg), void *child_stack, int flags, void *arg, |
35 | void *parent_tidptr, void *tls, void *child_tidptr) */ | |
a334319f UD |
36 | |
37 | .text | |
f850220b AJ |
38 | #if _MIPS_SIM == _ABIO32 |
39 | # define EXTRA_LOCALS 1 | |
40 | #else | |
41 | # define EXTRA_LOCALS 0 | |
42 | #endif | |
43 | LOCALSZ= 4 | |
a334319f UD |
44 | FRAMESZ= (((NARGSAVE+LOCALSZ)*SZREG)+ALSZ)&ALMASK |
45 | GPOFF= FRAMESZ-(1*SZREG) | |
46 | NESTED(__clone,4*SZREG,sp) | |
47 | #ifdef __PIC__ | |
48 | SETUP_GP | |
49 | #endif | |
50 | PTR_SUBU sp, FRAMESZ | |
51 | SETUP_GP64 (GPOFF, __clone) | |
52 | #ifdef __PIC__ | |
53 | SAVE_GP (GPOFF) | |
54 | #endif | |
55 | #ifdef PROF | |
56 | .set noat | |
57 | move $1,ra | |
58 | jal _mcount | |
59 | .set at | |
60 | #endif | |
61 | ||
62 | ||
63 | /* Sanity check arguments. */ | |
64 | li v0,EINVAL | |
65 | beqz a0,L(error) /* No NULL function pointers. */ | |
66 | beqz a1,L(error) /* No NULL stack pointers. */ | |
67 | ||
68 | PTR_SUBU a1,32 /* Reserve argument save space. */ | |
69 | PTR_S a0,0(a1) /* Save function pointer. */ | |
70 | PTR_S a3,PTRSIZE(a1) /* Save argument pointer. */ | |
f850220b AJ |
71 | #ifdef RESET_PID |
72 | LONG_S a2,(PTRSIZE*2)(a1) /* Save clone flags. */ | |
73 | #endif | |
a334319f | 74 | |
f850220b AJ |
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 | |
a334319f UD |
89 | |
90 | /* Do the system call */ | |
a334319f UD |
91 | li v0,__NR_clone |
92 | syscall | |
93 | ||
94 | bnez a3,L(error) | |
95 | beqz v0,L(thread_start) | |
96 | ||
97 | /* Successful return from the parent */ | |
98 | RESTORE_GP64 | |
99 | PTR_ADDU sp, FRAMESZ | |
100 | ret | |
101 | ||
102 | /* Something bad happened -- no child created */ | |
103 | L(error): | |
104 | #ifdef __PIC__ | |
105 | PTR_LA t9,__syscall_error | |
106 | RESTORE_GP64 | |
107 | PTR_ADDU sp, FRAMESZ | |
108 | jr t9 | |
109 | #else | |
110 | RESTORE_GP64 | |
111 | PTR_ADDU sp, FRAMESZ | |
112 | j __syscall_error | |
113 | #endif | |
114 | END(__clone) | |
115 | ||
116 | /* Load up the arguments to the function. Put this block of code in | |
117 | its own function so that we can terminate the stack trace with our | |
118 | debug info. */ | |
119 | ||
120 | ENTRY(__thread_start) | |
121 | L(thread_start): | |
122 | /* cp is already loaded. */ | |
123 | SAVE_GP (GPOFF) | |
124 | /* The stackframe has been created on entry of clone(). */ | |
f850220b AJ |
125 | |
126 | #ifdef RESET_PID | |
127 | /* Check and see if we need to reset the PID. */ | |
128 | LONG_L a0,(PTRSIZE*2)(sp) | |
129 | and a1,a0,CLONE_THREAD | |
130 | beqz a1,L(restore_pid) | |
131 | L(donepid): | |
132 | #endif | |
133 | ||
a334319f UD |
134 | /* Restore the arg for user's function. */ |
135 | PTR_L t9,0(sp) /* Function pointer. */ | |
136 | PTR_L a0,PTRSIZE(sp) /* Argument pointer. */ | |
137 | ||
138 | /* Call the user's function. */ | |
139 | jal t9 | |
140 | ||
141 | /* Call _exit rather than doing it inline for breakpoint purposes. */ | |
142 | move a0,v0 | |
143 | #ifdef __PIC__ | |
144 | PTR_LA t9,_exit | |
145 | jalr t9 | |
146 | #else | |
147 | jal _exit | |
148 | #endif | |
f850220b AJ |
149 | |
150 | #ifdef RESET_PID | |
151 | L(restore_pid): | |
152 | and a1,a0,CLONE_VM | |
153 | li v0,-1 | |
154 | bnez a1,L(gotpid) | |
155 | li v0,__NR_getpid | |
156 | syscall | |
157 | L(gotpid): | |
158 | READ_THREAD_POINTER(v1) | |
159 | INT_S v0,PID_OFFSET(v1) | |
160 | INT_S v0,TID_OFFSET(v1) | |
161 | b L(donepid) | |
162 | #endif | |
163 | ||
a334319f UD |
164 | END(__thread_start) |
165 | ||
1ab18a5b | 166 | weak_alias (__clone, clone) |