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