1/* Wrapper around clone system call. RISC-V version.
2 Copyright (C) 1996-2024 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/* 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
33LEAF (__clone)
34
35 /* Align stack to a 128-bit boundary as per RISC-V ABI. */
36 andi a1,a1,ALMASK
37
38 /* Sanity check arguments. */
39 beqz a0,L (invalid) /* No NULL function pointers. */
40 beqz a1,L (invalid) /* No NULL stack pointers. */
41
42 addi a1,a1,-16 /* Reserve argument save space. */
43 REG_S a0,0(a1) /* Save function pointer. */
44 REG_S a3,SZREG(a1) /* Save argument pointer. */
45
46 /* The syscall expects the args to be in different slots. */
47 mv a0,a2
48 mv a2,a4
49 mv a3,a5
50 mv a4,a6
51
52 /* Do the system call. */
53 li a7,__NR_clone
54 scall
55
56 bltz a0,L (error)
57 beqz a0,L (thread_start)
58
59 /* Successful return from the parent. */
60 ret
61
62L (invalid):
63 li a0, -EINVAL
64 /* Something bad happened -- no child created. */
65L (error):
66 tail __syscall_error
67 END (__clone)
68
69/* Load up the arguments to the function. Put this block of code in
70 its own function so that we can terminate the stack trace with our
71 debug info. */
72
73ENTRY (__thread_start)
74L (thread_start):
75 /* Terminate call stack by noting ra is undefined. Use a dummy
76 .cfi_label to force starting the FDE. */
77 .cfi_label .Ldummy
78 cfi_undefined (ra)
79
80 /* Restore the arg for user's function. */
81 REG_L a1,0(sp) /* Function pointer. */
82 REG_L a0,SZREG(sp) /* Argument pointer. */
83
84 /* Call the user's function. */
85 jalr a1
86
87 /* Call exit with the function's return value. */
88 li a7, __NR_exit
89 scall
90
91 END (__thread_start)
92
93libc_hidden_def (__clone)
94weak_alias (__clone, clone)
95

source code of glibc/sysdeps/unix/sysv/linux/riscv/clone.S