1/* The clone3 syscall wrapper. Linux/mips version.
2 Copyright (C) 2023-2024 Free Software Foundation, Inc.
3
4 This file is part of the GNU C Library.
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#include <sys/asm.h>
21#include <sysdep.h>
22#define _ERRNO_H 1
23#include <bits/errno.h>
24
25/* The userland implementation is:
26 int clone3 (struct clone_args *cl_args, size_t size,
27 int (*func)(void *arg), void *arg);
28
29 the kernel entry is:
30 int clone3 (struct clone_args *cl_args, size_t size);
31
32 The parameters are passed in registers from userland:
33 a0/$4: cl_args
34 a1/$5: size
35 a2/$6: func
36 a3/$7: arg */
37
38 .text
39 .set nomips16
40#define FRAMESZ ((NARGSAVE*SZREG)+ALSZ)&ALMASK
41GPOFF= FRAMESZ-(1*SZREG)
42NESTED(__clone3, SZREG, sp)
43#ifdef __PIC__
44 SETUP_GP
45#endif
46#if FRAMESZ
47 PTR_SUBU sp, FRAMESZ
48 cfi_adjust_cfa_offset (FRAMESZ)
49#endif
50 SETUP_GP64_STACK (GPOFF, __clone3)
51#ifdef __PIC__
52 SAVE_GP (GPOFF)
53#endif
54#ifdef PROF
55 .set noat
56 move $1,ra
57 jal _mcount
58 .set at
59#endif
60
61 /* Sanity check args. */
62 li v0, EINVAL
63 beqz a0, L(error) /* No NULL cl_args pointer. */
64 beqz a2, L(error) /* No NULL function pointer. */
65
66#if _MIPS_SIM == _ABIO32
67 /* Both stack and stack_size on clone_args are defined as uint64_t, and
68 there is no need to handle values larger than to 32 bits for o32. */
69# if __BYTE_ORDER == __BIG_ENDIAN
70# define CL_STACKPOINTER_OFFSET 44
71# define CL_STACKSIZE_OFFSET 52
72# else
73# define CL_STACKPOINTER_OFFSET 40
74# define CL_STACKSIZE_OFFSET 48
75# endif
76
77 /* For o32 we need to setup a minimal stack frame to allow cprestore
78 on __thread_start_clone3. Also there is no guarantee by kABI that
79 $8 will be preserved after syscall execution (so we need to save it
80 on the provided stack). */
81 lw t0, CL_STACKPOINTER_OFFSET(a0) /* Load the stack pointer. */
82 lw t1, CL_STACKSIZE_OFFSET(a0) /* Load the stack_size. */
83 addiu t1, -32 /* Update the stack size. */
84 addu t2, t1, t0 /* Calculate the thread stack. */
85 sw a3, 0(t2) /* Save argument pointer. */
86 sw t1, CL_STACKSIZE_OFFSET(a0) /* Save the new stack size. */
87#else
88 move $8, a3 /* a3 is set to 0/1 for syscall success/error
89 while a4/$8 is returned unmodified. */
90#endif
91
92 /* Do the system call, the kernel expects:
93 v0: system call number
94 a0: cl_args
95 a1: size */
96 li v0, __NR_clone3
97 cfi_endproc
98 syscall
99
100 bnez a3, L(error)
101 beqz v0, L(thread_start_clone3)
102
103 /* Successful return from the parent */
104 cfi_startproc
105#if FRAMESZ
106 cfi_adjust_cfa_offset (FRAMESZ)
107#endif
108 SETUP_GP64_STACK_CFI (GPOFF)
109 cfi_remember_state
110 RESTORE_GP64_STACK
111#if FRAMESZ
112 PTR_ADDU sp, FRAMESZ
113 cfi_adjust_cfa_offset (-FRAMESZ)
114#endif
115 ret
116
117L(error):
118 cfi_restore_state
119#ifdef __PIC__
120 PTR_LA t9, __syscall_error
121 RESTORE_GP64_STACK
122 PTR_ADDU sp, FRAMESZ
123 cfi_adjust_cfa_offset (-FRAMESZ)
124 jr t9
125#else
126 RESTORE_GP64_STACK
127 PTR_ADDU sp, FRAMESZ
128 cfi_adjust_cfa_offset (-FRAMESZ)
129 j __syscall_error
130#endif
131END (__clone3)
132
133/* Load up the arguments to the function. Put this block of code in
134 its own function so that we can terminate the stack trace with our
135 debug info. */
136
137ENTRY(__thread_start_clone3)
138L(thread_start_clone3):
139 cfi_undefined ($31)
140 /* cp is already loaded. */
141 SAVE_GP (GPOFF)
142 /* The stackframe has been created on entry of clone3. */
143
144 /* Restore the arg for user's function. */
145 move t9, a2 /* Function pointer. */
146#if _MIPS_SIM == _ABIO32
147 PTR_L a0, 0(sp)
148#else
149 move a0, $8 /* Argument pointer. */
150#endif
151
152 /* Call the user's function. */
153 jal t9
154
155 move a0, v0
156 li v0, __NR_exit
157 syscall
158END(__thread_start_clone3)
159
160libc_hidden_def (__clone3)
161weak_alias (__clone3, clone3)
162

source code of glibc/sysdeps/unix/sysv/linux/mips/clone3.S