]>
Commit | Line | Data |
---|---|---|
a334319f | 1 | /* Copyright (C) 2000, 2001, 2003, 2004 Free Software Foundation, Inc. |
41bdb6e2 | 2 | This file is part of the GNU C Library. |
101c92fc UD |
3 | |
4 | The GNU C Library is free software; you can redistribute it and/or | |
41bdb6e2 AJ |
5 | modify it under the terms of the GNU Lesser General Public |
6 | License as published by the Free Software Foundation; either | |
7 | version 2.1 of the License, or (at your option) any later version. | |
101c92fc UD |
8 | |
9 | The GNU C Library is distributed in the hope that it will be useful, | |
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
41bdb6e2 | 12 | Lesser General Public License for more details. |
101c92fc | 13 | |
41bdb6e2 AJ |
14 | You should have received a copy of the GNU Lesser General Public |
15 | License along with the GNU C Library; if not, write to the Free | |
16 | Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA | |
17 | 02111-1307 USA. */ | |
101c92fc UD |
18 | |
19 | ||
20 | #include <sysdep.h> | |
21 | #include <asm/errno.h> | |
22 | ||
23 | ||
24 | /* int __clone2(int (*fn) (void *arg), void *child_stack_base, */ | |
625f22fc | 25 | /* size_t child_stack_size, int flags, void *arg, */ |
b33e6163 | 26 | /* pid_t *parent_tid, void *tls, pid_t *child_tid) */ |
101c92fc | 27 | |
c776b3d7 UD |
28 | #define CHILD p8 |
29 | #define PARENT p9 | |
30 | ||
101c92fc | 31 | ENTRY(__clone2) |
c776b3d7 | 32 | .prologue |
484cc801 | 33 | alloc r2=ar.pfs,8,1,6,0 |
4c48dc93 | 34 | cmp.eq p6,p0=0,in0 |
101c92fc | 35 | mov r8=EINVAL |
4c48dc93 UD |
36 | mov out0=in3 /* Flags are first syscall argument. */ |
37 | mov out1=in1 /* Stack address. */ | |
a334319f | 38 | (p6) br.cond.spnt.many __syscall_error |
c776b3d7 | 39 | ;; |
4c48dc93 | 40 | mov out2=in2 /* Stack size. */ |
b5ec5617 UD |
41 | mov out3=in5 /* Parent TID Pointer */ |
42 | mov out4=in7 /* Child TID Pointer */ | |
b33e6163 | 43 | mov out5=in6 /* TLS pointer */ |
c776b3d7 UD |
44 | /* |
45 | * clone2() is special: the child cannot execute br.ret right | |
46 | * after the system call returns, because it starts out | |
47 | * executing on an empty stack. Because of this, we can't use | |
48 | * the new (lightweight) syscall convention here. Instead, we | |
49 | * just fall back on always using "break". | |
50 | * | |
51 | * Furthermore, since the child starts with an empty stack, we | |
52 | * need to avoid unwinding past invalid memory. To that end, | |
53 | * we'll pretend now that __clone2() is the end of the | |
54 | * call-chain. This is wrong for the parent, but only until | |
55 | * it returns from clone2() but it's better than the | |
56 | * alternative. | |
57 | */ | |
58 | mov r15=SYS_ify (clone2) | |
59 | .save rp, r0 | |
60 | break __BREAK_SYSCALL | |
61 | .body | |
101c92fc | 62 | cmp.eq p6,p0=-1,r10 |
c776b3d7 UD |
63 | cmp.eq CHILD,PARENT=0,r8 /* Are we the child? */ |
64 | (p6) br.cond.spnt.many __syscall_error | |
101c92fc | 65 | ;; |
484cc801 | 66 | (CHILD) mov loc0=gp |
101c92fc UD |
67 | (PARENT) ret |
68 | ;; | |
484cc801 UD |
69 | #ifdef RESET_PID |
70 | tbit.nz p6,p0=in3,16 /* CLONE_THREAD */ | |
71 | tbit.z p7,p10=in3,8 /* CLONE_VM */ | |
72 | (p6) br.cond.dptk 1f | |
73 | ;; | |
74 | mov r15=SYS_ify (getpid) | |
75 | (p10) addl r8=-1,r0 | |
76 | (p7) break __BREAK_SYSCALL | |
77 | ;; | |
78 | add r9=PID,r13 | |
79 | add r10=TID,r13 | |
80 | ;; | |
81 | st4 [r9]=r8 | |
82 | st4 [r10]=r8 | |
83 | ;; | |
84 | #endif | |
85 | 1: ld8 out1=[in0],8 /* Retrieve code pointer. */ | |
86 | mov out0=in4 /* Pass proper argument to fn */ | |
87 | ;; | |
c776b3d7 | 88 | ld8 gp=[in0] /* Load function gp. */ |
4c48dc93 | 89 | mov b6=out1 |
c776b3d7 | 90 | br.call.dptk.many rp=b6 /* Call fn(arg) in the child */ |
101c92fc | 91 | ;; |
4c48dc93 | 92 | mov out0=r8 /* Argument to _exit */ |
484cc801 | 93 | mov gp=loc0 |
ab8dc78f UD |
94 | .globl HIDDEN_JUMPTARGET(_exit) |
95 | br.call.dpnt.many rp=HIDDEN_JUMPTARGET(_exit) | |
96 | /* call _exit with result from fn. */ | |
101c92fc | 97 | ret /* Not reached. */ |
101c92fc UD |
98 | PSEUDO_END(__clone2) |
99 | ||
100 | /* For now we leave __clone undefined. This is unlikely to be a */ | |
101 | /* problem, since at least the i386 __clone in glibc always failed */ | |
102 | /* with a 0 sp (eventhough the kernel explicitly handled it). */ | |
103 | /* Thus all such calls needed to pass an explicit sp, and as a result, */ | |
104 | /* would be unlikely to work on ia64. */ |