1 /* 2 * Copyright (C) 2008-2010 The Android Open Source Project 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in 12 * the documentation and/or other materials provided with the 13 * distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 17 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 18 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 19 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 22 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 25 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 #include <linux/err.h> 30 #include <machine/asm.h> 31 #include <asm/unistd.h> 32 33 // int __pthread_clone(void* (*fn)(void*), void* child_stack, int flags, void* arg); 34 ENTRY(__pthread_clone) 35 # Copy the args onto the new stack. 36 stmdb r1!, {r0, r3} 37 38 # The sys_clone system call only takes two arguments: 'flags' and 'child_stack'. 39 # 'child_stack' is already in r1, but we need to move 'flags' into position. 40 mov r0, r2 41 stmfd sp!, {r4, r7} 42 43 # System call. 44 ldr r7, =__NR_clone 45 swi #0 46 movs r0, r0 47 beq 1f 48 49 # In parent, reload saved registers then either return or set errno. 50 ldmfd sp!, {r4, r7} 51 cmn r0, #(MAX_ERRNO + 1) 52 bxls lr 53 neg r0, r0 54 b __set_errno 55 56 1: # The child. 57 # pick the function arg and call address off the stack and jump 58 # to the C __thread_entry function which does some setup and then 59 # calls the thread's start function 60 pop {r0, r1} 61 # __thread_entry needs the TLS pointer 62 mov r2, sp 63 b __thread_entry 64 END(__pthread_clone) 65 66 67 # 68 # This function is defined as: 69 # 70 # pid_t __bionic_clone( int flags, void *child_stack, 71 # pid_t *pid, void *tls, pid_t *ctid, 72 # int (*fn)(void *), void* arg ); 73 # 74 # NOTE: This is not the same signature as the glibc 75 # __clone function. Placing 'fn' and 'arg' 76 # at the end of the parameter list makes the 77 # implementation much simpler. 78 # 79 80 ENTRY(__bionic_clone) 81 mov ip, sp 82 .save {r4, r5, r6, r7} 83 84 # save registers to parent stack 85 stmfd sp!, {r4, r5, r6, r7} 86 87 # load extra parameters 88 ldmfd ip, {r4, r5, r6} 89 90 # store 'fn' and 'arg' to the child stack 91 str r5, [r1, #-4] 92 str r6, [r1, #-8] 93 94 # System call 95 ldr r7, =__NR_clone 96 swi #0 97 movs r0, r0 98 beq 1f 99 100 # In the parent, reload saved registers then either return or set errno. 101 ldmfd sp!, {r4, r5, r6, r7} 102 cmn r0, #(MAX_ERRNO + 1) 103 bxls lr 104 neg r0, r0 105 b __set_errno 106 107 1: # The child. 108 ldr r0, [sp, #-4] 109 ldr r1, [sp, #-8] 110 b __bionic_clone_entry 111 END(__bionic_clone) 112