/* Copyright (C) 1996, 1997, 2000 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by David Huggins-Daines , 2000. Based on the Alpha version by Richard Henderson , 1996. The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The GNU C Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with the GNU C Library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ /* clone() is even more special than fork() as it mucks with stacks and invokes a function in the right context after its all over. */ #include #include #define _ERRNO_H 1 #include /* Non-thread code calls __clone with the following parameters: int clone(int (*fn)(void *arg), void *child_stack, int flags, void *arg) NPTL Code will call __clone with the following parameters: int clone(int (*fn)(void *arg), void *child_stack, int flags, void *arg, int *parent_tidptr, struct user_desc *newtls, int *child_pidptr) The code should not mangle the extra input registers. Syscall expects: Input to __clone: 4(r25) - function pointer (r26, arg0) 0(r25) - argument (r23, arg3) r26 - clone flags. (r24, arg2) r25+64 - user stack pointer. (r25, arg1) r24 - parent tid pointer. (stack - 52) r23 - struct user_desc newtls pointer. (stack - 56) r22 - child tid pointer. (stack - 60) r20 - clone syscall number (constant) Return: On success the thread ID of the child process is returend in the callers context. On error return -1, and set errno to the value returned by the syscall. */ .text ENTRY(__clone) /* Prologue */ stwm %r4, 64(%sp) stw %sp, -4(%sp) #ifdef PIC stw %r19, -32(%sp) #endif /* Sanity check arguments. */ comib,=,n 0, %arg0, .LerrorSanity /* no NULL function pointers */ comib,=,n 0, %arg1, .LerrorSanity /* no NULL stack pointers */ /* Save the function pointer, arg, and flags on the new stack. */ stwm %r26, 64(%r25) stw %r23, -60(%r25) stw %r24, -56(%r25) /* Clone arguments are (int flags, void * child_stack) */ copy %r24, %r26 /* flags are first */ /* User stack pointer is in the correct register already */ /* Load args from stack... */ ldw -116(%sp), %r24 /* Load parent_tidptr */ ldw -120(%sp), %r23 /* Load newtls */ ldw -124(%sp), %r22 /* Load child_tidptr */ /* Save the PIC register. */ #ifdef PIC copy %r19, %r4 /* parent */ #endif /* Do the system call */ ble 0x100(%sr2, %r0) ldi __NR_clone, %r20 ldi -4096, %r1 comclr,>>= %r1, %ret0, %r0 /* Note: unsigned compare. */ b,n .LerrorRest /* Restore the PIC register. */ #ifdef PIC copy %r4, %r19 /* parent */ #endif comib,=,n 0, %ret0, .LthreadStart /* Successful return from the parent No need to restore the PIC register, since we return immediately. */ ldw -84(%sp), %rp bv %r0(%rp) ldwm -64(%sp), %r4 .LerrorRest: /* Something bad happened -- no child created */ bl __syscall_error, %rp sub %r0, %ret0, %arg0 ldw -84(%sp), %rp /* Return after setting errno, ret0 is set to -1 by __syscall_error. */ bv %r0(%rp) ldwm -64(%sp), %r4 .LerrorSanity: /* Sanity checks failed, return -1, and set errno to EINVAL. */ bl __syscall_error, %rp ldi EINVAL, %arg0 ldw -84(%sp), %rp bv %r0(%rp) ldwm -64(%sp), %r4 .LthreadStart: #ifdef RESET_PID # define CLONE_VM_BIT 23 /* 0x00000100 */ # define CLONE_THREAD_BIT 15 /* 0x00010000 */ /* Load original clone flags. If CLONE_THREAD was passed, don't reset the PID/TID. If CLONE_VM was passed, we need to store -1 to PID/TID. If CLONE_VM and CLONE_THREAD were not set store the result of getpid to PID/TID. */ ldw -56(%sp), %r26 bb,<,n %r26, CLONE_THREAD_BIT, 1f bb,< %r26, CLONE_VM_BIT, 2f ldi -1, %ret0 ble 0x100(%sr2, %r0) ldi __NR_getpid, %r20 2: mfctl %cr27, %r26 stw %ret0, PID_THREAD_OFFSET(%r26) stw %ret0, TID_THREAD_OFFSET(%r26) 1: #endif /* Load up the arguments. */ ldw -60(%sp), %arg0 ldw -64(%sp), %r22 /* $$dyncall fixes childs PIC register */ /* Call the user's function */ #ifdef PIC copy %r19, %r4 #endif bl $$dyncall, %r31 copy %r31, %rp #ifdef PIC copy %r4, %r19 #endif /* The call to _exit needs saved r19. */ bl _exit, %rp copy %ret0, %arg0 /* We should not return from _exit. We do not restore r4, or the stack state. */ iitlbp %r0, (%sr0, %r0) PSEUDO_END(__clone) weak_alias (__clone, clone)