diff options
Diffstat (limited to 'arch/arm64')
-rw-r--r-- | arch/arm64/Kconfig | 2 | ||||
-rw-r--r-- | arch/arm64/include/asm/processor.h | 5 | ||||
-rw-r--r-- | arch/arm64/include/asm/syscalls.h | 3 | ||||
-rw-r--r-- | arch/arm64/include/asm/unistd.h | 1 | ||||
-rw-r--r-- | arch/arm64/include/asm/unistd32.h | 2 | ||||
-rw-r--r-- | arch/arm64/kernel/entry.S | 12 | ||||
-rw-r--r-- | arch/arm64/kernel/process.c | 77 | ||||
-rw-r--r-- | arch/arm64/kernel/sys.c | 65 | ||||
-rw-r--r-- | arch/arm64/kernel/sys32.S | 5 | ||||
-rw-r--r-- | arch/arm64/kernel/sys_compat.c | 18 |
10 files changed, 33 insertions, 157 deletions
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index 15ac18a56c93..20b688c81956 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -7,6 +7,8 @@ config ARM64 select GENERIC_IOMAP select GENERIC_IRQ_PROBE select GENERIC_IRQ_SHOW + select GENERIC_KERNEL_EXECVE + select GENERIC_KERNEL_THREAD select GENERIC_SMP_IDLE_THREAD select GENERIC_TIME_VSYSCALL select HARDIRQS_SW_RESEND diff --git a/arch/arm64/include/asm/processor.h b/arch/arm64/include/asm/processor.h index 77f696c14339..ab239b2c456f 100644 --- a/arch/arm64/include/asm/processor.h +++ b/arch/arm64/include/asm/processor.h @@ -128,11 +128,6 @@ unsigned long get_wchan(struct task_struct *p); extern struct task_struct *cpu_switch_to(struct task_struct *prev, struct task_struct *next); -/* - * Create a new kernel thread - */ -extern int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags); - #define task_pt_regs(p) \ ((struct pt_regs *)(THREAD_START_SP + task_stack_page(p)) - 1) diff --git a/arch/arm64/include/asm/syscalls.h b/arch/arm64/include/asm/syscalls.h index 09ff33572aab..81680a0ae913 100644 --- a/arch/arm64/include/asm/syscalls.h +++ b/arch/arm64/include/asm/syscalls.h @@ -23,9 +23,6 @@ /* * System call wrappers implemented in kernel/entry.S. */ -asmlinkage long sys_execve_wrapper(const char __user *filename, - const char __user *const __user *argv, - const char __user *const __user *envp); asmlinkage long sys_clone_wrapper(unsigned long clone_flags, unsigned long newsp, void __user *parent_tid, diff --git a/arch/arm64/include/asm/unistd.h b/arch/arm64/include/asm/unistd.h index 68aff2816e86..43064a8bd99e 100644 --- a/arch/arm64/include/asm/unistd.h +++ b/arch/arm64/include/asm/unistd.h @@ -25,4 +25,5 @@ #define __ARCH_WANT_COMPAT_SYS_RT_SIGSUSPEND #define __ARCH_WANT_COMPAT_SYS_SENDFILE #endif +#define __ARCH_WANT_SYS_EXECVE #include <uapi/asm/unistd.h> diff --git a/arch/arm64/include/asm/unistd32.h b/arch/arm64/include/asm/unistd32.h index 6d909faebf28..9035e6add3e4 100644 --- a/arch/arm64/include/asm/unistd32.h +++ b/arch/arm64/include/asm/unistd32.h @@ -32,7 +32,7 @@ __SYSCALL(7, sys_ni_syscall) /* 7 was sys_waitpid */ __SYSCALL(8, sys_creat) __SYSCALL(9, sys_link) __SYSCALL(10, sys_unlink) -__SYSCALL(11, compat_sys_execve_wrapper) +__SYSCALL(11, compat_sys_execve) __SYSCALL(12, sys_chdir) __SYSCALL(13, sys_ni_syscall) /* 13 was sys_time */ __SYSCALL(14, sys_mknod) diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S index a6f3f7da6880..616531862d52 100644 --- a/arch/arm64/kernel/entry.S +++ b/arch/arm64/kernel/entry.S @@ -594,7 +594,7 @@ work_resched: /* * "slow" syscall return path. */ -ENTRY(ret_to_user) +ret_to_user: disable_irq // disable interrupts ldr x1, [tsk, #TI_FLAGS] and x2, x1, #_TIF_WORK_MASK @@ -611,7 +611,10 @@ ENDPROC(ret_to_user) */ ENTRY(ret_from_fork) bl schedule_tail - get_thread_info tsk + cbz x19, 1f // not a kernel thread + mov x0, x20 + blr x19 +1: get_thread_info tsk b ret_to_user ENDPROC(ret_from_fork) @@ -673,11 +676,6 @@ __sys_trace_return: /* * Special system call wrappers. */ -ENTRY(sys_execve_wrapper) - mov x3, sp - b sys_execve -ENDPROC(sys_execve_wrapper) - ENTRY(sys_clone_wrapper) mov x5, sp b sys_clone diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c index e04cebdbb47f..a430b5cad308 100644 --- a/arch/arm64/kernel/process.c +++ b/arch/arm64/kernel/process.c @@ -240,27 +240,35 @@ int copy_thread(unsigned long clone_flags, unsigned long stack_start, struct pt_regs *childregs = task_pt_regs(p); unsigned long tls = p->thread.tp_value; - *childregs = *regs; - childregs->regs[0] = 0; + memset(&p->thread.cpu_context, 0, sizeof(struct cpu_context)); - if (is_compat_thread(task_thread_info(p))) - childregs->compat_sp = stack_start; - else { + if (likely(regs)) { + *childregs = *regs; + childregs->regs[0] = 0; + if (is_compat_thread(task_thread_info(p))) { + childregs->compat_sp = stack_start; + } else { + /* + * Read the current TLS pointer from tpidr_el0 as it may be + * out-of-sync with the saved value. + */ + asm("mrs %0, tpidr_el0" : "=r" (tls)); + childregs->sp = stack_start; + } /* - * Read the current TLS pointer from tpidr_el0 as it may be - * out-of-sync with the saved value. + * If a TLS pointer was passed to clone (4th argument), use it + * for the new thread. */ - asm("mrs %0, tpidr_el0" : "=r" (tls)); - childregs->sp = stack_start; + if (clone_flags & CLONE_SETTLS) + tls = regs->regs[3]; + } else { + memset(childregs, 0, sizeof(struct pt_regs)); + childregs->pstate = PSR_MODE_EL1h; + p->thread.cpu_context.x19 = stack_start; + p->thread.cpu_context.x20 = stk_sz; } - - memset(&p->thread.cpu_context, 0, sizeof(struct cpu_context)); - p->thread.cpu_context.sp = (unsigned long)childregs; p->thread.cpu_context.pc = (unsigned long)ret_from_fork; - - /* If a TLS pointer was passed to clone, use that for the new thread. */ - if (clone_flags & CLONE_SETTLS) - tls = regs->regs[3]; + p->thread.cpu_context.sp = (unsigned long)childregs; p->thread.tp_value = tls; ptrace_hw_copy_thread(p); @@ -309,43 +317,6 @@ struct task_struct *__switch_to(struct task_struct *prev, return last; } -/* - * Shuffle the argument into the correct register before calling the - * thread function. x1 is the thread argument, x2 is the pointer to - * the thread function, and x3 points to the exit function. - */ -extern void kernel_thread_helper(void); -asm( ".section .text\n" -" .align\n" -" .type kernel_thread_helper, #function\n" -"kernel_thread_helper:\n" -" mov x0, x1\n" -" mov x30, x3\n" -" br x2\n" -" .size kernel_thread_helper, . - kernel_thread_helper\n" -" .previous"); - -#define kernel_thread_exit do_exit - -/* - * Create a kernel thread. - */ -pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags) -{ - struct pt_regs regs; - - memset(®s, 0, sizeof(regs)); - - regs.regs[1] = (unsigned long)arg; - regs.regs[2] = (unsigned long)fn; - regs.regs[3] = (unsigned long)kernel_thread_exit; - regs.pc = (unsigned long)kernel_thread_helper; - regs.pstate = PSR_MODE_EL1h; - - return do_fork(flags|CLONE_VM|CLONE_UNTRACED, 0, ®s, 0, NULL, NULL); -} -EXPORT_SYMBOL(kernel_thread); - unsigned long get_wchan(struct task_struct *p) { struct stackframe frame; diff --git a/arch/arm64/kernel/sys.c b/arch/arm64/kernel/sys.c index b120df37de35..9c77c0bacc1d 100644 --- a/arch/arm64/kernel/sys.c +++ b/arch/arm64/kernel/sys.c @@ -41,70 +41,6 @@ asmlinkage long sys_clone(unsigned long clone_flags, unsigned long newsp, return do_fork(clone_flags, newsp, regs, 0, parent_tidptr, child_tidptr); } -/* - * sys_execve() executes a new program. - */ -asmlinkage long sys_execve(const char __user *filenamei, - const char __user *const __user *argv, - const char __user *const __user *envp, - struct pt_regs *regs) -{ - long error; - struct filename *filename; - - filename = getname(filenamei); - error = PTR_ERR(filename); - if (IS_ERR(filename)) - goto out; - error = do_execve(filename->name, argv, envp, regs); - putname(filename); -out: - return error; -} - -int kernel_execve(const char *filename, - const char *const argv[], - const char *const envp[]) -{ - struct pt_regs regs; - int ret; - - memset(®s, 0, sizeof(struct pt_regs)); - ret = do_execve(filename, - (const char __user *const __user *)argv, - (const char __user *const __user *)envp, ®s); - if (ret < 0) - goto out; - - /* - * Save argc to the register structure for userspace. - */ - regs.regs[0] = ret; - - /* - * We were successful. We won't be returning to our caller, but - * instead to user space by manipulating the kernel stack. - */ - asm( "add x0, %0, %1\n\t" - "mov x1, %2\n\t" - "mov x2, %3\n\t" - "bl memmove\n\t" /* copy regs to top of stack */ - "mov x27, #0\n\t" /* not a syscall */ - "mov x28, %0\n\t" /* thread structure */ - "mov sp, x0\n\t" /* reposition stack pointer */ - "b ret_to_user" - : - : "r" (current_thread_info()), - "Ir" (THREAD_START_SP - sizeof(regs)), - "r" (®s), - "Ir" (sizeof(regs)) - : "x0", "x1", "x2", "x27", "x28", "x30", "memory"); - - out: - return ret; -} -EXPORT_SYMBOL(kernel_execve); - asmlinkage long sys_mmap(unsigned long addr, unsigned long len, unsigned long prot, unsigned long flags, unsigned long fd, off_t off) @@ -118,7 +54,6 @@ asmlinkage long sys_mmap(unsigned long addr, unsigned long len, /* * Wrappers to pass the pt_regs argument. */ -#define sys_execve sys_execve_wrapper #define sys_clone sys_clone_wrapper #define sys_rt_sigreturn sys_rt_sigreturn_wrapper #define sys_sigaltstack sys_sigaltstack_wrapper diff --git a/arch/arm64/kernel/sys32.S b/arch/arm64/kernel/sys32.S index 54c4aec47a08..92145d402cf1 100644 --- a/arch/arm64/kernel/sys32.S +++ b/arch/arm64/kernel/sys32.S @@ -36,11 +36,6 @@ compat_sys_vfork_wrapper: b compat_sys_vfork ENDPROC(compat_sys_vfork_wrapper) -compat_sys_execve_wrapper: - mov x3, sp - b compat_sys_execve -ENDPROC(compat_sys_execve_wrapper) - compat_sys_clone_wrapper: mov x5, sp b compat_sys_clone diff --git a/arch/arm64/kernel/sys_compat.c b/arch/arm64/kernel/sys_compat.c index 906e3bd270b0..d140b73a8bc4 100644 --- a/arch/arm64/kernel/sys_compat.c +++ b/arch/arm64/kernel/sys_compat.c @@ -49,24 +49,6 @@ asmlinkage int compat_sys_vfork(struct pt_regs *regs) regs, 0, NULL, NULL); } -asmlinkage int compat_sys_execve(const char __user *filenamei, - compat_uptr_t argv, compat_uptr_t envp, - struct pt_regs *regs) -{ - int error; - struct filename *filename; - - filename = getname(filenamei); - error = PTR_ERR(filename); - if (IS_ERR(filename)) - goto out; - error = compat_do_execve(filename->name, compat_ptr(argv), - compat_ptr(envp), regs); - putname(filename); -out: - return error; -} - asmlinkage int compat_sys_sched_rr_get_interval(compat_pid_t pid, struct compat_timespec __user *interval) { |