[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20260116153051.21678-3-ludwig.rydberg@gaisler.com>
Date: Fri, 16 Jan 2026 16:30:50 +0100
From: Ludwig Rydberg <ludwig.rydberg@...sler.com>
To: davem@...emloft.net,
andreas@...sler.com,
brauner@...nel.org,
shuah@...nel.org
Cc: sparclinux@...r.kernel.org,
linux-kselftest@...r.kernel.org,
linux-kernel@...r.kernel.org,
arnd@...db.de,
glaubitz@...sik.fu-berlin.de,
geert@...ux-m68k.org,
schuster.simon@...mens-energy.com
Subject: [PATCH 2/3] sparc: Add architecture support for clone3
Add support for the clone3 system call to the SPARC architectures.
The implementation follows the pattern of the original clone syscall.
However, instead of explicitly calling kernel_clone, the clone3
handler calls the generic sys_clone3 handler in kernel/fork.
In case no stack is provided, the parents stack is reused.
The return call conventions for clone on SPARC are kept for clone3:
Parent --> %o0 == child's pid, %o1 == 0
Child --> %o0 == parent's pid, %o1 == 1
Closes: https://github.com/sparclinux/issues/issues/10
Signed-off-by: Ludwig Rydberg <ludwig.rydberg@...sler.com>
---
arch/sparc/include/asm/syscalls.h | 1 +
arch/sparc/include/asm/unistd.h | 2 --
arch/sparc/kernel/entry.S | 15 +++++++++++++++
arch/sparc/kernel/kernel.h | 1 +
arch/sparc/kernel/process.c | 25 +++++++++++++++++++++++++
arch/sparc/kernel/process_32.c | 2 +-
arch/sparc/kernel/process_64.c | 2 +-
arch/sparc/kernel/syscalls.S | 6 ++++++
arch/sparc/kernel/syscalls/syscall.tbl | 2 +-
9 files changed, 51 insertions(+), 5 deletions(-)
diff --git a/arch/sparc/include/asm/syscalls.h b/arch/sparc/include/asm/syscalls.h
index 35575fbfb9dc..282e62b66518 100644
--- a/arch/sparc/include/asm/syscalls.h
+++ b/arch/sparc/include/asm/syscalls.h
@@ -7,5 +7,6 @@ struct pt_regs;
asmlinkage long sparc_fork(struct pt_regs *regs);
asmlinkage long sparc_vfork(struct pt_regs *regs);
asmlinkage long sparc_clone(struct pt_regs *regs);
+asmlinkage long sparc_clone3(struct pt_regs *regs);
#endif /* _SPARC64_SYSCALLS_H */
diff --git a/arch/sparc/include/asm/unistd.h b/arch/sparc/include/asm/unistd.h
index 3380411a4537..d6bc76706a7a 100644
--- a/arch/sparc/include/asm/unistd.h
+++ b/arch/sparc/include/asm/unistd.h
@@ -49,8 +49,6 @@
#define __ARCH_WANT_COMPAT_STAT
#endif
-#define __ARCH_BROKEN_SYS_CLONE3
-
#ifdef __32bit_syscall_numbers__
/* Sparc 32-bit only has the "setresuid32", "getresuid32" variants,
* it never had the plain ones and there is no value to adding those
diff --git a/arch/sparc/kernel/entry.S b/arch/sparc/kernel/entry.S
index a3fdee4cd6fa..ea51ef52c952 100644
--- a/arch/sparc/kernel/entry.S
+++ b/arch/sparc/kernel/entry.S
@@ -907,6 +907,21 @@ flush_patch_four:
jmpl %l1 + %lo(sparc_vfork), %g0
add %sp, STACKFRAME_SZ, %o0
+ .globl __sys_clone3, flush_patch_five
+__sys_clone3:
+ mov %o7, %l5
+flush_patch_five:
+ FLUSH_ALL_KERNEL_WINDOWS;
+ ld [%curptr + TI_TASK], %o4
+ rd %psr, %g4
+ WRITE_PAUSE
+ rd %wim, %g5
+ WRITE_PAUSE
+ std %g4, [%o4 + AOFF_task_thread + AOFF_thread_fork_kpsr]
+ add %sp, STACKFRAME_SZ, %o0
+ call sparc_clone3
+ mov %l5, %o7
+
.align 4
linux_sparc_ni_syscall:
sethi %hi(sys_ni_syscall), %l7
diff --git a/arch/sparc/kernel/kernel.h b/arch/sparc/kernel/kernel.h
index 8328a3b78a44..4ee85051521a 100644
--- a/arch/sparc/kernel/kernel.h
+++ b/arch/sparc/kernel/kernel.h
@@ -18,6 +18,7 @@ extern int ncpus_probed;
asmlinkage long sparc_clone(struct pt_regs *regs);
asmlinkage long sparc_fork(struct pt_regs *regs);
asmlinkage long sparc_vfork(struct pt_regs *regs);
+asmlinkage long sparc_clone3(struct pt_regs *regs);
#ifdef CONFIG_SPARC64
/* setup_64.c */
diff --git a/arch/sparc/kernel/process.c b/arch/sparc/kernel/process.c
index 7d69877511fa..b8e23295db69 100644
--- a/arch/sparc/kernel/process.c
+++ b/arch/sparc/kernel/process.c
@@ -12,6 +12,7 @@
#include <linux/sched/task.h>
#include <linux/sched/task_stack.h>
#include <linux/signal.h>
+#include <linux/syscalls.h>
#include "kernel.h"
@@ -118,3 +119,27 @@ asmlinkage long sparc_clone(struct pt_regs *regs)
return ret;
}
+
+asmlinkage long sparc_clone3(struct pt_regs *regs)
+{
+ unsigned long sz;
+ long ret;
+ struct clone_args __user *cl_args;
+
+ synchronize_user_stack();
+
+ cl_args = (struct clone_args __user *)regs->u_regs[UREG_I0];
+ sz = regs->u_regs[UREG_I1];
+
+ ret = sys_clone3(cl_args, sz);
+
+ /* If we get an error and potentially restart the system
+ * call, we're screwed because copy_thread() clobbered
+ * the parent's %o1. So detect that case and restore it
+ * here.
+ */
+ if ((unsigned long)ret >= -ERESTART_RESTARTBLOCK)
+ regs->u_regs[UREG_I1] = sz;
+
+ return ret;
+}
diff --git a/arch/sparc/kernel/process_32.c b/arch/sparc/kernel/process_32.c
index 5a28c0e91bf1..216c07971c81 100644
--- a/arch/sparc/kernel/process_32.c
+++ b/arch/sparc/kernel/process_32.c
@@ -261,11 +261,11 @@ extern void ret_from_kernel_thread(void);
int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
{
u64 clone_flags = args->flags;
- unsigned long sp = args->stack;
unsigned long tls = args->tls;
struct thread_info *ti = task_thread_info(p);
struct pt_regs *childregs, *regs = current_pt_regs();
char *new_stack;
+ unsigned long sp = args->stack ? args->stack : regs->u_regs[UREG_FP];
#ifndef CONFIG_SMP
if(last_task_used_math == current) {
diff --git a/arch/sparc/kernel/process_64.c b/arch/sparc/kernel/process_64.c
index 25781923788a..885d617ba29d 100644
--- a/arch/sparc/kernel/process_64.c
+++ b/arch/sparc/kernel/process_64.c
@@ -568,13 +568,13 @@ void fault_in_user_windows(struct pt_regs *regs)
int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
{
u64 clone_flags = args->flags;
- unsigned long sp = args->stack;
unsigned long tls = args->tls;
struct thread_info *t = task_thread_info(p);
struct pt_regs *regs = current_pt_regs();
struct sparc_stackf *parent_sf;
unsigned long child_stack_sz;
char *child_trap_frame;
+ unsigned long sp = args->stack ? args->stack : regs->u_regs[UREG_FP];
/* Calculate offset to stack_frame & pt_regs */
child_stack_sz = (STACKFRAME_SZ + TRACEREG_SZ);
diff --git a/arch/sparc/kernel/syscalls.S b/arch/sparc/kernel/syscalls.S
index 0e8ab0602c36..c8d374a37f98 100644
--- a/arch/sparc/kernel/syscalls.S
+++ b/arch/sparc/kernel/syscalls.S
@@ -103,6 +103,12 @@ sys_clone:
ba,pt %xcc, sparc_clone
add %sp, PTREGS_OFF, %o0
+ .align 32
+__sys_clone3:
+ flushw
+ ba,pt %xcc, sparc_clone3
+ add %sp, PTREGS_OFF, %o0
+
.globl ret_from_fork
ret_from_fork:
/* Clear current_thread_info()->new_child. */
diff --git a/arch/sparc/kernel/syscalls/syscall.tbl b/arch/sparc/kernel/syscalls/syscall.tbl
index 39aa26b6a50b..c0307bb09892 100644
--- a/arch/sparc/kernel/syscalls/syscall.tbl
+++ b/arch/sparc/kernel/syscalls/syscall.tbl
@@ -480,7 +480,7 @@
432 common fsmount sys_fsmount
433 common fspick sys_fspick
434 common pidfd_open sys_pidfd_open
-# 435 reserved for clone3
+435 common clone3 __sys_clone3
436 common close_range sys_close_range
437 common openat2 sys_openat2
438 common pidfd_getfd sys_pidfd_getfd
--
2.35.3
Powered by blists - more mailing lists