1 /* The clone3 syscall wrapper. Linux/mips version.
2 Copyright (C) 2023-2024 Free Software Foundation, Inc.
4 This file is part of the GNU C Library.
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.
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.
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/>. */
23 #include <bits/errno.h>
25 /* The userland implementation is:
26 int clone3 (struct clone_args *cl_args, size_t size,
27 int (*func)(void *arg), void *arg);
30 int clone3 (struct clone_args *cl_args, size_t size);
32 The parameters are passed in registers from userland:
40 #define FRAMESZ ((NARGSAVE*SZREG)+ALSZ)&ALMASK
41 GPOFF= FRAMESZ-(1*SZREG)
42 NESTED(__clone3, SZREG, sp)
48 cfi_adjust_cfa_offset (FRAMESZ)
50 SETUP_GP64_STACK (GPOFF, __clone3)
61 /* Sanity check args. */
63 beqz a0, L(error) /* No NULL cl_args pointer. */
64 beqz a2, L(error) /* No NULL function pointer. */
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
73 # define CL_STACKPOINTER_OFFSET 40
74 # define CL_STACKSIZE_OFFSET 48
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. */
88 move $8, a3 /* a3 is set to 0/1 for syscall success/error
89 while a4/$8 is returned unmodified. */
92 /* Do the system call, the kernel expects:
93 v0: system call number
101 beqz v0, L(thread_start_clone3)
103 /* Successful return from the parent */
106 cfi_adjust_cfa_offset (FRAMESZ)
108 SETUP_GP64_STACK_CFI (GPOFF)
113 cfi_adjust_cfa_offset (-FRAMESZ)
120 PTR_LA t9, __syscall_error
123 cfi_adjust_cfa_offset (-FRAMESZ)
128 cfi_adjust_cfa_offset (-FRAMESZ)
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
137 ENTRY(__thread_start_clone3)
138 L(thread_start_clone3):
140 /* cp is already loaded. */
142 /* The stackframe has been created on entry of clone3. */
144 /* Restore the arg for user's function. */
145 move t9, a2 /* Function pointer. */
146 #if _MIPS_SIM == _ABIO32
149 move a0, $8 /* Argument pointer. */
152 /* Call the user's function. */
158 END(__thread_start_clone3)
160 libc_hidden_def (__clone3)
161 weak_alias (__clone3, clone3)