Home | History | Annotate | Download | only in bionic
      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