summaryrefslogtreecommitdiff
path: root/libc
diff options
context:
space:
mode:
Diffstat (limited to 'libc')
-rw-r--r--libc/sysdeps/linux/mips/clone.S156
1 files changed, 97 insertions, 59 deletions
diff --git a/libc/sysdeps/linux/mips/clone.S b/libc/sysdeps/linux/mips/clone.S
index a53d5c492..7148e9d2c 100644
--- a/libc/sysdeps/linux/mips/clone.S
+++ b/libc/sysdeps/linux/mips/clone.S
@@ -1,6 +1,6 @@
-/* Copyright (C) 1996, 1997, 2000 Free Software Foundation, Inc.
+/* Copyright (C) 1996, 1997, 2000, 2003, 2005 Free Software Foundation, Inc.
This file is part of the GNU C Library.
- Contributed by Ralf Baechle <ralf@gnu.ai.mit.edu>, 1996.
+ Contributed by Ralf Baechle <ralf@linux-mips.org>, 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
@@ -21,35 +21,43 @@
and invokes a function in the right context after its all over. */
#include <features.h>
-#include <asm/unistd.h>
-#include <sys/regdef.h>
-#define _ERRNO_H 1
-#include <bits/errno.h>
#include <sys/asm.h>
+#include <sysdep.h>
+#define _ERRNO_H 1
+#include <bits/errno.h>
+#ifdef RESET_PID
+#include <tls.h>
+#endif
-/* int clone(int (*fn)(void *arg), void *child_stack, int flags, void *arg) */
+#define CLONE_VM 0x00000100
+#define CLONE_THREAD 0x00010000
+
+/* int clone(int (*fn)(void *arg), void *child_stack, int flags, void *arg,
+ void *parent_tidptr, void *tls, void *child_tidptr) */
.text
-.globl clone ;
- .align 2;
- .type clone,@function;
- .ent clone, 0;
-
-clone:
- .frame sp, 4*SZREG, sp
-#ifdef __PIC__
-#if _MIPS_SIM == _MIPS_SIM_ABI32
- .set noreorder
- .cpload $25
- .set reorder
- subu sp,32
- .cprestore 16
-#else /* N32 */
- PTR_SUBU sp,32 /* fn, arg, gp, pad */
- .cpsetup $25, 16, clone
-#endif /* N32 */
+#if _MIPS_SIM == _ABIO32
+# define EXTRA_LOCALS 1
#else
- subu sp,32
+# define EXTRA_LOCALS 0
+#endif
+LOCALSZ= 4
+FRAMESZ= (((NARGSAVE+LOCALSZ)*SZREG)+ALSZ)&ALMASK
+GPOFF= FRAMESZ-(1*SZREG)
+NESTED(clone,4*SZREG,sp)
+#ifdef __PIC__
+ SETUP_GP
+#endif
+ PTR_SUBU sp, FRAMESZ
+ SETUP_GP64 (GPOFF, clone)
+#ifdef __PIC__
+ SAVE_GP (GPOFF)
+#endif
+#ifdef PROF
+ .set noat
+ move $1,ra
+ jal _mcount
+ .set at
#endif
@@ -58,64 +66,78 @@ clone:
beqz a0,L(error) /* No NULL function pointers. */
beqz a1,L(error) /* No NULL stack pointers. */
-#if _MIPS_SIM != _MIPS_SIM_ABI32
- and a1,~(16-1) /* force alignment */
-#endif
PTR_SUBU a1,32 /* Reserve argument save space. */
PTR_S a0,0(a1) /* Save function pointer. */
PTR_S a3,PTRSIZE(a1) /* Save argument pointer. */
+#ifdef RESET_PID
+ LONG_S a2,(PTRSIZE*2)(a1) /* Save clone flags. */
+#endif
+ move a0,a2
+
+ /* Shuffle in the last three arguments - arguments 5, 6, and 7 to
+ this function, but arguments 3, 4, and 5 to the syscall. */
+#if _MIPS_SIM == _ABIO32
+ PTR_L a2,(FRAMESZ+PTRSIZE+PTRSIZE+16)(sp)
+ PTR_S a2,16(sp)
+ PTR_L a2,(FRAMESZ+16)(sp)
+ PTR_L a3,(FRAMESZ+PTRSIZE+16)(sp)
+#else
+ move a2,a4
+ move a3,a5
+ move a4,a6
+#endif
/* Do the system call */
- move a0,a2
li v0,__NR_clone
syscall
bnez a3,L(error)
- beqz v0,L(__thread_start)
+ beqz v0,L(thread_start)
/* Successful return from the parent */
-#if _MIPS_SIM != _MIPS_SIM_ABI32
- .cpreturn
-#endif
- PTR_ADDU sp,32
+ RESTORE_GP64
+ PTR_ADDU sp, FRAMESZ
j $31 ; nop
/* Something bad happened -- no child created */
L(error):
-#if _MIPS_SIM != _MIPS_SIM_ABI32
- .cpreturn
-#endif
- PTR_ADDU sp,32
-
- /* uClibc change -- start */
- move a0,v0 /* Pass return val to C function. */
- /* uClibc change -- stop */
-
#ifdef __PIC__
PTR_LA t9,__syscall_error
+ RESTORE_GP64
+ PTR_ADDU sp, FRAMESZ
+ /* uClibc change -- start */
+ move a0,v0 /* Pass return val to C function. */
+ /* uClibc change -- stop */
jr t9
#else
+ RESTORE_GP64
+ PTR_ADDU sp, FRAMESZ
+ /* uClibc change -- start */
+ move a0,v0 /* Pass return val to C function. */
+ /* uClibc change -- stop */
j __syscall_error
#endif
- .end clone
+ END(clone)
/* Load up the arguments to the function. Put this block of code in
its own function so that we can terminate the stack trace with our
debug info. */
- .globl __thread_start;
- .align 2;
- .ent __thread_start, 0;
-
-__thread_start:
-L(__thread_start):
-#if _MIPS_SIM == _MIPS_SIM_ABI32
- .frame sp, 24, sp
+ENTRY(__thread_start)
+L(thread_start):
/* cp is already loaded. */
- .cprestore 16
-#endif
+ SAVE_GP (GPOFF)
/* The stackframe has been created on entry of clone(). */
+
+#ifdef RESET_PID
+ /* Check and see if we need to reset the PID. */
+ LONG_L a0,(PTRSIZE*2)(sp)
+ and a1,a0,CLONE_THREAD
+ beqz a1,L(restore_pid)
+L(donepid):
+#endif
+
/* Restore the arg for user's function. */
PTR_L t9,0(sp) /* Function pointer. */
PTR_L a0,PTRSIZE(sp) /* Argument pointer. */
@@ -126,10 +148,26 @@ L(__thread_start):
/* Call _exit rather than doing it inline for breakpoint purposes. */
move a0,v0
#ifdef __PIC__
- PTR_LA t9,_exit
- jalr t9
+ PTR_LA t9,_exit
+ jalr t9
#else
- jal _exit
+ jal _exit
#endif
- .end __thread_start
+
+#ifdef RESET_PID
+L(restore_pid):
+ and a1,a0,CLONE_VM
+ li v0,-1
+ bnez a1,L(gotpid)
+ li v0,__NR_getpid
+ syscall
+L(gotpid):
+ READ_THREAD_POINTER(v1)
+ INT_S v0,PID_OFFSET(v1)
+ INT_S v0,TID_OFFSET(v1)
+ b L(donepid)
+#endif
+
+ END(__thread_start)
+
weak_alias(clone, __clone)