fork-v5.9
-----BEGIN PGP SIGNATURE----- iHUEABYKAB0WIQRAhzRXHqcMeLMyaSiRxhvAZXjcogUCXyge/QAKCRCRxhvAZXjc oildAQCCWpnTeXm6hrIE3VZ36X5npFtbaEthdBVAUJM7mo0FYwEA8+Wbnubg6jCw mztkXCnTfU7tApUdhKtQzcpEws45/Qk= =REE/ -----END PGP SIGNATURE----- Merge tag 'fork-v5.9' of git://git.kernel.org/pub/scm/linux/kernel/git/brauner/linux Pull fork cleanups from Christian Brauner: "This is cleanup series from when we reworked a chunk of the process creation paths in the kernel and switched to struct {kernel_}clone_args. High-level this does two main things: - Remove the double export of both do_fork() and _do_fork() where do_fork() used the incosistent legacy clone calling convention. Now we only export _do_fork() which is based on struct kernel_clone_args. - Remove the copy_thread_tls()/copy_thread() split making the architecture specific HAVE_COYP_THREAD_TLS config option obsolete. This switches all remaining architectures to select HAVE_COPY_THREAD_TLS and thus to the copy_thread_tls() calling convention. The current split makes the process creation codepaths more convoluted than they need to be. Each architecture has their own copy_thread() function unless it selects HAVE_COPY_THREAD_TLS then it has a copy_thread_tls() function. The split is not needed anymore nowadays, all architectures support CLONE_SETTLS but quite a few of them never bothered to select HAVE_COPY_THREAD_TLS and instead simply continued to use copy_thread() and use the old calling convention. Removing this split cleans up the process creation codepaths and paves the way for implementing clone3() on such architectures since it requires the copy_thread_tls() calling convention. After having made each architectures support copy_thread_tls() this series simply renames that function back to copy_thread(). It also switches all architectures that call do_fork() directly over to _do_fork() and the struct kernel_clone_args calling convention. This is a corollary of switching the architectures that did not yet support it over to copy_thread_tls() since do_fork() is conditional on not supporting copy_thread_tls() (Mostly because it lacks a separate argument for tls which is trivial to fix but there's no need for this function to exist.). The do_fork() removal is in itself already useful as it allows to to remove the export of both do_fork() and _do_fork() we currently have in favor of only _do_fork(). This has already been discussed back when we added clone3(). The legacy clone() calling convention is - as is probably well-known - somewhat odd: # # ABI hall of shame # config CLONE_BACKWARDS config CLONE_BACKWARDS2 config CLONE_BACKWARDS3 that is aggravated by the fact that some architectures such as sparc follow the CLONE_BACKWARDSx calling convention but don't really select the corresponding config option since they call do_fork() directly. So do_fork() enforces a somewhat arbitrary calling convention in the first place that doesn't really help the individual architectures that deviate from it. They can thus simply be switched to _do_fork() enforcing a single calling convention. (I really hope that any new architectures will __not__ try to implement their own calling conventions...) Most architectures already have made a similar switch (m68k comes to mind). Overall this removes more code than it adds even with a good portion of added comments. It simplifies a chunk of arch specific assembly either by moving the code into C or by simply rewriting the assembly. Architectures that have been touched in non-trivial ways have all been actually boot and stress tested: sparc and ia64 have been tested with Debian 9 images. They are the two architectures which have been touched the most. All non-trivial changes to architectures have seen acks from the relevant maintainers. nios2 with a custom built buildroot image. h8300 I couldn't get something bootable to test on but the changes have been fairly automatic and I'm sure we'll hear people yell if I broke something there. All other architectures that have been touched in trivial ways have been compile tested for each single patch of the series via git rebase -x "make ..." v5.8-rc2. arm{64} and x86{_64} have been boot tested even though they have just been trivially touched (removal of the HAVE_COPY_THREAD_TLS macro from their Kconfig) because well they are basically "core architectures" and since it is trivial to get your hands on a useable image" * tag 'fork-v5.9' of git://git.kernel.org/pub/scm/linux/kernel/git/brauner/linux: arch: rename copy_thread_tls() back to copy_thread() arch: remove HAVE_COPY_THREAD_TLS unicore: switch to copy_thread_tls() sh: switch to copy_thread_tls() nds32: switch to copy_thread_tls() microblaze: switch to copy_thread_tls() hexagon: switch to copy_thread_tls() c6x: switch to copy_thread_tls() alpha: switch to copy_thread_tls() fork: remove do_fork() h8300: select HAVE_COPY_THREAD_TLS, switch to kernel_clone_args nios2: enable HAVE_COPY_THREAD_TLS, switch to kernel_clone_args ia64: enable HAVE_COPY_THREAD_TLS, switch to kernel_clone_args sparc: unconditionally enable HAVE_COPY_THREAD_TLS sparc: share process creation helpers between sparc and sparc64 sparc64: enable HAVE_COPY_THREAD_TLS fork: fold legacy_clone_args_valid() into _do_fork()
This commit is contained in:
commit
9ba27414f2
|
@ -754,13 +754,6 @@ config ARCH_WANT_DEFAULT_TOPDOWN_MMAP_LAYOUT
|
||||||
depends on MMU
|
depends on MMU
|
||||||
select ARCH_HAS_ELF_RANDOMIZE
|
select ARCH_HAS_ELF_RANDOMIZE
|
||||||
|
|
||||||
config HAVE_COPY_THREAD_TLS
|
|
||||||
bool
|
|
||||||
help
|
|
||||||
Architecture provides copy_thread_tls to accept tls argument via
|
|
||||||
normal C parameter passing, rather than extracting the syscall
|
|
||||||
argument from pt_regs.
|
|
||||||
|
|
||||||
config HAVE_STACK_VALIDATION
|
config HAVE_STACK_VALIDATION
|
||||||
bool
|
bool
|
||||||
help
|
help
|
||||||
|
|
|
@ -233,10 +233,9 @@ release_thread(struct task_struct *dead_task)
|
||||||
/*
|
/*
|
||||||
* Copy architecture-specific thread state
|
* Copy architecture-specific thread state
|
||||||
*/
|
*/
|
||||||
int
|
int copy_thread(unsigned long clone_flags, unsigned long usp,
|
||||||
copy_thread(unsigned long clone_flags, unsigned long usp,
|
unsigned long kthread_arg, struct task_struct *p,
|
||||||
unsigned long kthread_arg,
|
unsigned long tls)
|
||||||
struct task_struct *p)
|
|
||||||
{
|
{
|
||||||
extern void ret_from_fork(void);
|
extern void ret_from_fork(void);
|
||||||
extern void ret_from_kernel_thread(void);
|
extern void ret_from_kernel_thread(void);
|
||||||
|
@ -267,7 +266,7 @@ copy_thread(unsigned long clone_flags, unsigned long usp,
|
||||||
required for proper operation in the case of a threaded
|
required for proper operation in the case of a threaded
|
||||||
application calling fork. */
|
application calling fork. */
|
||||||
if (clone_flags & CLONE_SETTLS)
|
if (clone_flags & CLONE_SETTLS)
|
||||||
childti->pcb.unique = regs->r20;
|
childti->pcb.unique = tls;
|
||||||
else
|
else
|
||||||
regs->r20 = 0; /* OSF/1 has some strange fork() semantics. */
|
regs->r20 = 0; /* OSF/1 has some strange fork() semantics. */
|
||||||
childti->pcb.usp = usp ?: rdusp();
|
childti->pcb.usp = usp ?: rdusp();
|
||||||
|
|
|
@ -29,7 +29,6 @@ config ARC
|
||||||
select GENERIC_SMP_IDLE_THREAD
|
select GENERIC_SMP_IDLE_THREAD
|
||||||
select HAVE_ARCH_KGDB
|
select HAVE_ARCH_KGDB
|
||||||
select HAVE_ARCH_TRACEHOOK
|
select HAVE_ARCH_TRACEHOOK
|
||||||
select HAVE_COPY_THREAD_TLS
|
|
||||||
select HAVE_DEBUG_STACKOVERFLOW
|
select HAVE_DEBUG_STACKOVERFLOW
|
||||||
select HAVE_DEBUG_KMEMLEAK
|
select HAVE_DEBUG_KMEMLEAK
|
||||||
select HAVE_FUTEX_CMPXCHG if FUTEX
|
select HAVE_FUTEX_CMPXCHG if FUTEX
|
||||||
|
|
|
@ -173,8 +173,9 @@ asmlinkage void ret_from_fork(void);
|
||||||
* | user_r25 |
|
* | user_r25 |
|
||||||
* ------------------ <===== END of PAGE
|
* ------------------ <===== END of PAGE
|
||||||
*/
|
*/
|
||||||
int copy_thread_tls(unsigned long clone_flags, unsigned long usp,
|
int copy_thread(unsigned long clone_flags, unsigned long usp,
|
||||||
unsigned long kthread_arg, struct task_struct *p, unsigned long tls)
|
unsigned long kthread_arg, struct task_struct *p,
|
||||||
|
unsigned long tls)
|
||||||
{
|
{
|
||||||
struct pt_regs *c_regs; /* child's pt_regs */
|
struct pt_regs *c_regs; /* child's pt_regs */
|
||||||
unsigned long *childksp; /* to unwind out of __switch_to() */
|
unsigned long *childksp; /* to unwind out of __switch_to() */
|
||||||
|
|
|
@ -72,7 +72,6 @@ config ARM
|
||||||
select HAVE_ARM_SMCCC if CPU_V7
|
select HAVE_ARM_SMCCC if CPU_V7
|
||||||
select HAVE_EBPF_JIT if !CPU_ENDIAN_BE32
|
select HAVE_EBPF_JIT if !CPU_ENDIAN_BE32
|
||||||
select HAVE_CONTEXT_TRACKING
|
select HAVE_CONTEXT_TRACKING
|
||||||
select HAVE_COPY_THREAD_TLS
|
|
||||||
select HAVE_C_RECORDMCOUNT
|
select HAVE_C_RECORDMCOUNT
|
||||||
select HAVE_DEBUG_KMEMLEAK if !XIP_KERNEL
|
select HAVE_DEBUG_KMEMLEAK if !XIP_KERNEL
|
||||||
select HAVE_DMA_CONTIGUOUS if MMU
|
select HAVE_DMA_CONTIGUOUS if MMU
|
||||||
|
|
|
@ -225,9 +225,8 @@ void release_thread(struct task_struct *dead_task)
|
||||||
|
|
||||||
asmlinkage void ret_from_fork(void) __asm__("ret_from_fork");
|
asmlinkage void ret_from_fork(void) __asm__("ret_from_fork");
|
||||||
|
|
||||||
int
|
int copy_thread(unsigned long clone_flags, unsigned long stack_start,
|
||||||
copy_thread_tls(unsigned long clone_flags, unsigned long stack_start,
|
unsigned long stk_sz, struct task_struct *p, unsigned long tls)
|
||||||
unsigned long stk_sz, struct task_struct *p, unsigned long tls)
|
|
||||||
{
|
{
|
||||||
struct thread_info *thread = task_thread_info(p);
|
struct thread_info *thread = task_thread_info(p);
|
||||||
struct pt_regs *childregs = task_pt_regs(p);
|
struct pt_regs *childregs = task_pt_regs(p);
|
||||||
|
|
|
@ -149,7 +149,6 @@ config ARM64
|
||||||
select HAVE_CMPXCHG_DOUBLE
|
select HAVE_CMPXCHG_DOUBLE
|
||||||
select HAVE_CMPXCHG_LOCAL
|
select HAVE_CMPXCHG_LOCAL
|
||||||
select HAVE_CONTEXT_TRACKING
|
select HAVE_CONTEXT_TRACKING
|
||||||
select HAVE_COPY_THREAD_TLS
|
|
||||||
select HAVE_DEBUG_BUGVERBOSE
|
select HAVE_DEBUG_BUGVERBOSE
|
||||||
select HAVE_DEBUG_KMEMLEAK
|
select HAVE_DEBUG_KMEMLEAK
|
||||||
select HAVE_DMA_CONTIGUOUS
|
select HAVE_DMA_CONTIGUOUS
|
||||||
|
|
|
@ -375,7 +375,7 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
|
||||||
|
|
||||||
asmlinkage void ret_from_fork(void) asm("ret_from_fork");
|
asmlinkage void ret_from_fork(void) asm("ret_from_fork");
|
||||||
|
|
||||||
int copy_thread_tls(unsigned long clone_flags, unsigned long stack_start,
|
int copy_thread(unsigned long clone_flags, unsigned long stack_start,
|
||||||
unsigned long stk_sz, struct task_struct *p, unsigned long tls)
|
unsigned long stk_sz, struct task_struct *p, unsigned long tls)
|
||||||
{
|
{
|
||||||
struct pt_regs *childregs = task_pt_regs(p);
|
struct pt_regs *childregs = task_pt_regs(p);
|
||||||
|
|
|
@ -105,8 +105,8 @@ void start_thread(struct pt_regs *regs, unsigned int pc, unsigned long usp)
|
||||||
* Copy a new thread context in its stack.
|
* Copy a new thread context in its stack.
|
||||||
*/
|
*/
|
||||||
int copy_thread(unsigned long clone_flags, unsigned long usp,
|
int copy_thread(unsigned long clone_flags, unsigned long usp,
|
||||||
unsigned long ustk_size,
|
unsigned long ustk_size, struct task_struct *p,
|
||||||
struct task_struct *p)
|
unsigned long tls)
|
||||||
{
|
{
|
||||||
struct pt_regs *childregs;
|
struct pt_regs *childregs;
|
||||||
|
|
||||||
|
|
|
@ -38,7 +38,6 @@ config CSKY
|
||||||
select GX6605S_TIMER if CPU_CK610
|
select GX6605S_TIMER if CPU_CK610
|
||||||
select HAVE_ARCH_TRACEHOOK
|
select HAVE_ARCH_TRACEHOOK
|
||||||
select HAVE_ARCH_AUDITSYSCALL
|
select HAVE_ARCH_AUDITSYSCALL
|
||||||
select HAVE_COPY_THREAD_TLS
|
|
||||||
select HAVE_DEBUG_BUGVERBOSE
|
select HAVE_DEBUG_BUGVERBOSE
|
||||||
select HAVE_DYNAMIC_FTRACE
|
select HAVE_DYNAMIC_FTRACE
|
||||||
select HAVE_DYNAMIC_FTRACE_WITH_REGS
|
select HAVE_DYNAMIC_FTRACE_WITH_REGS
|
||||||
|
|
|
@ -40,7 +40,7 @@ unsigned long thread_saved_pc(struct task_struct *tsk)
|
||||||
return sw->r15;
|
return sw->r15;
|
||||||
}
|
}
|
||||||
|
|
||||||
int copy_thread_tls(unsigned long clone_flags,
|
int copy_thread(unsigned long clone_flags,
|
||||||
unsigned long usp,
|
unsigned long usp,
|
||||||
unsigned long kthread_arg,
|
unsigned long kthread_arg,
|
||||||
struct task_struct *p,
|
struct task_struct *p,
|
||||||
|
|
|
@ -105,9 +105,8 @@ void flush_thread(void)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
int copy_thread(unsigned long clone_flags,
|
int copy_thread(unsigned long clone_flags, unsigned long usp,
|
||||||
unsigned long usp, unsigned long topstk,
|
unsigned long topstk, struct task_struct *p, unsigned long tls)
|
||||||
struct task_struct *p)
|
|
||||||
{
|
{
|
||||||
struct pt_regs *childregs;
|
struct pt_regs *childregs;
|
||||||
|
|
||||||
|
@ -159,11 +158,19 @@ asmlinkage int sys_clone(unsigned long __user *args)
|
||||||
unsigned long newsp;
|
unsigned long newsp;
|
||||||
uintptr_t parent_tidptr;
|
uintptr_t parent_tidptr;
|
||||||
uintptr_t child_tidptr;
|
uintptr_t child_tidptr;
|
||||||
|
struct kernel_clone_args kargs = {};
|
||||||
|
|
||||||
get_user(clone_flags, &args[0]);
|
get_user(clone_flags, &args[0]);
|
||||||
get_user(newsp, &args[1]);
|
get_user(newsp, &args[1]);
|
||||||
get_user(parent_tidptr, &args[2]);
|
get_user(parent_tidptr, &args[2]);
|
||||||
get_user(child_tidptr, &args[3]);
|
get_user(child_tidptr, &args[3]);
|
||||||
return do_fork(clone_flags, newsp, 0,
|
|
||||||
(int __user *)parent_tidptr, (int __user *)child_tidptr);
|
kargs.flags = (lower_32_bits(clone_flags) & ~CSIGNAL);
|
||||||
|
kargs.pidfd = (int __user *)parent_tidptr;
|
||||||
|
kargs.child_tid = (int __user *)child_tidptr;
|
||||||
|
kargs.parent_tid = (int __user *)parent_tidptr;
|
||||||
|
kargs.exit_signal = (lower_32_bits(clone_flags) & CSIGNAL);
|
||||||
|
kargs.stack = newsp;
|
||||||
|
|
||||||
|
return _do_fork(&kargs);
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,8 +50,8 @@ void arch_cpu_idle(void)
|
||||||
/*
|
/*
|
||||||
* Copy architecture-specific thread state
|
* Copy architecture-specific thread state
|
||||||
*/
|
*/
|
||||||
int copy_thread(unsigned long clone_flags, unsigned long usp,
|
int copy_thread(unsigned long clone_flags, unsigned long usp, unsigned long arg,
|
||||||
unsigned long arg, struct task_struct *p)
|
struct task_struct *p, unsigned long tls)
|
||||||
{
|
{
|
||||||
struct thread_info *ti = task_thread_info(p);
|
struct thread_info *ti = task_thread_info(p);
|
||||||
struct hexagon_switch_stack *ss;
|
struct hexagon_switch_stack *ss;
|
||||||
|
@ -100,7 +100,7 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,
|
||||||
* ugp is used to provide TLS support.
|
* ugp is used to provide TLS support.
|
||||||
*/
|
*/
|
||||||
if (clone_flags & CLONE_SETTLS)
|
if (clone_flags & CLONE_SETTLS)
|
||||||
childregs->ugp = childregs->r04;
|
childregs->ugp = tls;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Parent sees new pid -- not necessary, not even possible at
|
* Parent sees new pid -- not necessary, not even possible at
|
||||||
|
|
|
@ -112,19 +112,16 @@ GLOBAL_ENTRY(sys_clone2)
|
||||||
.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8)
|
.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8)
|
||||||
alloc r16=ar.pfs,8,2,6,0
|
alloc r16=ar.pfs,8,2,6,0
|
||||||
DO_SAVE_SWITCH_STACK
|
DO_SAVE_SWITCH_STACK
|
||||||
adds r2=PT(R16)+IA64_SWITCH_STACK_SIZE+16,sp
|
|
||||||
mov loc0=rp
|
mov loc0=rp
|
||||||
mov loc1=r16 // save ar.pfs across do_fork
|
mov loc1=r16 // save ar.pfs across ia64_clone
|
||||||
.body
|
.body
|
||||||
|
mov out0=in0
|
||||||
mov out1=in1
|
mov out1=in1
|
||||||
mov out2=in2
|
mov out2=in2
|
||||||
tbit.nz p6,p0=in0,CLONE_SETTLS_BIT
|
mov out3=in3
|
||||||
mov out3=in3 // parent_tidptr: valid only w/CLONE_PARENT_SETTID
|
mov out4=in4
|
||||||
;;
|
mov out5=in5
|
||||||
(p6) st8 [r2]=in5 // store TLS in r16 for copy_thread()
|
br.call.sptk.many rp=ia64_clone
|
||||||
mov out4=in4 // child_tidptr: valid only w/CLONE_CHILD_SETTID or CLONE_CHILD_CLEARTID
|
|
||||||
mov out0=in0 // out0 = clone_flags
|
|
||||||
br.call.sptk.many rp=do_fork
|
|
||||||
.ret1: .restore sp
|
.ret1: .restore sp
|
||||||
adds sp=IA64_SWITCH_STACK_SIZE,sp // pop the switch stack
|
adds sp=IA64_SWITCH_STACK_SIZE,sp // pop the switch stack
|
||||||
mov ar.pfs=loc1
|
mov ar.pfs=loc1
|
||||||
|
@ -143,19 +140,16 @@ GLOBAL_ENTRY(sys_clone)
|
||||||
.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8)
|
.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8)
|
||||||
alloc r16=ar.pfs,8,2,6,0
|
alloc r16=ar.pfs,8,2,6,0
|
||||||
DO_SAVE_SWITCH_STACK
|
DO_SAVE_SWITCH_STACK
|
||||||
adds r2=PT(R16)+IA64_SWITCH_STACK_SIZE+16,sp
|
|
||||||
mov loc0=rp
|
mov loc0=rp
|
||||||
mov loc1=r16 // save ar.pfs across do_fork
|
mov loc1=r16 // save ar.pfs across ia64_clone
|
||||||
.body
|
.body
|
||||||
|
mov out0=in0
|
||||||
mov out1=in1
|
mov out1=in1
|
||||||
mov out2=16 // stacksize (compensates for 16-byte scratch area)
|
mov out2=16 // stacksize (compensates for 16-byte scratch area)
|
||||||
tbit.nz p6,p0=in0,CLONE_SETTLS_BIT
|
mov out3=in3
|
||||||
mov out3=in2 // parent_tidptr: valid only w/CLONE_PARENT_SETTID
|
mov out4=in4
|
||||||
;;
|
mov out5=in5
|
||||||
(p6) st8 [r2]=in4 // store TLS in r13 (tp)
|
br.call.sptk.many rp=ia64_clone
|
||||||
mov out4=in3 // child_tidptr: valid only w/CLONE_CHILD_SETTID or CLONE_CHILD_CLEARTID
|
|
||||||
mov out0=in0 // out0 = clone_flags
|
|
||||||
br.call.sptk.many rp=do_fork
|
|
||||||
.ret2: .restore sp
|
.ret2: .restore sp
|
||||||
adds sp=IA64_SWITCH_STACK_SIZE,sp // pop the switch stack
|
adds sp=IA64_SWITCH_STACK_SIZE,sp // pop the switch stack
|
||||||
mov ar.pfs=loc1
|
mov ar.pfs=loc1
|
||||||
|
@ -590,7 +584,7 @@ GLOBAL_ENTRY(ia64_ret_from_clone)
|
||||||
nop.i 0
|
nop.i 0
|
||||||
/*
|
/*
|
||||||
* We need to call schedule_tail() to complete the scheduling process.
|
* We need to call schedule_tail() to complete the scheduling process.
|
||||||
* Called by ia64_switch_to() after do_fork()->copy_thread(). r8 contains the
|
* Called by ia64_switch_to() after ia64_clone()->copy_thread(). r8 contains the
|
||||||
* address of the previously executing task.
|
* address of the previously executing task.
|
||||||
*/
|
*/
|
||||||
br.call.sptk.many rp=ia64_invoke_schedule_tail
|
br.call.sptk.many rp=ia64_invoke_schedule_tail
|
||||||
|
|
|
@ -296,7 +296,7 @@ ia64_load_extra (struct task_struct *task)
|
||||||
pfm_load_regs(task);
|
pfm_load_regs(task);
|
||||||
|
|
||||||
info = __this_cpu_read(pfm_syst_info);
|
info = __this_cpu_read(pfm_syst_info);
|
||||||
if (info & PFM_CPUINFO_SYST_WIDE)
|
if (info & PFM_CPUINFO_SYST_WIDE)
|
||||||
pfm_syst_wide_update_task(task, info, 1);
|
pfm_syst_wide_update_task(task, info, 1);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -310,7 +310,7 @@ ia64_load_extra (struct task_struct *task)
|
||||||
*
|
*
|
||||||
* <clone syscall> <some kernel call frames>
|
* <clone syscall> <some kernel call frames>
|
||||||
* sys_clone :
|
* sys_clone :
|
||||||
* do_fork do_fork
|
* _do_fork _do_fork
|
||||||
* copy_thread copy_thread
|
* copy_thread copy_thread
|
||||||
*
|
*
|
||||||
* This means that the stack layout is as follows:
|
* This means that the stack layout is as follows:
|
||||||
|
@ -333,9 +333,8 @@ ia64_load_extra (struct task_struct *task)
|
||||||
* so there is nothing to worry about.
|
* so there is nothing to worry about.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
copy_thread(unsigned long clone_flags,
|
copy_thread(unsigned long clone_flags, unsigned long user_stack_base,
|
||||||
unsigned long user_stack_base, unsigned long user_stack_size,
|
unsigned long user_stack_size, struct task_struct *p, unsigned long tls)
|
||||||
struct task_struct *p)
|
|
||||||
{
|
{
|
||||||
extern char ia64_ret_from_clone;
|
extern char ia64_ret_from_clone;
|
||||||
struct switch_stack *child_stack, *stack;
|
struct switch_stack *child_stack, *stack;
|
||||||
|
@ -416,7 +415,7 @@ copy_thread(unsigned long clone_flags,
|
||||||
rbs_size = stack->ar_bspstore - rbs;
|
rbs_size = stack->ar_bspstore - rbs;
|
||||||
memcpy((void *) child_rbs, (void *) rbs, rbs_size);
|
memcpy((void *) child_rbs, (void *) rbs, rbs_size);
|
||||||
if (clone_flags & CLONE_SETTLS)
|
if (clone_flags & CLONE_SETTLS)
|
||||||
child_ptregs->r13 = regs->r16; /* see sys_clone2() in entry.S */
|
child_ptregs->r13 = tls;
|
||||||
if (user_stack_base) {
|
if (user_stack_base) {
|
||||||
child_ptregs->r12 = user_stack_base + user_stack_size - 16;
|
child_ptregs->r12 = user_stack_base + user_stack_size - 16;
|
||||||
child_ptregs->ar_bspstore = user_stack_base;
|
child_ptregs->ar_bspstore = user_stack_base;
|
||||||
|
@ -441,6 +440,24 @@ copy_thread(unsigned long clone_flags,
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
asmlinkage long ia64_clone(unsigned long clone_flags, unsigned long stack_start,
|
||||||
|
unsigned long stack_size, unsigned long parent_tidptr,
|
||||||
|
unsigned long child_tidptr, unsigned long tls)
|
||||||
|
{
|
||||||
|
struct kernel_clone_args args = {
|
||||||
|
.flags = (lower_32_bits(clone_flags) & ~CSIGNAL),
|
||||||
|
.pidfd = (int __user *)parent_tidptr,
|
||||||
|
.child_tid = (int __user *)child_tidptr,
|
||||||
|
.parent_tid = (int __user *)parent_tidptr,
|
||||||
|
.exit_signal = (lower_32_bits(clone_flags) & CSIGNAL),
|
||||||
|
.stack = stack_start,
|
||||||
|
.stack_size = stack_size,
|
||||||
|
.tls = tls,
|
||||||
|
};
|
||||||
|
|
||||||
|
return _do_fork(&args);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
do_copy_task_regs (struct task_struct *task, struct unw_frame_info *info, void *arg)
|
do_copy_task_regs (struct task_struct *task, struct unw_frame_info *info, void *arg)
|
||||||
{
|
{
|
||||||
|
|
|
@ -14,7 +14,6 @@ config M68K
|
||||||
select HAVE_AOUT if MMU
|
select HAVE_AOUT if MMU
|
||||||
select HAVE_ASM_MODVERSIONS
|
select HAVE_ASM_MODVERSIONS
|
||||||
select HAVE_DEBUG_BUGVERBOSE
|
select HAVE_DEBUG_BUGVERBOSE
|
||||||
select HAVE_COPY_THREAD_TLS
|
|
||||||
select GENERIC_IRQ_SHOW
|
select GENERIC_IRQ_SHOW
|
||||||
select GENERIC_ATOMIC64
|
select GENERIC_ATOMIC64
|
||||||
select HAVE_UID16
|
select HAVE_UID16
|
||||||
|
|
|
@ -125,9 +125,6 @@ asmlinkage int m68k_clone(struct pt_regs *regs)
|
||||||
.tls = regs->d5,
|
.tls = regs->d5,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!legacy_clone_args_valid(&args))
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
return _do_fork(&args);
|
return _do_fork(&args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -141,9 +138,8 @@ asmlinkage int m68k_clone3(struct pt_regs *regs)
|
||||||
return sys_clone3((struct clone_args __user *)regs->d1, regs->d2);
|
return sys_clone3((struct clone_args __user *)regs->d1, regs->d2);
|
||||||
}
|
}
|
||||||
|
|
||||||
int copy_thread_tls(unsigned long clone_flags, unsigned long usp,
|
int copy_thread(unsigned long clone_flags, unsigned long usp, unsigned long arg,
|
||||||
unsigned long arg, struct task_struct *p,
|
struct task_struct *p, unsigned long tls)
|
||||||
unsigned long tls)
|
|
||||||
{
|
{
|
||||||
struct fork_frame {
|
struct fork_frame {
|
||||||
struct switch_stack sw;
|
struct switch_stack sw;
|
||||||
|
|
|
@ -54,8 +54,8 @@ void flush_thread(void)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
int copy_thread(unsigned long clone_flags, unsigned long usp,
|
int copy_thread(unsigned long clone_flags, unsigned long usp, unsigned long arg,
|
||||||
unsigned long arg, struct task_struct *p)
|
struct task_struct *p, unsigned long tls)
|
||||||
{
|
{
|
||||||
struct pt_regs *childregs = task_pt_regs(p);
|
struct pt_regs *childregs = task_pt_regs(p);
|
||||||
struct thread_info *ti = task_thread_info(p);
|
struct thread_info *ti = task_thread_info(p);
|
||||||
|
@ -114,7 +114,7 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,
|
||||||
* which contains TLS area
|
* which contains TLS area
|
||||||
*/
|
*/
|
||||||
if (clone_flags & CLONE_SETTLS)
|
if (clone_flags & CLONE_SETTLS)
|
||||||
childregs->r21 = childregs->r10;
|
childregs->r21 = tls;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,7 +51,6 @@ config MIPS
|
||||||
select HAVE_CBPF_JIT if !64BIT && !CPU_MICROMIPS
|
select HAVE_CBPF_JIT if !64BIT && !CPU_MICROMIPS
|
||||||
select HAVE_CONTEXT_TRACKING
|
select HAVE_CONTEXT_TRACKING
|
||||||
select HAVE_TIF_NOHZ
|
select HAVE_TIF_NOHZ
|
||||||
select HAVE_COPY_THREAD_TLS
|
|
||||||
select HAVE_C_RECORDMCOUNT
|
select HAVE_C_RECORDMCOUNT
|
||||||
select HAVE_DEBUG_KMEMLEAK
|
select HAVE_DEBUG_KMEMLEAK
|
||||||
select HAVE_DEBUG_STACKOVERFLOW
|
select HAVE_DEBUG_STACKOVERFLOW
|
||||||
|
|
|
@ -119,8 +119,9 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
|
||||||
/*
|
/*
|
||||||
* Copy architecture-specific thread state
|
* Copy architecture-specific thread state
|
||||||
*/
|
*/
|
||||||
int copy_thread_tls(unsigned long clone_flags, unsigned long usp,
|
int copy_thread(unsigned long clone_flags, unsigned long usp,
|
||||||
unsigned long kthread_arg, struct task_struct *p, unsigned long tls)
|
unsigned long kthread_arg, struct task_struct *p,
|
||||||
|
unsigned long tls)
|
||||||
{
|
{
|
||||||
struct thread_info *ti = task_thread_info(p);
|
struct thread_info *ti = task_thread_info(p);
|
||||||
struct pt_regs *childregs, *regs = current_pt_regs();
|
struct pt_regs *childregs, *regs = current_pt_regs();
|
||||||
|
|
|
@ -150,7 +150,7 @@ DEFINE_PER_CPU(struct task_struct *, __entry_task);
|
||||||
|
|
||||||
asmlinkage void ret_from_fork(void) __asm__("ret_from_fork");
|
asmlinkage void ret_from_fork(void) __asm__("ret_from_fork");
|
||||||
int copy_thread(unsigned long clone_flags, unsigned long stack_start,
|
int copy_thread(unsigned long clone_flags, unsigned long stack_start,
|
||||||
unsigned long stk_sz, struct task_struct *p)
|
unsigned long stk_sz, struct task_struct *p, unsigned long tls)
|
||||||
{
|
{
|
||||||
struct pt_regs *childregs = task_pt_regs(p);
|
struct pt_regs *childregs = task_pt_regs(p);
|
||||||
|
|
||||||
|
@ -170,7 +170,7 @@ int copy_thread(unsigned long clone_flags, unsigned long stack_start,
|
||||||
childregs->uregs[0] = 0;
|
childregs->uregs[0] = 0;
|
||||||
childregs->osp = 0;
|
childregs->osp = 0;
|
||||||
if (clone_flags & CLONE_SETTLS)
|
if (clone_flags & CLONE_SETTLS)
|
||||||
childregs->uregs[25] = childregs->uregs[3];
|
childregs->uregs[25] = tls;
|
||||||
}
|
}
|
||||||
/* cpu context switching */
|
/* cpu context switching */
|
||||||
p->thread.cpu_context.pc = (unsigned long)ret_from_fork;
|
p->thread.cpu_context.pc = (unsigned long)ret_from_fork;
|
||||||
|
|
|
@ -389,12 +389,7 @@ ENTRY(ret_from_interrupt)
|
||||||
*/
|
*/
|
||||||
ENTRY(sys_clone)
|
ENTRY(sys_clone)
|
||||||
SAVE_SWITCH_STACK
|
SAVE_SWITCH_STACK
|
||||||
addi sp, sp, -4
|
call nios2_clone
|
||||||
stw r7, 0(sp) /* Pass 5th arg thru stack */
|
|
||||||
mov r7, r6 /* 4th arg is 3rd of clone() */
|
|
||||||
mov r6, zero /* 3rd arg always 0 */
|
|
||||||
call do_fork
|
|
||||||
addi sp, sp, 4
|
|
||||||
RESTORE_SWITCH_STACK
|
RESTORE_SWITCH_STACK
|
||||||
ret
|
ret
|
||||||
|
|
||||||
|
|
|
@ -100,8 +100,8 @@ void flush_thread(void)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
int copy_thread(unsigned long clone_flags,
|
int copy_thread(unsigned long clone_flags, unsigned long usp, unsigned long arg,
|
||||||
unsigned long usp, unsigned long arg, struct task_struct *p)
|
struct task_struct *p, unsigned long tls)
|
||||||
{
|
{
|
||||||
struct pt_regs *childregs = task_pt_regs(p);
|
struct pt_regs *childregs = task_pt_regs(p);
|
||||||
struct pt_regs *regs;
|
struct pt_regs *regs;
|
||||||
|
@ -140,7 +140,7 @@ int copy_thread(unsigned long clone_flags,
|
||||||
|
|
||||||
/* Initialize tls register. */
|
/* Initialize tls register. */
|
||||||
if (clone_flags & CLONE_SETTLS)
|
if (clone_flags & CLONE_SETTLS)
|
||||||
childstack->r23 = regs->r8;
|
childstack->r23 = tls;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -259,3 +259,20 @@ int dump_fpu(struct pt_regs *regs, elf_fpregset_t *r)
|
||||||
{
|
{
|
||||||
return 0; /* Nios2 has no FPU and thus no FPU registers */
|
return 0; /* Nios2 has no FPU and thus no FPU registers */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
asmlinkage int nios2_clone(unsigned long clone_flags, unsigned long newsp,
|
||||||
|
int __user *parent_tidptr, int __user *child_tidptr,
|
||||||
|
unsigned long tls)
|
||||||
|
{
|
||||||
|
struct kernel_clone_args args = {
|
||||||
|
.flags = (lower_32_bits(clone_flags) & ~CSIGNAL),
|
||||||
|
.pidfd = parent_tidptr,
|
||||||
|
.child_tid = child_tidptr,
|
||||||
|
.parent_tid = parent_tidptr,
|
||||||
|
.exit_signal = (lower_32_bits(clone_flags) & CSIGNAL),
|
||||||
|
.stack = newsp,
|
||||||
|
.tls = tls,
|
||||||
|
};
|
||||||
|
|
||||||
|
return _do_fork(&args);
|
||||||
|
}
|
||||||
|
|
|
@ -16,7 +16,6 @@ config OPENRISC
|
||||||
select HANDLE_DOMAIN_IRQ
|
select HANDLE_DOMAIN_IRQ
|
||||||
select GPIOLIB
|
select GPIOLIB
|
||||||
select HAVE_ARCH_TRACEHOOK
|
select HAVE_ARCH_TRACEHOOK
|
||||||
select HAVE_COPY_THREAD_TLS
|
|
||||||
select SPARSE_IRQ
|
select SPARSE_IRQ
|
||||||
select GENERIC_IRQ_CHIP
|
select GENERIC_IRQ_CHIP
|
||||||
select GENERIC_IRQ_PROBE
|
select GENERIC_IRQ_PROBE
|
||||||
|
|
|
@ -116,7 +116,7 @@ void release_thread(struct task_struct *dead_task)
|
||||||
extern asmlinkage void ret_from_fork(void);
|
extern asmlinkage void ret_from_fork(void);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* copy_thread_tls
|
* copy_thread
|
||||||
* @clone_flags: flags
|
* @clone_flags: flags
|
||||||
* @usp: user stack pointer or fn for kernel thread
|
* @usp: user stack pointer or fn for kernel thread
|
||||||
* @arg: arg to fn for kernel thread; always NULL for userspace thread
|
* @arg: arg to fn for kernel thread; always NULL for userspace thread
|
||||||
|
@ -147,8 +147,8 @@ extern asmlinkage void ret_from_fork(void);
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int
|
int
|
||||||
copy_thread_tls(unsigned long clone_flags, unsigned long usp,
|
copy_thread(unsigned long clone_flags, unsigned long usp, unsigned long arg,
|
||||||
unsigned long arg, struct task_struct *p, unsigned long tls)
|
struct task_struct *p, unsigned long tls)
|
||||||
{
|
{
|
||||||
struct pt_regs *userregs;
|
struct pt_regs *userregs;
|
||||||
struct pt_regs *kregs;
|
struct pt_regs *kregs;
|
||||||
|
|
|
@ -62,7 +62,6 @@ config PARISC
|
||||||
select HAVE_FTRACE_MCOUNT_RECORD if HAVE_DYNAMIC_FTRACE
|
select HAVE_FTRACE_MCOUNT_RECORD if HAVE_DYNAMIC_FTRACE
|
||||||
select HAVE_KPROBES_ON_FTRACE
|
select HAVE_KPROBES_ON_FTRACE
|
||||||
select HAVE_DYNAMIC_FTRACE_WITH_REGS
|
select HAVE_DYNAMIC_FTRACE_WITH_REGS
|
||||||
select HAVE_COPY_THREAD_TLS
|
|
||||||
|
|
||||||
help
|
help
|
||||||
The PA-RISC microprocessor is designed by Hewlett-Packard and used
|
The PA-RISC microprocessor is designed by Hewlett-Packard and used
|
||||||
|
|
|
@ -208,7 +208,7 @@ arch_initcall(parisc_idle_init);
|
||||||
* Copy architecture-specific thread state
|
* Copy architecture-specific thread state
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
copy_thread_tls(unsigned long clone_flags, unsigned long usp,
|
copy_thread(unsigned long clone_flags, unsigned long usp,
|
||||||
unsigned long kthread_arg, struct task_struct *p, unsigned long tls)
|
unsigned long kthread_arg, struct task_struct *p, unsigned long tls)
|
||||||
{
|
{
|
||||||
struct pt_regs *cregs = &(p->thread.regs);
|
struct pt_regs *cregs = &(p->thread.regs);
|
||||||
|
|
|
@ -186,7 +186,6 @@ config PPC
|
||||||
select HAVE_STACKPROTECTOR if PPC32 && $(cc-option,-mstack-protector-guard=tls -mstack-protector-guard-reg=r2)
|
select HAVE_STACKPROTECTOR if PPC32 && $(cc-option,-mstack-protector-guard=tls -mstack-protector-guard-reg=r2)
|
||||||
select HAVE_CONTEXT_TRACKING if PPC64
|
select HAVE_CONTEXT_TRACKING if PPC64
|
||||||
select HAVE_TIF_NOHZ if PPC64
|
select HAVE_TIF_NOHZ if PPC64
|
||||||
select HAVE_COPY_THREAD_TLS
|
|
||||||
select HAVE_DEBUG_KMEMLEAK
|
select HAVE_DEBUG_KMEMLEAK
|
||||||
select HAVE_DEBUG_STACKOVERFLOW
|
select HAVE_DEBUG_STACKOVERFLOW
|
||||||
select HAVE_DYNAMIC_FTRACE
|
select HAVE_DYNAMIC_FTRACE
|
||||||
|
|
|
@ -1593,7 +1593,7 @@ static void setup_ksp_vsid(struct task_struct *p, unsigned long sp)
|
||||||
/*
|
/*
|
||||||
* Copy architecture-specific thread state
|
* Copy architecture-specific thread state
|
||||||
*/
|
*/
|
||||||
int copy_thread_tls(unsigned long clone_flags, unsigned long usp,
|
int copy_thread(unsigned long clone_flags, unsigned long usp,
|
||||||
unsigned long kthread_arg, struct task_struct *p,
|
unsigned long kthread_arg, struct task_struct *p,
|
||||||
unsigned long tls)
|
unsigned long tls)
|
||||||
{
|
{
|
||||||
|
|
|
@ -54,7 +54,6 @@ config RISCV
|
||||||
select HAVE_ARCH_SECCOMP_FILTER
|
select HAVE_ARCH_SECCOMP_FILTER
|
||||||
select HAVE_ARCH_TRACEHOOK
|
select HAVE_ARCH_TRACEHOOK
|
||||||
select HAVE_ASM_MODVERSIONS
|
select HAVE_ASM_MODVERSIONS
|
||||||
select HAVE_COPY_THREAD_TLS
|
|
||||||
select HAVE_DMA_CONTIGUOUS if MMU
|
select HAVE_DMA_CONTIGUOUS if MMU
|
||||||
select HAVE_EBPF_JIT if MMU
|
select HAVE_EBPF_JIT if MMU
|
||||||
select HAVE_FUTEX_CMPXCHG if FUTEX
|
select HAVE_FUTEX_CMPXCHG if FUTEX
|
||||||
|
|
|
@ -101,8 +101,8 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int copy_thread_tls(unsigned long clone_flags, unsigned long usp,
|
int copy_thread(unsigned long clone_flags, unsigned long usp, unsigned long arg,
|
||||||
unsigned long arg, struct task_struct *p, unsigned long tls)
|
struct task_struct *p, unsigned long tls)
|
||||||
{
|
{
|
||||||
struct pt_regs *childregs = task_pt_regs(p);
|
struct pt_regs *childregs = task_pt_regs(p);
|
||||||
|
|
||||||
|
|
|
@ -136,7 +136,6 @@ config S390
|
||||||
select HAVE_EBPF_JIT if PACK_STACK && HAVE_MARCH_Z196_FEATURES
|
select HAVE_EBPF_JIT if PACK_STACK && HAVE_MARCH_Z196_FEATURES
|
||||||
select HAVE_CMPXCHG_DOUBLE
|
select HAVE_CMPXCHG_DOUBLE
|
||||||
select HAVE_CMPXCHG_LOCAL
|
select HAVE_CMPXCHG_LOCAL
|
||||||
select HAVE_COPY_THREAD_TLS
|
|
||||||
select HAVE_DEBUG_KMEMLEAK
|
select HAVE_DEBUG_KMEMLEAK
|
||||||
select HAVE_DMA_CONTIGUOUS
|
select HAVE_DMA_CONTIGUOUS
|
||||||
select HAVE_DYNAMIC_FTRACE
|
select HAVE_DYNAMIC_FTRACE
|
||||||
|
|
|
@ -80,8 +80,8 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int copy_thread_tls(unsigned long clone_flags, unsigned long new_stackp,
|
int copy_thread(unsigned long clone_flags, unsigned long new_stackp,
|
||||||
unsigned long arg, struct task_struct *p, unsigned long tls)
|
unsigned long arg, struct task_struct *p, unsigned long tls)
|
||||||
{
|
{
|
||||||
struct fake_frame
|
struct fake_frame
|
||||||
{
|
{
|
||||||
|
|
|
@ -115,8 +115,8 @@ EXPORT_SYMBOL(dump_fpu);
|
||||||
asmlinkage void ret_from_fork(void);
|
asmlinkage void ret_from_fork(void);
|
||||||
asmlinkage void ret_from_kernel_thread(void);
|
asmlinkage void ret_from_kernel_thread(void);
|
||||||
|
|
||||||
int copy_thread(unsigned long clone_flags, unsigned long usp,
|
int copy_thread(unsigned long clone_flags, unsigned long usp, unsigned long arg,
|
||||||
unsigned long arg, struct task_struct *p)
|
struct task_struct *p, unsigned long tls)
|
||||||
{
|
{
|
||||||
struct thread_info *ti = task_thread_info(p);
|
struct thread_info *ti = task_thread_info(p);
|
||||||
struct pt_regs *childregs;
|
struct pt_regs *childregs;
|
||||||
|
@ -158,7 +158,7 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,
|
||||||
ti->addr_limit = USER_DS;
|
ti->addr_limit = USER_DS;
|
||||||
|
|
||||||
if (clone_flags & CLONE_SETTLS)
|
if (clone_flags & CLONE_SETTLS)
|
||||||
childregs->gbr = childregs->regs[0];
|
childregs->gbr = tls;
|
||||||
|
|
||||||
childregs->regs[0] = 0; /* Set return value for child */
|
childregs->regs[0] = 0; /* Set return value for child */
|
||||||
p->thread.pc = (unsigned long) ret_from_fork;
|
p->thread.pc = (unsigned long) ret_from_fork;
|
||||||
|
|
|
@ -4,9 +4,8 @@
|
||||||
|
|
||||||
struct pt_regs;
|
struct pt_regs;
|
||||||
|
|
||||||
asmlinkage long sparc_do_fork(unsigned long clone_flags,
|
asmlinkage long sparc_fork(struct pt_regs *regs);
|
||||||
unsigned long stack_start,
|
asmlinkage long sparc_vfork(struct pt_regs *regs);
|
||||||
struct pt_regs *regs,
|
asmlinkage long sparc_clone(struct pt_regs *regs);
|
||||||
unsigned long stack_size);
|
|
||||||
|
|
||||||
#endif /* _SPARC64_SYSCALLS_H */
|
#endif /* _SPARC64_SYSCALLS_H */
|
||||||
|
|
|
@ -33,6 +33,7 @@ obj-y += irq_$(BITS).o
|
||||||
obj-$(CONFIG_SPARC32) += sun4m_irq.o sun4d_irq.o
|
obj-$(CONFIG_SPARC32) += sun4m_irq.o sun4d_irq.o
|
||||||
|
|
||||||
obj-y += process_$(BITS).o
|
obj-y += process_$(BITS).o
|
||||||
|
obj-y += process.o
|
||||||
obj-y += signal_$(BITS).o
|
obj-y += signal_$(BITS).o
|
||||||
obj-y += sigutil_$(BITS).o
|
obj-y += sigutil_$(BITS).o
|
||||||
obj-$(CONFIG_SPARC32) += ioport.o
|
obj-$(CONFIG_SPARC32) += ioport.o
|
||||||
|
|
|
@ -869,14 +869,11 @@ flush_patch_two:
|
||||||
ld [%curptr + TI_TASK], %o4
|
ld [%curptr + TI_TASK], %o4
|
||||||
rd %psr, %g4
|
rd %psr, %g4
|
||||||
WRITE_PAUSE
|
WRITE_PAUSE
|
||||||
mov SIGCHLD, %o0 ! arg0: clone flags
|
|
||||||
rd %wim, %g5
|
rd %wim, %g5
|
||||||
WRITE_PAUSE
|
WRITE_PAUSE
|
||||||
mov %fp, %o1 ! arg1: usp
|
|
||||||
std %g4, [%o4 + AOFF_task_thread + AOFF_thread_fork_kpsr]
|
std %g4, [%o4 + AOFF_task_thread + AOFF_thread_fork_kpsr]
|
||||||
add %sp, STACKFRAME_SZ, %o2 ! arg2: pt_regs ptr
|
add %sp, STACKFRAME_SZ, %o0
|
||||||
mov 0, %o3
|
call sparc_fork
|
||||||
call sparc_do_fork
|
|
||||||
mov %l5, %o7
|
mov %l5, %o7
|
||||||
|
|
||||||
/* Whee, kernel threads! */
|
/* Whee, kernel threads! */
|
||||||
|
@ -888,19 +885,11 @@ flush_patch_three:
|
||||||
ld [%curptr + TI_TASK], %o4
|
ld [%curptr + TI_TASK], %o4
|
||||||
rd %psr, %g4
|
rd %psr, %g4
|
||||||
WRITE_PAUSE
|
WRITE_PAUSE
|
||||||
|
|
||||||
/* arg0,1: flags,usp -- loaded already */
|
|
||||||
cmp %o1, 0x0 ! Is new_usp NULL?
|
|
||||||
rd %wim, %g5
|
rd %wim, %g5
|
||||||
WRITE_PAUSE
|
WRITE_PAUSE
|
||||||
be,a 1f
|
|
||||||
mov %fp, %o1 ! yes, use callers usp
|
|
||||||
andn %o1, 7, %o1 ! no, align to 8 bytes
|
|
||||||
1:
|
|
||||||
std %g4, [%o4 + AOFF_task_thread + AOFF_thread_fork_kpsr]
|
std %g4, [%o4 + AOFF_task_thread + AOFF_thread_fork_kpsr]
|
||||||
add %sp, STACKFRAME_SZ, %o2 ! arg2: pt_regs ptr
|
add %sp, STACKFRAME_SZ, %o0
|
||||||
mov 0, %o3
|
call sparc_clone
|
||||||
call sparc_do_fork
|
|
||||||
mov %l5, %o7
|
mov %l5, %o7
|
||||||
|
|
||||||
/* Whee, real vfork! */
|
/* Whee, real vfork! */
|
||||||
|
@ -914,13 +903,9 @@ flush_patch_four:
|
||||||
rd %wim, %g5
|
rd %wim, %g5
|
||||||
WRITE_PAUSE
|
WRITE_PAUSE
|
||||||
std %g4, [%o4 + AOFF_task_thread + AOFF_thread_fork_kpsr]
|
std %g4, [%o4 + AOFF_task_thread + AOFF_thread_fork_kpsr]
|
||||||
sethi %hi(0x4000 | 0x0100 | SIGCHLD), %o0
|
sethi %hi(sparc_vfork), %l1
|
||||||
mov %fp, %o1
|
jmpl %l1 + %lo(sparc_vfork), %g0
|
||||||
or %o0, %lo(0x4000 | 0x0100 | SIGCHLD), %o0
|
add %sp, STACKFRAME_SZ, %o0
|
||||||
sethi %hi(sparc_do_fork), %l1
|
|
||||||
mov 0, %o3
|
|
||||||
jmpl %l1 + %lo(sparc_do_fork), %g0
|
|
||||||
add %sp, STACKFRAME_SZ, %o2
|
|
||||||
|
|
||||||
.align 4
|
.align 4
|
||||||
linux_sparc_ni_syscall:
|
linux_sparc_ni_syscall:
|
||||||
|
|
|
@ -14,6 +14,11 @@ extern const char *sparc_pmu_type;
|
||||||
extern unsigned int fsr_storage;
|
extern unsigned int fsr_storage;
|
||||||
extern int ncpus_probed;
|
extern int ncpus_probed;
|
||||||
|
|
||||||
|
/* process{_32,_64}.c */
|
||||||
|
asmlinkage long sparc_clone(struct pt_regs *regs);
|
||||||
|
asmlinkage long sparc_fork(struct pt_regs *regs);
|
||||||
|
asmlinkage long sparc_vfork(struct pt_regs *regs);
|
||||||
|
|
||||||
#ifdef CONFIG_SPARC64
|
#ifdef CONFIG_SPARC64
|
||||||
/* setup_64.c */
|
/* setup_64.c */
|
||||||
struct seq_file;
|
struct seq_file;
|
||||||
|
@ -153,12 +158,6 @@ void floppy_hardint(void);
|
||||||
extern unsigned long sun4m_cpu_startup;
|
extern unsigned long sun4m_cpu_startup;
|
||||||
extern unsigned long sun4d_cpu_startup;
|
extern unsigned long sun4d_cpu_startup;
|
||||||
|
|
||||||
/* process_32.c */
|
|
||||||
asmlinkage int sparc_do_fork(unsigned long clone_flags,
|
|
||||||
unsigned long stack_start,
|
|
||||||
struct pt_regs *regs,
|
|
||||||
unsigned long stack_size);
|
|
||||||
|
|
||||||
/* signal_32.c */
|
/* signal_32.c */
|
||||||
asmlinkage void do_sigreturn(struct pt_regs *regs);
|
asmlinkage void do_sigreturn(struct pt_regs *regs);
|
||||||
asmlinkage void do_rt_sigreturn(struct pt_regs *regs);
|
asmlinkage void do_rt_sigreturn(struct pt_regs *regs);
|
||||||
|
|
|
@ -0,0 +1,110 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file handles the architecture independent parts of process handling..
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/compat.h>
|
||||||
|
#include <linux/errno.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/ptrace.h>
|
||||||
|
#include <linux/sched.h>
|
||||||
|
#include <linux/sched/task.h>
|
||||||
|
#include <linux/sched/task_stack.h>
|
||||||
|
#include <linux/signal.h>
|
||||||
|
|
||||||
|
#include "kernel.h"
|
||||||
|
|
||||||
|
asmlinkage long sparc_fork(struct pt_regs *regs)
|
||||||
|
{
|
||||||
|
unsigned long orig_i1 = regs->u_regs[UREG_I1];
|
||||||
|
long ret;
|
||||||
|
struct kernel_clone_args args = {
|
||||||
|
.exit_signal = SIGCHLD,
|
||||||
|
/* Reuse the parent's stack for the child. */
|
||||||
|
.stack = regs->u_regs[UREG_FP],
|
||||||
|
};
|
||||||
|
|
||||||
|
ret = _do_fork(&args);
|
||||||
|
|
||||||
|
/* 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] = orig_i1;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
asmlinkage long sparc_vfork(struct pt_regs *regs)
|
||||||
|
{
|
||||||
|
unsigned long orig_i1 = regs->u_regs[UREG_I1];
|
||||||
|
long ret;
|
||||||
|
|
||||||
|
struct kernel_clone_args args = {
|
||||||
|
.flags = CLONE_VFORK | CLONE_VM,
|
||||||
|
.exit_signal = SIGCHLD,
|
||||||
|
/* Reuse the parent's stack for the child. */
|
||||||
|
.stack = regs->u_regs[UREG_FP],
|
||||||
|
};
|
||||||
|
|
||||||
|
ret = _do_fork(&args);
|
||||||
|
|
||||||
|
/* 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] = orig_i1;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
asmlinkage long sparc_clone(struct pt_regs *regs)
|
||||||
|
{
|
||||||
|
unsigned long orig_i1 = regs->u_regs[UREG_I1];
|
||||||
|
unsigned int flags = lower_32_bits(regs->u_regs[UREG_I0]);
|
||||||
|
long ret;
|
||||||
|
|
||||||
|
struct kernel_clone_args args = {
|
||||||
|
.flags = (flags & ~CSIGNAL),
|
||||||
|
.exit_signal = (flags & CSIGNAL),
|
||||||
|
.tls = regs->u_regs[UREG_I3],
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef CONFIG_COMPAT
|
||||||
|
if (test_thread_flag(TIF_32BIT)) {
|
||||||
|
args.pidfd = compat_ptr(regs->u_regs[UREG_I2]);
|
||||||
|
args.child_tid = compat_ptr(regs->u_regs[UREG_I4]);
|
||||||
|
args.parent_tid = compat_ptr(regs->u_regs[UREG_I2]);
|
||||||
|
} else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
args.pidfd = (int __user *)regs->u_regs[UREG_I2];
|
||||||
|
args.child_tid = (int __user *)regs->u_regs[UREG_I4];
|
||||||
|
args.parent_tid = (int __user *)regs->u_regs[UREG_I2];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Did userspace give setup a separate stack for the child or are we
|
||||||
|
* reusing the parent's?
|
||||||
|
*/
|
||||||
|
if (regs->u_regs[UREG_I1])
|
||||||
|
args.stack = regs->u_regs[UREG_I1];
|
||||||
|
else
|
||||||
|
args.stack = regs->u_regs[UREG_FP];
|
||||||
|
|
||||||
|
ret = _do_fork(&args);
|
||||||
|
|
||||||
|
/* 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] = orig_i1;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
|
@ -257,33 +257,6 @@ clone_stackframe(struct sparc_stackf __user *dst,
|
||||||
return sp;
|
return sp;
|
||||||
}
|
}
|
||||||
|
|
||||||
asmlinkage int sparc_do_fork(unsigned long clone_flags,
|
|
||||||
unsigned long stack_start,
|
|
||||||
struct pt_regs *regs,
|
|
||||||
unsigned long stack_size)
|
|
||||||
{
|
|
||||||
unsigned long parent_tid_ptr, child_tid_ptr;
|
|
||||||
unsigned long orig_i1 = regs->u_regs[UREG_I1];
|
|
||||||
long ret;
|
|
||||||
|
|
||||||
parent_tid_ptr = regs->u_regs[UREG_I2];
|
|
||||||
child_tid_ptr = regs->u_regs[UREG_I4];
|
|
||||||
|
|
||||||
ret = do_fork(clone_flags, stack_start, stack_size,
|
|
||||||
(int __user *) parent_tid_ptr,
|
|
||||||
(int __user *) child_tid_ptr);
|
|
||||||
|
|
||||||
/* 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] = orig_i1;
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Copy a Sparc thread. The fork() return value conventions
|
/* Copy a Sparc thread. The fork() return value conventions
|
||||||
* under SunOS are nothing short of bletcherous:
|
* under SunOS are nothing short of bletcherous:
|
||||||
* Parent --> %o0 == childs pid, %o1 == 0
|
* Parent --> %o0 == childs pid, %o1 == 0
|
||||||
|
@ -300,8 +273,8 @@ asmlinkage int sparc_do_fork(unsigned long clone_flags,
|
||||||
extern void ret_from_fork(void);
|
extern void ret_from_fork(void);
|
||||||
extern void ret_from_kernel_thread(void);
|
extern void ret_from_kernel_thread(void);
|
||||||
|
|
||||||
int copy_thread(unsigned long clone_flags, unsigned long sp,
|
int copy_thread(unsigned long clone_flags, unsigned long sp, unsigned long arg,
|
||||||
unsigned long arg, struct task_struct *p)
|
struct task_struct *p, unsigned long tls)
|
||||||
{
|
{
|
||||||
struct thread_info *ti = task_thread_info(p);
|
struct thread_info *ti = task_thread_info(p);
|
||||||
struct pt_regs *childregs, *regs = current_pt_regs();
|
struct pt_regs *childregs, *regs = current_pt_regs();
|
||||||
|
@ -403,7 +376,7 @@ int copy_thread(unsigned long clone_flags, unsigned long sp,
|
||||||
regs->u_regs[UREG_I1] = 0;
|
regs->u_regs[UREG_I1] = 0;
|
||||||
|
|
||||||
if (clone_flags & CLONE_SETTLS)
|
if (clone_flags & CLONE_SETTLS)
|
||||||
childregs->u_regs[UREG_G7] = regs->u_regs[UREG_I3];
|
childregs->u_regs[UREG_G7] = tls;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -572,47 +572,13 @@ barf:
|
||||||
force_sig(SIGSEGV);
|
force_sig(SIGSEGV);
|
||||||
}
|
}
|
||||||
|
|
||||||
asmlinkage long sparc_do_fork(unsigned long clone_flags,
|
|
||||||
unsigned long stack_start,
|
|
||||||
struct pt_regs *regs,
|
|
||||||
unsigned long stack_size)
|
|
||||||
{
|
|
||||||
int __user *parent_tid_ptr, *child_tid_ptr;
|
|
||||||
unsigned long orig_i1 = regs->u_regs[UREG_I1];
|
|
||||||
long ret;
|
|
||||||
|
|
||||||
#ifdef CONFIG_COMPAT
|
|
||||||
if (test_thread_flag(TIF_32BIT)) {
|
|
||||||
parent_tid_ptr = compat_ptr(regs->u_regs[UREG_I2]);
|
|
||||||
child_tid_ptr = compat_ptr(regs->u_regs[UREG_I4]);
|
|
||||||
} else
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
parent_tid_ptr = (int __user *) regs->u_regs[UREG_I2];
|
|
||||||
child_tid_ptr = (int __user *) regs->u_regs[UREG_I4];
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = do_fork(clone_flags, stack_start, stack_size,
|
|
||||||
parent_tid_ptr, child_tid_ptr);
|
|
||||||
|
|
||||||
/* 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] = orig_i1;
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Copy a Sparc thread. The fork() return value conventions
|
/* Copy a Sparc thread. The fork() return value conventions
|
||||||
* under SunOS are nothing short of bletcherous:
|
* under SunOS are nothing short of bletcherous:
|
||||||
* Parent --> %o0 == childs pid, %o1 == 0
|
* Parent --> %o0 == childs pid, %o1 == 0
|
||||||
* Child --> %o0 == parents pid, %o1 == 1
|
* Child --> %o0 == parents pid, %o1 == 1
|
||||||
*/
|
*/
|
||||||
int copy_thread(unsigned long clone_flags, unsigned long sp,
|
int copy_thread(unsigned long clone_flags, unsigned long sp, unsigned long arg,
|
||||||
unsigned long arg, struct task_struct *p)
|
struct task_struct *p, unsigned long tls)
|
||||||
{
|
{
|
||||||
struct thread_info *t = task_thread_info(p);
|
struct thread_info *t = task_thread_info(p);
|
||||||
struct pt_regs *regs = current_pt_regs();
|
struct pt_regs *regs = current_pt_regs();
|
||||||
|
@ -670,7 +636,7 @@ int copy_thread(unsigned long clone_flags, unsigned long sp,
|
||||||
regs->u_regs[UREG_I1] = 0;
|
regs->u_regs[UREG_I1] = 0;
|
||||||
|
|
||||||
if (clone_flags & CLONE_SETTLS)
|
if (clone_flags & CLONE_SETTLS)
|
||||||
t->kregs->u_regs[UREG_G7] = regs->u_regs[UREG_I3];
|
t->kregs->u_regs[UREG_G7] = tls;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -86,19 +86,22 @@ sys32_rt_sigreturn:
|
||||||
* during system calls...
|
* during system calls...
|
||||||
*/
|
*/
|
||||||
.align 32
|
.align 32
|
||||||
sys_vfork: /* Under Linux, vfork and fork are just special cases of clone. */
|
sys_vfork:
|
||||||
sethi %hi(0x4000 | 0x0100 | SIGCHLD), %o0
|
flushw
|
||||||
or %o0, %lo(0x4000 | 0x0100 | SIGCHLD), %o0
|
ba,pt %xcc, sparc_vfork
|
||||||
ba,pt %xcc, sys_clone
|
add %sp, PTREGS_OFF, %o0
|
||||||
|
|
||||||
|
.align 32
|
||||||
sys_fork:
|
sys_fork:
|
||||||
clr %o1
|
flushw
|
||||||
mov SIGCHLD, %o0
|
ba,pt %xcc, sparc_fork
|
||||||
|
add %sp, PTREGS_OFF, %o0
|
||||||
|
|
||||||
|
.align 32
|
||||||
sys_clone:
|
sys_clone:
|
||||||
flushw
|
flushw
|
||||||
movrz %o1, %fp, %o1
|
ba,pt %xcc, sparc_clone
|
||||||
mov 0, %o3
|
add %sp, PTREGS_OFF, %o0
|
||||||
ba,pt %xcc, sparc_do_fork
|
|
||||||
add %sp, PTREGS_OFF, %o2
|
|
||||||
|
|
||||||
.globl ret_from_fork
|
.globl ret_from_fork
|
||||||
ret_from_fork:
|
ret_from_fork:
|
||||||
|
|
|
@ -14,7 +14,6 @@ config UML
|
||||||
select HAVE_FUTEX_CMPXCHG if FUTEX
|
select HAVE_FUTEX_CMPXCHG if FUTEX
|
||||||
select HAVE_DEBUG_KMEMLEAK
|
select HAVE_DEBUG_KMEMLEAK
|
||||||
select HAVE_DEBUG_BUGVERBOSE
|
select HAVE_DEBUG_BUGVERBOSE
|
||||||
select HAVE_COPY_THREAD_TLS
|
|
||||||
select GENERIC_IRQ_SHOW
|
select GENERIC_IRQ_SHOW
|
||||||
select GENERIC_CPU_DEVICES
|
select GENERIC_CPU_DEVICES
|
||||||
select GENERIC_CLOCKEVENTS
|
select GENERIC_CLOCKEVENTS
|
||||||
|
|
|
@ -152,7 +152,7 @@ void fork_handler(void)
|
||||||
userspace(¤t->thread.regs.regs, current_thread_info()->aux_fp_regs);
|
userspace(¤t->thread.regs.regs, current_thread_info()->aux_fp_regs);
|
||||||
}
|
}
|
||||||
|
|
||||||
int copy_thread_tls(unsigned long clone_flags, unsigned long sp,
|
int copy_thread(unsigned long clone_flags, unsigned long sp,
|
||||||
unsigned long arg, struct task_struct * p, unsigned long tls)
|
unsigned long arg, struct task_struct * p, unsigned long tls)
|
||||||
{
|
{
|
||||||
void (*handler)(void);
|
void (*handler)(void);
|
||||||
|
|
|
@ -161,7 +161,6 @@ config X86
|
||||||
select HAVE_CMPXCHG_DOUBLE
|
select HAVE_CMPXCHG_DOUBLE
|
||||||
select HAVE_CMPXCHG_LOCAL
|
select HAVE_CMPXCHG_LOCAL
|
||||||
select HAVE_CONTEXT_TRACKING if X86_64
|
select HAVE_CONTEXT_TRACKING if X86_64
|
||||||
select HAVE_COPY_THREAD_TLS
|
|
||||||
select HAVE_C_RECORDMCOUNT
|
select HAVE_C_RECORDMCOUNT
|
||||||
select HAVE_DEBUG_KMEMLEAK
|
select HAVE_DEBUG_KMEMLEAK
|
||||||
select HAVE_DMA_CONTIGUOUS
|
select HAVE_DMA_CONTIGUOUS
|
||||||
|
|
|
@ -121,8 +121,8 @@ static int set_new_tls(struct task_struct *p, unsigned long tls)
|
||||||
return do_set_thread_area_64(p, ARCH_SET_FS, tls);
|
return do_set_thread_area_64(p, ARCH_SET_FS, tls);
|
||||||
}
|
}
|
||||||
|
|
||||||
int copy_thread_tls(unsigned long clone_flags, unsigned long sp,
|
int copy_thread(unsigned long clone_flags, unsigned long sp, unsigned long arg,
|
||||||
unsigned long arg, struct task_struct *p, unsigned long tls)
|
struct task_struct *p, unsigned long tls)
|
||||||
{
|
{
|
||||||
struct inactive_task_frame *frame;
|
struct inactive_task_frame *frame;
|
||||||
struct fork_frame *fork_frame;
|
struct fork_frame *fork_frame;
|
||||||
|
|
|
@ -251,9 +251,6 @@ COMPAT_SYSCALL_DEFINE5(ia32_clone, unsigned long, clone_flags,
|
||||||
.tls = tls_val,
|
.tls = tls_val,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!legacy_clone_args_valid(&args))
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
return _do_fork(&args);
|
return _do_fork(&args);
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_IA32_EMULATION */
|
#endif /* CONFIG_IA32_EMULATION */
|
||||||
|
|
|
@ -269,7 +269,7 @@ bool unwind_next_frame(struct unwind_state *state)
|
||||||
/*
|
/*
|
||||||
* kthreads (other than the boot CPU's idle thread) have some
|
* kthreads (other than the boot CPU's idle thread) have some
|
||||||
* partial regs at the end of their stack which were placed
|
* partial regs at the end of their stack which were placed
|
||||||
* there by copy_thread_tls(). But the regs don't have any
|
* there by copy_thread(). But the regs don't have any
|
||||||
* useful information, so we can skip them.
|
* useful information, so we can skip them.
|
||||||
*
|
*
|
||||||
* This user_mode() check is slightly broader than a PF_KTHREAD
|
* This user_mode() check is slightly broader than a PF_KTHREAD
|
||||||
|
|
|
@ -24,7 +24,6 @@ config XTENSA
|
||||||
select HAVE_ARCH_JUMP_LABEL if !XIP_KERNEL
|
select HAVE_ARCH_JUMP_LABEL if !XIP_KERNEL
|
||||||
select HAVE_ARCH_KASAN if MMU && !XIP_KERNEL
|
select HAVE_ARCH_KASAN if MMU && !XIP_KERNEL
|
||||||
select HAVE_ARCH_TRACEHOOK
|
select HAVE_ARCH_TRACEHOOK
|
||||||
select HAVE_COPY_THREAD_TLS
|
|
||||||
select HAVE_DEBUG_KMEMLEAK
|
select HAVE_DEBUG_KMEMLEAK
|
||||||
select HAVE_DMA_CONTIGUOUS
|
select HAVE_DMA_CONTIGUOUS
|
||||||
select HAVE_EXIT_THREAD
|
select HAVE_EXIT_THREAD
|
||||||
|
|
|
@ -201,7 +201,7 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
|
||||||
* involved. Much simpler to just not copy those live frames across.
|
* involved. Much simpler to just not copy those live frames across.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int copy_thread_tls(unsigned long clone_flags, unsigned long usp_thread_fn,
|
int copy_thread(unsigned long clone_flags, unsigned long usp_thread_fn,
|
||||||
unsigned long thread_fn_arg, struct task_struct *p,
|
unsigned long thread_fn_arg, struct task_struct *p,
|
||||||
unsigned long tls)
|
unsigned long tls)
|
||||||
{
|
{
|
||||||
|
|
|
@ -66,22 +66,9 @@ extern void fork_init(void);
|
||||||
|
|
||||||
extern void release_task(struct task_struct * p);
|
extern void release_task(struct task_struct * p);
|
||||||
|
|
||||||
#ifdef CONFIG_HAVE_COPY_THREAD_TLS
|
|
||||||
extern int copy_thread_tls(unsigned long, unsigned long, unsigned long,
|
|
||||||
struct task_struct *, unsigned long);
|
|
||||||
#else
|
|
||||||
extern int copy_thread(unsigned long, unsigned long, unsigned long,
|
extern int copy_thread(unsigned long, unsigned long, unsigned long,
|
||||||
struct task_struct *);
|
struct task_struct *, unsigned long);
|
||||||
|
|
||||||
/* Architectures that haven't opted into copy_thread_tls get the tls argument
|
|
||||||
* via pt_regs, so ignore the tls argument passed via C. */
|
|
||||||
static inline int copy_thread_tls(
|
|
||||||
unsigned long clone_flags, unsigned long sp, unsigned long arg,
|
|
||||||
struct task_struct *p, unsigned long tls)
|
|
||||||
{
|
|
||||||
return copy_thread(clone_flags, sp, arg, p);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
extern void flush_thread(void);
|
extern void flush_thread(void);
|
||||||
|
|
||||||
#ifdef CONFIG_HAVE_EXIT_THREAD
|
#ifdef CONFIG_HAVE_EXIT_THREAD
|
||||||
|
@ -97,8 +84,6 @@ extern void exit_files(struct task_struct *);
|
||||||
extern void exit_itimers(struct signal_struct *);
|
extern void exit_itimers(struct signal_struct *);
|
||||||
|
|
||||||
extern long _do_fork(struct kernel_clone_args *kargs);
|
extern long _do_fork(struct kernel_clone_args *kargs);
|
||||||
extern bool legacy_clone_args_valid(const struct kernel_clone_args *kargs);
|
|
||||||
extern long do_fork(unsigned long, unsigned long, unsigned long, int __user *, int __user *);
|
|
||||||
struct task_struct *fork_idle(int);
|
struct task_struct *fork_idle(int);
|
||||||
struct mm_struct *copy_init_mm(void);
|
struct mm_struct *copy_init_mm(void);
|
||||||
extern pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags);
|
extern pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags);
|
||||||
|
|
|
@ -2097,8 +2097,7 @@ static __latent_entropy struct task_struct *copy_process(
|
||||||
retval = copy_io(clone_flags, p);
|
retval = copy_io(clone_flags, p);
|
||||||
if (retval)
|
if (retval)
|
||||||
goto bad_fork_cleanup_namespaces;
|
goto bad_fork_cleanup_namespaces;
|
||||||
retval = copy_thread_tls(clone_flags, args->stack, args->stack_size, p,
|
retval = copy_thread(clone_flags, args->stack, args->stack_size, p, args->tls);
|
||||||
args->tls);
|
|
||||||
if (retval)
|
if (retval)
|
||||||
goto bad_fork_cleanup_io;
|
goto bad_fork_cleanup_io;
|
||||||
|
|
||||||
|
@ -2416,6 +2415,20 @@ long _do_fork(struct kernel_clone_args *args)
|
||||||
int trace = 0;
|
int trace = 0;
|
||||||
long nr;
|
long nr;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For legacy clone() calls, CLONE_PIDFD uses the parent_tid argument
|
||||||
|
* to return the pidfd. Hence, CLONE_PIDFD and CLONE_PARENT_SETTID are
|
||||||
|
* mutually exclusive. With clone3() CLONE_PIDFD has grown a separate
|
||||||
|
* field in struct clone_args and it still doesn't make sense to have
|
||||||
|
* them both point at the same memory location. Performing this check
|
||||||
|
* here has the advantage that we don't need to have a separate helper
|
||||||
|
* to check for legacy clone().
|
||||||
|
*/
|
||||||
|
if ((args->flags & CLONE_PIDFD) &&
|
||||||
|
(args->flags & CLONE_PARENT_SETTID) &&
|
||||||
|
(args->pidfd == args->parent_tid))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Determine whether and which event to report to ptracer. When
|
* Determine whether and which event to report to ptracer. When
|
||||||
* called from kernel_thread or CLONE_UNTRACED is explicitly
|
* called from kernel_thread or CLONE_UNTRACED is explicitly
|
||||||
|
@ -2473,42 +2486,6 @@ long _do_fork(struct kernel_clone_args *args)
|
||||||
return nr;
|
return nr;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool legacy_clone_args_valid(const struct kernel_clone_args *kargs)
|
|
||||||
{
|
|
||||||
/* clone(CLONE_PIDFD) uses parent_tidptr to return a pidfd */
|
|
||||||
if ((kargs->flags & CLONE_PIDFD) &&
|
|
||||||
(kargs->flags & CLONE_PARENT_SETTID))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifndef CONFIG_HAVE_COPY_THREAD_TLS
|
|
||||||
/* For compatibility with architectures that call do_fork directly rather than
|
|
||||||
* using the syscall entry points below. */
|
|
||||||
long do_fork(unsigned long clone_flags,
|
|
||||||
unsigned long stack_start,
|
|
||||||
unsigned long stack_size,
|
|
||||||
int __user *parent_tidptr,
|
|
||||||
int __user *child_tidptr)
|
|
||||||
{
|
|
||||||
struct kernel_clone_args args = {
|
|
||||||
.flags = (lower_32_bits(clone_flags) & ~CSIGNAL),
|
|
||||||
.pidfd = parent_tidptr,
|
|
||||||
.child_tid = child_tidptr,
|
|
||||||
.parent_tid = parent_tidptr,
|
|
||||||
.exit_signal = (lower_32_bits(clone_flags) & CSIGNAL),
|
|
||||||
.stack = stack_start,
|
|
||||||
.stack_size = stack_size,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!legacy_clone_args_valid(&args))
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
return _do_fork(&args);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Create a kernel thread.
|
* Create a kernel thread.
|
||||||
*/
|
*/
|
||||||
|
@ -2587,24 +2564,12 @@ SYSCALL_DEFINE5(clone, unsigned long, clone_flags, unsigned long, newsp,
|
||||||
.tls = tls,
|
.tls = tls,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!legacy_clone_args_valid(&args))
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
return _do_fork(&args);
|
return _do_fork(&args);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef __ARCH_WANT_SYS_CLONE3
|
#ifdef __ARCH_WANT_SYS_CLONE3
|
||||||
|
|
||||||
/*
|
|
||||||
* copy_thread implementations handle CLONE_SETTLS by reading the TLS value from
|
|
||||||
* the registers containing the syscall arguments for clone. This doesn't work
|
|
||||||
* with clone3 since the TLS value is passed in clone_args instead.
|
|
||||||
*/
|
|
||||||
#ifndef CONFIG_HAVE_COPY_THREAD_TLS
|
|
||||||
#error clone3 requires copy_thread_tls support in arch
|
|
||||||
#endif
|
|
||||||
|
|
||||||
noinline static int copy_clone_args_from_user(struct kernel_clone_args *kargs,
|
noinline static int copy_clone_args_from_user(struct kernel_clone_args *kargs,
|
||||||
struct clone_args __user *uargs,
|
struct clone_args __user *uargs,
|
||||||
size_t usize)
|
size_t usize)
|
||||||
|
@ -2919,7 +2884,7 @@ static int unshare_fd(unsigned long unshare_flags, struct files_struct **new_fdp
|
||||||
/*
|
/*
|
||||||
* unshare allows a process to 'unshare' part of the process
|
* unshare allows a process to 'unshare' part of the process
|
||||||
* context which was originally shared using clone. copy_*
|
* context which was originally shared using clone. copy_*
|
||||||
* functions used by do_fork() cannot be used here directly
|
* functions used by _do_fork() cannot be used here directly
|
||||||
* because they modify an inactive task_struct that is being
|
* because they modify an inactive task_struct that is being
|
||||||
* constructed. Here we are modifying the current, active,
|
* constructed. Here we are modifying the current, active,
|
||||||
* task_struct.
|
* task_struct.
|
||||||
|
|
Loading…
Reference in New Issue