Update copyright dates with scripts/update-copyrights.
[glibc.git] / sysdeps / unix / sysv / linux / mips / clone.S
blob4afb9ba64619eaf18daccf00247a8277a2abea6e
1 /* Copyright (C) 1996-2015 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 #include <tls.h>
28 #define CLONE_VM      0x00000100
29 #define CLONE_THREAD  0x00010000
31 /* int clone(int (*fn)(void *arg), void *child_stack, int flags, void *arg,
32              void *parent_tidptr, void *tls, void *child_tidptr) */
34         .text
35         .set            nomips16
36 #if _MIPS_SIM == _ABIO32
37 # define EXTRA_LOCALS 1
38 #else
39 # define EXTRA_LOCALS 0
40 #endif
41 LOCALSZ= 4
42 FRAMESZ= (((NARGSAVE+LOCALSZ)*SZREG)+ALSZ)&ALMASK
43 GPOFF= FRAMESZ-(1*SZREG)
44 NESTED(__clone,4*SZREG,sp)
45 #ifdef __PIC__
46         SETUP_GP
47 #endif
48         PTR_SUBU sp, FRAMESZ
49         cfi_adjust_cfa_offset (FRAMESZ)
50         SETUP_GP64_STACK (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         LONG_S          a2,(PTRSIZE*2)(a1)      /* Save clone flags.  */
72         move            a0,a2
74         /* Shuffle in the last three arguments - arguments 5, 6, and 7 to
75            this function, but arguments 3, 4, and 5 to the syscall.  */
76 #if _MIPS_SIM == _ABIO32
77         PTR_L           a2,(FRAMESZ+PTRSIZE+PTRSIZE+16)(sp)
78         PTR_S           a2,16(sp)
79         PTR_L           a2,(FRAMESZ+16)(sp)
80         PTR_L           a3,(FRAMESZ+PTRSIZE+16)(sp)
81 #else
82         move            a2,a4
83         move            a3,a5
84         move            a4,a6
85 #endif
87         /* Do the system call */
88         li              v0,__NR_clone
89         cfi_endproc
90         syscall
92         bnez            a3,L(error)
93         beqz            v0,L(thread_start)
95         /* Successful return from the parent */
96         cfi_startproc
97         cfi_adjust_cfa_offset (FRAMESZ)
98         SETUP_GP64_STACK_CFI (GPOFF)
99         cfi_remember_state
100         RESTORE_GP64_STACK
101         PTR_ADDU        sp, FRAMESZ
102         cfi_adjust_cfa_offset (-FRAMESZ)
103         ret
105         /* Something bad happened -- no child created */
106 L(error):
107         cfi_restore_state
108 #ifdef __PIC__
109         PTR_LA          t9,__syscall_error
110         RESTORE_GP64_STACK
111         PTR_ADDU        sp, FRAMESZ
112         cfi_adjust_cfa_offset (-FRAMESZ)
113         jr              t9
114 #else
115         RESTORE_GP64_STACK
116         PTR_ADDU        sp, FRAMESZ
117         cfi_adjust_cfa_offset (-FRAMESZ)
118         j               __syscall_error
119 #endif
120         END(__clone)
122 /* Load up the arguments to the function.  Put this block of code in
123    its own function so that we can terminate the stack trace with our
124    debug info.  */
126 ENTRY(__thread_start)
127 L(thread_start):
128         cfi_undefined ($31)
129         /* cp is already loaded.  */
130         SAVE_GP (GPOFF)
131         /* The stackframe has been created on entry of clone().  */
133         /* Check and see if we need to reset the PID.  */
134         LONG_L          a0,(PTRSIZE*2)(sp)
135         and             a1,a0,CLONE_THREAD
136         beqz            a1,L(restore_pid)
137 L(donepid):
139         /* Restore the arg for user's function.  */
140         PTR_L           t9,0(sp)        /* Function pointer.  */
141         PTR_L           a0,PTRSIZE(sp)  /* Argument pointer.  */
143         /* Call the user's function.  */
144         jal             t9
146         /* Call _exit rather than doing it inline for breakpoint purposes.  */
147         move            a0,v0
148 #ifdef __PIC__
149         PTR_LA          t9,_exit
150         jalr            t9
151 #else
152         jal             _exit
153 #endif
155 L(restore_pid):
156         and             a1,a0,CLONE_VM
157         li              v0,-1
158         bnez            a1,L(gotpid)
159         li              v0,__NR_getpid
160         syscall
161 L(gotpid):
162         READ_THREAD_POINTER(v1)
163         INT_S           v0,PID_OFFSET(v1)
164         INT_S           v0,TID_OFFSET(v1)
165         b               L(donepid)
167         END(__thread_start)
169 weak_alias (__clone, clone)