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