diff options
author | Catalin Marinas <catalin.marinas@arm.com> | 2012-11-14 05:12:54 -0500 |
---|---|---|
committer | Catalin Marinas <catalin.marinas@arm.com> | 2012-11-14 05:12:54 -0500 |
commit | 908816dfe6043a9e28df17066d117a5c7df2a75d (patch) | |
tree | 89057a9a89ce8d6557e5db17a317d14e3ebd274e /arch/arm64 | |
parent | 938edf5c04202b59b8ff01a4033e9413646b105b (diff) | |
parent | 6097a07411005c0184cf90256743c784079198fc (diff) |
Merge branch 'execve' into upstream
* execve:
arm64: Use generic sys_execve() implementation
arm64: Use generic kernel_execve() implementation
arm64: Use generic kernel_thread() implementation
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 | |||
7 | select GENERIC_IOMAP | 7 | select GENERIC_IOMAP |
8 | select GENERIC_IRQ_PROBE | 8 | select GENERIC_IRQ_PROBE |
9 | select GENERIC_IRQ_SHOW | 9 | select GENERIC_IRQ_SHOW |
10 | select GENERIC_KERNEL_EXECVE | ||
11 | select GENERIC_KERNEL_THREAD | ||
10 | select GENERIC_SMP_IDLE_THREAD | 12 | select GENERIC_SMP_IDLE_THREAD |
11 | select GENERIC_TIME_VSYSCALL | 13 | select GENERIC_TIME_VSYSCALL |
12 | select HARDIRQS_SW_RESEND | 14 | 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); | |||
128 | extern struct task_struct *cpu_switch_to(struct task_struct *prev, | 128 | extern struct task_struct *cpu_switch_to(struct task_struct *prev, |
129 | struct task_struct *next); | 129 | struct task_struct *next); |
130 | 130 | ||
131 | /* | ||
132 | * Create a new kernel thread | ||
133 | */ | ||
134 | extern int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags); | ||
135 | |||
136 | #define task_pt_regs(p) \ | 131 | #define task_pt_regs(p) \ |
137 | ((struct pt_regs *)(THREAD_START_SP + task_stack_page(p)) - 1) | 132 | ((struct pt_regs *)(THREAD_START_SP + task_stack_page(p)) - 1) |
138 | 133 | ||
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 @@ | |||
23 | /* | 23 | /* |
24 | * System call wrappers implemented in kernel/entry.S. | 24 | * System call wrappers implemented in kernel/entry.S. |
25 | */ | 25 | */ |
26 | asmlinkage long sys_execve_wrapper(const char __user *filename, | ||
27 | const char __user *const __user *argv, | ||
28 | const char __user *const __user *envp); | ||
29 | asmlinkage long sys_clone_wrapper(unsigned long clone_flags, | 26 | asmlinkage long sys_clone_wrapper(unsigned long clone_flags, |
30 | unsigned long newsp, | 27 | unsigned long newsp, |
31 | void __user *parent_tid, | 28 | 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 @@ | |||
25 | #define __ARCH_WANT_COMPAT_SYS_RT_SIGSUSPEND | 25 | #define __ARCH_WANT_COMPAT_SYS_RT_SIGSUSPEND |
26 | #define __ARCH_WANT_COMPAT_SYS_SENDFILE | 26 | #define __ARCH_WANT_COMPAT_SYS_SENDFILE |
27 | #endif | 27 | #endif |
28 | #define __ARCH_WANT_SYS_EXECVE | ||
28 | #include <uapi/asm/unistd.h> | 29 | #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 */ | |||
32 | __SYSCALL(8, sys_creat) | 32 | __SYSCALL(8, sys_creat) |
33 | __SYSCALL(9, sys_link) | 33 | __SYSCALL(9, sys_link) |
34 | __SYSCALL(10, sys_unlink) | 34 | __SYSCALL(10, sys_unlink) |
35 | __SYSCALL(11, compat_sys_execve_wrapper) | 35 | __SYSCALL(11, compat_sys_execve) |
36 | __SYSCALL(12, sys_chdir) | 36 | __SYSCALL(12, sys_chdir) |
37 | __SYSCALL(13, sys_ni_syscall) /* 13 was sys_time */ | 37 | __SYSCALL(13, sys_ni_syscall) /* 13 was sys_time */ |
38 | __SYSCALL(14, sys_mknod) | 38 | __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: | |||
594 | /* | 594 | /* |
595 | * "slow" syscall return path. | 595 | * "slow" syscall return path. |
596 | */ | 596 | */ |
597 | ENTRY(ret_to_user) | 597 | ret_to_user: |
598 | disable_irq // disable interrupts | 598 | disable_irq // disable interrupts |
599 | ldr x1, [tsk, #TI_FLAGS] | 599 | ldr x1, [tsk, #TI_FLAGS] |
600 | and x2, x1, #_TIF_WORK_MASK | 600 | and x2, x1, #_TIF_WORK_MASK |
@@ -611,7 +611,10 @@ ENDPROC(ret_to_user) | |||
611 | */ | 611 | */ |
612 | ENTRY(ret_from_fork) | 612 | ENTRY(ret_from_fork) |
613 | bl schedule_tail | 613 | bl schedule_tail |
614 | get_thread_info tsk | 614 | cbz x19, 1f // not a kernel thread |
615 | mov x0, x20 | ||
616 | blr x19 | ||
617 | 1: get_thread_info tsk | ||
615 | b ret_to_user | 618 | b ret_to_user |
616 | ENDPROC(ret_from_fork) | 619 | ENDPROC(ret_from_fork) |
617 | 620 | ||
@@ -673,11 +676,6 @@ __sys_trace_return: | |||
673 | /* | 676 | /* |
674 | * Special system call wrappers. | 677 | * Special system call wrappers. |
675 | */ | 678 | */ |
676 | ENTRY(sys_execve_wrapper) | ||
677 | mov x3, sp | ||
678 | b sys_execve | ||
679 | ENDPROC(sys_execve_wrapper) | ||
680 | |||
681 | ENTRY(sys_clone_wrapper) | 679 | ENTRY(sys_clone_wrapper) |
682 | mov x5, sp | 680 | mov x5, sp |
683 | b sys_clone | 681 | 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, | |||
240 | struct pt_regs *childregs = task_pt_regs(p); | 240 | struct pt_regs *childregs = task_pt_regs(p); |
241 | unsigned long tls = p->thread.tp_value; | 241 | unsigned long tls = p->thread.tp_value; |
242 | 242 | ||
243 | *childregs = *regs; | 243 | memset(&p->thread.cpu_context, 0, sizeof(struct cpu_context)); |
244 | childregs->regs[0] = 0; | ||
245 | 244 | ||
246 | if (is_compat_thread(task_thread_info(p))) | 245 | if (likely(regs)) { |
247 | childregs->compat_sp = stack_start; | 246 | *childregs = *regs; |
248 | else { | 247 | childregs->regs[0] = 0; |
248 | if (is_compat_thread(task_thread_info(p))) { | ||
249 | childregs->compat_sp = stack_start; | ||
250 | } else { | ||
251 | /* | ||
252 | * Read the current TLS pointer from tpidr_el0 as it may be | ||
253 | * out-of-sync with the saved value. | ||
254 | */ | ||
255 | asm("mrs %0, tpidr_el0" : "=r" (tls)); | ||
256 | childregs->sp = stack_start; | ||
257 | } | ||
249 | /* | 258 | /* |
250 | * Read the current TLS pointer from tpidr_el0 as it may be | 259 | * If a TLS pointer was passed to clone (4th argument), use it |
251 | * out-of-sync with the saved value. | 260 | * for the new thread. |
252 | */ | 261 | */ |
253 | asm("mrs %0, tpidr_el0" : "=r" (tls)); | 262 | if (clone_flags & CLONE_SETTLS) |
254 | childregs->sp = stack_start; | 263 | tls = regs->regs[3]; |
264 | } else { | ||
265 | memset(childregs, 0, sizeof(struct pt_regs)); | ||
266 | childregs->pstate = PSR_MODE_EL1h; | ||
267 | p->thread.cpu_context.x19 = stack_start; | ||
268 | p->thread.cpu_context.x20 = stk_sz; | ||
255 | } | 269 | } |
256 | |||
257 | memset(&p->thread.cpu_context, 0, sizeof(struct cpu_context)); | ||
258 | p->thread.cpu_context.sp = (unsigned long)childregs; | ||
259 | p->thread.cpu_context.pc = (unsigned long)ret_from_fork; | 270 | p->thread.cpu_context.pc = (unsigned long)ret_from_fork; |
260 | 271 | p->thread.cpu_context.sp = (unsigned long)childregs; | |
261 | /* If a TLS pointer was passed to clone, use that for the new thread. */ | ||
262 | if (clone_flags & CLONE_SETTLS) | ||
263 | tls = regs->regs[3]; | ||
264 | p->thread.tp_value = tls; | 272 | p->thread.tp_value = tls; |
265 | 273 | ||
266 | ptrace_hw_copy_thread(p); | 274 | ptrace_hw_copy_thread(p); |
@@ -309,43 +317,6 @@ struct task_struct *__switch_to(struct task_struct *prev, | |||
309 | return last; | 317 | return last; |
310 | } | 318 | } |
311 | 319 | ||
312 | /* | ||
313 | * Shuffle the argument into the correct register before calling the | ||
314 | * thread function. x1 is the thread argument, x2 is the pointer to | ||
315 | * the thread function, and x3 points to the exit function. | ||
316 | */ | ||
317 | extern void kernel_thread_helper(void); | ||
318 | asm( ".section .text\n" | ||
319 | " .align\n" | ||
320 | " .type kernel_thread_helper, #function\n" | ||
321 | "kernel_thread_helper:\n" | ||
322 | " mov x0, x1\n" | ||
323 | " mov x30, x3\n" | ||
324 | " br x2\n" | ||
325 | " .size kernel_thread_helper, . - kernel_thread_helper\n" | ||
326 | " .previous"); | ||
327 | |||
328 | #define kernel_thread_exit do_exit | ||
329 | |||
330 | /* | ||
331 | * Create a kernel thread. | ||
332 | */ | ||
333 | pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags) | ||
334 | { | ||
335 | struct pt_regs regs; | ||
336 | |||
337 | memset(®s, 0, sizeof(regs)); | ||
338 | |||
339 | regs.regs[1] = (unsigned long)arg; | ||
340 | regs.regs[2] = (unsigned long)fn; | ||
341 | regs.regs[3] = (unsigned long)kernel_thread_exit; | ||
342 | regs.pc = (unsigned long)kernel_thread_helper; | ||
343 | regs.pstate = PSR_MODE_EL1h; | ||
344 | |||
345 | return do_fork(flags|CLONE_VM|CLONE_UNTRACED, 0, ®s, 0, NULL, NULL); | ||
346 | } | ||
347 | EXPORT_SYMBOL(kernel_thread); | ||
348 | |||
349 | unsigned long get_wchan(struct task_struct *p) | 320 | unsigned long get_wchan(struct task_struct *p) |
350 | { | 321 | { |
351 | struct stackframe frame; | 322 | 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, | |||
41 | return do_fork(clone_flags, newsp, regs, 0, parent_tidptr, child_tidptr); | 41 | return do_fork(clone_flags, newsp, regs, 0, parent_tidptr, child_tidptr); |
42 | } | 42 | } |
43 | 43 | ||
44 | /* | ||
45 | * sys_execve() executes a new program. | ||
46 | */ | ||
47 | asmlinkage long sys_execve(const char __user *filenamei, | ||
48 | const char __user *const __user *argv, | ||
49 | const char __user *const __user *envp, | ||
50 | struct pt_regs *regs) | ||
51 | { | ||
52 | long error; | ||
53 | struct filename *filename; | ||
54 | |||
55 | filename = getname(filenamei); | ||
56 | error = PTR_ERR(filename); | ||
57 | if (IS_ERR(filename)) | ||
58 | goto out; | ||
59 | error = do_execve(filename->name, argv, envp, regs); | ||
60 | putname(filename); | ||
61 | out: | ||
62 | return error; | ||
63 | } | ||
64 | |||
65 | int kernel_execve(const char *filename, | ||
66 | const char *const argv[], | ||
67 | const char *const envp[]) | ||
68 | { | ||
69 | struct pt_regs regs; | ||
70 | int ret; | ||
71 | |||
72 | memset(®s, 0, sizeof(struct pt_regs)); | ||
73 | ret = do_execve(filename, | ||
74 | (const char __user *const __user *)argv, | ||
75 | (const char __user *const __user *)envp, ®s); | ||
76 | if (ret < 0) | ||
77 | goto out; | ||
78 | |||
79 | /* | ||
80 | * Save argc to the register structure for userspace. | ||
81 | */ | ||
82 | regs.regs[0] = ret; | ||
83 | |||
84 | /* | ||
85 | * We were successful. We won't be returning to our caller, but | ||
86 | * instead to user space by manipulating the kernel stack. | ||
87 | */ | ||
88 | asm( "add x0, %0, %1\n\t" | ||
89 | "mov x1, %2\n\t" | ||
90 | "mov x2, %3\n\t" | ||
91 | "bl memmove\n\t" /* copy regs to top of stack */ | ||
92 | "mov x27, #0\n\t" /* not a syscall */ | ||
93 | "mov x28, %0\n\t" /* thread structure */ | ||
94 | "mov sp, x0\n\t" /* reposition stack pointer */ | ||
95 | "b ret_to_user" | ||
96 | : | ||
97 | : "r" (current_thread_info()), | ||
98 | "Ir" (THREAD_START_SP - sizeof(regs)), | ||
99 | "r" (®s), | ||
100 | "Ir" (sizeof(regs)) | ||
101 | : "x0", "x1", "x2", "x27", "x28", "x30", "memory"); | ||
102 | |||
103 | out: | ||
104 | return ret; | ||
105 | } | ||
106 | EXPORT_SYMBOL(kernel_execve); | ||
107 | |||
108 | asmlinkage long sys_mmap(unsigned long addr, unsigned long len, | 44 | asmlinkage long sys_mmap(unsigned long addr, unsigned long len, |
109 | unsigned long prot, unsigned long flags, | 45 | unsigned long prot, unsigned long flags, |
110 | unsigned long fd, off_t off) | 46 | unsigned long fd, off_t off) |
@@ -118,7 +54,6 @@ asmlinkage long sys_mmap(unsigned long addr, unsigned long len, | |||
118 | /* | 54 | /* |
119 | * Wrappers to pass the pt_regs argument. | 55 | * Wrappers to pass the pt_regs argument. |
120 | */ | 56 | */ |
121 | #define sys_execve sys_execve_wrapper | ||
122 | #define sys_clone sys_clone_wrapper | 57 | #define sys_clone sys_clone_wrapper |
123 | #define sys_rt_sigreturn sys_rt_sigreturn_wrapper | 58 | #define sys_rt_sigreturn sys_rt_sigreturn_wrapper |
124 | #define sys_sigaltstack sys_sigaltstack_wrapper | 59 | #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: | |||
36 | b compat_sys_vfork | 36 | b compat_sys_vfork |
37 | ENDPROC(compat_sys_vfork_wrapper) | 37 | ENDPROC(compat_sys_vfork_wrapper) |
38 | 38 | ||
39 | compat_sys_execve_wrapper: | ||
40 | mov x3, sp | ||
41 | b compat_sys_execve | ||
42 | ENDPROC(compat_sys_execve_wrapper) | ||
43 | |||
44 | compat_sys_clone_wrapper: | 39 | compat_sys_clone_wrapper: |
45 | mov x5, sp | 40 | mov x5, sp |
46 | b compat_sys_clone | 41 | 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) | |||
49 | regs, 0, NULL, NULL); | 49 | regs, 0, NULL, NULL); |
50 | } | 50 | } |
51 | 51 | ||
52 | asmlinkage int compat_sys_execve(const char __user *filenamei, | ||
53 | compat_uptr_t argv, compat_uptr_t envp, | ||
54 | struct pt_regs *regs) | ||
55 | { | ||
56 | int error; | ||
57 | struct filename *filename; | ||
58 | |||
59 | filename = getname(filenamei); | ||
60 | error = PTR_ERR(filename); | ||
61 | if (IS_ERR(filename)) | ||
62 | goto out; | ||
63 | error = compat_do_execve(filename->name, compat_ptr(argv), | ||
64 | compat_ptr(envp), regs); | ||
65 | putname(filename); | ||
66 | out: | ||
67 | return error; | ||
68 | } | ||
69 | |||
70 | asmlinkage int compat_sys_sched_rr_get_interval(compat_pid_t pid, | 52 | asmlinkage int compat_sys_sched_rr_get_interval(compat_pid_t pid, |
71 | struct compat_timespec __user *interval) | 53 | struct compat_timespec __user *interval) |
72 | { | 54 | { |