Move all files into ports/ subdirectory in preparation for merge with glibc
[glibc.git] / ports / sysdeps / unix / sysv / linux / mips / clone.S
blobce49cb57d1a5ee05f89a3d9f68e56f743fb2bbb4
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, see
17    <http://www.gnu.org/licenses/>.  */
19 /* clone() is even more special than fork() as it mucks with stacks
20    and invokes a function in the right context after its all over.  */
22 #include <sys/asm.h>
23 #include <sysdep.h>
24 #define _ERRNO_H        1
25 #include <bits/errno.h>
26 #ifdef RESET_PID
27 #include <tls.h>
28 #endif
30 #define CLONE_VM      0x00000100
31 #define CLONE_THREAD  0x00010000
33 /* int clone(int (*fn)(void *arg), void *child_stack, int flags, void *arg,
34              void *parent_tidptr, void *tls, void *child_tidptr) */
36         .text
37 #if _MIPS_SIM == _ABIO32
38 # define EXTRA_LOCALS 1
39 #else
40 # define EXTRA_LOCALS 0
41 #endif
42 LOCALSZ= 4
43 FRAMESZ= (((NARGSAVE+LOCALSZ)*SZREG)+ALSZ)&ALMASK
44 GPOFF= FRAMESZ-(1*SZREG)
45 NESTED(__clone,4*SZREG,sp)
46 #ifdef __PIC__
47         SETUP_GP
48 #endif
49         PTR_SUBU sp, FRAMESZ
50         SETUP_GP64 (GPOFF, __clone)
51 #ifdef __PIC__
52         SAVE_GP (GPOFF)
53 #endif
54 #ifdef PROF
55         .set            noat
56         move            $1,ra
57         jal             _mcount
58         .set            at
59 #endif
62         /* Sanity check arguments.  */
63         li              v0,EINVAL
64         beqz            a0,L(error)     /* No NULL function pointers.  */
65         beqz            a1,L(error)     /* No NULL stack pointers.  */
67         PTR_SUBU        a1,32           /* Reserve argument save space.  */
68         PTR_S           a0,0(a1)        /* Save function pointer.  */
69         PTR_S           a3,PTRSIZE(a1)  /* Save argument pointer.  */
70 #ifdef RESET_PID
71         LONG_S          a2,(PTRSIZE*2)(a1)      /* Save clone flags.  */
72 #endif
74         move            a0,a2
76         /* Shuffle in the last three arguments - arguments 5, 6, and 7 to
77            this function, but arguments 3, 4, and 5 to the syscall.  */
78 #if _MIPS_SIM == _ABIO32
79         PTR_L           a2,(FRAMESZ+PTRSIZE+PTRSIZE+16)(sp)
80         PTR_S           a2,16(sp)
81         PTR_L           a2,(FRAMESZ+16)(sp)
82         PTR_L           a3,(FRAMESZ+PTRSIZE+16)(sp)
83 #else
84         move            a2,a4
85         move            a3,a5
86         move            a4,a6
87 #endif
89         /* Do the system call */
90         li              v0,__NR_clone
91         syscall
93         bnez            a3,L(error)
94         beqz            v0,L(thread_start)
96         /* Successful return from the parent */
97         RESTORE_GP64
98         PTR_ADDU        sp, FRAMESZ
99         ret
101         /* Something bad happened -- no child created */
102 L(error):
103 #ifdef __PIC__
104         PTR_LA          t9,__syscall_error
105         RESTORE_GP64
106         PTR_ADDU        sp, FRAMESZ
107         jr              t9
108 #else
109         RESTORE_GP64
110         PTR_ADDU        sp, FRAMESZ
111         j               __syscall_error
112 #endif
113         END(__clone)
115 /* Load up the arguments to the function.  Put this block of code in
116    its own function so that we can terminate the stack trace with our
117    debug info.  */
119 ENTRY(__thread_start)
120 L(thread_start):
121         /* cp is already loaded.  */
122         SAVE_GP (GPOFF)
123         /* The stackframe has been created on entry of clone().  */
125 #ifdef RESET_PID
126         /* Check and see if we need to reset the PID.  */
127         LONG_L          a0,(PTRSIZE*2)(sp)
128         and             a1,a0,CLONE_THREAD
129         beqz            a1,L(restore_pid)
130 L(donepid):
131 #endif
133         /* Restore the arg for user's function.  */
134         PTR_L           t9,0(sp)        /* Function pointer.  */
135         PTR_L           a0,PTRSIZE(sp)  /* Argument pointer.  */
137         /* Call the user's function.  */
138         jal             t9
140         /* Call _exit rather than doing it inline for breakpoint purposes.  */
141         move            a0,v0
142 #ifdef __PIC__
143         PTR_LA          t9,_exit
144         jalr            t9
145 #else
146         jal             _exit
147 #endif
149 #ifdef RESET_PID
150 L(restore_pid):
151         and             a1,a0,CLONE_VM
152         li              v0,-1
153         bnez            a1,L(gotpid)
154         li              v0,__NR_getpid
155         syscall
156 L(gotpid):
157         READ_THREAD_POINTER(v1)
158         INT_S           v0,PID_OFFSET(v1)
159         INT_S           v0,TID_OFFSET(v1)
160         b               L(donepid)
161 #endif
163         END(__thread_start)
165 weak_alias (__clone, clone)