Update.
[glibc.git] / sysdeps / unix / sysv / linux / mips / clone.S
blob8b8e0072f555a5f03902b5ae0060f359418ca2a9
1 /* Copyright (C) 1996, 1997, 2000, 2003, 2005 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3    Contributed by Ralf Baechle <ralf@linux-mips.org>, 1996.
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.
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.
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.  */
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.  */
23 #include <sys/asm.h>
24 #include <sysdep.h>
25 #define _ERRNO_H        1
26 #include <bits/errno.h>
27 #ifdef RESET_PID
28 #include <tls.h>
29 #endif
31 #define CLONE_VM      0x00000100
32 #define CLONE_THREAD  0x00010000
34 /* int clone(int (*fn)(void *arg), void *child_stack, int flags, void *arg,
35              void *parent_tidptr, void *tls, void *child_tidptr) */
37         .text
38 #if _MIPS_SIM == _ABIO32
39 # define EXTRA_LOCALS 1
40 #else
41 # define EXTRA_LOCALS 0
42 #endif
43 LOCALSZ= 4
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
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.  */
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.  */
71 #ifdef RESET_PID
72         LONG_S          a2,(PTRSIZE*2)(a1)      /* Save clone flags.  */
73 #endif
75         move            a0,a2
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
90         /* Do the system call */
91         li              v0,__NR_clone
92         syscall
94         bnez            a3,L(error)
95         beqz            v0,L(thread_start)
97         /* Successful return from the parent */
98         RESTORE_GP64
99         PTR_ADDU        sp, FRAMESZ
100         ret
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)
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.  */
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().  */
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
134         /* Restore the arg for user's function.  */
135         PTR_L           t9,0(sp)        /* Function pointer.  */
136         PTR_L           a0,PTRSIZE(sp)  /* Argument pointer.  */
138         /* Call the user's function.  */
139         jal             t9
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
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
164         END(__thread_start)
166 weak_alias(__clone, clone)