Updated to fedora-glibc-20060426T2000
[kopensolaris-gnu/glibc.git] / sysdeps / unix / sysv / linux / ia64 / clone2.S
1 /* Copyright (C) 2000, 2001, 2003, 2004, 2006 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3
4    The GNU C Library is free software; you can redistribute it and/or
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.
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
12    Lesser General Public License for more details.
13
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.  */
18
19
20 #include <sysdep.h>
21 #include <asm/errno.h>
22
23
24 /* int  __clone2(int (*fn) (void *arg), void *child_stack_base,         */
25 /*               size_t child_stack_size, int flags, void *arg,         */
26 /*               pid_t *parent_tid, void *tls, pid_t *child_tid)        */
27
28 #define CHILD   p8
29 #define PARENT  p9
30
31 ENTRY(__clone2)
32         .prologue
33         alloc r2=ar.pfs,8,1,6,0
34         cmp.eq p6,p0=0,in0
35         cmp.eq p7,p0=0,in1
36         mov r8=EINVAL
37         mov out0=in3            /* Flags are first syscall argument.    */
38         mov out1=in1            /* Stack address.                       */
39 (p6)    br.cond.spnt.many __syscall_error       /* no NULL function pointers */
40 (p7)    br.cond.spnt.many __syscall_error       /* no NULL stack pointers */
41         ;;
42         mov out2=in2            /* Stack size.                          */
43         mov out3=in5            /* Parent TID Pointer                   */
44         mov out4=in7            /* Child TID Pointer                    */
45         mov out5=in6            /* TLS pointer                          */
46         /*
47          * clone2() is special: the child cannot execute br.ret right
48          * after the system call returns, because it starts out
49          * executing on an empty stack.  Because of this, we can't use
50          * the new (lightweight) syscall convention here.  Instead, we
51          * just fall back on always using "break".
52          *
53          * Furthermore, since the child starts with an empty stack, we
54          * need to avoid unwinding past invalid memory.  To that end,
55          * we'll pretend now that __clone2() is the end of the
56          * call-chain.  This is wrong for the parent, but only until
57          * it returns from clone2() but it's better than the
58          * alternative.
59          */
60         mov r15=SYS_ify (clone2)
61         .save rp, r0
62         break __BREAK_SYSCALL
63         .body
64         cmp.eq p6,p0=-1,r10
65         cmp.eq CHILD,PARENT=0,r8 /* Are we the child?   */
66 (p6)    br.cond.spnt.many __syscall_error
67         ;;
68 (CHILD) mov loc0=gp
69 (PARENT) ret
70         ;;
71 #ifdef RESET_PID
72         tbit.nz p6,p0=in3,16    /* CLONE_THREAD */
73         tbit.z p7,p10=in3,8     /* CLONE_VM */
74 (p6)    br.cond.dptk 1f
75         ;;
76         mov r15=SYS_ify (getpid)
77 (p10)   addl r8=-1,r0
78 (p7)    break __BREAK_SYSCALL
79         ;;
80         add r9=PID,r13
81         add r10=TID,r13
82         ;;
83         st4 [r9]=r8
84         st4 [r10]=r8
85         ;;
86 #endif
87 1:      ld8 out1=[in0],8        /* Retrieve code pointer.       */
88         mov out0=in4            /* Pass proper argument to fn */
89         ;;
90         ld8 gp=[in0]            /* Load function gp.            */
91         mov b6=out1
92         br.call.dptk.many rp=b6 /* Call fn(arg) in the child    */
93         ;;
94         mov out0=r8             /* Argument to _exit            */
95         mov gp=loc0
96         .globl HIDDEN_JUMPTARGET(_exit)
97         br.call.dpnt.many rp=HIDDEN_JUMPTARGET(_exit)
98                                 /* call _exit with result from fn.      */
99         ret                     /* Not reached.         */
100 PSEUDO_END(__clone2)
101
102 /* For now we leave __clone undefined.  This is unlikely to be a        */
103 /* problem, since at least the i386 __clone in glibc always failed      */
104 /* with a 0 sp (eventhough the kernel explicitly handled it).           */
105 /* Thus all such calls needed to pass an explicit sp, and as a result,  */
106 /* would be unlikely to work on ia64.                                   */