]>
Commit | Line | Data |
---|---|---|
36960f0c | 1 | /* Wrapper around clone system call. RISC-V version. |
d614a753 | 2 | Copyright (C) 1996-2020 Free Software Foundation, Inc. |
36960f0c PD |
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 | |
5a82c748 | 17 | <https://www.gnu.org/licenses/>. */ |
36960f0c PD |
18 | |
19 | /* clone() is even more special than fork() as it mucks with stacks | |
20 | and invokes a function in the right context after its all over. */ | |
21 | ||
22 | #include <sys/asm.h> | |
23 | #include <sysdep.h> | |
24 | #define _ERRNO_H 1 | |
25 | #include <bits/errno.h> | |
26 | #include <tls.h> | |
27 | #include "tcb-offsets.h" | |
28 | ||
29 | /* int clone(int (*fn)(void *arg), void *child_stack, int flags, void *arg, | |
30 | void *parent_tidptr, void *tls, void *child_tidptr) */ | |
31 | ||
32 | .text | |
33 | LEAF (__clone) | |
34 | ||
35 | /* Sanity check arguments. */ | |
36 | beqz a0,L (invalid) /* No NULL function pointers. */ | |
37 | beqz a1,L (invalid) /* No NULL stack pointers. */ | |
38 | ||
39 | addi a1,a1,-16 /* Reserve argument save space. */ | |
40 | REG_S a0,0(a1) /* Save function pointer. */ | |
41 | REG_S a3,SZREG(a1) /* Save argument pointer. */ | |
42 | ||
43 | /* The syscall expects the args to be in different slots. */ | |
44 | mv a0,a2 | |
45 | mv a2,a4 | |
46 | mv a3,a5 | |
47 | mv a4,a6 | |
48 | ||
49 | /* Do the system call. */ | |
50 | li a7,__NR_clone | |
51 | scall | |
52 | ||
53 | bltz a0,L (error) | |
54 | beqz a0,L (thread_start) | |
55 | ||
56 | /* Successful return from the parent. */ | |
57 | ret | |
58 | ||
59 | L (invalid): | |
60 | li a0, -EINVAL | |
61 | /* Something bad happened -- no child created. */ | |
62 | L (error): | |
63 | j __syscall_error | |
64 | END (__clone) | |
65 | ||
66 | /* Load up the arguments to the function. Put this block of code in | |
67 | its own function so that we can terminate the stack trace with our | |
68 | debug info. */ | |
69 | ||
70 | ENTRY (__thread_start) | |
71 | L (thread_start): | |
85bd1ddb JW |
72 | /* Terminate call stack by noting ra is undefined. Use a dummy |
73 | .cfi_label to force starting the FDE. */ | |
74 | .cfi_label .Ldummy | |
75 | cfi_undefined (ra) | |
76 | ||
36960f0c PD |
77 | /* Restore the arg for user's function. */ |
78 | REG_L a1,0(sp) /* Function pointer. */ | |
79 | REG_L a0,SZREG(sp) /* Argument pointer. */ | |
80 | ||
81 | /* Call the user's function. */ | |
82 | jalr a1 | |
83 | ||
84 | /* Call exit with the function's return value. */ | |
85 | li a7, __NR_exit | |
86 | scall | |
87 | ||
88 | END (__thread_start) | |
89 | ||
90 | libc_hidden_def (__clone) | |
91 | weak_alias (__clone, clone) |