mirror of
https://github.com/torvalds/linux.git
synced 2026-03-08 03:04:51 +01:00
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: https://github.com/sparclinux/issues/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>
This commit is contained in:
parent
e38eba3b77
commit
2153b2e891
9 changed files with 78 additions and 15 deletions
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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,16 @@ asmlinkage long sparc_clone(struct pt_regs *regs)
|
|||
|
||||
return ret;
|
||||
}
|
||||
|
||||
asmlinkage long sparc_clone3(struct pt_regs *regs)
|
||||
{
|
||||
unsigned long sz;
|
||||
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];
|
||||
|
||||
return sys_clone3(cl_args, sz);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -247,6 +247,8 @@ clone_stackframe(struct sparc_stackf __user *dst,
|
|||
* Parent --> %o0 == childs pid, %o1 == 0
|
||||
* Child --> %o0 == parents pid, %o1 == 1
|
||||
*
|
||||
* clone3() - Uses regular kernel return value conventions
|
||||
*
|
||||
* NOTE: We have a separate fork kpsr/kwim because
|
||||
* the parent could change these values between
|
||||
* sys_fork invocation and when we reach here
|
||||
|
|
@ -261,11 +263,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) {
|
||||
|
|
@ -350,13 +352,22 @@ int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
|
|||
childregs->psr &= ~PSR_EF;
|
||||
clear_tsk_thread_flag(p, TIF_USEDFPU);
|
||||
#endif
|
||||
/* Handle return value conventions */
|
||||
if (regs->u_regs[UREG_G1] == __NR_clone3) {
|
||||
/* clone3() - use regular kernel return value convention */
|
||||
|
||||
/* Set the return value for the child. */
|
||||
childregs->u_regs[UREG_I0] = current->pid;
|
||||
childregs->u_regs[UREG_I1] = 1;
|
||||
/* Set the return value for the child. */
|
||||
childregs->u_regs[UREG_I0] = 0;
|
||||
} else {
|
||||
/* clone()/fork() - use SunOS return value convention */
|
||||
|
||||
/* Set the return value for the parent. */
|
||||
regs->u_regs[UREG_I1] = 0;
|
||||
/* Set the return value for the child. */
|
||||
childregs->u_regs[UREG_I0] = current->pid;
|
||||
childregs->u_regs[UREG_I1] = 1;
|
||||
|
||||
/* Set the return value for the parent. */
|
||||
regs->u_regs[UREG_I1] = 0;
|
||||
}
|
||||
|
||||
if (clone_flags & CLONE_SETTLS)
|
||||
childregs->u_regs[UREG_G7] = tls;
|
||||
|
|
|
|||
|
|
@ -564,17 +564,19 @@ barf:
|
|||
* under SunOS are nothing short of bletcherous:
|
||||
* Parent --> %o0 == childs pid, %o1 == 0
|
||||
* Child --> %o0 == parents pid, %o1 == 1
|
||||
*
|
||||
* clone3() - Uses regular kernel return value conventions
|
||||
*/
|
||||
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);
|
||||
|
|
@ -616,12 +618,25 @@ int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
|
|||
if (t->utraps)
|
||||
t->utraps[0]++;
|
||||
|
||||
/* Set the return value for the child. */
|
||||
t->kregs->u_regs[UREG_I0] = current->pid;
|
||||
t->kregs->u_regs[UREG_I1] = 1;
|
||||
/* Handle return value conventions */
|
||||
if (regs->u_regs[UREG_G1] == __NR_clone3) {
|
||||
/* clone3() - use regular kernel return value convention */
|
||||
|
||||
/* Set the second return value for the parent. */
|
||||
regs->u_regs[UREG_I1] = 0;
|
||||
/* Set the return value for the child. */
|
||||
t->kregs->u_regs[UREG_I0] = 0;
|
||||
|
||||
/* Clear g1 to indicate user thread */
|
||||
t->kregs->u_regs[UREG_G1] = 0;
|
||||
} else {
|
||||
/* clone()/fork() - use SunOS return value convention */
|
||||
|
||||
/* Set the return value for the child. */
|
||||
t->kregs->u_regs[UREG_I0] = current->pid;
|
||||
t->kregs->u_regs[UREG_I1] = 1;
|
||||
|
||||
/* Set the second return value for the parent. */
|
||||
regs->u_regs[UREG_I1] = 0;
|
||||
}
|
||||
|
||||
if (clone_flags & CLONE_SETTLS)
|
||||
t->kregs->u_regs[UREG_G7] = tls;
|
||||
|
|
|
|||
|
|
@ -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. */
|
||||
|
|
@ -113,6 +119,8 @@ ret_from_fork:
|
|||
brnz,pt %o0, ret_sys_call
|
||||
ldx [%g6 + TI_FLAGS], %l0
|
||||
ldx [%sp + PTREGS_OFF + PT_V9_G1], %l1
|
||||
brz,pt %l1, ret_sys_call
|
||||
nop
|
||||
call %l1
|
||||
ldx [%sp + PTREGS_OFF + PT_V9_G2], %o0
|
||||
ba,pt %xcc, ret_sys_call
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue