Update copyright notices with scripts/update-copyrights
[glibc.git] / ports / sysdeps / unix / sysv / linux / mips / clone.S
blobd3fd80f993f2c0609763187a260d061efa2bfaee
1 /* Copyright (C) 1996-2014 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         .set            nomips16
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         cfi_adjust_cfa_offset (FRAMESZ)
52         SETUP_GP64_STACK (GPOFF, __clone)
53 #ifdef __PIC__
54         SAVE_GP (GPOFF)
55 #endif
56 #ifdef PROF
57         .set            noat
58         move            $1,ra
59         jal             _mcount
60         .set            at
61 #endif
64         /* Sanity check arguments.  */
65         li              v0,EINVAL
66         beqz            a0,L(error)     /* No NULL function pointers.  */
67         beqz            a1,L(error)     /* No NULL stack pointers.  */
69         PTR_SUBU        a1,32           /* Reserve argument save space.  */
70         PTR_S           a0,0(a1)        /* Save function pointer.  */
71         PTR_S           a3,PTRSIZE(a1)  /* Save argument pointer.  */
72 #ifdef RESET_PID
73         LONG_S          a2,(PTRSIZE*2)(a1)      /* Save clone flags.  */
74 #endif
76         move            a0,a2
78         /* Shuffle in the last three arguments - arguments 5, 6, and 7 to
79            this function, but arguments 3, 4, and 5 to the syscall.  */
80 #if _MIPS_SIM == _ABIO32
81         PTR_L           a2,(FRAMESZ+PTRSIZE+PTRSIZE+16)(sp)
82         PTR_S           a2,16(sp)
83         PTR_L           a2,(FRAMESZ+16)(sp)
84         PTR_L           a3,(FRAMESZ+PTRSIZE+16)(sp)
85 #else
86         move            a2,a4
87         move            a3,a5
88         move            a4,a6
89 #endif
91         /* Do the system call */
92         li              v0,__NR_clone
93         cfi_endproc
94         syscall
96         bnez            a3,L(error)
97         beqz            v0,L(thread_start)
99         /* Successful return from the parent */
100         cfi_startproc
101         cfi_adjust_cfa_offset (FRAMESZ)
102         SETUP_GP64_STACK_CFI (GPOFF)
103         cfi_remember_state
104         RESTORE_GP64_STACK
105         PTR_ADDU        sp, FRAMESZ
106         cfi_adjust_cfa_offset (-FRAMESZ)
107         ret
109         /* Something bad happened -- no child created */
110 L(error):
111         cfi_restore_state
112 #ifdef __PIC__
113         PTR_LA          t9,__syscall_error
114         RESTORE_GP64_STACK
115         PTR_ADDU        sp, FRAMESZ
116         cfi_adjust_cfa_offset (-FRAMESZ)
117         jr              t9
118 #else
119         RESTORE_GP64_STACK
120         PTR_ADDU        sp, FRAMESZ
121         cfi_adjust_cfa_offset (-FRAMESZ)
122         j               __syscall_error
123 #endif
124         END(__clone)
126 /* Load up the arguments to the function.  Put this block of code in
127    its own function so that we can terminate the stack trace with our
128    debug info.  */
130 ENTRY(__thread_start)
131 L(thread_start):
132         cfi_undefined ($31)
133         /* cp is already loaded.  */
134         SAVE_GP (GPOFF)
135         /* The stackframe has been created on entry of clone().  */
137 #ifdef RESET_PID
138         /* Check and see if we need to reset the PID.  */
139         LONG_L          a0,(PTRSIZE*2)(sp)
140         and             a1,a0,CLONE_THREAD
141         beqz            a1,L(restore_pid)
142 L(donepid):
143 #endif
145         /* Restore the arg for user's function.  */
146         PTR_L           t9,0(sp)        /* Function pointer.  */
147         PTR_L           a0,PTRSIZE(sp)  /* Argument pointer.  */
149         /* Call the user's function.  */
150         jal             t9
152         /* Call _exit rather than doing it inline for breakpoint purposes.  */
153         move            a0,v0
154 #ifdef __PIC__
155         PTR_LA          t9,_exit
156         jalr            t9
157 #else
158         jal             _exit
159 #endif
161 #ifdef RESET_PID
162 L(restore_pid):
163         and             a1,a0,CLONE_VM
164         li              v0,-1
165         bnez            a1,L(gotpid)
166         li              v0,__NR_getpid
167         syscall
168 L(gotpid):
169         READ_THREAD_POINTER(v1)
170         INT_S           v0,PID_OFFSET(v1)
171         INT_S           v0,TID_OFFSET(v1)
172         b               L(donepid)
173 #endif
175         END(__thread_start)
177 weak_alias (__clone, clone)