summaryrefslogtreecommitdiffstats
path: root/arch/arm64
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm64')
-rw-r--r--arch/arm64/Kconfig2
-rw-r--r--arch/arm64/include/asm/processor.h5
-rw-r--r--arch/arm64/include/asm/syscalls.h14
-rw-r--r--arch/arm64/include/asm/unistd.h1
-rw-r--r--arch/arm64/include/asm/unistd32.h8
-rw-r--r--arch/arm64/kernel/entry.S17
-rw-r--r--arch/arm64/kernel/process.c83
-rw-r--r--arch/arm64/kernel/sys.c76
-rw-r--r--arch/arm64/kernel/sys32.S19
-rw-r--r--arch/arm64/kernel/sys_compat.c38
10 files changed, 56 insertions, 207 deletions
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 15ac18a..20b688c 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 77f696c..ab239b2 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 09ff335..a1b00cd 100644
--- a/arch/arm64/include/asm/syscalls.h
+++ b/arch/arm64/include/asm/syscalls.h
@@ -23,18 +23,16 @@
/*
* 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,
- unsigned long tls_val,
- void __user *child_tid);
asmlinkage long sys_rt_sigreturn_wrapper(void);
asmlinkage long sys_sigaltstack_wrapper(const stack_t __user *uss,
stack_t __user *uoss);
+/*
+ * AArch64 sys_clone implementation has a different prototype than the generic
+ * one (additional TLS value argument).
+ */
+#define sys_clone sys_clone
+
#include <asm-generic/syscalls.h>
#endif /* __ASM_SYSCALLS_H */
diff --git a/arch/arm64/include/asm/unistd.h b/arch/arm64/include/asm/unistd.h
index 68aff28..43064a8 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 6d909fa..d9850cf 100644
--- a/arch/arm64/include/asm/unistd32.h
+++ b/arch/arm64/include/asm/unistd32.h
@@ -23,7 +23,7 @@
__SYSCALL(0, sys_restart_syscall)
__SYSCALL(1, sys_exit)
-__SYSCALL(2, compat_sys_fork_wrapper)
+__SYSCALL(2, compat_sys_fork)
__SYSCALL(3, sys_read)
__SYSCALL(4, sys_write)
__SYSCALL(5, compat_sys_open)
@@ -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)
@@ -141,7 +141,7 @@ __SYSCALL(116, compat_sys_sysinfo)
__SYSCALL(117, sys_ni_syscall) /* 117 was sys_ipc */
__SYSCALL(118, sys_fsync)
__SYSCALL(119, compat_sys_sigreturn_wrapper)
-__SYSCALL(120, compat_sys_clone_wrapper)
+__SYSCALL(120, sys_clone)
__SYSCALL(121, sys_setdomainname)
__SYSCALL(122, sys_newuname)
__SYSCALL(123, sys_ni_syscall) /* 123 was sys_modify_ldt */
@@ -211,7 +211,7 @@ __SYSCALL(186, compat_sys_sigaltstack_wrapper)
__SYSCALL(187, compat_sys_sendfile)
__SYSCALL(188, sys_ni_syscall) /* 188 reserved */
__SYSCALL(189, sys_ni_syscall) /* 189 reserved */
-__SYSCALL(190, compat_sys_vfork_wrapper)
+__SYSCALL(190, compat_sys_vfork)
__SYSCALL(191, compat_sys_getrlimit) /* SuS compliant getrlimit */
__SYSCALL(192, sys_mmap_pgoff)
__SYSCALL(193, compat_sys_truncate64_wrapper)
diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S
index a6f3f7d..cbfa4d2 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,16 +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
-ENDPROC(sys_clone_wrapper)
-
ENTRY(sys_rt_sigreturn_wrapper)
mov x0, sp
b sys_rt_sigreturn
diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c
index e04cebd..8a5f334 100644
--- a/arch/arm64/kernel/process.c
+++ b/arch/arm64/kernel/process.c
@@ -240,27 +240,41 @@ 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))) {
+ if (stack_start)
+ 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));
+ if (stack_start) {
+ /* 16-byte aligned stack mandatory on AArch64 */
+ if (stack_start & 15)
+ return -EINVAL;
+ 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 +323,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(&regs, 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, &regs, 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 b120df3..4364df8 100644
--- a/arch/arm64/kernel/sys.c
+++ b/arch/arm64/kernel/sys.c
@@ -31,79 +31,11 @@
*/
asmlinkage long sys_clone(unsigned long clone_flags, unsigned long newsp,
int __user *parent_tidptr, unsigned long tls_val,
- int __user *child_tidptr, struct pt_regs *regs)
+ int __user *child_tidptr)
{
- if (!newsp)
- newsp = regs->sp;
- /* 16-byte aligned stack mandatory on AArch64 */
- if (newsp & 15)
- return -EINVAL;
- 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(&regs, 0, sizeof(struct pt_regs));
- ret = do_execve(filename,
- (const char __user *const __user *)argv,
- (const char __user *const __user *)envp, &regs);
- 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" (&regs),
- "Ir" (sizeof(regs))
- : "x0", "x1", "x2", "x27", "x28", "x30", "memory");
-
- out:
- return ret;
+ return do_fork(clone_flags, newsp, current_pt_regs(), 0,
+ parent_tidptr, child_tidptr);
}
-EXPORT_SYMBOL(kernel_execve);
asmlinkage long sys_mmap(unsigned long addr, unsigned long len,
unsigned long prot, unsigned long flags,
@@ -118,8 +50,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 54c4aec..7ef59e9 100644
--- a/arch/arm64/kernel/sys32.S
+++ b/arch/arm64/kernel/sys32.S
@@ -26,25 +26,6 @@
/*
* System call wrappers for the AArch32 compatibility layer.
*/
-compat_sys_fork_wrapper:
- mov x0, sp
- b compat_sys_fork
-ENDPROC(compat_sys_fork_wrapper)
-
-compat_sys_vfork_wrapper:
- mov x0, sp
- 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
-ENDPROC(compat_sys_clone_wrapper)
compat_sys_sigreturn_wrapper:
mov x0, sp
diff --git a/arch/arm64/kernel/sys_compat.c b/arch/arm64/kernel/sys_compat.c
index 906e3bd..6fabc19 100644
--- a/arch/arm64/kernel/sys_compat.c
+++ b/arch/arm64/kernel/sys_compat.c
@@ -28,43 +28,15 @@
#include <asm/cacheflush.h>
#include <asm/unistd32.h>
-asmlinkage int compat_sys_fork(struct pt_regs *regs)
+asmlinkage int compat_sys_fork(void)
{
- return do_fork(SIGCHLD, regs->compat_sp, regs, 0, NULL, NULL);
+ return do_fork(SIGCHLD, 0, current_pt_regs(), 0, NULL, NULL);
}
-asmlinkage int compat_sys_clone(unsigned long clone_flags, unsigned long newsp,
- int __user *parent_tidptr, int tls_val,
- int __user *child_tidptr, struct pt_regs *regs)
+asmlinkage int compat_sys_vfork(void)
{
- if (!newsp)
- newsp = regs->compat_sp;
-
- return do_fork(clone_flags, newsp, regs, 0, parent_tidptr, child_tidptr);
-}
-
-asmlinkage int compat_sys_vfork(struct pt_regs *regs)
-{
- return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->compat_sp,
- 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;
+ return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, 0,
+ current_pt_regs(), 0, NULL, NULL);
}
asmlinkage int compat_sys_sched_rr_get_interval(compat_pid_t pid,
OpenPOWER on IntegriCloud