1/* clone() implementation for ARC. 2 Copyright (C) 2020-2022 Free Software Foundation, Inc. 3 This file is part of the GNU C Library. 4 5 The GNU C Library is free software; you can redistribute it and/or 6 modify it under the terms of the GNU Lesser General Public 7 License as published by the Free Software Foundation; either 8 version 2.1 of the License, or (at your option) any later version. 9 10 The GNU C Library is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 Lesser General Public License for more details. 14 15 You should have received a copy of the GNU Lesser General Public 16 License along with the GNU C Library; if not, see 17 <https://www.gnu.org/licenses/>. */ 18 19 20#include <sysdep.h> 21#define _ERRNO_H 1 22#include <bits/errno.h> 23#include <tcb-offsets.h> 24 25#define CLONE_SETTLS 0x00080000 26 27/* int clone(int (*fn)(void *), void *child_stack, 28 int flags, void *arg, ... 29 < pid_t *ptid, struct user_desc *tls, pid_t *ctid > ); 30 31 NOTE: I'm assuming that the last 3 args are NOT var-args and in case all 32 3 are not relevant, caller will nevertheless pass those as NULL. 33 34 clone syscall in kernel (ABI: CONFIG_CLONE_BACKWARDS) 35 36 int sys_clone(unsigned long int clone_flags, 37 unsigned long int newsp, 38 int __user *parent_tidptr, 39 void *tls, 40 int __user *child_tidptr). */ 41 42ENTRY (__clone) 43 cmp r0, 0 /* @fn can't be NULL. */ 44 cmp.ne r1, 0 /* @child_stack can't be NULL. */ 45 bz L (__sys_err) 46 47 /* save some of the orig args 48 r0 containg @fn will be clobbered AFTER syscall (with ret val) 49 rest are clobbered BEFORE syscall due to different arg ordering. */ 50 mov r10, r0 /* @fn. */ 51 mov r11, r3 /* @args. */ 52 mov r12, r2 /* @clone_flags. */ 53 mov r9, r5 /* @tls. */ 54 55 /* adjust libc args for syscall. */ 56 57 mov r0, r2 /* libc @flags is 1st syscall arg. */ 58 mov r2, r4 /* libc @ptid. */ 59 mov r3, r5 /* libc @tls. */ 60 mov r4, r6 /* libc @ctid. */ 61 mov r8, __NR_clone 62 ARC_TRAP_INSN 63 64 cmp r0, 0 /* return code : 0 new process, !0 parent. */ 65 blt L (__sys_err2) /* < 0 (signed) error. */ 66 jnz [blink] /* Parent returns. */ 67 68 /* child jumps off to @fn with @arg as argument 69 TP register already set by kernel. */ 70 jl.d [r10] 71 mov r0, r11 72 73 /* exit() with result from @fn (already in r0). */ 74 mov r8, __NR_exit 75 ARC_TRAP_INSN 76 /* In case it ever came back. */ 77 flag 1 78 79L (__sys_err): 80 mov r0, -EINVAL 81L (__sys_err2): 82 /* (1) No need to make -ve kernel error code as positive errno 83 __syscall_error expects the -ve error code returned by kernel 84 (2) r0 still had orig -ve kernel error code 85 (3) Tail call to __syscall_error so we dont have to come back 86 here hence instead of jmp-n-link (reg push/pop) we do jmp 87 (4) No need to route __syscall_error via PLT, B is inherently 88 position independent. */ 89 b __syscall_error 90PSEUDO_END (__clone) 91libc_hidden_def (__clone) 92weak_alias (__clone, clone) 93