diff options
Diffstat (limited to 'libc/sysdeps/linux/nds32/clone.S')
-rw-r--r-- | libc/sysdeps/linux/nds32/clone.S | 200 |
1 files changed, 144 insertions, 56 deletions
diff --git a/libc/sysdeps/linux/nds32/clone.S b/libc/sysdeps/linux/nds32/clone.S index 5dba17896..1ed77fb2e 100644 --- a/libc/sysdeps/linux/nds32/clone.S +++ b/libc/sysdeps/linux/nds32/clone.S @@ -1,92 +1,180 @@ /* - * Copyright (C) 2016 Andes Technology, Inc. + * Copyright (C) 2016-2017 Andes Technology, Inc. * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. */ +/* Copyright (C) 2010-2014 Free Software Foundation, Inc. + Contributed by Pat Beirne <patb@corelcomputer.com> + + 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 <sysdep.h> -#include <sys/syscall.h> #define _ERRNO_H 1 #include <bits/errno.h> -/* - int clone(int (*fn)(void *), void *child_stack, int flags, void *arg); - _syscall2(int, clone, int, flags, void *, child_stack) -*/ +#ifdef RESET_PID +#include <tcb-offsets.h> +#endif + +#define CLONE_VM 0x00000100 +#define CLONE_THREAD 0x00010000 + +/* int clone(int (*fn)(void *), void *child_stack, int flags, void *arg); + _syscall2(int, clone, int, flags, void *, child_stack) */ ENTRY(__clone) +#ifdef __NDS32_ABI_2FP_PLUS__ + lwi $r4, [$sp] + lwi $r5, [$sp+4] +#endif #ifdef PIC /* set GP register to parent only, cause child's $SP will be $r1. */ pushm $fp, $gp -#ifndef __NDS32_N1213_43U1H__ - mfusr $r15, $PC -#endif - sethi $gp, hi20(_GLOBAL_OFFSET_TABLE_+4) - ori $gp, $gp, lo12(_GLOBAL_OFFSET_TABLE_+8) - add $gp, $gp, $r15 -#endif - /* sanity check arguments. */ - beqz $r0, 1f - bnez $r1, 2f + cfi_adjust_cfa_offset(8) + cfi_rel_offset(fp, 0) + cfi_rel_offset(gp, 4) + mfusr $r15, $pc + sethi $gp, hi20(_GLOBAL_OFFSET_TABLE_+4) + ori $gp, $gp, lo12(_GLOBAL_OFFSET_TABLE_+8) + add $gp, $gp, $r15 +#endif /* PIC */ + + /* sanity check arguments. */ + beqz $r0, 1f + bnez $r1, 2f 1: - movi $r0, -EINVAL + movi $r0, -EINVAL + 5: #ifdef PIC - /* restore GP register, only in parent's stack */ - popm $fp, $gp - la $r15, C_SYMBOL_NAME(__syscall_error@PLT) - jr $r15 -#else - b C_SYMBOL_NAME(__syscall_error) -#endif + /* restore GP register, only in parent's stack */ + la $r15, C_SYMBOL_NAME(__syscall_error@PLT) + push $lp + cfi_adjust_cfa_offset(4) + cfi_rel_offset(lp, 0) + addi $sp, $sp, -4 + cfi_adjust_cfa_offset(4) + jral $r15 + addi $sp, $sp, 4 + cfi_adjust_cfa_offset(-4) + pop $lp + cfi_adjust_cfa_offset(-4) + cfi_restore(lp) + popm $fp, $gp + cfi_adjust_cfa_offset(-8) + cfi_restore(fp) + cfi_restore(gp) + ret +#else /* ! PIC */ + la $r15, C_SYMBOL_NAME(__syscall_error) + jr $r15 +#endif /* ! PIC */ 2: - /* Child's $SP will be $r1, push to child's stack only. */ + /* Child's $sp will be $r1, make $sp 8-byte alignment */ + bitci $r1, $r1, 7 + /* push to child's stack only. */ addi $r1, $r1, -4 - swi.p $r3, [$r1], -4 ! arg - swi $r0, [$r1] ! fn + swi.p $r3, [$r1], -4 ! arg + swi $r0, [$r1] ! fn + + /* do the system call */ + or $r0, $r2, $r2 ! move $r0, $r2 + + move $r3, $r5 + move $r5, $r2 ! Use $r5 to backup $r2 + ! The pt_regs is placed in $r5 in kerenl (sys_clone_wrapper) + move $r2, $r4 - /* do the system call */ - or $r0, $r2, $r2 ! move r0, r2 - __do_syscall(clone) - !syscall (__NR_clone) - beqz $r0, 4f - bltz $r0, 5b +#ifdef __NDS32_ABI_2FP_PLUS__ +# ifdef PIC + lwi $r4, [$sp+#0x10] +# else + lwi $r4, [$sp+#0x8] +# endif +#else +# ifdef PIC + lwi $r4, [$sp+#0x8] +# else + lwi $r4, [$sp] +# endif +#endif + + __do_syscall(clone) + beqz $r0, 4f + bltz $r0, 5b - ! parent + +10: #ifdef PIC - /* restore GP register, only in parent's stack */ + /* restore GP register, only in parent's stack */ popm $fp, $gp -#endif - ret + cfi_adjust_cfa_offset(-8) + cfi_restore(gp) + cfi_restore(fp) +#endif /* PIC */ + ret +#ifdef RESET_PID 4: - /* Only in child's stack. */ - pop $r1 ! fn - pop $r0 ! arg -#if defined(NDS32_ABI_2) || defined(NDS32_ABI_2FP) + cfi_undefined(lp) + movi $r0, CLONE_THREAD ! Skip when CLONE_THREAD is set. + and $r0, $r5, $r0 + bnez $r0, 8f + movi $r0, CLONE_VM ! Value = -1 when CLONE_VM is set. + and $r0, $r5, $r0 + beqz $r0, 6f + movi $r0, -1 + j 7f +6: + __do_syscall(getpid) ! __do_syscall(gettid) ! __do_syscall(getpid) +7: + swi $r0, [$r25 + PID_OFFSET] + swi $r0, [$r25 + TID_OFFSET] +8: #else - addi $sp, $sp, -24 -#endif - ! use r15 in case _exit is PIC -#ifdef __NDS32_N1213_43U1H__ - or $r15, $r1, $r1 ! move r15, r2 +4: #endif - bral $r1 -#if defined(NDS32_ABI_2) || defined(NDS32_ABI_2FP) -#else + /* Only in child's stack. */ + pop $r1 ! fn + pop $r0 ! arg + + +#if !defined(__NDS32_ABI_2__) && !defined(__NDS32_ABI_2FP_PLUS__) + addi $sp, $sp, -24 +#endif /* !defined(__NDS32_ABI_2__) && !defined(__NDS32_ABI_2FP_PLUS__) */ + + ! use $r15 in case _exit is PIC + bral $r1 + +#if !defined(__NDS32_ABI_2__) && !defined(__NDS32_ABI_2FP_PLUS__) addi $sp, $sp, 24 -#endif - ! use r15 in case _exit is PIC +#endif /* !defined(__NDS32_ABI_2__) && !defined(__NDS32_ABI_2FP_PLUS__) */ + + ! use $r15 in case _exit is PIC #ifdef PIC - la $r15, C_SYMBOL_NAME(_exit@PLT) - jr $r15 -#else - b C_SYMBOL_NAME(_exit) -#endif + la $r15, C_SYMBOL_NAME(_exit@PLT) +#else /* ! PIC */ + la $r15, C_SYMBOL_NAME(_exit) +#endif /* ! PIC */ + jr $r15 PSEUDO_END (__clone) |