Skip to content

Commit 2153b2e

Browse files
Ludwig Rydbergandreas-gaisler
authored andcommitted
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 value convention for clone3 follows the regular kernel return value convention (in contrast to the original clone/fork on SPARC). Closes: sparclinux/issues#10 Signed-off-by: Ludwig Rydberg <ludwig.rydberg@gaisler.com> Acked-by: Arnd Bergmann <arnd@arndb.de> Reviewed-by: Andreas Larsson <andreas@gaisler.com> Tested-by: Andreas Larsson <andreas@gaisler.com> Tested-by: John Paul Adrian Glaubitz <glaubitz@physik.fu-berlin.de> Link: https://lore.kernel.org/r/20260119144753.27945-3-ludwig.rydberg@gaisler.com Signed-off-by: Andreas Larsson <andreas@gaisler.com>
1 parent e38eba3 commit 2153b2e

9 files changed

Lines changed: 78 additions & 15 deletions

File tree

arch/sparc/include/asm/syscalls.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,6 @@ struct pt_regs;
77
asmlinkage long sparc_fork(struct pt_regs *regs);
88
asmlinkage long sparc_vfork(struct pt_regs *regs);
99
asmlinkage long sparc_clone(struct pt_regs *regs);
10+
asmlinkage long sparc_clone3(struct pt_regs *regs);
1011

1112
#endif /* _SPARC64_SYSCALLS_H */

arch/sparc/include/asm/unistd.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,6 @@
4949
#define __ARCH_WANT_COMPAT_STAT
5050
#endif
5151

52-
#define __ARCH_BROKEN_SYS_CLONE3
53-
5452
#ifdef __32bit_syscall_numbers__
5553
/* Sparc 32-bit only has the "setresuid32", "getresuid32" variants,
5654
* it never had the plain ones and there is no value to adding those

arch/sparc/kernel/entry.S

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -907,6 +907,21 @@ flush_patch_four:
907907
jmpl %l1 + %lo(sparc_vfork), %g0
908908
add %sp, STACKFRAME_SZ, %o0
909909

910+
.globl __sys_clone3, flush_patch_five
911+
__sys_clone3:
912+
mov %o7, %l5
913+
flush_patch_five:
914+
FLUSH_ALL_KERNEL_WINDOWS;
915+
ld [%curptr + TI_TASK], %o4
916+
rd %psr, %g4
917+
WRITE_PAUSE
918+
rd %wim, %g5
919+
WRITE_PAUSE
920+
std %g4, [%o4 + AOFF_task_thread + AOFF_thread_fork_kpsr]
921+
add %sp, STACKFRAME_SZ, %o0
922+
call sparc_clone3
923+
mov %l5, %o7
924+
910925
.align 4
911926
linux_sparc_ni_syscall:
912927
sethi %hi(sys_ni_syscall), %l7

arch/sparc/kernel/kernel.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ extern int ncpus_probed;
1818
asmlinkage long sparc_clone(struct pt_regs *regs);
1919
asmlinkage long sparc_fork(struct pt_regs *regs);
2020
asmlinkage long sparc_vfork(struct pt_regs *regs);
21+
asmlinkage long sparc_clone3(struct pt_regs *regs);
2122

2223
#ifdef CONFIG_SPARC64
2324
/* setup_64.c */

arch/sparc/kernel/process.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include <linux/sched/task.h>
1313
#include <linux/sched/task_stack.h>
1414
#include <linux/signal.h>
15+
#include <linux/syscalls.h>
1516

1617
#include "kernel.h"
1718

@@ -118,3 +119,16 @@ asmlinkage long sparc_clone(struct pt_regs *regs)
118119

119120
return ret;
120121
}
122+
123+
asmlinkage long sparc_clone3(struct pt_regs *regs)
124+
{
125+
unsigned long sz;
126+
struct clone_args __user *cl_args;
127+
128+
synchronize_user_stack();
129+
130+
cl_args = (struct clone_args __user *)regs->u_regs[UREG_I0];
131+
sz = regs->u_regs[UREG_I1];
132+
133+
return sys_clone3(cl_args, sz);
134+
}

arch/sparc/kernel/process_32.c

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,8 @@ clone_stackframe(struct sparc_stackf __user *dst,
247247
* Parent --> %o0 == childs pid, %o1 == 0
248248
* Child --> %o0 == parents pid, %o1 == 1
249249
*
250+
* clone3() - Uses regular kernel return value conventions
251+
*
250252
* NOTE: We have a separate fork kpsr/kwim because
251253
* the parent could change these values between
252254
* sys_fork invocation and when we reach here
@@ -261,11 +263,11 @@ extern void ret_from_kernel_thread(void);
261263
int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
262264
{
263265
u64 clone_flags = args->flags;
264-
unsigned long sp = args->stack;
265266
unsigned long tls = args->tls;
266267
struct thread_info *ti = task_thread_info(p);
267268
struct pt_regs *childregs, *regs = current_pt_regs();
268269
char *new_stack;
270+
unsigned long sp = args->stack ? args->stack : regs->u_regs[UREG_FP];
269271

270272
#ifndef CONFIG_SMP
271273
if(last_task_used_math == current) {
@@ -350,13 +352,22 @@ int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
350352
childregs->psr &= ~PSR_EF;
351353
clear_tsk_thread_flag(p, TIF_USEDFPU);
352354
#endif
355+
/* Handle return value conventions */
356+
if (regs->u_regs[UREG_G1] == __NR_clone3) {
357+
/* clone3() - use regular kernel return value convention */
358+
359+
/* Set the return value for the child. */
360+
childregs->u_regs[UREG_I0] = 0;
361+
} else {
362+
/* clone()/fork() - use SunOS return value convention */
353363

354-
/* Set the return value for the child. */
355-
childregs->u_regs[UREG_I0] = current->pid;
356-
childregs->u_regs[UREG_I1] = 1;
364+
/* Set the return value for the child. */
365+
childregs->u_regs[UREG_I0] = current->pid;
366+
childregs->u_regs[UREG_I1] = 1;
357367

358-
/* Set the return value for the parent. */
359-
regs->u_regs[UREG_I1] = 0;
368+
/* Set the return value for the parent. */
369+
regs->u_regs[UREG_I1] = 0;
370+
}
360371

361372
if (clone_flags & CLONE_SETTLS)
362373
childregs->u_regs[UREG_G7] = tls;

arch/sparc/kernel/process_64.c

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -564,17 +564,19 @@ void fault_in_user_windows(struct pt_regs *regs)
564564
* under SunOS are nothing short of bletcherous:
565565
* Parent --> %o0 == childs pid, %o1 == 0
566566
* Child --> %o0 == parents pid, %o1 == 1
567+
*
568+
* clone3() - Uses regular kernel return value conventions
567569
*/
568570
int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
569571
{
570572
u64 clone_flags = args->flags;
571-
unsigned long sp = args->stack;
572573
unsigned long tls = args->tls;
573574
struct thread_info *t = task_thread_info(p);
574575
struct pt_regs *regs = current_pt_regs();
575576
struct sparc_stackf *parent_sf;
576577
unsigned long child_stack_sz;
577578
char *child_trap_frame;
579+
unsigned long sp = args->stack ? args->stack : regs->u_regs[UREG_FP];
578580

579581
/* Calculate offset to stack_frame & pt_regs */
580582
child_stack_sz = (STACKFRAME_SZ + TRACEREG_SZ);
@@ -616,12 +618,25 @@ int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
616618
if (t->utraps)
617619
t->utraps[0]++;
618620

619-
/* Set the return value for the child. */
620-
t->kregs->u_regs[UREG_I0] = current->pid;
621-
t->kregs->u_regs[UREG_I1] = 1;
621+
/* Handle return value conventions */
622+
if (regs->u_regs[UREG_G1] == __NR_clone3) {
623+
/* clone3() - use regular kernel return value convention */
624+
625+
/* Set the return value for the child. */
626+
t->kregs->u_regs[UREG_I0] = 0;
627+
628+
/* Clear g1 to indicate user thread */
629+
t->kregs->u_regs[UREG_G1] = 0;
630+
} else {
631+
/* clone()/fork() - use SunOS return value convention */
632+
633+
/* Set the return value for the child. */
634+
t->kregs->u_regs[UREG_I0] = current->pid;
635+
t->kregs->u_regs[UREG_I1] = 1;
622636

623-
/* Set the second return value for the parent. */
624-
regs->u_regs[UREG_I1] = 0;
637+
/* Set the second return value for the parent. */
638+
regs->u_regs[UREG_I1] = 0;
639+
}
625640

626641
if (clone_flags & CLONE_SETTLS)
627642
t->kregs->u_regs[UREG_G7] = tls;

arch/sparc/kernel/syscalls.S

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,12 @@ sys_clone:
103103
ba,pt %xcc, sparc_clone
104104
add %sp, PTREGS_OFF, %o0
105105

106+
.align 32
107+
__sys_clone3:
108+
flushw
109+
ba,pt %xcc, sparc_clone3
110+
add %sp, PTREGS_OFF, %o0
111+
106112
.globl ret_from_fork
107113
ret_from_fork:
108114
/* Clear current_thread_info()->new_child. */
@@ -113,6 +119,8 @@ ret_from_fork:
113119
brnz,pt %o0, ret_sys_call
114120
ldx [%g6 + TI_FLAGS], %l0
115121
ldx [%sp + PTREGS_OFF + PT_V9_G1], %l1
122+
brz,pt %l1, ret_sys_call
123+
nop
116124
call %l1
117125
ldx [%sp + PTREGS_OFF + PT_V9_G2], %o0
118126
ba,pt %xcc, ret_sys_call

arch/sparc/kernel/syscalls/syscall.tbl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -480,7 +480,7 @@
480480
432 common fsmount sys_fsmount
481481
433 common fspick sys_fspick
482482
434 common pidfd_open sys_pidfd_open
483-
# 435 reserved for clone3
483+
435 common clone3 __sys_clone3
484484
436 common close_range sys_close_range
485485
437 common openat2 sys_openat2
486486
438 common pidfd_getfd sys_pidfd_getfd

0 commit comments

Comments
 (0)