diff options
Diffstat (limited to 'arch')
164 files changed, 982 insertions, 2779 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..a1b00cd6f786 100644 --- a/arch/arm64/include/asm/syscalls.h +++ b/arch/arm64/include/asm/syscalls.h | |||
@@ -23,18 +23,16 @@ | |||
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, | ||
30 | unsigned long newsp, | ||
31 | void __user *parent_tid, | ||
32 | unsigned long tls_val, | ||
33 | void __user *child_tid); | ||
34 | asmlinkage long sys_rt_sigreturn_wrapper(void); | 26 | asmlinkage long sys_rt_sigreturn_wrapper(void); |
35 | asmlinkage long sys_sigaltstack_wrapper(const stack_t __user *uss, | 27 | asmlinkage long sys_sigaltstack_wrapper(const stack_t __user *uss, |
36 | stack_t __user *uoss); | 28 | stack_t __user *uoss); |
37 | 29 | ||
30 | /* | ||
31 | * AArch64 sys_clone implementation has a different prototype than the generic | ||
32 | * one (additional TLS value argument). | ||
33 | */ | ||
34 | #define sys_clone sys_clone | ||
35 | |||
38 | #include <asm-generic/syscalls.h> | 36 | #include <asm-generic/syscalls.h> |
39 | 37 | ||
40 | #endif /* __ASM_SYSCALLS_H */ | 38 | #endif /* __ASM_SYSCALLS_H */ |
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..d9850cf9870d 100644 --- a/arch/arm64/include/asm/unistd32.h +++ b/arch/arm64/include/asm/unistd32.h | |||
@@ -23,7 +23,7 @@ | |||
23 | 23 | ||
24 | __SYSCALL(0, sys_restart_syscall) | 24 | __SYSCALL(0, sys_restart_syscall) |
25 | __SYSCALL(1, sys_exit) | 25 | __SYSCALL(1, sys_exit) |
26 | __SYSCALL(2, compat_sys_fork_wrapper) | 26 | __SYSCALL(2, compat_sys_fork) |
27 | __SYSCALL(3, sys_read) | 27 | __SYSCALL(3, sys_read) |
28 | __SYSCALL(4, sys_write) | 28 | __SYSCALL(4, sys_write) |
29 | __SYSCALL(5, compat_sys_open) | 29 | __SYSCALL(5, compat_sys_open) |
@@ -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) |
@@ -141,7 +141,7 @@ __SYSCALL(116, compat_sys_sysinfo) | |||
141 | __SYSCALL(117, sys_ni_syscall) /* 117 was sys_ipc */ | 141 | __SYSCALL(117, sys_ni_syscall) /* 117 was sys_ipc */ |
142 | __SYSCALL(118, sys_fsync) | 142 | __SYSCALL(118, sys_fsync) |
143 | __SYSCALL(119, compat_sys_sigreturn_wrapper) | 143 | __SYSCALL(119, compat_sys_sigreturn_wrapper) |
144 | __SYSCALL(120, compat_sys_clone_wrapper) | 144 | __SYSCALL(120, sys_clone) |
145 | __SYSCALL(121, sys_setdomainname) | 145 | __SYSCALL(121, sys_setdomainname) |
146 | __SYSCALL(122, sys_newuname) | 146 | __SYSCALL(122, sys_newuname) |
147 | __SYSCALL(123, sys_ni_syscall) /* 123 was sys_modify_ldt */ | 147 | __SYSCALL(123, sys_ni_syscall) /* 123 was sys_modify_ldt */ |
@@ -211,7 +211,7 @@ __SYSCALL(186, compat_sys_sigaltstack_wrapper) | |||
211 | __SYSCALL(187, compat_sys_sendfile) | 211 | __SYSCALL(187, compat_sys_sendfile) |
212 | __SYSCALL(188, sys_ni_syscall) /* 188 reserved */ | 212 | __SYSCALL(188, sys_ni_syscall) /* 188 reserved */ |
213 | __SYSCALL(189, sys_ni_syscall) /* 189 reserved */ | 213 | __SYSCALL(189, sys_ni_syscall) /* 189 reserved */ |
214 | __SYSCALL(190, compat_sys_vfork_wrapper) | 214 | __SYSCALL(190, compat_sys_vfork) |
215 | __SYSCALL(191, compat_sys_getrlimit) /* SuS compliant getrlimit */ | 215 | __SYSCALL(191, compat_sys_getrlimit) /* SuS compliant getrlimit */ |
216 | __SYSCALL(192, sys_mmap_pgoff) | 216 | __SYSCALL(192, sys_mmap_pgoff) |
217 | __SYSCALL(193, compat_sys_truncate64_wrapper) | 217 | __SYSCALL(193, compat_sys_truncate64_wrapper) |
diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S index a6f3f7da6880..cbfa4d28100e 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,16 +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) | ||
682 | mov x5, sp | ||
683 | b sys_clone | ||
684 | ENDPROC(sys_clone_wrapper) | ||
685 | |||
686 | ENTRY(sys_rt_sigreturn_wrapper) | 679 | ENTRY(sys_rt_sigreturn_wrapper) |
687 | mov x0, sp | 680 | mov x0, sp |
688 | b sys_rt_sigreturn | 681 | b sys_rt_sigreturn |
diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c index e04cebdbb47f..8a5f3341861e 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, | |||
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 | if (stack_start) | ||
250 | childregs->compat_sp = stack_start; | ||
251 | } else { | ||
252 | /* | ||
253 | * Read the current TLS pointer from tpidr_el0 as it may be | ||
254 | * out-of-sync with the saved value. | ||
255 | */ | ||
256 | asm("mrs %0, tpidr_el0" : "=r" (tls)); | ||
257 | if (stack_start) { | ||
258 | /* 16-byte aligned stack mandatory on AArch64 */ | ||
259 | if (stack_start & 15) | ||
260 | return -EINVAL; | ||
261 | childregs->sp = stack_start; | ||
262 | } | ||
263 | } | ||
249 | /* | 264 | /* |
250 | * Read the current TLS pointer from tpidr_el0 as it may be | 265 | * If a TLS pointer was passed to clone (4th argument), use it |
251 | * out-of-sync with the saved value. | 266 | * for the new thread. |
252 | */ | 267 | */ |
253 | asm("mrs %0, tpidr_el0" : "=r" (tls)); | 268 | if (clone_flags & CLONE_SETTLS) |
254 | childregs->sp = stack_start; | 269 | tls = regs->regs[3]; |
270 | } else { | ||
271 | memset(childregs, 0, sizeof(struct pt_regs)); | ||
272 | childregs->pstate = PSR_MODE_EL1h; | ||
273 | p->thread.cpu_context.x19 = stack_start; | ||
274 | p->thread.cpu_context.x20 = stk_sz; | ||
255 | } | 275 | } |
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; | 276 | p->thread.cpu_context.pc = (unsigned long)ret_from_fork; |
260 | 277 | 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; | 278 | p->thread.tp_value = tls; |
265 | 279 | ||
266 | ptrace_hw_copy_thread(p); | 280 | ptrace_hw_copy_thread(p); |
@@ -309,43 +323,6 @@ struct task_struct *__switch_to(struct task_struct *prev, | |||
309 | return last; | 323 | return last; |
310 | } | 324 | } |
311 | 325 | ||
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) | 326 | unsigned long get_wchan(struct task_struct *p) |
350 | { | 327 | { |
351 | struct stackframe frame; | 328 | struct stackframe frame; |
diff --git a/arch/arm64/kernel/sys.c b/arch/arm64/kernel/sys.c index b120df37de35..4364df85050e 100644 --- a/arch/arm64/kernel/sys.c +++ b/arch/arm64/kernel/sys.c | |||
@@ -31,79 +31,11 @@ | |||
31 | */ | 31 | */ |
32 | asmlinkage long sys_clone(unsigned long clone_flags, unsigned long newsp, | 32 | asmlinkage long sys_clone(unsigned long clone_flags, unsigned long newsp, |
33 | int __user *parent_tidptr, unsigned long tls_val, | 33 | int __user *parent_tidptr, unsigned long tls_val, |
34 | int __user *child_tidptr, struct pt_regs *regs) | 34 | int __user *child_tidptr) |
35 | { | 35 | { |
36 | if (!newsp) | 36 | return do_fork(clone_flags, newsp, current_pt_regs(), 0, |
37 | newsp = regs->sp; | 37 | parent_tidptr, child_tidptr); |
38 | /* 16-byte aligned stack mandatory on AArch64 */ | ||
39 | if (newsp & 15) | ||
40 | return -EINVAL; | ||
41 | return do_fork(clone_flags, newsp, regs, 0, parent_tidptr, child_tidptr); | ||
42 | } | ||
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 | } | 38 | } |
106 | EXPORT_SYMBOL(kernel_execve); | ||
107 | 39 | ||
108 | asmlinkage long sys_mmap(unsigned long addr, unsigned long len, | 40 | asmlinkage long sys_mmap(unsigned long addr, unsigned long len, |
109 | unsigned long prot, unsigned long flags, | 41 | unsigned long prot, unsigned long flags, |
@@ -118,8 +50,6 @@ asmlinkage long sys_mmap(unsigned long addr, unsigned long len, | |||
118 | /* | 50 | /* |
119 | * Wrappers to pass the pt_regs argument. | 51 | * Wrappers to pass the pt_regs argument. |
120 | */ | 52 | */ |
121 | #define sys_execve sys_execve_wrapper | ||
122 | #define sys_clone sys_clone_wrapper | ||
123 | #define sys_rt_sigreturn sys_rt_sigreturn_wrapper | 53 | #define sys_rt_sigreturn sys_rt_sigreturn_wrapper |
124 | #define sys_sigaltstack sys_sigaltstack_wrapper | 54 | #define sys_sigaltstack sys_sigaltstack_wrapper |
125 | 55 | ||
diff --git a/arch/arm64/kernel/sys32.S b/arch/arm64/kernel/sys32.S index 54c4aec47a08..7ef59e9245ef 100644 --- a/arch/arm64/kernel/sys32.S +++ b/arch/arm64/kernel/sys32.S | |||
@@ -26,25 +26,6 @@ | |||
26 | /* | 26 | /* |
27 | * System call wrappers for the AArch32 compatibility layer. | 27 | * System call wrappers for the AArch32 compatibility layer. |
28 | */ | 28 | */ |
29 | compat_sys_fork_wrapper: | ||
30 | mov x0, sp | ||
31 | b compat_sys_fork | ||
32 | ENDPROC(compat_sys_fork_wrapper) | ||
33 | |||
34 | compat_sys_vfork_wrapper: | ||
35 | mov x0, sp | ||
36 | b compat_sys_vfork | ||
37 | ENDPROC(compat_sys_vfork_wrapper) | ||
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: | ||
45 | mov x5, sp | ||
46 | b compat_sys_clone | ||
47 | ENDPROC(compat_sys_clone_wrapper) | ||
48 | 29 | ||
49 | compat_sys_sigreturn_wrapper: | 30 | compat_sys_sigreturn_wrapper: |
50 | mov x0, sp | 31 | mov x0, sp |
diff --git a/arch/arm64/kernel/sys_compat.c b/arch/arm64/kernel/sys_compat.c index 906e3bd270b0..6fabc1912da0 100644 --- a/arch/arm64/kernel/sys_compat.c +++ b/arch/arm64/kernel/sys_compat.c | |||
@@ -28,43 +28,15 @@ | |||
28 | #include <asm/cacheflush.h> | 28 | #include <asm/cacheflush.h> |
29 | #include <asm/unistd32.h> | 29 | #include <asm/unistd32.h> |
30 | 30 | ||
31 | asmlinkage int compat_sys_fork(struct pt_regs *regs) | 31 | asmlinkage int compat_sys_fork(void) |
32 | { | 32 | { |
33 | return do_fork(SIGCHLD, regs->compat_sp, regs, 0, NULL, NULL); | 33 | return do_fork(SIGCHLD, 0, current_pt_regs(), 0, NULL, NULL); |
34 | } | 34 | } |
35 | 35 | ||
36 | asmlinkage int compat_sys_clone(unsigned long clone_flags, unsigned long newsp, | 36 | asmlinkage int compat_sys_vfork(void) |
37 | int __user *parent_tidptr, int tls_val, | ||
38 | int __user *child_tidptr, struct pt_regs *regs) | ||
39 | { | 37 | { |
40 | if (!newsp) | 38 | return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, 0, |
41 | newsp = regs->compat_sp; | 39 | current_pt_regs(), 0, NULL, NULL); |
42 | |||
43 | return do_fork(clone_flags, newsp, regs, 0, parent_tidptr, child_tidptr); | ||
44 | } | ||
45 | |||
46 | asmlinkage int compat_sys_vfork(struct pt_regs *regs) | ||
47 | { | ||
48 | return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->compat_sp, | ||
49 | regs, 0, NULL, NULL); | ||
50 | } | ||
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 | } | 40 | } |
69 | 41 | ||
70 | asmlinkage int compat_sys_sched_rr_get_interval(compat_pid_t pid, | 42 | asmlinkage int compat_sys_sched_rr_get_interval(compat_pid_t pid, |
diff --git a/arch/avr32/Kconfig b/arch/avr32/Kconfig index 06e73bf665e9..649aeb9acecb 100644 --- a/arch/avr32/Kconfig +++ b/arch/avr32/Kconfig | |||
@@ -17,6 +17,8 @@ config AVR32 | |||
17 | select GENERIC_CLOCKEVENTS | 17 | select GENERIC_CLOCKEVENTS |
18 | select HAVE_MOD_ARCH_SPECIFIC | 18 | select HAVE_MOD_ARCH_SPECIFIC |
19 | select MODULES_USE_ELF_RELA | 19 | select MODULES_USE_ELF_RELA |
20 | select GENERIC_KERNEL_THREAD | ||
21 | select GENERIC_KERNEL_EXECVE | ||
20 | help | 22 | help |
21 | AVR32 is a high-performance 32-bit RISC microprocessor core, | 23 | AVR32 is a high-performance 32-bit RISC microprocessor core, |
22 | designed for cost-sensitive embedded applications, with particular | 24 | designed for cost-sensitive embedded applications, with particular |
diff --git a/arch/avr32/include/asm/processor.h b/arch/avr32/include/asm/processor.h index 87d8baccc60e..48d71c5c898a 100644 --- a/arch/avr32/include/asm/processor.h +++ b/arch/avr32/include/asm/processor.h | |||
@@ -142,9 +142,6 @@ struct task_struct; | |||
142 | /* Free all resources held by a thread */ | 142 | /* Free all resources held by a thread */ |
143 | extern void release_thread(struct task_struct *); | 143 | extern void release_thread(struct task_struct *); |
144 | 144 | ||
145 | /* Create a kernel thread without removing it from tasklists */ | ||
146 | extern int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags); | ||
147 | |||
148 | /* Return saved PC of a blocked thread */ | 145 | /* Return saved PC of a blocked thread */ |
149 | #define thread_saved_pc(tsk) ((tsk)->thread.cpu_context.pc) | 146 | #define thread_saved_pc(tsk) ((tsk)->thread.cpu_context.pc) |
150 | 147 | ||
diff --git a/arch/avr32/include/asm/unistd.h b/arch/avr32/include/asm/unistd.h index 157b4bd3d5e5..641023d1bcb5 100644 --- a/arch/avr32/include/asm/unistd.h +++ b/arch/avr32/include/asm/unistd.h | |||
@@ -39,6 +39,7 @@ | |||
39 | #define __ARCH_WANT_SYS_GETPGRP | 39 | #define __ARCH_WANT_SYS_GETPGRP |
40 | #define __ARCH_WANT_SYS_RT_SIGACTION | 40 | #define __ARCH_WANT_SYS_RT_SIGACTION |
41 | #define __ARCH_WANT_SYS_RT_SIGSUSPEND | 41 | #define __ARCH_WANT_SYS_RT_SIGSUSPEND |
42 | #define __ARCH_WANT_SYS_EXECVE | ||
42 | 43 | ||
43 | /* | 44 | /* |
44 | * "Conditional" syscalls | 45 | * "Conditional" syscalls |
diff --git a/arch/avr32/kernel/Makefile b/arch/avr32/kernel/Makefile index 9e2c465ef3a6..119a2e41defe 100644 --- a/arch/avr32/kernel/Makefile +++ b/arch/avr32/kernel/Makefile | |||
@@ -7,7 +7,7 @@ extra-y := head.o vmlinux.lds | |||
7 | obj-$(CONFIG_SUBARCH_AVR32B) += entry-avr32b.o | 7 | obj-$(CONFIG_SUBARCH_AVR32B) += entry-avr32b.o |
8 | obj-y += syscall_table.o syscall-stubs.o irq.o | 8 | obj-y += syscall_table.o syscall-stubs.o irq.o |
9 | obj-y += setup.o traps.o ocd.o ptrace.o | 9 | obj-y += setup.o traps.o ocd.o ptrace.o |
10 | obj-y += signal.o sys_avr32.o process.o time.o | 10 | obj-y += signal.o process.o time.o |
11 | obj-y += switch_to.o cpu.o | 11 | obj-y += switch_to.o cpu.o |
12 | obj-$(CONFIG_MODULES) += module.o avr32_ksyms.o | 12 | obj-$(CONFIG_MODULES) += module.o avr32_ksyms.o |
13 | obj-$(CONFIG_KPROBES) += kprobes.o | 13 | obj-$(CONFIG_KPROBES) += kprobes.o |
diff --git a/arch/avr32/kernel/entry-avr32b.S b/arch/avr32/kernel/entry-avr32b.S index df2884181313..9899d3cc6f03 100644 --- a/arch/avr32/kernel/entry-avr32b.S +++ b/arch/avr32/kernel/entry-avr32b.S | |||
@@ -251,13 +251,15 @@ syscall_badsys: | |||
251 | .global ret_from_fork | 251 | .global ret_from_fork |
252 | ret_from_fork: | 252 | ret_from_fork: |
253 | call schedule_tail | 253 | call schedule_tail |
254 | mov r12, 0 | ||
255 | rjmp syscall_return | ||
254 | 256 | ||
255 | /* check for syscall tracing */ | 257 | .global ret_from_kernel_thread |
256 | get_thread_info r0 | 258 | ret_from_kernel_thread: |
257 | ld.w r1, r0[TI_flags] | 259 | call schedule_tail |
258 | andl r1, _TIF_ALLWORK_MASK, COH | 260 | mov r12, r0 |
259 | brne syscall_exit_work | 261 | mov lr, r2 /* syscall_return */ |
260 | rjmp syscall_exit_cont | 262 | mov pc, r1 |
261 | 263 | ||
262 | syscall_trace_enter: | 264 | syscall_trace_enter: |
263 | pushm r8-r12 | 265 | pushm r8-r12 |
diff --git a/arch/avr32/kernel/process.c b/arch/avr32/kernel/process.c index 1bb0a8abd79b..09b894d96d6e 100644 --- a/arch/avr32/kernel/process.c +++ b/arch/avr32/kernel/process.c | |||
@@ -69,44 +69,6 @@ void machine_restart(char *cmd) | |||
69 | } | 69 | } |
70 | 70 | ||
71 | /* | 71 | /* |
72 | * PC is actually discarded when returning from a system call -- the | ||
73 | * return address must be stored in LR. This function will make sure | ||
74 | * LR points to do_exit before starting the thread. | ||
75 | * | ||
76 | * Also, when returning from fork(), r12 is 0, so we must copy the | ||
77 | * argument as well. | ||
78 | * | ||
79 | * r0 : The argument to the main thread function | ||
80 | * r1 : The address of do_exit | ||
81 | * r2 : The address of the main thread function | ||
82 | */ | ||
83 | asmlinkage extern void kernel_thread_helper(void); | ||
84 | __asm__(" .type kernel_thread_helper, @function\n" | ||
85 | "kernel_thread_helper:\n" | ||
86 | " mov r12, r0\n" | ||
87 | " mov lr, r2\n" | ||
88 | " mov pc, r1\n" | ||
89 | " .size kernel_thread_helper, . - kernel_thread_helper"); | ||
90 | |||
91 | int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags) | ||
92 | { | ||
93 | struct pt_regs regs; | ||
94 | |||
95 | memset(®s, 0, sizeof(regs)); | ||
96 | |||
97 | regs.r0 = (unsigned long)arg; | ||
98 | regs.r1 = (unsigned long)fn; | ||
99 | regs.r2 = (unsigned long)do_exit; | ||
100 | regs.lr = (unsigned long)kernel_thread_helper; | ||
101 | regs.pc = (unsigned long)kernel_thread_helper; | ||
102 | regs.sr = MODE_SUPERVISOR; | ||
103 | |||
104 | return do_fork(flags | CLONE_VM | CLONE_UNTRACED, | ||
105 | 0, ®s, 0, NULL, NULL); | ||
106 | } | ||
107 | EXPORT_SYMBOL(kernel_thread); | ||
108 | |||
109 | /* | ||
110 | * Free current thread data structures etc | 72 | * Free current thread data structures etc |
111 | */ | 73 | */ |
112 | void exit_thread(void) | 74 | void exit_thread(void) |
@@ -332,26 +294,31 @@ int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu) | |||
332 | } | 294 | } |
333 | 295 | ||
334 | asmlinkage void ret_from_fork(void); | 296 | asmlinkage void ret_from_fork(void); |
297 | asmlinkage void ret_from_kernel_thread(void); | ||
298 | asmlinkage void syscall_return(void); | ||
335 | 299 | ||
336 | int copy_thread(unsigned long clone_flags, unsigned long usp, | 300 | int copy_thread(unsigned long clone_flags, unsigned long usp, |
337 | unsigned long unused, | 301 | unsigned long arg, |
338 | struct task_struct *p, struct pt_regs *regs) | 302 | struct task_struct *p, struct pt_regs *regs) |
339 | { | 303 | { |
340 | struct pt_regs *childregs; | 304 | struct pt_regs *childregs = task_pt_regs(p); |
341 | 305 | ||
342 | childregs = ((struct pt_regs *)(THREAD_SIZE + (unsigned long)task_stack_page(p))) - 1; | 306 | if (unlikely(!regs)) { |
343 | *childregs = *regs; | 307 | memset(childregs, 0, sizeof(struct pt_regs)); |
344 | 308 | p->thread.cpu_context.r0 = arg; | |
345 | if (user_mode(regs)) | 309 | p->thread.cpu_context.r1 = usp; /* fn */ |
310 | p->thread.cpu_context.r2 = syscall_return; | ||
311 | p->thread.cpu_context.pc = (unsigned long)ret_from_kernel_thread; | ||
312 | childregs->sr = MODE_SUPERVISOR; | ||
313 | } else { | ||
314 | *childregs = *regs; | ||
346 | childregs->sp = usp; | 315 | childregs->sp = usp; |
347 | else | 316 | childregs->r12 = 0; /* Set return value for child */ |
348 | childregs->sp = (unsigned long)task_stack_page(p) + THREAD_SIZE; | 317 | p->thread.cpu_context.pc = (unsigned long)ret_from_fork; |
349 | 318 | } | |
350 | childregs->r12 = 0; /* Set return value for child */ | ||
351 | 319 | ||
352 | p->thread.cpu_context.sr = MODE_SUPERVISOR | SR_GM; | 320 | p->thread.cpu_context.sr = MODE_SUPERVISOR | SR_GM; |
353 | p->thread.cpu_context.ksp = (unsigned long)childregs; | 321 | p->thread.cpu_context.ksp = (unsigned long)childregs; |
354 | p->thread.cpu_context.pc = (unsigned long)ret_from_fork; | ||
355 | 322 | ||
356 | clear_tsk_thread_flag(p, TIF_DEBUG); | 323 | clear_tsk_thread_flag(p, TIF_DEBUG); |
357 | if ((clone_flags & CLONE_PTRACE) && test_thread_flag(TIF_DEBUG)) | 324 | if ((clone_flags & CLONE_PTRACE) && test_thread_flag(TIF_DEBUG)) |
@@ -382,27 +349,6 @@ asmlinkage int sys_vfork(struct pt_regs *regs) | |||
382 | 0, NULL, NULL); | 349 | 0, NULL, NULL); |
383 | } | 350 | } |
384 | 351 | ||
385 | asmlinkage int sys_execve(const char __user *ufilename, | ||
386 | const char __user *const __user *uargv, | ||
387 | const char __user *const __user *uenvp, | ||
388 | struct pt_regs *regs) | ||
389 | { | ||
390 | int error; | ||
391 | struct filename *filename; | ||
392 | |||
393 | filename = getname(ufilename); | ||
394 | error = PTR_ERR(filename); | ||
395 | if (IS_ERR(filename)) | ||
396 | goto out; | ||
397 | |||
398 | error = do_execve(filename->name, uargv, uenvp, regs); | ||
399 | putname(filename); | ||
400 | |||
401 | out: | ||
402 | return error; | ||
403 | } | ||
404 | |||
405 | |||
406 | /* | 352 | /* |
407 | * This function is supposed to answer the question "who called | 353 | * This function is supposed to answer the question "who called |
408 | * schedule()?" | 354 | * schedule()?" |
diff --git a/arch/avr32/kernel/sys_avr32.c b/arch/avr32/kernel/sys_avr32.c deleted file mode 100644 index 62635a09ae3e..000000000000 --- a/arch/avr32/kernel/sys_avr32.c +++ /dev/null | |||
@@ -1,24 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2004-2006 Atmel Corporation | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | */ | ||
8 | #include <linux/unistd.h> | ||
9 | |||
10 | int kernel_execve(const char *file, | ||
11 | const char *const *argv, | ||
12 | const char *const *envp) | ||
13 | { | ||
14 | register long scno asm("r8") = __NR_execve; | ||
15 | register long sc1 asm("r12") = (long)file; | ||
16 | register long sc2 asm("r11") = (long)argv; | ||
17 | register long sc3 asm("r10") = (long)envp; | ||
18 | |||
19 | asm volatile("scall" | ||
20 | : "=r"(sc1) | ||
21 | : "r"(scno), "0"(sc1), "r"(sc2), "r"(sc3) | ||
22 | : "cc", "memory"); | ||
23 | return sc1; | ||
24 | } | ||
diff --git a/arch/avr32/kernel/syscall-stubs.S b/arch/avr32/kernel/syscall-stubs.S index 0447a3e2ba64..285a61b9194e 100644 --- a/arch/avr32/kernel/syscall-stubs.S +++ b/arch/avr32/kernel/syscall-stubs.S | |||
@@ -50,12 +50,6 @@ __sys_vfork: | |||
50 | mov r12, sp | 50 | mov r12, sp |
51 | rjmp sys_vfork | 51 | rjmp sys_vfork |
52 | 52 | ||
53 | .global __sys_execve | ||
54 | .type __sys_execve,@function | ||
55 | __sys_execve: | ||
56 | mov r9, sp | ||
57 | rjmp sys_execve | ||
58 | |||
59 | .global __sys_mmap2 | 53 | .global __sys_mmap2 |
60 | .type __sys_mmap2,@function | 54 | .type __sys_mmap2,@function |
61 | __sys_mmap2: | 55 | __sys_mmap2: |
diff --git a/arch/avr32/kernel/syscall_table.S b/arch/avr32/kernel/syscall_table.S index 6eba53530d1c..fc6497706819 100644 --- a/arch/avr32/kernel/syscall_table.S +++ b/arch/avr32/kernel/syscall_table.S | |||
@@ -24,7 +24,7 @@ sys_call_table: | |||
24 | .long sys_creat | 24 | .long sys_creat |
25 | .long sys_link | 25 | .long sys_link |
26 | .long sys_unlink /* 10 */ | 26 | .long sys_unlink /* 10 */ |
27 | .long __sys_execve | 27 | .long sys_execve |
28 | .long sys_chdir | 28 | .long sys_chdir |
29 | .long sys_time | 29 | .long sys_time |
30 | .long sys_mknod | 30 | .long sys_mknod |
diff --git a/arch/blackfin/Kconfig b/arch/blackfin/Kconfig index b6f3ad5441c5..ab9ff4075f4d 100644 --- a/arch/blackfin/Kconfig +++ b/arch/blackfin/Kconfig | |||
@@ -45,6 +45,8 @@ config BLACKFIN | |||
45 | select ARCH_USES_GETTIMEOFFSET if !GENERIC_CLOCKEVENTS | 45 | select ARCH_USES_GETTIMEOFFSET if !GENERIC_CLOCKEVENTS |
46 | select HAVE_MOD_ARCH_SPECIFIC | 46 | select HAVE_MOD_ARCH_SPECIFIC |
47 | select MODULES_USE_ELF_RELA | 47 | select MODULES_USE_ELF_RELA |
48 | select GENERIC_KERNEL_THREAD | ||
49 | select GENERIC_KERNEL_EXECVE | ||
48 | 50 | ||
49 | config GENERIC_CSUM | 51 | config GENERIC_CSUM |
50 | def_bool y | 52 | def_bool y |
diff --git a/arch/blackfin/include/asm/processor.h b/arch/blackfin/include/asm/processor.h index 4ef7cfe43ceb..d0e72e9475a6 100644 --- a/arch/blackfin/include/asm/processor.h +++ b/arch/blackfin/include/asm/processor.h | |||
@@ -75,8 +75,6 @@ static inline void release_thread(struct task_struct *dead_task) | |||
75 | { | 75 | { |
76 | } | 76 | } |
77 | 77 | ||
78 | extern int kernel_thread(int (*fn) (void *), void *arg, unsigned long flags); | ||
79 | |||
80 | /* | 78 | /* |
81 | * Free current thread data structures etc.. | 79 | * Free current thread data structures etc.. |
82 | */ | 80 | */ |
diff --git a/arch/blackfin/include/asm/unistd.h b/arch/blackfin/include/asm/unistd.h index 5b2a0748d7d3..b4ec1bb3d5d4 100644 --- a/arch/blackfin/include/asm/unistd.h +++ b/arch/blackfin/include/asm/unistd.h | |||
@@ -446,6 +446,7 @@ | |||
446 | #define __ARCH_WANT_SYS_NICE | 446 | #define __ARCH_WANT_SYS_NICE |
447 | #define __ARCH_WANT_SYS_RT_SIGACTION | 447 | #define __ARCH_WANT_SYS_RT_SIGACTION |
448 | #define __ARCH_WANT_SYS_RT_SIGSUSPEND | 448 | #define __ARCH_WANT_SYS_RT_SIGSUSPEND |
449 | #define __ARCH_WANT_SYS_EXECVE | ||
449 | 450 | ||
450 | /* | 451 | /* |
451 | * "Conditional" syscalls | 452 | * "Conditional" syscalls |
diff --git a/arch/blackfin/kernel/entry.S b/arch/blackfin/kernel/entry.S index f33792cc1a0d..78f4f637e155 100644 --- a/arch/blackfin/kernel/entry.S +++ b/arch/blackfin/kernel/entry.S | |||
@@ -46,22 +46,16 @@ ENTRY(_ret_from_fork) | |||
46 | SP += -12; | 46 | SP += -12; |
47 | pseudo_long_call _schedule_tail, p5; | 47 | pseudo_long_call _schedule_tail, p5; |
48 | SP += 12; | 48 | SP += 12; |
49 | r0 = [sp + PT_IPEND]; | 49 | p1 = [sp++]; |
50 | cc = bittst(r0,1); | 50 | r0 = [sp++]; |
51 | if cc jump .Lin_kernel; | 51 | cc = p1 == 0; |
52 | if cc jump .Lfork; | ||
53 | sp += -12; | ||
54 | call (p1); | ||
55 | sp += 12; | ||
56 | .Lfork: | ||
52 | RESTORE_CONTEXT | 57 | RESTORE_CONTEXT |
53 | rti; | 58 | rti; |
54 | .Lin_kernel: | ||
55 | bitclr(r0,1); | ||
56 | [sp + PT_IPEND] = r0; | ||
57 | /* do a 'fake' RTI by jumping to [RETI] | ||
58 | * to avoid clearing supervisor mode in child | ||
59 | */ | ||
60 | r0 = [sp + PT_PC]; | ||
61 | [sp + PT_P0] = r0; | ||
62 | |||
63 | RESTORE_ALL_SYS | ||
64 | jump (p0); | ||
65 | ENDPROC(_ret_from_fork) | 59 | ENDPROC(_ret_from_fork) |
66 | 60 | ||
67 | ENTRY(_sys_vfork) | 61 | ENTRY(_sys_vfork) |
diff --git a/arch/blackfin/kernel/process.c b/arch/blackfin/kernel/process.c index bb1cc721fcf7..da8df0e504ac 100644 --- a/arch/blackfin/kernel/process.c +++ b/arch/blackfin/kernel/process.c | |||
@@ -102,40 +102,6 @@ void cpu_idle(void) | |||
102 | } | 102 | } |
103 | 103 | ||
104 | /* | 104 | /* |
105 | * This gets run with P1 containing the | ||
106 | * function to call, and R1 containing | ||
107 | * the "args". Note P0 is clobbered on the way here. | ||
108 | */ | ||
109 | void kernel_thread_helper(void); | ||
110 | __asm__(".section .text\n" | ||
111 | ".align 4\n" | ||
112 | "_kernel_thread_helper:\n\t" | ||
113 | "\tsp += -12;\n\t" | ||
114 | "\tr0 = r1;\n\t" "\tcall (p1);\n\t" "\tcall _do_exit;\n" ".previous"); | ||
115 | |||
116 | /* | ||
117 | * Create a kernel thread. | ||
118 | */ | ||
119 | pid_t kernel_thread(int (*fn) (void *), void *arg, unsigned long flags) | ||
120 | { | ||
121 | struct pt_regs regs; | ||
122 | |||
123 | memset(®s, 0, sizeof(regs)); | ||
124 | |||
125 | regs.r1 = (unsigned long)arg; | ||
126 | regs.p1 = (unsigned long)fn; | ||
127 | regs.pc = (unsigned long)kernel_thread_helper; | ||
128 | regs.orig_p0 = -1; | ||
129 | /* Set bit 2 to tell ret_from_fork we should be returning to kernel | ||
130 | mode. */ | ||
131 | regs.ipend = 0x8002; | ||
132 | __asm__ __volatile__("%0 = syscfg;":"=da"(regs.syscfg):); | ||
133 | return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, ®s, 0, NULL, | ||
134 | NULL); | ||
135 | } | ||
136 | EXPORT_SYMBOL(kernel_thread); | ||
137 | |||
138 | /* | ||
139 | * Do necessary setup to start up a newly executed thread. | 105 | * Do necessary setup to start up a newly executed thread. |
140 | * | 106 | * |
141 | * pass the data segment into user programs if it exists, | 107 | * pass the data segment into user programs if it exists, |
@@ -193,38 +159,31 @@ copy_thread(unsigned long clone_flags, | |||
193 | struct task_struct *p, struct pt_regs *regs) | 159 | struct task_struct *p, struct pt_regs *regs) |
194 | { | 160 | { |
195 | struct pt_regs *childregs; | 161 | struct pt_regs *childregs; |
162 | unsigned long *v; | ||
196 | 163 | ||
197 | childregs = (struct pt_regs *) (task_stack_page(p) + THREAD_SIZE) - 1; | 164 | childregs = (struct pt_regs *) (task_stack_page(p) + THREAD_SIZE) - 1; |
198 | *childregs = *regs; | 165 | v = ((unsigned long *)childregs) - 2; |
199 | childregs->r0 = 0; | 166 | if (unlikely(!regs)) { |
167 | memset(childregs, 0, sizeof(struct pt_regs)); | ||
168 | v[0] = usp; | ||
169 | v[1] = topstk; | ||
170 | childregs->orig_p0 = -1; | ||
171 | childregs->ipend = 0x8000; | ||
172 | __asm__ __volatile__("%0 = syscfg;":"=da"(childregs->syscfg):); | ||
173 | p->thread.usp = 0; | ||
174 | } else { | ||
175 | *childregs = *regs; | ||
176 | childregs->r0 = 0; | ||
177 | p->thread.usp = usp; | ||
178 | v[0] = v[1] = 0; | ||
179 | } | ||
200 | 180 | ||
201 | p->thread.usp = usp; | 181 | p->thread.ksp = (unsigned long)v; |
202 | p->thread.ksp = (unsigned long)childregs; | ||
203 | p->thread.pc = (unsigned long)ret_from_fork; | 182 | p->thread.pc = (unsigned long)ret_from_fork; |
204 | 183 | ||
205 | return 0; | 184 | return 0; |
206 | } | 185 | } |
207 | 186 | ||
208 | /* | ||
209 | * sys_execve() executes a new program. | ||
210 | */ | ||
211 | asmlinkage int sys_execve(const char __user *name, | ||
212 | const char __user *const __user *argv, | ||
213 | const char __user *const __user *envp) | ||
214 | { | ||
215 | int error; | ||
216 | struct filename *filename; | ||
217 | struct pt_regs *regs = (struct pt_regs *)((&name) + 6); | ||
218 | |||
219 | filename = getname(name); | ||
220 | error = PTR_ERR(filename); | ||
221 | if (IS_ERR(filename)) | ||
222 | return error; | ||
223 | error = do_execve(filename->name, argv, envp, regs); | ||
224 | putname(filename); | ||
225 | return error; | ||
226 | } | ||
227 | |||
228 | unsigned long get_wchan(struct task_struct *p) | 187 | unsigned long get_wchan(struct task_struct *p) |
229 | { | 188 | { |
230 | unsigned long fp, pc; | 189 | unsigned long fp, pc; |
diff --git a/arch/blackfin/mach-common/entry.S b/arch/blackfin/mach-common/entry.S index 1c3d2c5bb0bb..4a38c68e2dde 100644 --- a/arch/blackfin/mach-common/entry.S +++ b/arch/blackfin/mach-common/entry.S | |||
@@ -530,61 +530,6 @@ ENTRY(_trap) /* Exception: 4th entry into system event table(supervisor mode)*/ | |||
530 | jump .Lsyscall_really_exit; | 530 | jump .Lsyscall_really_exit; |
531 | ENDPROC(_trap) | 531 | ENDPROC(_trap) |
532 | 532 | ||
533 | ENTRY(_kernel_execve) | ||
534 | link SIZEOF_PTREGS; | ||
535 | p0 = sp; | ||
536 | r3 = SIZEOF_PTREGS / 4; | ||
537 | r4 = 0(x); | ||
538 | .Lclear_regs: | ||
539 | [p0++] = r4; | ||
540 | r3 += -1; | ||
541 | cc = r3 == 0; | ||
542 | if !cc jump .Lclear_regs (bp); | ||
543 | |||
544 | p0 = sp; | ||
545 | sp += -16; | ||
546 | [sp + 12] = p0; | ||
547 | pseudo_long_call _do_execve, p5; | ||
548 | SP += 16; | ||
549 | cc = r0 == 0; | ||
550 | if ! cc jump .Lexecve_failed; | ||
551 | /* Success. Copy our temporary pt_regs to the top of the kernel | ||
552 | * stack and do a normal exception return. | ||
553 | */ | ||
554 | r1 = sp; | ||
555 | r0 = (-KERNEL_STACK_SIZE) (x); | ||
556 | r1 = r1 & r0; | ||
557 | p2 = r1; | ||
558 | p3 = [p2]; | ||
559 | r0 = KERNEL_STACK_SIZE - 4 (z); | ||
560 | p1 = r0; | ||
561 | p1 = p1 + p2; | ||
562 | |||
563 | p0 = fp; | ||
564 | r4 = [p0--]; | ||
565 | r3 = SIZEOF_PTREGS / 4; | ||
566 | .Lcopy_regs: | ||
567 | r4 = [p0--]; | ||
568 | [p1--] = r4; | ||
569 | r3 += -1; | ||
570 | cc = r3 == 0; | ||
571 | if ! cc jump .Lcopy_regs (bp); | ||
572 | |||
573 | r0 = (KERNEL_STACK_SIZE - SIZEOF_PTREGS) (z); | ||
574 | p1 = r0; | ||
575 | p1 = p1 + p2; | ||
576 | sp = p1; | ||
577 | r0 = syscfg; | ||
578 | [SP + PT_SYSCFG] = r0; | ||
579 | [p3 + (TASK_THREAD + THREAD_KSP)] = sp; | ||
580 | |||
581 | RESTORE_CONTEXT; | ||
582 | rti; | ||
583 | .Lexecve_failed: | ||
584 | unlink; | ||
585 | rts; | ||
586 | ENDPROC(_kernel_execve) | ||
587 | |||
588 | ENTRY(_system_call) | 533 | ENTRY(_system_call) |
589 | /* Store IPEND */ | 534 | /* Store IPEND */ |
590 | p2.l = lo(IPEND); | 535 | p2.l = lo(IPEND); |
diff --git a/arch/c6x/Kconfig b/arch/c6x/Kconfig index aee1b569ee6e..66eab3703c75 100644 --- a/arch/c6x/Kconfig +++ b/arch/c6x/Kconfig | |||
@@ -18,6 +18,7 @@ config C6X | |||
18 | select OF_EARLY_FLATTREE | 18 | select OF_EARLY_FLATTREE |
19 | select GENERIC_CLOCKEVENTS | 19 | select GENERIC_CLOCKEVENTS |
20 | select GENERIC_KERNEL_THREAD | 20 | select GENERIC_KERNEL_THREAD |
21 | select GENERIC_KERNEL_EXECVE | ||
21 | select MODULES_USE_ELF_RELA | 22 | select MODULES_USE_ELF_RELA |
22 | 23 | ||
23 | config MMU | 24 | config MMU |
diff --git a/arch/c6x/include/uapi/asm/unistd.h b/arch/c6x/include/uapi/asm/unistd.h index 4ff747d12dad..625beafb9cd1 100644 --- a/arch/c6x/include/uapi/asm/unistd.h +++ b/arch/c6x/include/uapi/asm/unistd.h | |||
@@ -14,7 +14,6 @@ | |||
14 | * more details. | 14 | * more details. |
15 | */ | 15 | */ |
16 | 16 | ||
17 | #define __ARCH_WANT_KERNEL_EXECVE | ||
18 | #define __ARCH_WANT_SYS_EXECVE | 17 | #define __ARCH_WANT_SYS_EXECVE |
19 | 18 | ||
20 | /* Use the standard ABI for syscalls. */ | 19 | /* Use the standard ABI for syscalls. */ |
diff --git a/arch/c6x/kernel/entry.S b/arch/c6x/kernel/entry.S index 5449c36018fe..75f6f36472cf 100644 --- a/arch/c6x/kernel/entry.S +++ b/arch/c6x/kernel/entry.S | |||
@@ -413,19 +413,9 @@ ENTRY(ret_from_kernel_thread) | |||
413 | 0: | 413 | 0: |
414 | B .S2 B10 /* call fn */ | 414 | B .S2 B10 /* call fn */ |
415 | LDW .D2T1 *+SP(REGS_A1+8),A4 /* get arg */ | 415 | LDW .D2T1 *+SP(REGS_A1+8),A4 /* get arg */ |
416 | MVKL .S2 sys_exit,B11 | 416 | ADDKPC .S2 ret_from_fork_2,B3,3 |
417 | MVKH .S2 sys_exit,B11 | ||
418 | ADDKPC .S2 0f,B3,1 | ||
419 | 0: | ||
420 | BNOP .S2 B11,5 /* jump to sys_exit */ | ||
421 | ENDPROC(ret_from_kernel_thread) | 417 | ENDPROC(ret_from_kernel_thread) |
422 | 418 | ||
423 | ENTRY(ret_from_kernel_execve) | ||
424 | GET_THREAD_INFO A12 | ||
425 | BNOP .S2 syscall_exit,4 | ||
426 | ADD .D2X A4,-8,SP | ||
427 | ENDPROC(ret_from_kernel_execve) | ||
428 | |||
429 | ;; | 419 | ;; |
430 | ;; These are the interrupt handlers, responsible for calling __do_IRQ() | 420 | ;; These are the interrupt handlers, responsible for calling __do_IRQ() |
431 | ;; int6 is used for syscalls (see _system_call entry) | 421 | ;; int6 is used for syscalls (see _system_call entry) |
diff --git a/arch/cris/Kconfig b/arch/cris/Kconfig index a67244473a39..81b59d18867e 100644 --- a/arch/cris/Kconfig +++ b/arch/cris/Kconfig | |||
@@ -49,6 +49,8 @@ config CRIS | |||
49 | select GENERIC_SMP_IDLE_THREAD if ETRAX_ARCH_V32 | 49 | select GENERIC_SMP_IDLE_THREAD if ETRAX_ARCH_V32 |
50 | select GENERIC_CMOS_UPDATE | 50 | select GENERIC_CMOS_UPDATE |
51 | select MODULES_USE_ELF_RELA | 51 | select MODULES_USE_ELF_RELA |
52 | select GENERIC_KERNEL_THREAD | ||
53 | select GENERIC_KERNEL_EXECVE | ||
52 | 54 | ||
53 | config HZ | 55 | config HZ |
54 | int | 56 | int |
diff --git a/arch/cris/arch-v10/kernel/entry.S b/arch/cris/arch-v10/kernel/entry.S index 592fbe9dfb62..897bba67bf7a 100644 --- a/arch/cris/arch-v10/kernel/entry.S +++ b/arch/cris/arch-v10/kernel/entry.S | |||
@@ -35,6 +35,7 @@ | |||
35 | .globl system_call | 35 | .globl system_call |
36 | .globl ret_from_intr | 36 | .globl ret_from_intr |
37 | .globl ret_from_fork | 37 | .globl ret_from_fork |
38 | .globl ret_from_kernel_thread | ||
38 | .globl resume | 39 | .globl resume |
39 | .globl multiple_interrupt | 40 | .globl multiple_interrupt |
40 | .globl hwbreakpoint | 41 | .globl hwbreakpoint |
@@ -81,7 +82,14 @@ ret_from_fork: | |||
81 | jsr schedule_tail | 82 | jsr schedule_tail |
82 | ba ret_from_sys_call | 83 | ba ret_from_sys_call |
83 | nop | 84 | nop |
84 | 85 | ||
86 | ret_from_kernel_thread: | ||
87 | jsr schedule_tail | ||
88 | move.d $r2, $r10 ; argument is here | ||
89 | jsr $r1 ; call the payload | ||
90 | moveq 0, $r9 ; no syscall restarts, TYVM... | ||
91 | ba ret_from_sys_call | ||
92 | |||
85 | ret_from_intr: | 93 | ret_from_intr: |
86 | ;; check for resched if preemptive kernel or if we're going back to user-mode | 94 | ;; check for resched if preemptive kernel or if we're going back to user-mode |
87 | ;; this test matches the user_regs(regs) macro | 95 | ;; this test matches the user_regs(regs) macro |
@@ -586,13 +594,6 @@ _ugdb_handle_breakpoint: | |||
586 | ba do_sigtrap ; SIGTRAP the offending process. | 594 | ba do_sigtrap ; SIGTRAP the offending process. |
587 | pop $dccr ; Restore dccr in delay slot. | 595 | pop $dccr ; Restore dccr in delay slot. |
588 | 596 | ||
589 | .global kernel_execve | ||
590 | kernel_execve: | ||
591 | move.d __NR_execve, $r9 | ||
592 | break 13 | ||
593 | ret | ||
594 | nop | ||
595 | |||
596 | .data | 597 | .data |
597 | 598 | ||
598 | hw_bp_trigs: | 599 | hw_bp_trigs: |
diff --git a/arch/cris/arch-v10/kernel/process.c b/arch/cris/arch-v10/kernel/process.c index 15ac7150371f..1d6458287f38 100644 --- a/arch/cris/arch-v10/kernel/process.c +++ b/arch/cris/arch-v10/kernel/process.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include <arch/svinto.h> | 17 | #include <arch/svinto.h> |
18 | #include <linux/init.h> | 18 | #include <linux/init.h> |
19 | #include <arch/system.h> | 19 | #include <arch/system.h> |
20 | #include <asm/ptrace.h> | ||
20 | 21 | ||
21 | #ifdef CONFIG_ETRAX_GPIO | 22 | #ifdef CONFIG_ETRAX_GPIO |
22 | void etrax_gpio_wake_up_check(void); /* drivers/gpio.c */ | 23 | void etrax_gpio_wake_up_check(void); /* drivers/gpio.c */ |
@@ -81,31 +82,6 @@ unsigned long thread_saved_pc(struct task_struct *t) | |||
81 | return task_pt_regs(t)->irp; | 82 | return task_pt_regs(t)->irp; |
82 | } | 83 | } |
83 | 84 | ||
84 | static void kernel_thread_helper(void* dummy, int (*fn)(void *), void * arg) | ||
85 | { | ||
86 | fn(arg); | ||
87 | do_exit(-1); /* Should never be called, return bad exit value */ | ||
88 | } | ||
89 | |||
90 | /* | ||
91 | * Create a kernel thread | ||
92 | */ | ||
93 | int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) | ||
94 | { | ||
95 | struct pt_regs regs; | ||
96 | |||
97 | memset(®s, 0, sizeof(regs)); | ||
98 | |||
99 | /* Don't use r10 since that is set to 0 in copy_thread */ | ||
100 | regs.r11 = (unsigned long)fn; | ||
101 | regs.r12 = (unsigned long)arg; | ||
102 | regs.irp = (unsigned long)kernel_thread_helper; | ||
103 | regs.dccr = 1 << I_DCCR_BITNR; | ||
104 | |||
105 | /* Ok, create the new process.. */ | ||
106 | return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, ®s, 0, NULL, NULL); | ||
107 | } | ||
108 | |||
109 | /* setup the child's kernel stack with a pt_regs and switch_stack on it. | 85 | /* setup the child's kernel stack with a pt_regs and switch_stack on it. |
110 | * it will be un-nested during _resume and _ret_from_sys_call when the | 86 | * it will be un-nested during _resume and _ret_from_sys_call when the |
111 | * new thread is scheduled. | 87 | * new thread is scheduled. |
@@ -115,29 +91,35 @@ int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) | |||
115 | * | 91 | * |
116 | */ | 92 | */ |
117 | asmlinkage void ret_from_fork(void); | 93 | asmlinkage void ret_from_fork(void); |
94 | asmlinkage void ret_from_kernel_thread(void); | ||
118 | 95 | ||
119 | int copy_thread(unsigned long clone_flags, unsigned long usp, | 96 | int copy_thread(unsigned long clone_flags, unsigned long usp, |
120 | unsigned long unused, | 97 | unsigned long arg, |
121 | struct task_struct *p, struct pt_regs *regs) | 98 | struct task_struct *p, struct pt_regs *regs) |
122 | { | 99 | { |
123 | struct pt_regs * childregs; | 100 | struct pt_regs *childregs = task_pt_regs(p); |
124 | struct switch_stack *swstack; | 101 | struct switch_stack *swstack = ((struct switch_stack *)childregs) - 1; |
125 | 102 | ||
126 | /* put the pt_regs structure at the end of the new kernel stack page and fix it up | 103 | /* put the pt_regs structure at the end of the new kernel stack page and fix it up |
127 | * remember that the task_struct doubles as the kernel stack for the task | 104 | * remember that the task_struct doubles as the kernel stack for the task |
128 | */ | 105 | */ |
129 | 106 | ||
130 | childregs = task_pt_regs(p); | 107 | if (unlikely(p->flags & PF_KTHREAD)) { |
131 | 108 | memset(swstack, 0, | |
109 | sizeof(struct switch_stack) + sizeof(struct pt_regs)); | ||
110 | swstack->r1 = usp; | ||
111 | swstack->r2 = arg; | ||
112 | childregs->dccr = 1 << I_DCCR_BITNR; | ||
113 | swstack->return_ip = (unsigned long) ret_from_kernel_thread; | ||
114 | p->thread.ksp = (unsigned long) swstack; | ||
115 | p->thread.usp = 0; | ||
116 | return 0; | ||
117 | } | ||
132 | *childregs = *regs; /* struct copy of pt_regs */ | 118 | *childregs = *regs; /* struct copy of pt_regs */ |
133 | |||
134 | p->set_child_tid = p->clear_child_tid = NULL; | ||
135 | 119 | ||
136 | childregs->r10 = 0; /* child returns 0 after a fork/clone */ | 120 | childregs->r10 = 0; /* child returns 0 after a fork/clone */ |
137 | |||
138 | /* put the switch stack right below the pt_regs */ | ||
139 | 121 | ||
140 | swstack = ((struct switch_stack *)childregs) - 1; | 122 | /* put the switch stack right below the pt_regs */ |
141 | 123 | ||
142 | swstack->r9 = 0; /* parameter to ret_from_sys_call, 0 == dont restart the syscall */ | 124 | swstack->r9 = 0; /* parameter to ret_from_sys_call, 0 == dont restart the syscall */ |
143 | 125 | ||
@@ -147,7 +129,7 @@ int copy_thread(unsigned long clone_flags, unsigned long usp, | |||
147 | 129 | ||
148 | /* fix the user-mode stackpointer */ | 130 | /* fix the user-mode stackpointer */ |
149 | 131 | ||
150 | p->thread.usp = usp; | 132 | p->thread.usp = usp; |
151 | 133 | ||
152 | /* and the kernel-mode one */ | 134 | /* and the kernel-mode one */ |
153 | 135 | ||
@@ -161,68 +143,28 @@ int copy_thread(unsigned long clone_flags, unsigned long usp, | |||
161 | return 0; | 143 | return 0; |
162 | } | 144 | } |
163 | 145 | ||
164 | /* | 146 | asmlinkage int sys_fork(void) |
165 | * Be aware of the "magic" 7th argument in the four system-calls below. | ||
166 | * They need the latest stackframe, which is put as the 7th argument by | ||
167 | * entry.S. The previous arguments are dummies or actually used, but need | ||
168 | * to be defined to reach the 7th argument. | ||
169 | * | ||
170 | * N.B.: Another method to get the stackframe is to use current_regs(). But | ||
171 | * it returns the latest stack-frame stacked when going from _user mode_ and | ||
172 | * some of these (at least sys_clone) are called from kernel-mode sometimes | ||
173 | * (for example during kernel_thread, above) and thus cannot use it. Thus, | ||
174 | * to be sure not to get any surprises, we use the method for the other calls | ||
175 | * as well. | ||
176 | */ | ||
177 | |||
178 | asmlinkage int sys_fork(long r10, long r11, long r12, long r13, long mof, long srp, | ||
179 | struct pt_regs *regs) | ||
180 | { | 147 | { |
181 | return do_fork(SIGCHLD, rdusp(), regs, 0, NULL, NULL); | 148 | return do_fork(SIGCHLD, rdusp(), current_pt_regs(), 0, NULL, NULL); |
182 | } | 149 | } |
183 | 150 | ||
184 | /* if newusp is 0, we just grab the old usp */ | 151 | /* if newusp is 0, we just grab the old usp */ |
185 | /* FIXME: Is parent_tid/child_tid really third/fourth argument? Update lib? */ | 152 | /* FIXME: Is parent_tid/child_tid really third/fourth argument? Update lib? */ |
186 | asmlinkage int sys_clone(unsigned long newusp, unsigned long flags, | 153 | asmlinkage int sys_clone(unsigned long newusp, unsigned long flags, |
187 | int* parent_tid, int* child_tid, long mof, long srp, | 154 | int* parent_tid, int* child_tid) |
188 | struct pt_regs *regs) | ||
189 | { | 155 | { |
190 | if (!newusp) | 156 | if (!newusp) |
191 | newusp = rdusp(); | 157 | newusp = rdusp(); |
192 | return do_fork(flags, newusp, regs, 0, parent_tid, child_tid); | 158 | return do_fork(flags, newusp, current_pt_regs(), 0, parent_tid, child_tid); |
193 | } | 159 | } |
194 | 160 | ||
195 | /* vfork is a system call in i386 because of register-pressure - maybe | 161 | /* vfork is a system call in i386 because of register-pressure - maybe |
196 | * we can remove it and handle it in libc but we put it here until then. | 162 | * we can remove it and handle it in libc but we put it here until then. |
197 | */ | 163 | */ |
198 | 164 | ||
199 | asmlinkage int sys_vfork(long r10, long r11, long r12, long r13, long mof, long srp, | 165 | asmlinkage int sys_vfork(void) |
200 | struct pt_regs *regs) | ||
201 | { | ||
202 | return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), regs, 0, NULL, NULL); | ||
203 | } | ||
204 | |||
205 | /* | ||
206 | * sys_execve() executes a new program. | ||
207 | */ | ||
208 | asmlinkage int sys_execve(const char *fname, | ||
209 | const char *const *argv, | ||
210 | const char *const *envp, | ||
211 | long r13, long mof, long srp, | ||
212 | struct pt_regs *regs) | ||
213 | { | 166 | { |
214 | int error; | 167 | return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), current_pt_regs(), 0, NULL, NULL); |
215 | struct filename *filename; | ||
216 | |||
217 | filename = getname(fname); | ||
218 | error = PTR_ERR(filename); | ||
219 | |||
220 | if (IS_ERR(filename)) | ||
221 | goto out; | ||
222 | error = do_execve(filename->name, argv, envp, regs); | ||
223 | putname(filename); | ||
224 | out: | ||
225 | return error; | ||
226 | } | 168 | } |
227 | 169 | ||
228 | unsigned long get_wchan(struct task_struct *p) | 170 | unsigned long get_wchan(struct task_struct *p) |
diff --git a/arch/cris/arch-v32/kernel/entry.S b/arch/cris/arch-v32/kernel/entry.S index c3ea4694fbaf..faa644111feb 100644 --- a/arch/cris/arch-v32/kernel/entry.S +++ b/arch/cris/arch-v32/kernel/entry.S | |||
@@ -31,6 +31,7 @@ | |||
31 | .globl system_call | 31 | .globl system_call |
32 | .globl ret_from_intr | 32 | .globl ret_from_intr |
33 | .globl ret_from_fork | 33 | .globl ret_from_fork |
34 | .globl ret_from_kernel_thread | ||
34 | .globl resume | 35 | .globl resume |
35 | .globl multiple_interrupt | 36 | .globl multiple_interrupt |
36 | .globl nmi_interrupt | 37 | .globl nmi_interrupt |
@@ -84,6 +85,18 @@ ret_from_fork: | |||
84 | nop | 85 | nop |
85 | .size ret_from_fork, . - ret_from_fork | 86 | .size ret_from_fork, . - ret_from_fork |
86 | 87 | ||
88 | .type ret_from_kernel_thread,@function | ||
89 | ret_from_kernel_thread: | ||
90 | jsr schedule_tail | ||
91 | nop | ||
92 | move.d $r2, $r10 | ||
93 | jsr $r1 | ||
94 | nop | ||
95 | moveq 0, $r9 ; no syscall restarts, TYVM... | ||
96 | ba ret_from_sys_call | ||
97 | nop | ||
98 | .size ret_from_kernel_thread, . - ret_from_kernel_thread | ||
99 | |||
87 | .type ret_from_intr,@function | 100 | .type ret_from_intr,@function |
88 | ret_from_intr: | 101 | ret_from_intr: |
89 | ;; Check for resched if preemptive kernel, or if we're going back to | 102 | ;; Check for resched if preemptive kernel, or if we're going back to |
@@ -531,15 +544,6 @@ _ugdb_handle_exception: | |||
531 | ba do_sigtrap ; SIGTRAP the offending process. | 544 | ba do_sigtrap ; SIGTRAP the offending process. |
532 | move.d [$sp+], $r0 ; Restore R0 in delay slot. | 545 | move.d [$sp+], $r0 ; Restore R0 in delay slot. |
533 | 546 | ||
534 | .global kernel_execve | ||
535 | .type kernel_execve,@function | ||
536 | kernel_execve: | ||
537 | move.d __NR_execve, $r9 | ||
538 | break 13 | ||
539 | ret | ||
540 | nop | ||
541 | .size kernel_execve, . - kernel_execve | ||
542 | |||
543 | .data | 547 | .data |
544 | 548 | ||
545 | .section .rodata,"a" | 549 | .section .rodata,"a" |
diff --git a/arch/cris/arch-v32/kernel/process.c b/arch/cris/arch-v32/kernel/process.c index 4e9992246359..fe465401b6ec 100644 --- a/arch/cris/arch-v32/kernel/process.c +++ b/arch/cris/arch-v32/kernel/process.c | |||
@@ -16,6 +16,7 @@ | |||
16 | #include <hwregs/reg_map.h> | 16 | #include <hwregs/reg_map.h> |
17 | #include <hwregs/timer_defs.h> | 17 | #include <hwregs/timer_defs.h> |
18 | #include <hwregs/intr_vect_defs.h> | 18 | #include <hwregs/intr_vect_defs.h> |
19 | #include <asm/ptrace.h> | ||
19 | 20 | ||
20 | extern void stop_watchdog(void); | 21 | extern void stop_watchdog(void); |
21 | 22 | ||
@@ -94,31 +95,6 @@ unsigned long thread_saved_pc(struct task_struct *t) | |||
94 | return task_pt_regs(t)->erp; | 95 | return task_pt_regs(t)->erp; |
95 | } | 96 | } |
96 | 97 | ||
97 | static void | ||
98 | kernel_thread_helper(void* dummy, int (*fn)(void *), void * arg) | ||
99 | { | ||
100 | fn(arg); | ||
101 | do_exit(-1); /* Should never be called, return bad exit value. */ | ||
102 | } | ||
103 | |||
104 | /* Create a kernel thread. */ | ||
105 | int | ||
106 | kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) | ||
107 | { | ||
108 | struct pt_regs regs; | ||
109 | |||
110 | memset(®s, 0, sizeof(regs)); | ||
111 | |||
112 | /* Don't use r10 since that is set to 0 in copy_thread. */ | ||
113 | regs.r11 = (unsigned long) fn; | ||
114 | regs.r12 = (unsigned long) arg; | ||
115 | regs.erp = (unsigned long) kernel_thread_helper; | ||
116 | regs.ccs = 1 << (I_CCS_BITNR + CCS_SHIFT); | ||
117 | |||
118 | /* Create the new process. */ | ||
119 | return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, ®s, 0, NULL, NULL); | ||
120 | } | ||
121 | |||
122 | /* | 98 | /* |
123 | * Setup the child's kernel stack with a pt_regs and call switch_stack() on it. | 99 | * Setup the child's kernel stack with a pt_regs and call switch_stack() on it. |
124 | * It will be unnested during _resume and _ret_from_sys_call when the new thread | 100 | * It will be unnested during _resume and _ret_from_sys_call when the new thread |
@@ -129,23 +105,33 @@ kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) | |||
129 | */ | 105 | */ |
130 | 106 | ||
131 | extern asmlinkage void ret_from_fork(void); | 107 | extern asmlinkage void ret_from_fork(void); |
108 | extern asmlinkage void ret_from_kernel_thread(void); | ||
132 | 109 | ||
133 | int | 110 | int |
134 | copy_thread(unsigned long clone_flags, unsigned long usp, | 111 | copy_thread(unsigned long clone_flags, unsigned long usp, |
135 | unsigned long unused, | 112 | unsigned long arg, |
136 | struct task_struct *p, struct pt_regs *regs) | 113 | struct task_struct *p, struct pt_regs *regs) |
137 | { | 114 | { |
138 | struct pt_regs *childregs; | 115 | struct pt_regs *childregs = task_pt_regs(p); |
139 | struct switch_stack *swstack; | 116 | struct switch_stack *swstack = ((struct switch_stack *) childregs) - 1; |
140 | 117 | ||
141 | /* | 118 | /* |
142 | * Put the pt_regs structure at the end of the new kernel stack page and | 119 | * Put the pt_regs structure at the end of the new kernel stack page and |
143 | * fix it up. Note: the task_struct doubles as the kernel stack for the | 120 | * fix it up. Note: the task_struct doubles as the kernel stack for the |
144 | * task. | 121 | * task. |
145 | */ | 122 | */ |
146 | childregs = task_pt_regs(p); | 123 | if (unlikely(p->flags & PF_KTHREAD)) { |
124 | memset(swstack, 0, | ||
125 | sizeof(struct switch_stack) + sizeof(struct pt_regs)); | ||
126 | swstack->r1 = usp; | ||
127 | swstack->r2 = arg; | ||
128 | childregs->ccs = 1 << (I_CCS_BITNR + CCS_SHIFT); | ||
129 | swstack->return_ip = (unsigned long) ret_from_kernel_thread; | ||
130 | p->thread.ksp = (unsigned long) swstack; | ||
131 | p->thread.usp = 0; | ||
132 | return 0; | ||
133 | } | ||
147 | *childregs = *regs; /* Struct copy of pt_regs. */ | 134 | *childregs = *regs; /* Struct copy of pt_regs. */ |
148 | p->set_child_tid = p->clear_child_tid = NULL; | ||
149 | childregs->r10 = 0; /* Child returns 0 after a fork/clone. */ | 135 | childregs->r10 = 0; /* Child returns 0 after a fork/clone. */ |
150 | 136 | ||
151 | /* Set a new TLS ? | 137 | /* Set a new TLS ? |
@@ -156,7 +142,6 @@ copy_thread(unsigned long clone_flags, unsigned long usp, | |||
156 | } | 142 | } |
157 | 143 | ||
158 | /* Put the switch stack right below the pt_regs. */ | 144 | /* Put the switch stack right below the pt_regs. */ |
159 | swstack = ((struct switch_stack *) childregs) - 1; | ||
160 | 145 | ||
161 | /* Parameter to ret_from_sys_call. 0 is don't restart the syscall. */ | 146 | /* Parameter to ret_from_sys_call. 0 is don't restart the syscall. */ |
162 | swstack->r9 = 0; | 147 | swstack->r9 = 0; |
@@ -174,35 +159,21 @@ copy_thread(unsigned long clone_flags, unsigned long usp, | |||
174 | return 0; | 159 | return 0; |
175 | } | 160 | } |
176 | 161 | ||
177 | /* | ||
178 | * Be aware of the "magic" 7th argument in the four system-calls below. | ||
179 | * They need the latest stackframe, which is put as the 7th argument by | ||
180 | * entry.S. The previous arguments are dummies or actually used, but need | ||
181 | * to be defined to reach the 7th argument. | ||
182 | * | ||
183 | * N.B.: Another method to get the stackframe is to use current_regs(). But | ||
184 | * it returns the latest stack-frame stacked when going from _user mode_ and | ||
185 | * some of these (at least sys_clone) are called from kernel-mode sometimes | ||
186 | * (for example during kernel_thread, above) and thus cannot use it. Thus, | ||
187 | * to be sure not to get any surprises, we use the method for the other calls | ||
188 | * as well. | ||
189 | */ | ||
190 | asmlinkage int | 162 | asmlinkage int |
191 | sys_fork(long r10, long r11, long r12, long r13, long mof, long srp, | 163 | sys_fork(void) |
192 | struct pt_regs *regs) | ||
193 | { | 164 | { |
194 | return do_fork(SIGCHLD, rdusp(), regs, 0, NULL, NULL); | 165 | return do_fork(SIGCHLD, rdusp(), current_pt_regs(), 0, NULL, NULL); |
195 | } | 166 | } |
196 | 167 | ||
197 | /* FIXME: Is parent_tid/child_tid really third/fourth argument? Update lib? */ | 168 | /* FIXME: Is parent_tid/child_tid really third/fourth argument? Update lib? */ |
198 | asmlinkage int | 169 | asmlinkage int |
199 | sys_clone(unsigned long newusp, unsigned long flags, int *parent_tid, int *child_tid, | 170 | sys_clone(unsigned long newusp, unsigned long flags, int *parent_tid, int *child_tid, |
200 | unsigned long tls, long srp, struct pt_regs *regs) | 171 | unsigned long tls) |
201 | { | 172 | { |
202 | if (!newusp) | 173 | if (!newusp) |
203 | newusp = rdusp(); | 174 | newusp = rdusp(); |
204 | 175 | ||
205 | return do_fork(flags, newusp, regs, 0, parent_tid, child_tid); | 176 | return do_fork(flags, newusp, current_pt_regs(), 0, parent_tid, child_tid); |
206 | } | 177 | } |
207 | 178 | ||
208 | /* | 179 | /* |
@@ -210,32 +181,9 @@ sys_clone(unsigned long newusp, unsigned long flags, int *parent_tid, int *child | |||
210 | * we can remove it and handle it in libc but we put it here until then. | 181 | * we can remove it and handle it in libc but we put it here until then. |
211 | */ | 182 | */ |
212 | asmlinkage int | 183 | asmlinkage int |
213 | sys_vfork(long r10, long r11, long r12, long r13, long mof, long srp, | 184 | sys_vfork(void) |
214 | struct pt_regs *regs) | ||
215 | { | ||
216 | return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), regs, 0, NULL, NULL); | ||
217 | } | ||
218 | |||
219 | /* sys_execve() executes a new program. */ | ||
220 | asmlinkage int | ||
221 | sys_execve(const char *fname, | ||
222 | const char *const *argv, | ||
223 | const char *const *envp, long r13, long mof, long srp, | ||
224 | struct pt_regs *regs) | ||
225 | { | 185 | { |
226 | int error; | 186 | return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), current_pt_regs(), 0, NULL, NULL); |
227 | struct filename *filename; | ||
228 | |||
229 | filename = getname(fname); | ||
230 | error = PTR_ERR(filename); | ||
231 | |||
232 | if (IS_ERR(filename)) | ||
233 | goto out; | ||
234 | |||
235 | error = do_execve(filename->name, argv, envp, regs); | ||
236 | putname(filename); | ||
237 | out: | ||
238 | return error; | ||
239 | } | 187 | } |
240 | 188 | ||
241 | unsigned long | 189 | unsigned long |
diff --git a/arch/cris/include/asm/processor.h b/arch/cris/include/asm/processor.h index ef4e1bc3efc8..675823f70c0f 100644 --- a/arch/cris/include/asm/processor.h +++ b/arch/cris/include/asm/processor.h | |||
@@ -49,8 +49,6 @@ struct task_struct; | |||
49 | #define task_pt_regs(task) user_regs(task_thread_info(task)) | 49 | #define task_pt_regs(task) user_regs(task_thread_info(task)) |
50 | #define current_regs() task_pt_regs(current) | 50 | #define current_regs() task_pt_regs(current) |
51 | 51 | ||
52 | extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags); | ||
53 | |||
54 | unsigned long get_wchan(struct task_struct *p); | 52 | unsigned long get_wchan(struct task_struct *p); |
55 | 53 | ||
56 | #define KSTK_ESP(tsk) ((tsk) == current ? rdusp() : (tsk)->thread.usp) | 54 | #define KSTK_ESP(tsk) ((tsk) == current ? rdusp() : (tsk)->thread.usp) |
diff --git a/arch/cris/include/asm/unistd.h b/arch/cris/include/asm/unistd.h index 51873a446f87..f181d1fc7632 100644 --- a/arch/cris/include/asm/unistd.h +++ b/arch/cris/include/asm/unistd.h | |||
@@ -371,6 +371,7 @@ | |||
371 | #define __ARCH_WANT_SYS_SIGPROCMASK | 371 | #define __ARCH_WANT_SYS_SIGPROCMASK |
372 | #define __ARCH_WANT_SYS_RT_SIGACTION | 372 | #define __ARCH_WANT_SYS_RT_SIGACTION |
373 | #define __ARCH_WANT_SYS_RT_SIGSUSPEND | 373 | #define __ARCH_WANT_SYS_RT_SIGSUSPEND |
374 | #define __ARCH_WANT_SYS_EXECVE | ||
374 | 375 | ||
375 | /* | 376 | /* |
376 | * "Conditional" syscalls | 377 | * "Conditional" syscalls |
diff --git a/arch/cris/kernel/crisksyms.c b/arch/cris/kernel/crisksyms.c index 7ac000f6a888..5868cee20ebd 100644 --- a/arch/cris/kernel/crisksyms.c +++ b/arch/cris/kernel/crisksyms.c | |||
@@ -30,7 +30,6 @@ extern void __negdi2(void); | |||
30 | extern void iounmap(volatile void * __iomem); | 30 | extern void iounmap(volatile void * __iomem); |
31 | 31 | ||
32 | /* Platform dependent support */ | 32 | /* Platform dependent support */ |
33 | EXPORT_SYMBOL(kernel_thread); | ||
34 | EXPORT_SYMBOL(get_cmos_time); | 33 | EXPORT_SYMBOL(get_cmos_time); |
35 | EXPORT_SYMBOL(loops_per_usec); | 34 | EXPORT_SYMBOL(loops_per_usec); |
36 | 35 | ||
diff --git a/arch/h8300/Kconfig b/arch/h8300/Kconfig index 98fabd10e95f..04bef4d25b4a 100644 --- a/arch/h8300/Kconfig +++ b/arch/h8300/Kconfig | |||
@@ -8,6 +8,8 @@ config H8300 | |||
8 | select GENERIC_IRQ_SHOW | 8 | select GENERIC_IRQ_SHOW |
9 | select GENERIC_CPU_DEVICES | 9 | select GENERIC_CPU_DEVICES |
10 | select MODULES_USE_ELF_RELA | 10 | select MODULES_USE_ELF_RELA |
11 | select GENERIC_KERNEL_THREAD | ||
12 | select GENERIC_KERNEL_EXECVE | ||
11 | 13 | ||
12 | config SYMBOL_PREFIX | 14 | config SYMBOL_PREFIX |
13 | string | 15 | string |
diff --git a/arch/h8300/include/asm/processor.h b/arch/h8300/include/asm/processor.h index 4c9f6f87b617..4b0ca49bb463 100644 --- a/arch/h8300/include/asm/processor.h +++ b/arch/h8300/include/asm/processor.h | |||
@@ -107,8 +107,6 @@ static inline void release_thread(struct task_struct *dead_task) | |||
107 | { | 107 | { |
108 | } | 108 | } |
109 | 109 | ||
110 | extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags); | ||
111 | |||
112 | /* | 110 | /* |
113 | * Free current thread data structures etc.. | 111 | * Free current thread data structures etc.. |
114 | */ | 112 | */ |
diff --git a/arch/h8300/include/asm/ptrace.h b/arch/h8300/include/asm/ptrace.h index d09c440bdba7..00502a61bf0a 100644 --- a/arch/h8300/include/asm/ptrace.h +++ b/arch/h8300/include/asm/ptrace.h | |||
@@ -60,6 +60,8 @@ struct pt_regs { | |||
60 | #define user_mode(regs) (!((regs)->ccr & PS_S)) | 60 | #define user_mode(regs) (!((regs)->ccr & PS_S)) |
61 | #define instruction_pointer(regs) ((regs)->pc) | 61 | #define instruction_pointer(regs) ((regs)->pc) |
62 | #define profile_pc(regs) instruction_pointer(regs) | 62 | #define profile_pc(regs) instruction_pointer(regs) |
63 | #define current_pt_regs() ((struct pt_regs *) \ | ||
64 | (THREAD_SIZE + (unsigned long)current_thread_info()) - 1) | ||
63 | #endif /* __KERNEL__ */ | 65 | #endif /* __KERNEL__ */ |
64 | #endif /* __ASSEMBLY__ */ | 66 | #endif /* __ASSEMBLY__ */ |
65 | #endif /* _H8300_PTRACE_H */ | 67 | #endif /* _H8300_PTRACE_H */ |
diff --git a/arch/h8300/include/asm/unistd.h b/arch/h8300/include/asm/unistd.h index 5cd882801d79..07afcfaec995 100644 --- a/arch/h8300/include/asm/unistd.h +++ b/arch/h8300/include/asm/unistd.h | |||
@@ -356,6 +356,7 @@ | |||
356 | #define __ARCH_WANT_SYS_SIGPROCMASK | 356 | #define __ARCH_WANT_SYS_SIGPROCMASK |
357 | #define __ARCH_WANT_SYS_RT_SIGACTION | 357 | #define __ARCH_WANT_SYS_RT_SIGACTION |
358 | #define __ARCH_WANT_SYS_RT_SIGSUSPEND | 358 | #define __ARCH_WANT_SYS_RT_SIGSUSPEND |
359 | #define __ARCH_WANT_SYS_EXECVE | ||
359 | 360 | ||
360 | /* | 361 | /* |
361 | * "Conditional" syscalls | 362 | * "Conditional" syscalls |
diff --git a/arch/h8300/kernel/entry.S b/arch/h8300/kernel/entry.S index ca7431690300..617a6878787f 100644 --- a/arch/h8300/kernel/entry.S +++ b/arch/h8300/kernel/entry.S | |||
@@ -158,6 +158,7 @@ INTERRUPTS = 128 | |||
158 | .globl SYMBOL_NAME(system_call) | 158 | .globl SYMBOL_NAME(system_call) |
159 | .globl SYMBOL_NAME(ret_from_exception) | 159 | .globl SYMBOL_NAME(ret_from_exception) |
160 | .globl SYMBOL_NAME(ret_from_fork) | 160 | .globl SYMBOL_NAME(ret_from_fork) |
161 | .globl SYMBOL_NAME(ret_from_kernel_thread) | ||
161 | .globl SYMBOL_NAME(ret_from_interrupt) | 162 | .globl SYMBOL_NAME(ret_from_interrupt) |
162 | .globl SYMBOL_NAME(interrupt_redirect_table) | 163 | .globl SYMBOL_NAME(interrupt_redirect_table) |
163 | .globl SYMBOL_NAME(sw_ksp),SYMBOL_NAME(sw_usp) | 164 | .globl SYMBOL_NAME(sw_ksp),SYMBOL_NAME(sw_usp) |
@@ -330,6 +331,14 @@ SYMBOL_NAME_LABEL(ret_from_fork) | |||
330 | jsr @SYMBOL_NAME(schedule_tail) | 331 | jsr @SYMBOL_NAME(schedule_tail) |
331 | jmp @SYMBOL_NAME(ret_from_exception) | 332 | jmp @SYMBOL_NAME(ret_from_exception) |
332 | 333 | ||
334 | SYMBOL_NAME_LABEL(ret_from_kernel_thread) | ||
335 | mov.l er2,er0 | ||
336 | jsr @SYMBOL_NAME(schedule_tail) | ||
337 | mov.l @(LER4:16,sp),er0 | ||
338 | mov.l @(LER5:16,sp),er1 | ||
339 | jsr @er1 | ||
340 | jmp @SYMBOL_NAME(ret_from_exception) | ||
341 | |||
333 | SYMBOL_NAME_LABEL(resume) | 342 | SYMBOL_NAME_LABEL(resume) |
334 | /* | 343 | /* |
335 | * Beware - when entering resume, offset of tss is in d1, | 344 | * Beware - when entering resume, offset of tss is in d1, |
diff --git a/arch/h8300/kernel/h8300_ksyms.c b/arch/h8300/kernel/h8300_ksyms.c index 6866bd9c7fb4..53d7c0e4bd83 100644 --- a/arch/h8300/kernel/h8300_ksyms.c +++ b/arch/h8300/kernel/h8300_ksyms.c | |||
@@ -33,7 +33,6 @@ EXPORT_SYMBOL(strncmp); | |||
33 | 33 | ||
34 | EXPORT_SYMBOL(ip_fast_csum); | 34 | EXPORT_SYMBOL(ip_fast_csum); |
35 | 35 | ||
36 | EXPORT_SYMBOL(kernel_thread); | ||
37 | EXPORT_SYMBOL(enable_irq); | 36 | EXPORT_SYMBOL(enable_irq); |
38 | EXPORT_SYMBOL(disable_irq); | 37 | EXPORT_SYMBOL(disable_irq); |
39 | 38 | ||
diff --git a/arch/h8300/kernel/process.c b/arch/h8300/kernel/process.c index e8dc1393a13a..2a45718cc5e8 100644 --- a/arch/h8300/kernel/process.c +++ b/arch/h8300/kernel/process.c | |||
@@ -47,6 +47,7 @@ void (*pm_power_off)(void) = NULL; | |||
47 | EXPORT_SYMBOL(pm_power_off); | 47 | EXPORT_SYMBOL(pm_power_off); |
48 | 48 | ||
49 | asmlinkage void ret_from_fork(void); | 49 | asmlinkage void ret_from_fork(void); |
50 | asmlinkage void ret_from_kernel_thread(void); | ||
50 | 51 | ||
51 | /* | 52 | /* |
52 | * The idle loop on an H8/300.. | 53 | * The idle loop on an H8/300.. |
@@ -122,39 +123,6 @@ void show_regs(struct pt_regs * regs) | |||
122 | printk("\n"); | 123 | printk("\n"); |
123 | } | 124 | } |
124 | 125 | ||
125 | /* | ||
126 | * Create a kernel thread | ||
127 | */ | ||
128 | int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) | ||
129 | { | ||
130 | long retval; | ||
131 | long clone_arg; | ||
132 | mm_segment_t fs; | ||
133 | |||
134 | fs = get_fs(); | ||
135 | set_fs (KERNEL_DS); | ||
136 | clone_arg = flags | CLONE_VM; | ||
137 | __asm__("mov.l sp,er3\n\t" | ||
138 | "sub.l er2,er2\n\t" | ||
139 | "mov.l %2,er1\n\t" | ||
140 | "mov.l %1,er0\n\t" | ||
141 | "trapa #0\n\t" | ||
142 | "cmp.l sp,er3\n\t" | ||
143 | "beq 1f\n\t" | ||
144 | "mov.l %4,er0\n\t" | ||
145 | "mov.l %3,er1\n\t" | ||
146 | "jsr @er1\n\t" | ||
147 | "mov.l %5,er0\n\t" | ||
148 | "trapa #0\n" | ||
149 | "1:\n\t" | ||
150 | "mov.l er0,%0" | ||
151 | :"=r"(retval) | ||
152 | :"i"(__NR_clone),"g"(clone_arg),"g"(fn),"g"(arg),"i"(__NR_exit) | ||
153 | :"er0","er1","er2","er3"); | ||
154 | set_fs (fs); | ||
155 | return retval; | ||
156 | } | ||
157 | |||
158 | void flush_thread(void) | 126 | void flush_thread(void) |
159 | { | 127 | { |
160 | } | 128 | } |
@@ -198,6 +166,13 @@ int copy_thread(unsigned long clone_flags, | |||
198 | 166 | ||
199 | childregs = (struct pt_regs *) (THREAD_SIZE + task_stack_page(p)) - 1; | 167 | childregs = (struct pt_regs *) (THREAD_SIZE + task_stack_page(p)) - 1; |
200 | 168 | ||
169 | if (unlikely(p->flags & PF_KTHREAD)) { | ||
170 | memset(childregs, 0, sizeof(struct pt_regs)); | ||
171 | childregs->retpc = (unsigned long) ret_from_kernel_thread; | ||
172 | childregs->er4 = topstk; /* arg */ | ||
173 | childregs->er5 = usp; /* fn */ | ||
174 | p->thread.ksp = (unsigned long)childregs; | ||
175 | } | ||
201 | *childregs = *regs; | 176 | *childregs = *regs; |
202 | childregs->retpc = (unsigned long) ret_from_fork; | 177 | childregs->retpc = (unsigned long) ret_from_fork; |
203 | childregs->er0 = 0; | 178 | childregs->er0 = 0; |
@@ -208,27 +183,6 @@ int copy_thread(unsigned long clone_flags, | |||
208 | return 0; | 183 | return 0; |
209 | } | 184 | } |
210 | 185 | ||
211 | /* | ||
212 | * sys_execve() executes a new program. | ||
213 | */ | ||
214 | asmlinkage int sys_execve(const char *name, | ||
215 | const char *const *argv, | ||
216 | const char *const *envp, | ||
217 | int dummy, ...) | ||
218 | { | ||
219 | int error; | ||
220 | struct filename *filename; | ||
221 | struct pt_regs *regs = (struct pt_regs *) ((unsigned char *)&dummy-4); | ||
222 | |||
223 | filename = getname(name); | ||
224 | error = PTR_ERR(filename); | ||
225 | if (IS_ERR(filename)) | ||
226 | return error; | ||
227 | error = do_execve(filename->name, argv, envp, regs); | ||
228 | putname(filename); | ||
229 | return error; | ||
230 | } | ||
231 | |||
232 | unsigned long thread_saved_pc(struct task_struct *tsk) | 186 | unsigned long thread_saved_pc(struct task_struct *tsk) |
233 | { | 187 | { |
234 | return ((struct pt_regs *)tsk->thread.esp0)->pc; | 188 | return ((struct pt_regs *)tsk->thread.esp0)->pc; |
diff --git a/arch/h8300/kernel/sys_h8300.c b/arch/h8300/kernel/sys_h8300.c index 4bdc7311784e..bf350cb7f597 100644 --- a/arch/h8300/kernel/sys_h8300.c +++ b/arch/h8300/kernel/sys_h8300.c | |||
@@ -46,29 +46,3 @@ asmlinkage void syscall_print(void *dummy,...) | |||
46 | ((regs->pc)&0xffffff)-2,regs->orig_er0,regs->er1,regs->er2,regs->er3,regs->er0); | 46 | ((regs->pc)&0xffffff)-2,regs->orig_er0,regs->er1,regs->er2,regs->er3,regs->er0); |
47 | } | 47 | } |
48 | #endif | 48 | #endif |
49 | |||
50 | /* | ||
51 | * Do a system call from kernel instead of calling sys_execve so we | ||
52 | * end up with proper pt_regs. | ||
53 | */ | ||
54 | asmlinkage | ||
55 | int kernel_execve(const char *filename, | ||
56 | const char *const argv[], | ||
57 | const char *const envp[]) | ||
58 | { | ||
59 | register long res __asm__("er0"); | ||
60 | register const char *const *_c __asm__("er3") = envp; | ||
61 | register const char *const *_b __asm__("er2") = argv; | ||
62 | register const char * _a __asm__("er1") = filename; | ||
63 | __asm__ __volatile__ ("mov.l %1,er0\n\t" | ||
64 | "trapa #0\n\t" | ||
65 | : "=r" (res) | ||
66 | : "g" (__NR_execve), | ||
67 | "g" (_a), | ||
68 | "g" (_b), | ||
69 | "g" (_c) | ||
70 | : "cc", "memory"); | ||
71 | return res; | ||
72 | } | ||
73 | |||
74 | |||
diff --git a/arch/hexagon/Kconfig b/arch/hexagon/Kconfig index 0744f7d7b1fd..e418803b6c8e 100644 --- a/arch/hexagon/Kconfig +++ b/arch/hexagon/Kconfig | |||
@@ -31,6 +31,8 @@ config HEXAGON | |||
31 | select GENERIC_CLOCKEVENTS | 31 | select GENERIC_CLOCKEVENTS |
32 | select GENERIC_CLOCKEVENTS_BROADCAST | 32 | select GENERIC_CLOCKEVENTS_BROADCAST |
33 | select MODULES_USE_ELF_RELA | 33 | select MODULES_USE_ELF_RELA |
34 | select GENERIC_KERNEL_THREAD | ||
35 | select GENERIC_KERNEL_EXECVE | ||
34 | ---help--- | 36 | ---help--- |
35 | Qualcomm Hexagon is a processor architecture designed for high | 37 | Qualcomm Hexagon is a processor architecture designed for high |
36 | performance and low power across a wide variety of applications. | 38 | performance and low power across a wide variety of applications. |
diff --git a/arch/hexagon/include/asm/processor.h b/arch/hexagon/include/asm/processor.h index a03323ab9d44..6dd5d3706869 100644 --- a/arch/hexagon/include/asm/processor.h +++ b/arch/hexagon/include/asm/processor.h | |||
@@ -34,7 +34,6 @@ | |||
34 | struct task_struct; | 34 | struct task_struct; |
35 | 35 | ||
36 | /* this is defined in arch/process.c */ | 36 | /* this is defined in arch/process.c */ |
37 | extern pid_t kernel_thread(int (*fn)(void *), void * arg, unsigned long flags); | ||
38 | extern unsigned long thread_saved_pc(struct task_struct *tsk); | 37 | extern unsigned long thread_saved_pc(struct task_struct *tsk); |
39 | 38 | ||
40 | extern void start_thread(struct pt_regs *, unsigned long, unsigned long); | 39 | extern void start_thread(struct pt_regs *, unsigned long, unsigned long); |
diff --git a/arch/hexagon/include/uapi/asm/ptrace.h b/arch/hexagon/include/uapi/asm/ptrace.h index 8ef784047a74..1ffce0c6ee07 100644 --- a/arch/hexagon/include/uapi/asm/ptrace.h +++ b/arch/hexagon/include/uapi/asm/ptrace.h | |||
@@ -32,4 +32,8 @@ | |||
32 | extern int regs_query_register_offset(const char *name); | 32 | extern int regs_query_register_offset(const char *name); |
33 | extern const char *regs_query_register_name(unsigned int offset); | 33 | extern const char *regs_query_register_name(unsigned int offset); |
34 | 34 | ||
35 | #define current_pt_regs() \ | ||
36 | ((struct pt_regs *) \ | ||
37 | ((unsigned long)current_thread_info() + THREAD_SIZE) - 1) | ||
38 | |||
35 | #endif | 39 | #endif |
diff --git a/arch/hexagon/include/uapi/asm/unistd.h b/arch/hexagon/include/uapi/asm/unistd.h index 81312d6a52e6..26b2e0f909c8 100644 --- a/arch/hexagon/include/uapi/asm/unistd.h +++ b/arch/hexagon/include/uapi/asm/unistd.h | |||
@@ -27,5 +27,6 @@ | |||
27 | */ | 27 | */ |
28 | 28 | ||
29 | #define sys_mmap2 sys_mmap_pgoff | 29 | #define sys_mmap2 sys_mmap_pgoff |
30 | #define __ARCH_WANT_SYS_EXECVE | ||
30 | 31 | ||
31 | #include <asm-generic/unistd.h> | 32 | #include <asm-generic/unistd.h> |
diff --git a/arch/hexagon/kernel/process.c b/arch/hexagon/kernel/process.c index 9f6d7411b574..cfbc52bd5227 100644 --- a/arch/hexagon/kernel/process.c +++ b/arch/hexagon/kernel/process.c | |||
@@ -26,33 +26,6 @@ | |||
26 | #include <linux/slab.h> | 26 | #include <linux/slab.h> |
27 | 27 | ||
28 | /* | 28 | /* |
29 | * Kernel thread creation. The desired kernel function is "wrapped" | ||
30 | * in the kernel_thread_helper function, which does cleanup | ||
31 | * afterwards. | ||
32 | */ | ||
33 | static void __noreturn kernel_thread_helper(void *arg, int (*fn)(void *)) | ||
34 | { | ||
35 | do_exit(fn(arg)); | ||
36 | } | ||
37 | |||
38 | int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags) | ||
39 | { | ||
40 | struct pt_regs regs; | ||
41 | |||
42 | memset(®s, 0, sizeof(regs)); | ||
43 | /* | ||
44 | * Yes, we're exploting illicit knowledge of the ABI here. | ||
45 | */ | ||
46 | regs.r00 = (unsigned long) arg; | ||
47 | regs.r01 = (unsigned long) fn; | ||
48 | pt_set_elr(®s, (unsigned long)kernel_thread_helper); | ||
49 | pt_set_kmode(®s); | ||
50 | |||
51 | return do_fork(flags|CLONE_VM|CLONE_UNTRACED, 0, ®s, 0, NULL, NULL); | ||
52 | } | ||
53 | EXPORT_SYMBOL(kernel_thread); | ||
54 | |||
55 | /* | ||
56 | * Program thread launch. Often defined as a macro in processor.h, | 29 | * Program thread launch. Often defined as a macro in processor.h, |
57 | * but we're shooting for a small footprint and it's not an inner-loop | 30 | * but we're shooting for a small footprint and it's not an inner-loop |
58 | * performance-critical operation. | 31 | * performance-critical operation. |
@@ -114,7 +87,7 @@ unsigned long thread_saved_pc(struct task_struct *tsk) | |||
114 | * Copy architecture-specific thread state | 87 | * Copy architecture-specific thread state |
115 | */ | 88 | */ |
116 | int copy_thread(unsigned long clone_flags, unsigned long usp, | 89 | int copy_thread(unsigned long clone_flags, unsigned long usp, |
117 | unsigned long unused, struct task_struct *p, | 90 | unsigned long arg, struct task_struct *p, |
118 | struct pt_regs *regs) | 91 | struct pt_regs *regs) |
119 | { | 92 | { |
120 | struct thread_info *ti = task_thread_info(p); | 93 | struct thread_info *ti = task_thread_info(p); |
@@ -125,61 +98,50 @@ int copy_thread(unsigned long clone_flags, unsigned long usp, | |||
125 | childregs = (struct pt_regs *) (((unsigned long) ti + THREAD_SIZE) - | 98 | childregs = (struct pt_regs *) (((unsigned long) ti + THREAD_SIZE) - |
126 | sizeof(*childregs)); | 99 | sizeof(*childregs)); |
127 | 100 | ||
128 | memcpy(childregs, regs, sizeof(*childregs)); | ||
129 | ti->regs = childregs; | 101 | ti->regs = childregs; |
130 | 102 | ||
131 | /* | 103 | /* |
132 | * Establish kernel stack pointer and initial PC for new thread | 104 | * Establish kernel stack pointer and initial PC for new thread |
105 | * Note that unlike the usual situation, we do not copy the | ||
106 | * parent's callee-saved here; those are in pt_regs and whatever | ||
107 | * we leave here will be overridden on return to userland. | ||
133 | */ | 108 | */ |
134 | ss = (struct hexagon_switch_stack *) ((unsigned long) childregs - | 109 | ss = (struct hexagon_switch_stack *) ((unsigned long) childregs - |
135 | sizeof(*ss)); | 110 | sizeof(*ss)); |
136 | ss->lr = (unsigned long)ret_from_fork; | 111 | ss->lr = (unsigned long)ret_from_fork; |
137 | p->thread.switch_sp = ss; | 112 | p->thread.switch_sp = ss; |
138 | 113 | if (unlikely(p->flags & PF_KTHREAD)) { | |
139 | /* If User mode thread, set pt_reg stack pointer as per parameter */ | 114 | memset(childregs, 0, sizeof(struct pt_regs)); |
140 | if (user_mode(childregs)) { | 115 | /* r24 <- fn, r25 <- arg */ |
141 | pt_set_rte_sp(childregs, usp); | 116 | ss->r2524 = usp | ((u64)arg << 32); |
142 | 117 | pt_set_kmode(childregs); | |
143 | /* Child sees zero return value */ | 118 | return 0; |
144 | childregs->r00 = 0; | ||
145 | |||
146 | /* | ||
147 | * The clone syscall has the C signature: | ||
148 | * int [r0] clone(int flags [r0], | ||
149 | * void *child_frame [r1], | ||
150 | * void *parent_tid [r2], | ||
151 | * void *child_tid [r3], | ||
152 | * void *thread_control_block [r4]); | ||
153 | * ugp is used to provide TLS support. | ||
154 | */ | ||
155 | if (clone_flags & CLONE_SETTLS) | ||
156 | childregs->ugp = childregs->r04; | ||
157 | |||
158 | /* | ||
159 | * Parent sees new pid -- not necessary, not even possible at | ||
160 | * this point in the fork process | ||
161 | * Might also want to set things like ti->addr_limit | ||
162 | */ | ||
163 | } else { | ||
164 | /* | ||
165 | * If kernel thread, resume stack is kernel stack base. | ||
166 | * Note that this is pointer arithmetic on pt_regs * | ||
167 | */ | ||
168 | pt_set_rte_sp(childregs, (unsigned long)(childregs + 1)); | ||
169 | /* | ||
170 | * We need the current thread_info fast path pointer | ||
171 | * set up in pt_regs. The register to be used is | ||
172 | * parametric for assembler code, but the mechanism | ||
173 | * doesn't drop neatly into C. Needs to be fixed. | ||
174 | */ | ||
175 | childregs->THREADINFO_REG = (unsigned long) ti; | ||
176 | } | 119 | } |
120 | memcpy(childregs, regs, sizeof(*childregs)); | ||
121 | ss->r2524 = 0; | ||
122 | |||
123 | pt_set_rte_sp(childregs, usp); | ||
124 | |||
125 | /* Child sees zero return value */ | ||
126 | childregs->r00 = 0; | ||
127 | |||
128 | /* | ||
129 | * The clone syscall has the C signature: | ||
130 | * int [r0] clone(int flags [r0], | ||
131 | * void *child_frame [r1], | ||
132 | * void *parent_tid [r2], | ||
133 | * void *child_tid [r3], | ||
134 | * void *thread_control_block [r4]); | ||
135 | * ugp is used to provide TLS support. | ||
136 | */ | ||
137 | if (clone_flags & CLONE_SETTLS) | ||
138 | childregs->ugp = childregs->r04; | ||
177 | 139 | ||
178 | /* | 140 | /* |
179 | * thread_info pointer is pulled out of task_struct "stack" | 141 | * Parent sees new pid -- not necessary, not even possible at |
180 | * field on switch_to. | 142 | * this point in the fork process |
143 | * Might also want to set things like ti->addr_limit | ||
181 | */ | 144 | */ |
182 | p->stack = (void *)ti; | ||
183 | 145 | ||
184 | return 0; | 146 | return 0; |
185 | } | 147 | } |
diff --git a/arch/hexagon/kernel/signal.c b/arch/hexagon/kernel/signal.c index 5047b8b879c0..fe0d1373165d 100644 --- a/arch/hexagon/kernel/signal.c +++ b/arch/hexagon/kernel/signal.c | |||
@@ -249,14 +249,14 @@ void do_notify_resume(struct pt_regs *regs, unsigned long thread_info_flags) | |||
249 | */ | 249 | */ |
250 | asmlinkage int sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss) | 250 | asmlinkage int sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss) |
251 | { | 251 | { |
252 | struct pt_regs *regs = current_thread_info()->regs; | 252 | struct pt_regs *regs = current_pt_regs(); |
253 | 253 | ||
254 | return do_sigaltstack(uss, uoss, regs->r29); | 254 | return do_sigaltstack(uss, uoss, regs->r29); |
255 | } | 255 | } |
256 | 256 | ||
257 | asmlinkage int sys_rt_sigreturn(void) | 257 | asmlinkage int sys_rt_sigreturn(void) |
258 | { | 258 | { |
259 | struct pt_regs *regs = current_thread_info()->regs; | 259 | struct pt_regs *regs = current_pt_regs(); |
260 | struct rt_sigframe __user *frame; | 260 | struct rt_sigframe __user *frame; |
261 | sigset_t blocked; | 261 | sigset_t blocked; |
262 | 262 | ||
diff --git a/arch/hexagon/kernel/syscall.c b/arch/hexagon/kernel/syscall.c index 319fa6494f58..d2cc3270af3e 100644 --- a/arch/hexagon/kernel/syscall.c +++ b/arch/hexagon/kernel/syscall.c | |||
@@ -35,55 +35,13 @@ | |||
35 | * See signal.c for signal-related system call wrappers. | 35 | * See signal.c for signal-related system call wrappers. |
36 | */ | 36 | */ |
37 | 37 | ||
38 | asmlinkage int sys_execve(char __user *ufilename, | ||
39 | const char __user *const __user *argv, | ||
40 | const char __user *const __user *envp) | ||
41 | { | ||
42 | struct pt_regs *pregs = current_thread_info()->regs; | ||
43 | struct filename *filename; | ||
44 | int retval; | ||
45 | |||
46 | filename = getname(ufilename); | ||
47 | retval = PTR_ERR(filename); | ||
48 | if (IS_ERR(filename)) | ||
49 | return retval; | ||
50 | |||
51 | retval = do_execve(filename->name, argv, envp, pregs); | ||
52 | putname(filename); | ||
53 | |||
54 | return retval; | ||
55 | } | ||
56 | |||
57 | asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp, | 38 | asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp, |
58 | unsigned long parent_tidp, unsigned long child_tidp) | 39 | unsigned long parent_tidp, unsigned long child_tidp) |
59 | { | 40 | { |
60 | struct pt_regs *pregs = current_thread_info()->regs; | 41 | struct pt_regs *pregs = current_pt_regs(); |
61 | 42 | ||
62 | if (!newsp) | 43 | if (!newsp) |
63 | newsp = pregs->SP; | 44 | newsp = pregs->SP; |
64 | return do_fork(clone_flags, newsp, pregs, 0, (int __user *)parent_tidp, | 45 | return do_fork(clone_flags, newsp, pregs, 0, (int __user *)parent_tidp, |
65 | (int __user *)child_tidp); | 46 | (int __user *)child_tidp); |
66 | } | 47 | } |
67 | |||
68 | /* | ||
69 | * Do a system call from the kernel, so as to have a proper pt_regs | ||
70 | * and recycle the sys_execvpe infrustructure. | ||
71 | */ | ||
72 | int kernel_execve(const char *filename, | ||
73 | const char *const argv[], const char *const envp[]) | ||
74 | { | ||
75 | register unsigned long __a0 asm("r0") = (unsigned long) filename; | ||
76 | register unsigned long __a1 asm("r1") = (unsigned long) argv; | ||
77 | register unsigned long __a2 asm("r2") = (unsigned long) envp; | ||
78 | int retval; | ||
79 | |||
80 | __asm__ volatile( | ||
81 | " R6 = #%4;\n" | ||
82 | " trap0(#1);\n" | ||
83 | " %0 = R0;\n" | ||
84 | : "=r" (retval) | ||
85 | : "r" (__a0), "r" (__a1), "r" (__a2), "i" (__NR_execve) | ||
86 | ); | ||
87 | |||
88 | return retval; | ||
89 | } | ||
diff --git a/arch/hexagon/kernel/vm_entry.S b/arch/hexagon/kernel/vm_entry.S index cd71673ac259..425e50c694f7 100644 --- a/arch/hexagon/kernel/vm_entry.S +++ b/arch/hexagon/kernel/vm_entry.S | |||
@@ -266,4 +266,8 @@ _K_enter_machcheck: | |||
266 | .globl ret_from_fork | 266 | .globl ret_from_fork |
267 | ret_from_fork: | 267 | ret_from_fork: |
268 | call schedule_tail | 268 | call schedule_tail |
269 | P0 = cmp.eq(R24, #0); | ||
270 | if P0 jump return_from_syscall | ||
271 | R0 = R25; | ||
272 | callr R24 | ||
269 | jump return_from_syscall | 273 | jump return_from_syscall |
diff --git a/arch/ia64/Kconfig b/arch/ia64/Kconfig index 3279646120e3..670600468128 100644 --- a/arch/ia64/Kconfig +++ b/arch/ia64/Kconfig | |||
@@ -42,6 +42,8 @@ config IA64 | |||
42 | select GENERIC_TIME_VSYSCALL_OLD | 42 | select GENERIC_TIME_VSYSCALL_OLD |
43 | select HAVE_MOD_ARCH_SPECIFIC | 43 | select HAVE_MOD_ARCH_SPECIFIC |
44 | select MODULES_USE_ELF_RELA | 44 | select MODULES_USE_ELF_RELA |
45 | select GENERIC_KERNEL_THREAD | ||
46 | select GENERIC_KERNEL_EXECVE | ||
45 | default y | 47 | default y |
46 | help | 48 | help |
47 | The Itanium Processor Family is Intel's 64-bit successor to | 49 | The Itanium Processor Family is Intel's 64-bit successor to |
diff --git a/arch/ia64/include/asm/processor.h b/arch/ia64/include/asm/processor.h index 944152a50912..e0a899a1a8a6 100644 --- a/arch/ia64/include/asm/processor.h +++ b/arch/ia64/include/asm/processor.h | |||
@@ -340,22 +340,6 @@ struct task_struct; | |||
340 | */ | 340 | */ |
341 | #define release_thread(dead_task) | 341 | #define release_thread(dead_task) |
342 | 342 | ||
343 | /* | ||
344 | * This is the mechanism for creating a new kernel thread. | ||
345 | * | ||
346 | * NOTE 1: Only a kernel-only process (ie the swapper or direct | ||
347 | * descendants who haven't done an "execve()") should use this: it | ||
348 | * will work within a system call from a "real" process, but the | ||
349 | * process memory space will not be free'd until both the parent and | ||
350 | * the child have exited. | ||
351 | * | ||
352 | * NOTE 2: This MUST NOT be an inlined function. Otherwise, we get | ||
353 | * into trouble in init/main.c when the child thread returns to | ||
354 | * do_basic_setup() and the timing is such that free_initmem() has | ||
355 | * been called already. | ||
356 | */ | ||
357 | extern pid_t kernel_thread (int (*fn)(void *), void *arg, unsigned long flags); | ||
358 | |||
359 | /* Get wait channel for task P. */ | 343 | /* Get wait channel for task P. */ |
360 | extern unsigned long get_wchan (struct task_struct *p); | 344 | extern unsigned long get_wchan (struct task_struct *p); |
361 | 345 | ||
diff --git a/arch/ia64/include/asm/unistd.h b/arch/ia64/include/asm/unistd.h index 8b3ff2f5b861..1574bca86138 100644 --- a/arch/ia64/include/asm/unistd.h +++ b/arch/ia64/include/asm/unistd.h | |||
@@ -29,6 +29,7 @@ | |||
29 | 29 | ||
30 | #define __ARCH_WANT_SYS_RT_SIGACTION | 30 | #define __ARCH_WANT_SYS_RT_SIGACTION |
31 | #define __ARCH_WANT_SYS_RT_SIGSUSPEND | 31 | #define __ARCH_WANT_SYS_RT_SIGSUSPEND |
32 | #define __ARCH_WANT_SYS_EXECVE | ||
32 | 33 | ||
33 | #if !defined(__ASSEMBLY__) && !defined(ASSEMBLER) | 34 | #if !defined(__ASSEMBLY__) && !defined(ASSEMBLER) |
34 | 35 | ||
diff --git a/arch/ia64/kernel/entry.S b/arch/ia64/kernel/entry.S index 1ccbe12a4d84..940a67263629 100644 --- a/arch/ia64/kernel/entry.S +++ b/arch/ia64/kernel/entry.S | |||
@@ -61,14 +61,13 @@ ENTRY(ia64_execve) | |||
61 | * Allocate 8 input registers since ptrace() may clobber them | 61 | * Allocate 8 input registers since ptrace() may clobber them |
62 | */ | 62 | */ |
63 | .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8) | 63 | .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8) |
64 | alloc loc1=ar.pfs,8,2,4,0 | 64 | alloc loc1=ar.pfs,8,2,3,0 |
65 | mov loc0=rp | 65 | mov loc0=rp |
66 | .body | 66 | .body |
67 | mov out0=in0 // filename | 67 | mov out0=in0 // filename |
68 | ;; // stop bit between alloc and call | 68 | ;; // stop bit between alloc and call |
69 | mov out1=in1 // argv | 69 | mov out1=in1 // argv |
70 | mov out2=in2 // envp | 70 | mov out2=in2 // envp |
71 | add out3=16,sp // regs | ||
72 | br.call.sptk.many rp=sys_execve | 71 | br.call.sptk.many rp=sys_execve |
73 | .ret0: | 72 | .ret0: |
74 | cmp4.ge p6,p7=r8,r0 | 73 | cmp4.ge p6,p7=r8,r0 |
@@ -76,7 +75,6 @@ ENTRY(ia64_execve) | |||
76 | sxt4 r8=r8 // return 64-bit result | 75 | sxt4 r8=r8 // return 64-bit result |
77 | ;; | 76 | ;; |
78 | stf.spill [sp]=f0 | 77 | stf.spill [sp]=f0 |
79 | (p6) cmp.ne pKStk,pUStk=r0,r0 // a successful execve() lands us in user-mode... | ||
80 | mov rp=loc0 | 78 | mov rp=loc0 |
81 | (p6) mov ar.pfs=r0 // clear ar.pfs on success | 79 | (p6) mov ar.pfs=r0 // clear ar.pfs on success |
82 | (p7) br.ret.sptk.many rp | 80 | (p7) br.ret.sptk.many rp |
@@ -484,19 +482,6 @@ GLOBAL_ENTRY(prefetch_stack) | |||
484 | br.ret.sptk.many rp | 482 | br.ret.sptk.many rp |
485 | END(prefetch_stack) | 483 | END(prefetch_stack) |
486 | 484 | ||
487 | GLOBAL_ENTRY(kernel_execve) | ||
488 | rum psr.ac | ||
489 | mov r15=__NR_execve // put syscall number in place | ||
490 | break __BREAK_SYSCALL | ||
491 | br.ret.sptk.many rp | ||
492 | END(kernel_execve) | ||
493 | |||
494 | GLOBAL_ENTRY(clone) | ||
495 | mov r15=__NR_clone // put syscall number in place | ||
496 | break __BREAK_SYSCALL | ||
497 | br.ret.sptk.many rp | ||
498 | END(clone) | ||
499 | |||
500 | /* | 485 | /* |
501 | * Invoke a system call, but do some tracing before and after the call. | 486 | * Invoke a system call, but do some tracing before and after the call. |
502 | * We MUST preserve the current register frame throughout this routine | 487 | * We MUST preserve the current register frame throughout this routine |
@@ -600,6 +585,27 @@ GLOBAL_ENTRY(ia64_strace_leave_kernel) | |||
600 | .ret4: br.cond.sptk ia64_leave_kernel | 585 | .ret4: br.cond.sptk ia64_leave_kernel |
601 | END(ia64_strace_leave_kernel) | 586 | END(ia64_strace_leave_kernel) |
602 | 587 | ||
588 | ENTRY(call_payload) | ||
589 | .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(0) | ||
590 | /* call the kernel_thread payload; fn is in r4, arg - in r5 */ | ||
591 | alloc loc1=ar.pfs,0,3,1,0 | ||
592 | mov loc0=rp | ||
593 | mov loc2=gp | ||
594 | mov out0=r5 // arg | ||
595 | ld8 r14 = [r4], 8 // fn.address | ||
596 | ;; | ||
597 | mov b6 = r14 | ||
598 | ld8 gp = [r4] // fn.gp | ||
599 | ;; | ||
600 | br.call.sptk.many rp=b6 // fn(arg) | ||
601 | .ret12: mov gp=loc2 | ||
602 | mov rp=loc0 | ||
603 | mov ar.pfs=loc1 | ||
604 | /* ... and if it has returned, we are going to userland */ | ||
605 | cmp.ne pKStk,pUStk=r0,r0 | ||
606 | br.ret.sptk.many rp | ||
607 | END(call_payload) | ||
608 | |||
603 | GLOBAL_ENTRY(ia64_ret_from_clone) | 609 | GLOBAL_ENTRY(ia64_ret_from_clone) |
604 | PT_REGS_UNWIND_INFO(0) | 610 | PT_REGS_UNWIND_INFO(0) |
605 | { /* | 611 | { /* |
@@ -616,6 +622,7 @@ GLOBAL_ENTRY(ia64_ret_from_clone) | |||
616 | br.call.sptk.many rp=ia64_invoke_schedule_tail | 622 | br.call.sptk.many rp=ia64_invoke_schedule_tail |
617 | } | 623 | } |
618 | .ret8: | 624 | .ret8: |
625 | (pKStk) br.call.sptk.many rp=call_payload | ||
619 | adds r2=TI_FLAGS+IA64_TASK_SIZE,r13 | 626 | adds r2=TI_FLAGS+IA64_TASK_SIZE,r13 |
620 | ;; | 627 | ;; |
621 | ld4 r2=[r2] | 628 | ld4 r2=[r2] |
diff --git a/arch/ia64/kernel/head.S b/arch/ia64/kernel/head.S index 629a250f7c19..4738ff7bd66a 100644 --- a/arch/ia64/kernel/head.S +++ b/arch/ia64/kernel/head.S | |||
@@ -1093,19 +1093,6 @@ GLOBAL_ENTRY(cycle_to_cputime) | |||
1093 | END(cycle_to_cputime) | 1093 | END(cycle_to_cputime) |
1094 | #endif /* CONFIG_VIRT_CPU_ACCOUNTING */ | 1094 | #endif /* CONFIG_VIRT_CPU_ACCOUNTING */ |
1095 | 1095 | ||
1096 | GLOBAL_ENTRY(start_kernel_thread) | ||
1097 | .prologue | ||
1098 | .save rp, r0 // this is the end of the call-chain | ||
1099 | .body | ||
1100 | alloc r2 = ar.pfs, 0, 0, 2, 0 | ||
1101 | mov out0 = r9 | ||
1102 | mov out1 = r11;; | ||
1103 | br.call.sptk.many rp = kernel_thread_helper;; | ||
1104 | mov out0 = r8 | ||
1105 | br.call.sptk.many rp = sys_exit;; | ||
1106 | 1: br.sptk.few 1b // not reached | ||
1107 | END(start_kernel_thread) | ||
1108 | |||
1109 | #ifdef CONFIG_IA64_BRL_EMU | 1096 | #ifdef CONFIG_IA64_BRL_EMU |
1110 | 1097 | ||
1111 | /* | 1098 | /* |
diff --git a/arch/ia64/kernel/process.c b/arch/ia64/kernel/process.c index 35e106f2ed13..25543a295ad9 100644 --- a/arch/ia64/kernel/process.c +++ b/arch/ia64/kernel/process.c | |||
@@ -401,64 +401,15 @@ copy_thread(unsigned long clone_flags, | |||
401 | struct pt_regs *child_ptregs; | 401 | struct pt_regs *child_ptregs; |
402 | int retval = 0; | 402 | int retval = 0; |
403 | 403 | ||
404 | #ifdef CONFIG_SMP | ||
405 | /* | ||
406 | * For SMP idle threads, fork_by_hand() calls do_fork with | ||
407 | * NULL regs. | ||
408 | */ | ||
409 | if (!regs) | ||
410 | return 0; | ||
411 | #endif | ||
412 | |||
413 | stack = ((struct switch_stack *) regs) - 1; | ||
414 | |||
415 | child_ptregs = (struct pt_regs *) ((unsigned long) p + IA64_STK_OFFSET) - 1; | 404 | child_ptregs = (struct pt_regs *) ((unsigned long) p + IA64_STK_OFFSET) - 1; |
416 | child_stack = (struct switch_stack *) child_ptregs - 1; | 405 | child_stack = (struct switch_stack *) child_ptregs - 1; |
417 | 406 | ||
418 | /* copy parent's switch_stack & pt_regs to child: */ | ||
419 | memcpy(child_stack, stack, sizeof(*child_ptregs) + sizeof(*child_stack)); | ||
420 | |||
421 | rbs = (unsigned long) current + IA64_RBS_OFFSET; | 407 | rbs = (unsigned long) current + IA64_RBS_OFFSET; |
422 | child_rbs = (unsigned long) p + IA64_RBS_OFFSET; | 408 | child_rbs = (unsigned long) p + IA64_RBS_OFFSET; |
423 | rbs_size = stack->ar_bspstore - rbs; | ||
424 | |||
425 | /* copy the parent's register backing store to the child: */ | ||
426 | memcpy((void *) child_rbs, (void *) rbs, rbs_size); | ||
427 | |||
428 | if (likely(user_mode(child_ptregs))) { | ||
429 | if (clone_flags & CLONE_SETTLS) | ||
430 | child_ptregs->r13 = regs->r16; /* see sys_clone2() in entry.S */ | ||
431 | if (user_stack_base) { | ||
432 | child_ptregs->r12 = user_stack_base + user_stack_size - 16; | ||
433 | child_ptregs->ar_bspstore = user_stack_base; | ||
434 | child_ptregs->ar_rnat = 0; | ||
435 | child_ptregs->loadrs = 0; | ||
436 | } | ||
437 | } else { | ||
438 | /* | ||
439 | * Note: we simply preserve the relative position of | ||
440 | * the stack pointer here. There is no need to | ||
441 | * allocate a scratch area here, since that will have | ||
442 | * been taken care of by the caller of sys_clone() | ||
443 | * already. | ||
444 | */ | ||
445 | child_ptregs->r12 = (unsigned long) child_ptregs - 16; /* kernel sp */ | ||
446 | child_ptregs->r13 = (unsigned long) p; /* set `current' pointer */ | ||
447 | } | ||
448 | child_stack->ar_bspstore = child_rbs + rbs_size; | ||
449 | child_stack->b0 = (unsigned long) &ia64_ret_from_clone; | ||
450 | 409 | ||
451 | /* copy parts of thread_struct: */ | 410 | /* copy parts of thread_struct: */ |
452 | p->thread.ksp = (unsigned long) child_stack - 16; | 411 | p->thread.ksp = (unsigned long) child_stack - 16; |
453 | 412 | ||
454 | /* stop some PSR bits from being inherited. | ||
455 | * the psr.up/psr.pp bits must be cleared on fork but inherited on execve() | ||
456 | * therefore we must specify them explicitly here and not include them in | ||
457 | * IA64_PSR_BITS_TO_CLEAR. | ||
458 | */ | ||
459 | child_ptregs->cr_ipsr = ((child_ptregs->cr_ipsr | IA64_PSR_BITS_TO_SET) | ||
460 | & ~(IA64_PSR_BITS_TO_CLEAR | IA64_PSR_PP | IA64_PSR_UP)); | ||
461 | |||
462 | /* | 413 | /* |
463 | * NOTE: The calling convention considers all floating point | 414 | * NOTE: The calling convention considers all floating point |
464 | * registers in the high partition (fph) to be scratch. Since | 415 | * registers in the high partition (fph) to be scratch. Since |
@@ -480,8 +431,66 @@ copy_thread(unsigned long clone_flags, | |||
480 | # define THREAD_FLAGS_TO_SET 0 | 431 | # define THREAD_FLAGS_TO_SET 0 |
481 | p->thread.flags = ((current->thread.flags & ~THREAD_FLAGS_TO_CLEAR) | 432 | p->thread.flags = ((current->thread.flags & ~THREAD_FLAGS_TO_CLEAR) |
482 | | THREAD_FLAGS_TO_SET); | 433 | | THREAD_FLAGS_TO_SET); |
434 | |||
483 | ia64_drop_fpu(p); /* don't pick up stale state from a CPU's fph */ | 435 | ia64_drop_fpu(p); /* don't pick up stale state from a CPU's fph */ |
484 | 436 | ||
437 | if (unlikely(p->flags & PF_KTHREAD)) { | ||
438 | if (unlikely(!user_stack_base)) { | ||
439 | /* fork_idle() called us */ | ||
440 | return 0; | ||
441 | } | ||
442 | memset(child_stack, 0, sizeof(*child_ptregs) + sizeof(*child_stack)); | ||
443 | child_stack->r4 = user_stack_base; /* payload */ | ||
444 | child_stack->r5 = user_stack_size; /* argument */ | ||
445 | /* | ||
446 | * Preserve PSR bits, except for bits 32-34 and 37-45, | ||
447 | * which we can't read. | ||
448 | */ | ||
449 | child_ptregs->cr_ipsr = ia64_getreg(_IA64_REG_PSR) | IA64_PSR_BN; | ||
450 | /* mark as valid, empty frame */ | ||
451 | child_ptregs->cr_ifs = 1UL << 63; | ||
452 | child_stack->ar_fpsr = child_ptregs->ar_fpsr | ||
453 | = ia64_getreg(_IA64_REG_AR_FPSR); | ||
454 | child_stack->pr = (1 << PRED_KERNEL_STACK); | ||
455 | child_stack->ar_bspstore = child_rbs; | ||
456 | child_stack->b0 = (unsigned long) &ia64_ret_from_clone; | ||
457 | |||
458 | /* stop some PSR bits from being inherited. | ||
459 | * the psr.up/psr.pp bits must be cleared on fork but inherited on execve() | ||
460 | * therefore we must specify them explicitly here and not include them in | ||
461 | * IA64_PSR_BITS_TO_CLEAR. | ||
462 | */ | ||
463 | child_ptregs->cr_ipsr = ((child_ptregs->cr_ipsr | IA64_PSR_BITS_TO_SET) | ||
464 | & ~(IA64_PSR_BITS_TO_CLEAR | IA64_PSR_PP | IA64_PSR_UP)); | ||
465 | |||
466 | return 0; | ||
467 | } | ||
468 | stack = ((struct switch_stack *) regs) - 1; | ||
469 | /* copy parent's switch_stack & pt_regs to child: */ | ||
470 | memcpy(child_stack, stack, sizeof(*child_ptregs) + sizeof(*child_stack)); | ||
471 | |||
472 | /* copy the parent's register backing store to the child: */ | ||
473 | rbs_size = stack->ar_bspstore - rbs; | ||
474 | memcpy((void *) child_rbs, (void *) rbs, rbs_size); | ||
475 | if (clone_flags & CLONE_SETTLS) | ||
476 | child_ptregs->r13 = regs->r16; /* see sys_clone2() in entry.S */ | ||
477 | if (user_stack_base) { | ||
478 | child_ptregs->r12 = user_stack_base + user_stack_size - 16; | ||
479 | child_ptregs->ar_bspstore = user_stack_base; | ||
480 | child_ptregs->ar_rnat = 0; | ||
481 | child_ptregs->loadrs = 0; | ||
482 | } | ||
483 | child_stack->ar_bspstore = child_rbs + rbs_size; | ||
484 | child_stack->b0 = (unsigned long) &ia64_ret_from_clone; | ||
485 | |||
486 | /* stop some PSR bits from being inherited. | ||
487 | * the psr.up/psr.pp bits must be cleared on fork but inherited on execve() | ||
488 | * therefore we must specify them explicitly here and not include them in | ||
489 | * IA64_PSR_BITS_TO_CLEAR. | ||
490 | */ | ||
491 | child_ptregs->cr_ipsr = ((child_ptregs->cr_ipsr | IA64_PSR_BITS_TO_SET) | ||
492 | & ~(IA64_PSR_BITS_TO_CLEAR | IA64_PSR_PP | IA64_PSR_UP)); | ||
493 | |||
485 | #ifdef CONFIG_PERFMON | 494 | #ifdef CONFIG_PERFMON |
486 | if (current->thread.pfm_context) | 495 | if (current->thread.pfm_context) |
487 | pfm_inherit(p, child_ptregs); | 496 | pfm_inherit(p, child_ptregs); |
@@ -608,57 +617,6 @@ dump_fpu (struct pt_regs *pt, elf_fpregset_t dst) | |||
608 | return 1; /* f0-f31 are always valid so we always return 1 */ | 617 | return 1; /* f0-f31 are always valid so we always return 1 */ |
609 | } | 618 | } |
610 | 619 | ||
611 | long | ||
612 | sys_execve (const char __user *filename, | ||
613 | const char __user *const __user *argv, | ||
614 | const char __user *const __user *envp, | ||
615 | struct pt_regs *regs) | ||
616 | { | ||
617 | struct filename *fname; | ||
618 | int error; | ||
619 | |||
620 | fname = getname(filename); | ||
621 | error = PTR_ERR(fname); | ||
622 | if (IS_ERR(fname)) | ||
623 | goto out; | ||
624 | error = do_execve(fname->name, argv, envp, regs); | ||
625 | putname(fname); | ||
626 | out: | ||
627 | return error; | ||
628 | } | ||
629 | |||
630 | pid_t | ||
631 | kernel_thread (int (*fn)(void *), void *arg, unsigned long flags) | ||
632 | { | ||
633 | extern void start_kernel_thread (void); | ||
634 | unsigned long *helper_fptr = (unsigned long *) &start_kernel_thread; | ||
635 | struct { | ||
636 | struct switch_stack sw; | ||
637 | struct pt_regs pt; | ||
638 | } regs; | ||
639 | |||
640 | memset(®s, 0, sizeof(regs)); | ||
641 | regs.pt.cr_iip = helper_fptr[0]; /* set entry point (IP) */ | ||
642 | regs.pt.r1 = helper_fptr[1]; /* set GP */ | ||
643 | regs.pt.r9 = (unsigned long) fn; /* 1st argument */ | ||
644 | regs.pt.r11 = (unsigned long) arg; /* 2nd argument */ | ||
645 | /* Preserve PSR bits, except for bits 32-34 and 37-45, which we can't read. */ | ||
646 | regs.pt.cr_ipsr = ia64_getreg(_IA64_REG_PSR) | IA64_PSR_BN; | ||
647 | regs.pt.cr_ifs = 1UL << 63; /* mark as valid, empty frame */ | ||
648 | regs.sw.ar_fpsr = regs.pt.ar_fpsr = ia64_getreg(_IA64_REG_AR_FPSR); | ||
649 | regs.sw.ar_bspstore = (unsigned long) current + IA64_RBS_OFFSET; | ||
650 | regs.sw.pr = (1 << PRED_KERNEL_STACK); | ||
651 | return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, ®s.pt, 0, NULL, NULL); | ||
652 | } | ||
653 | EXPORT_SYMBOL(kernel_thread); | ||
654 | |||
655 | /* This gets called from kernel_thread() via ia64_invoke_thread_helper(). */ | ||
656 | int | ||
657 | kernel_thread_helper (int (*fn)(void *), void *arg) | ||
658 | { | ||
659 | return (*fn)(arg); | ||
660 | } | ||
661 | |||
662 | /* | 620 | /* |
663 | * Flush thread state. This is called when a thread does an execve(). | 621 | * Flush thread state. This is called when a thread does an execve(). |
664 | */ | 622 | */ |
diff --git a/arch/m32r/Kconfig b/arch/m32r/Kconfig index f807721e19a5..5183f43a2cf7 100644 --- a/arch/m32r/Kconfig +++ b/arch/m32r/Kconfig | |||
@@ -15,6 +15,8 @@ config M32R | |||
15 | select GENERIC_ATOMIC64 | 15 | select GENERIC_ATOMIC64 |
16 | select ARCH_USES_GETTIMEOFFSET | 16 | select ARCH_USES_GETTIMEOFFSET |
17 | select MODULES_USE_ELF_RELA | 17 | select MODULES_USE_ELF_RELA |
18 | select GENERIC_KERNEL_THREAD | ||
19 | select GENERIC_KERNEL_EXECVE | ||
18 | 20 | ||
19 | config SBUS | 21 | config SBUS |
20 | bool | 22 | bool |
diff --git a/arch/m32r/include/asm/processor.h b/arch/m32r/include/asm/processor.h index da17253b5735..5767367550c6 100644 --- a/arch/m32r/include/asm/processor.h +++ b/arch/m32r/include/asm/processor.h | |||
@@ -118,11 +118,6 @@ struct mm_struct; | |||
118 | /* Free all resources held by a thread. */ | 118 | /* Free all resources held by a thread. */ |
119 | extern void release_thread(struct task_struct *); | 119 | extern void release_thread(struct task_struct *); |
120 | 120 | ||
121 | /* | ||
122 | * create a kernel thread without removing it from tasklists | ||
123 | */ | ||
124 | extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags); | ||
125 | |||
126 | /* Copy and release all segment info associated with a VM */ | 121 | /* Copy and release all segment info associated with a VM */ |
127 | extern void copy_segments(struct task_struct *p, struct mm_struct * mm); | 122 | extern void copy_segments(struct task_struct *p, struct mm_struct * mm); |
128 | extern void release_segments(struct mm_struct * mm); | 123 | extern void release_segments(struct mm_struct * mm); |
diff --git a/arch/m32r/include/asm/ptrace.h b/arch/m32r/include/asm/ptrace.h index 4313aa62b51b..c4432f1fb2cf 100644 --- a/arch/m32r/include/asm/ptrace.h +++ b/arch/m32r/include/asm/ptrace.h | |||
@@ -139,6 +139,8 @@ extern void withdraw_debug_trap(struct pt_regs *regs); | |||
139 | 139 | ||
140 | #define task_pt_regs(task) \ | 140 | #define task_pt_regs(task) \ |
141 | ((struct pt_regs *)(task_stack_page(task) + THREAD_SIZE) - 1) | 141 | ((struct pt_regs *)(task_stack_page(task) + THREAD_SIZE) - 1) |
142 | #define current_pt_regs() ((struct pt_regs *) \ | ||
143 | ((unsigned long)current_thread_info() + THREAD_SIZE) - 1) | ||
142 | 144 | ||
143 | #endif /* __KERNEL */ | 145 | #endif /* __KERNEL */ |
144 | 146 | ||
diff --git a/arch/m32r/include/asm/unistd.h b/arch/m32r/include/asm/unistd.h index d5e66a480782..b27bdcbc7c2c 100644 --- a/arch/m32r/include/asm/unistd.h +++ b/arch/m32r/include/asm/unistd.h | |||
@@ -352,6 +352,7 @@ | |||
352 | #define __ARCH_WANT_SYS_OLDUMOUNT | 352 | #define __ARCH_WANT_SYS_OLDUMOUNT |
353 | #define __ARCH_WANT_SYS_RT_SIGACTION | 353 | #define __ARCH_WANT_SYS_RT_SIGACTION |
354 | #define __ARCH_WANT_SYS_RT_SIGSUSPEND | 354 | #define __ARCH_WANT_SYS_RT_SIGSUSPEND |
355 | #define __ARCH_WANT_SYS_EXECVE | ||
355 | 356 | ||
356 | #define __IGNORE_lchown | 357 | #define __IGNORE_lchown |
357 | #define __IGNORE_setuid | 358 | #define __IGNORE_setuid |
diff --git a/arch/m32r/kernel/entry.S b/arch/m32r/kernel/entry.S index 225412bc227e..0c01543f10cd 100644 --- a/arch/m32r/kernel/entry.S +++ b/arch/m32r/kernel/entry.S | |||
@@ -125,6 +125,15 @@ | |||
125 | and \reg, sp | 125 | and \reg, sp |
126 | .endm | 126 | .endm |
127 | 127 | ||
128 | ENTRY(ret_from_kernel_thread) | ||
129 | pop r0 | ||
130 | bl schedule_tail | ||
131 | GET_THREAD_INFO(r8) | ||
132 | ld r0, R0(r8) | ||
133 | ld r1, R1(r8) | ||
134 | jl r1 | ||
135 | bra syscall_exit | ||
136 | |||
128 | ENTRY(ret_from_fork) | 137 | ENTRY(ret_from_fork) |
129 | pop r0 | 138 | pop r0 |
130 | bl schedule_tail | 139 | bl schedule_tail |
diff --git a/arch/m32r/kernel/process.c b/arch/m32r/kernel/process.c index e7366276ef30..62c713f5694a 100644 --- a/arch/m32r/kernel/process.c +++ b/arch/m32r/kernel/process.c | |||
@@ -165,41 +165,6 @@ void show_regs(struct pt_regs * regs) | |||
165 | } | 165 | } |
166 | 166 | ||
167 | /* | 167 | /* |
168 | * Create a kernel thread | ||
169 | */ | ||
170 | |||
171 | /* | ||
172 | * This is the mechanism for creating a new kernel thread. | ||
173 | * | ||
174 | * NOTE! Only a kernel-only process(ie the swapper or direct descendants | ||
175 | * who haven't done an "execve()") should use this: it will work within | ||
176 | * a system call from a "real" process, but the process memory space will | ||
177 | * not be free'd until both the parent and the child have exited. | ||
178 | */ | ||
179 | static void kernel_thread_helper(void *nouse, int (*fn)(void *), void *arg) | ||
180 | { | ||
181 | fn(arg); | ||
182 | do_exit(-1); | ||
183 | } | ||
184 | |||
185 | int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags) | ||
186 | { | ||
187 | struct pt_regs regs; | ||
188 | |||
189 | memset(®s, 0, sizeof (regs)); | ||
190 | regs.r1 = (unsigned long)fn; | ||
191 | regs.r2 = (unsigned long)arg; | ||
192 | |||
193 | regs.bpc = (unsigned long)kernel_thread_helper; | ||
194 | |||
195 | regs.psw = M32R_PSW_BIE; | ||
196 | |||
197 | /* Ok, create the new process. */ | ||
198 | return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, ®s, 0, NULL, | ||
199 | NULL); | ||
200 | } | ||
201 | |||
202 | /* | ||
203 | * Free current thread data structures etc.. | 168 | * Free current thread data structures etc.. |
204 | */ | 169 | */ |
205 | void exit_thread(void) | 170 | void exit_thread(void) |
@@ -227,29 +192,35 @@ int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu) | |||
227 | } | 192 | } |
228 | 193 | ||
229 | int copy_thread(unsigned long clone_flags, unsigned long spu, | 194 | int copy_thread(unsigned long clone_flags, unsigned long spu, |
230 | unsigned long unused, struct task_struct *tsk, struct pt_regs *regs) | 195 | unsigned long arg, struct task_struct *tsk, struct pt_regs *regs) |
231 | { | 196 | { |
232 | struct pt_regs *childregs = task_pt_regs(tsk); | 197 | struct pt_regs *childregs = task_pt_regs(tsk); |
233 | extern void ret_from_fork(void); | 198 | extern void ret_from_fork(void); |
234 | 199 | extern void ret_from_kernel_thread(void); | |
235 | /* Copy registers */ | 200 | |
236 | *childregs = *regs; | 201 | if (unlikely(tsk->flags & PF_KTHREAD)) { |
237 | 202 | memset(childregs, 0, sizeof(struct pt_regs)); | |
238 | childregs->spu = spu; | 203 | childregs->psw = M32R_PSW_BIE; |
239 | childregs->r0 = 0; /* Child gets zero as return value */ | 204 | childregs->r1 = spu; /* fn */ |
240 | regs->r0 = tsk->pid; | 205 | childregs->r0 = arg; |
206 | tsk->thread.lr = (unsigned long)ret_from_kernel_thread; | ||
207 | } else { | ||
208 | /* Copy registers */ | ||
209 | *childregs = *regs; | ||
210 | childregs->spu = spu; | ||
211 | childregs->r0 = 0; /* Child gets zero as return value */ | ||
212 | tsk->thread.lr = (unsigned long)ret_from_fork; | ||
213 | } | ||
241 | tsk->thread.sp = (unsigned long)childregs; | 214 | tsk->thread.sp = (unsigned long)childregs; |
242 | tsk->thread.lr = (unsigned long)ret_from_fork; | ||
243 | 215 | ||
244 | return 0; | 216 | return 0; |
245 | } | 217 | } |
246 | 218 | ||
247 | asmlinkage int sys_fork(unsigned long r0, unsigned long r1, unsigned long r2, | 219 | asmlinkage int sys_fork(void) |
248 | unsigned long r3, unsigned long r4, unsigned long r5, unsigned long r6, | ||
249 | struct pt_regs regs) | ||
250 | { | 220 | { |
251 | #ifdef CONFIG_MMU | 221 | #ifdef CONFIG_MMU |
252 | return do_fork(SIGCHLD, regs.spu, ®s, 0, NULL, NULL); | 222 | struct pt_regs *regs = current_pt_regs(); |
223 | return do_fork(SIGCHLD, regs->spu, regs, 0, NULL, NULL); | ||
253 | #else | 224 | #else |
254 | return -EINVAL; | 225 | return -EINVAL; |
255 | #endif /* CONFIG_MMU */ | 226 | #endif /* CONFIG_MMU */ |
@@ -257,14 +228,13 @@ asmlinkage int sys_fork(unsigned long r0, unsigned long r1, unsigned long r2, | |||
257 | 228 | ||
258 | asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp, | 229 | asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp, |
259 | unsigned long parent_tidptr, | 230 | unsigned long parent_tidptr, |
260 | unsigned long child_tidptr, | 231 | unsigned long child_tidptr) |
261 | unsigned long r4, unsigned long r5, unsigned long r6, | ||
262 | struct pt_regs regs) | ||
263 | { | 232 | { |
233 | struct pt_regs *regs = current_pt_regs(); | ||
264 | if (!newsp) | 234 | if (!newsp) |
265 | newsp = regs.spu; | 235 | newsp = regs->spu; |
266 | 236 | ||
267 | return do_fork(clone_flags, newsp, ®s, 0, | 237 | return do_fork(clone_flags, newsp, regs, 0, |
268 | (int __user *)parent_tidptr, (int __user *)child_tidptr); | 238 | (int __user *)parent_tidptr, (int __user *)child_tidptr); |
269 | } | 239 | } |
270 | 240 | ||
@@ -278,38 +248,14 @@ asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp, | |||
278 | * do not have enough call-clobbered registers to hold all | 248 | * do not have enough call-clobbered registers to hold all |
279 | * the information you need. | 249 | * the information you need. |
280 | */ | 250 | */ |
281 | asmlinkage int sys_vfork(unsigned long r0, unsigned long r1, unsigned long r2, | 251 | asmlinkage int sys_vfork(void) |
282 | unsigned long r3, unsigned long r4, unsigned long r5, unsigned long r6, | ||
283 | struct pt_regs regs) | ||
284 | { | 252 | { |
285 | return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs.spu, ®s, 0, | 253 | struct pt_regs *regs = current_pt_regs(); |
254 | return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->spu, regs, 0, | ||
286 | NULL, NULL); | 255 | NULL, NULL); |
287 | } | 256 | } |
288 | 257 | ||
289 | /* | 258 | /* |
290 | * sys_execve() executes a new program. | ||
291 | */ | ||
292 | asmlinkage int sys_execve(const char __user *ufilename, | ||
293 | const char __user *const __user *uargv, | ||
294 | const char __user *const __user *uenvp, | ||
295 | unsigned long r3, unsigned long r4, unsigned long r5, | ||
296 | unsigned long r6, struct pt_regs regs) | ||
297 | { | ||
298 | int error; | ||
299 | struct filename *filename; | ||
300 | |||
301 | filename = getname(ufilename); | ||
302 | error = PTR_ERR(filename); | ||
303 | if (IS_ERR(filename)) | ||
304 | goto out; | ||
305 | |||
306 | error = do_execve(filename->name, uargv, uenvp, ®s); | ||
307 | putname(filename); | ||
308 | out: | ||
309 | return error; | ||
310 | } | ||
311 | |||
312 | /* | ||
313 | * These bracket the sleeping functions.. | 259 | * These bracket the sleeping functions.. |
314 | */ | 260 | */ |
315 | #define first_sched ((unsigned long) scheduling_functions_start_here) | 261 | #define first_sched ((unsigned long) scheduling_functions_start_here) |
diff --git a/arch/m32r/kernel/sys_m32r.c b/arch/m32r/kernel/sys_m32r.c index d841fb6cc703..c3fdd632fba7 100644 --- a/arch/m32r/kernel/sys_m32r.c +++ b/arch/m32r/kernel/sys_m32r.c | |||
@@ -88,24 +88,3 @@ asmlinkage int sys_cachectl(char *addr, int nbytes, int op) | |||
88 | /* Not implemented yet. */ | 88 | /* Not implemented yet. */ |
89 | return -ENOSYS; | 89 | return -ENOSYS; |
90 | } | 90 | } |
91 | |||
92 | /* | ||
93 | * Do a system call from kernel instead of calling sys_execve so we | ||
94 | * end up with proper pt_regs. | ||
95 | */ | ||
96 | int kernel_execve(const char *filename, | ||
97 | const char *const argv[], | ||
98 | const char *const envp[]) | ||
99 | { | ||
100 | register long __scno __asm__ ("r7") = __NR_execve; | ||
101 | register long __arg3 __asm__ ("r2") = (long)(envp); | ||
102 | register long __arg2 __asm__ ("r1") = (long)(argv); | ||
103 | register long __res __asm__ ("r0") = (long)(filename); | ||
104 | __asm__ __volatile__ ( | ||
105 | "trap #" SYSCALL_VECTOR "|| nop" | ||
106 | : "=r" (__res) | ||
107 | : "r" (__scno), "0" (__res), "r" (__arg2), | ||
108 | "r" (__arg3) | ||
109 | : "memory"); | ||
110 | return __res; | ||
111 | } | ||
diff --git a/arch/m68k/Kconfig b/arch/m68k/Kconfig index e7c161433eae..953a7ba5d050 100644 --- a/arch/m68k/Kconfig +++ b/arch/m68k/Kconfig | |||
@@ -16,6 +16,7 @@ config M68K | |||
16 | select ARCH_WANT_IPC_PARSE_VERSION | 16 | select ARCH_WANT_IPC_PARSE_VERSION |
17 | select ARCH_USES_GETTIMEOFFSET if MMU && !COLDFIRE | 17 | select ARCH_USES_GETTIMEOFFSET if MMU && !COLDFIRE |
18 | select GENERIC_KERNEL_THREAD | 18 | select GENERIC_KERNEL_THREAD |
19 | select GENERIC_KERNEL_EXECVE | ||
19 | select HAVE_MOD_ARCH_SPECIFIC | 20 | select HAVE_MOD_ARCH_SPECIFIC |
20 | select MODULES_USE_ELF_REL | 21 | select MODULES_USE_ELF_REL |
21 | select MODULES_USE_ELF_RELA | 22 | select MODULES_USE_ELF_RELA |
diff --git a/arch/m68k/include/asm/unistd.h b/arch/m68k/include/asm/unistd.h index 5fc7f7bec1c8..0aa165405966 100644 --- a/arch/m68k/include/asm/unistd.h +++ b/arch/m68k/include/asm/unistd.h | |||
@@ -32,7 +32,6 @@ | |||
32 | #define __ARCH_WANT_SYS_RT_SIGACTION | 32 | #define __ARCH_WANT_SYS_RT_SIGACTION |
33 | #define __ARCH_WANT_SYS_RT_SIGSUSPEND | 33 | #define __ARCH_WANT_SYS_RT_SIGSUSPEND |
34 | #define __ARCH_WANT_SYS_EXECVE | 34 | #define __ARCH_WANT_SYS_EXECVE |
35 | #define __ARCH_WANT_KERNEL_EXECVE | ||
36 | 35 | ||
37 | /* | 36 | /* |
38 | * "Conditional" syscalls | 37 | * "Conditional" syscalls |
diff --git a/arch/m68k/kernel/entry.S b/arch/m68k/kernel/entry.S index 946cb0187751..45b2f293f8cf 100644 --- a/arch/m68k/kernel/entry.S +++ b/arch/m68k/kernel/entry.S | |||
@@ -115,16 +115,9 @@ ENTRY(ret_from_kernel_thread) | |||
115 | | a3 contains the kernel thread payload, d7 - its argument | 115 | | a3 contains the kernel thread payload, d7 - its argument |
116 | movel %d1,%sp@- | 116 | movel %d1,%sp@- |
117 | jsr schedule_tail | 117 | jsr schedule_tail |
118 | GET_CURRENT(%d0) | ||
119 | movel %d7,(%sp) | 118 | movel %d7,(%sp) |
120 | jsr %a3@ | 119 | jsr %a3@ |
121 | addql #4,%sp | 120 | addql #4,%sp |
122 | movel %d0,(%sp) | ||
123 | jra sys_exit | ||
124 | |||
125 | ENTRY(ret_from_kernel_execve) | ||
126 | movel 4(%sp), %sp | ||
127 | GET_CURRENT(%d0) | ||
128 | jra ret_from_exception | 121 | jra ret_from_exception |
129 | 122 | ||
130 | #if defined(CONFIG_COLDFIRE) || !defined(CONFIG_MMU) | 123 | #if defined(CONFIG_COLDFIRE) || !defined(CONFIG_MMU) |
diff --git a/arch/microblaze/Kconfig b/arch/microblaze/Kconfig index 4cba7439f9de..198abf6d41c4 100644 --- a/arch/microblaze/Kconfig +++ b/arch/microblaze/Kconfig | |||
@@ -26,6 +26,8 @@ config MICROBLAZE | |||
26 | select GENERIC_ATOMIC64 | 26 | select GENERIC_ATOMIC64 |
27 | select GENERIC_CLOCKEVENTS | 27 | select GENERIC_CLOCKEVENTS |
28 | select MODULES_USE_ELF_RELA | 28 | select MODULES_USE_ELF_RELA |
29 | select GENERIC_KERNEL_THREAD | ||
30 | select GENERIC_KERNEL_EXECVE | ||
29 | 31 | ||
30 | config SWAP | 32 | config SWAP |
31 | def_bool n | 33 | def_bool n |
diff --git a/arch/microblaze/include/asm/processor.h b/arch/microblaze/include/asm/processor.h index af2bb9652392..0759153e8117 100644 --- a/arch/microblaze/include/asm/processor.h +++ b/arch/microblaze/include/asm/processor.h | |||
@@ -31,6 +31,7 @@ extern const struct seq_operations cpuinfo_op; | |||
31 | void start_thread(struct pt_regs *regs, unsigned long pc, unsigned long usp); | 31 | void start_thread(struct pt_regs *regs, unsigned long pc, unsigned long usp); |
32 | 32 | ||
33 | extern void ret_from_fork(void); | 33 | extern void ret_from_fork(void); |
34 | extern void ret_from_kernel_thread(void); | ||
34 | 35 | ||
35 | # endif /* __ASSEMBLY__ */ | 36 | # endif /* __ASSEMBLY__ */ |
36 | 37 | ||
@@ -78,11 +79,6 @@ extern unsigned long thread_saved_pc(struct task_struct *t); | |||
78 | 79 | ||
79 | extern unsigned long get_wchan(struct task_struct *p); | 80 | extern unsigned long get_wchan(struct task_struct *p); |
80 | 81 | ||
81 | /* | ||
82 | * create a kernel thread without removing it from tasklists | ||
83 | */ | ||
84 | extern int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags); | ||
85 | |||
86 | # define KSTK_EIP(tsk) (0) | 82 | # define KSTK_EIP(tsk) (0) |
87 | # define KSTK_ESP(tsk) (0) | 83 | # define KSTK_ESP(tsk) (0) |
88 | 84 | ||
@@ -131,8 +127,6 @@ extern inline void release_thread(struct task_struct *dead_task) | |||
131 | { | 127 | { |
132 | } | 128 | } |
133 | 129 | ||
134 | extern int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags); | ||
135 | |||
136 | /* Free current thread data structures etc. */ | 130 | /* Free current thread data structures etc. */ |
137 | static inline void exit_thread(void) | 131 | static inline void exit_thread(void) |
138 | { | 132 | { |
diff --git a/arch/microblaze/include/asm/unistd.h b/arch/microblaze/include/asm/unistd.h index 6985e6e9d826..ea7442834294 100644 --- a/arch/microblaze/include/asm/unistd.h +++ b/arch/microblaze/include/asm/unistd.h | |||
@@ -422,6 +422,7 @@ | |||
422 | #define __ARCH_WANT_SYS_SIGPROCMASK | 422 | #define __ARCH_WANT_SYS_SIGPROCMASK |
423 | #define __ARCH_WANT_SYS_RT_SIGACTION | 423 | #define __ARCH_WANT_SYS_RT_SIGACTION |
424 | #define __ARCH_WANT_SYS_RT_SIGSUSPEND | 424 | #define __ARCH_WANT_SYS_RT_SIGSUSPEND |
425 | #define __ARCH_WANT_SYS_EXECVE | ||
425 | 426 | ||
426 | /* | 427 | /* |
427 | * "Conditional" syscalls | 428 | * "Conditional" syscalls |
diff --git a/arch/microblaze/kernel/entry-nommu.S b/arch/microblaze/kernel/entry-nommu.S index 75c3ea1f48a1..673a49c04a02 100644 --- a/arch/microblaze/kernel/entry-nommu.S +++ b/arch/microblaze/kernel/entry-nommu.S | |||
@@ -474,6 +474,14 @@ ENTRY(ret_from_fork) | |||
474 | brid ret_to_user | 474 | brid ret_to_user |
475 | nop | 475 | nop |
476 | 476 | ||
477 | ENTRY(ret_from_kernel_thread) | ||
478 | brlid r15, schedule_tail | ||
479 | addk r5, r0, r3 | ||
480 | brald r15, r20 | ||
481 | addk r5, r0, r19 | ||
482 | brid ret_to_user | ||
483 | addk r3, r0, r0 | ||
484 | |||
477 | work_pending: | 485 | work_pending: |
478 | enable_irq | 486 | enable_irq |
479 | 487 | ||
@@ -559,10 +567,6 @@ sys_clone: | |||
559 | brid microblaze_clone | 567 | brid microblaze_clone |
560 | addk r7, r1, r0 | 568 | addk r7, r1, r0 |
561 | 569 | ||
562 | sys_execve: | ||
563 | brid microblaze_execve | ||
564 | addk r8, r1, r0 | ||
565 | |||
566 | sys_rt_sigreturn_wrapper: | 570 | sys_rt_sigreturn_wrapper: |
567 | brid sys_rt_sigreturn | 571 | brid sys_rt_sigreturn |
568 | addk r5, r1, r0 | 572 | addk r5, r1, r0 |
diff --git a/arch/microblaze/kernel/entry.S b/arch/microblaze/kernel/entry.S index 03f7b8ce6b6b..10f360ed82b4 100644 --- a/arch/microblaze/kernel/entry.S +++ b/arch/microblaze/kernel/entry.S | |||
@@ -293,24 +293,6 @@ C_ENTRY(_user_exception): | |||
293 | swi r1, r0, TOPHYS(PER_CPU(ENTRY_SP)) /* save stack */ | 293 | swi r1, r0, TOPHYS(PER_CPU(ENTRY_SP)) /* save stack */ |
294 | addi r14, r14, 4 /* return address is 4 byte after call */ | 294 | addi r14, r14, 4 /* return address is 4 byte after call */ |
295 | 295 | ||
296 | mfs r1, rmsr | ||
297 | nop | ||
298 | andi r1, r1, MSR_UMS | ||
299 | bnei r1, 1f | ||
300 | |||
301 | /* Kernel-mode state save - kernel execve */ | ||
302 | lwi r1, r0, TOPHYS(PER_CPU(ENTRY_SP)); /* Reload kernel stack-ptr*/ | ||
303 | tophys(r1,r1); | ||
304 | |||
305 | addik r1, r1, -PT_SIZE; /* Make room on the stack. */ | ||
306 | SAVE_REGS | ||
307 | |||
308 | swi r1, r1, PT_MODE; /* pt_regs -> kernel mode */ | ||
309 | brid 2f; | ||
310 | nop; /* Fill delay slot */ | ||
311 | |||
312 | /* User-mode state save. */ | ||
313 | 1: | ||
314 | lwi r1, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); /* get saved current */ | 296 | lwi r1, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); /* get saved current */ |
315 | tophys(r1,r1); | 297 | tophys(r1,r1); |
316 | lwi r1, r1, TS_THREAD_INFO; /* get stack from task_struct */ | 298 | lwi r1, r1, TS_THREAD_INFO; /* get stack from task_struct */ |
@@ -479,11 +461,20 @@ C_ENTRY(sys_fork_wrapper): | |||
479 | saved context). */ | 461 | saved context). */ |
480 | C_ENTRY(ret_from_fork): | 462 | C_ENTRY(ret_from_fork): |
481 | bralid r15, schedule_tail; /* ...which is schedule_tail's arg */ | 463 | bralid r15, schedule_tail; /* ...which is schedule_tail's arg */ |
482 | add r3, r5, r0; /* switch_thread returns the prev task */ | 464 | add r5, r3, r0; /* switch_thread returns the prev task */ |
483 | /* ( in the delay slot ) */ | 465 | /* ( in the delay slot ) */ |
484 | brid ret_from_trap; /* Do normal trap return */ | 466 | brid ret_from_trap; /* Do normal trap return */ |
485 | add r3, r0, r0; /* Child's fork call should return 0. */ | 467 | add r3, r0, r0; /* Child's fork call should return 0. */ |
486 | 468 | ||
469 | C_ENTRY(ret_from_kernel_thread): | ||
470 | bralid r15, schedule_tail; /* ...which is schedule_tail's arg */ | ||
471 | add r5, r3, r0; /* switch_thread returns the prev task */ | ||
472 | /* ( in the delay slot ) */ | ||
473 | brald r15, r20 /* fn was left in r20 */ | ||
474 | addk r5, r0, r19 /* ... and argument - in r19 */ | ||
475 | brid ret_from_trap | ||
476 | add r3, r0, r0 | ||
477 | |||
487 | C_ENTRY(sys_vfork): | 478 | C_ENTRY(sys_vfork): |
488 | brid microblaze_vfork /* Do real work (tail-call) */ | 479 | brid microblaze_vfork /* Do real work (tail-call) */ |
489 | addik r5, r1, 0 | 480 | addik r5, r1, 0 |
@@ -498,10 +489,6 @@ C_ENTRY(sys_clone): | |||
498 | brid do_fork /* Do real work (tail-call) */ | 489 | brid do_fork /* Do real work (tail-call) */ |
499 | add r8, r0, r0; /* Arg 3: (unused) */ | 490 | add r8, r0, r0; /* Arg 3: (unused) */ |
500 | 491 | ||
501 | C_ENTRY(sys_execve): | ||
502 | brid microblaze_execve; /* Do real work (tail-call).*/ | ||
503 | addik r8, r1, 0; /* add user context as 4th arg */ | ||
504 | |||
505 | C_ENTRY(sys_rt_sigreturn_wrapper): | 492 | C_ENTRY(sys_rt_sigreturn_wrapper): |
506 | brid sys_rt_sigreturn /* Do real work */ | 493 | brid sys_rt_sigreturn /* Do real work */ |
507 | addik r5, r1, 0; /* add user context as 1st arg */ | 494 | addik r5, r1, 0; /* add user context as 1st arg */ |
diff --git a/arch/microblaze/kernel/process.c b/arch/microblaze/kernel/process.c index 1944e00f07e1..29768c3dc358 100644 --- a/arch/microblaze/kernel/process.c +++ b/arch/microblaze/kernel/process.c | |||
@@ -119,46 +119,38 @@ void flush_thread(void) | |||
119 | } | 119 | } |
120 | 120 | ||
121 | int copy_thread(unsigned long clone_flags, unsigned long usp, | 121 | int copy_thread(unsigned long clone_flags, unsigned long usp, |
122 | unsigned long unused, | 122 | unsigned long arg, |
123 | struct task_struct *p, struct pt_regs *regs) | 123 | struct task_struct *p, struct pt_regs *regs) |
124 | { | 124 | { |
125 | struct pt_regs *childregs = task_pt_regs(p); | 125 | struct pt_regs *childregs = task_pt_regs(p); |
126 | struct thread_info *ti = task_thread_info(p); | 126 | struct thread_info *ti = task_thread_info(p); |
127 | 127 | ||
128 | if (unlikely(p->flags & PF_KTHREAD)) { | ||
129 | /* if we're creating a new kernel thread then just zeroing all | ||
130 | * the registers. That's OK for a brand new thread.*/ | ||
131 | memset(childregs, 0, sizeof(struct pt_regs)); | ||
132 | memset(&ti->cpu_context, 0, sizeof(struct cpu_context)); | ||
133 | ti->cpu_context.r1 = (unsigned long)childregs; | ||
134 | ti->cpu_context.r20 = (unsigned long)usp; /* fn */ | ||
135 | ti->cpu_context.r19 = (unsigned long)arg; | ||
136 | childregs->pt_mode = 1; | ||
137 | local_save_flags(childregs->msr); | ||
138 | #ifdef CONFIG_MMU | ||
139 | ti->cpu_context.msr = childregs->msr & ~MSR_IE; | ||
140 | #endif | ||
141 | ti->cpu_context.r15 = (unsigned long)ret_from_kernel_thread - 8; | ||
142 | return 0; | ||
143 | } | ||
128 | *childregs = *regs; | 144 | *childregs = *regs; |
129 | if (user_mode(regs)) | 145 | childregs->r1 = usp; |
130 | childregs->r1 = usp; | ||
131 | else | ||
132 | childregs->r1 = ((unsigned long) ti) + THREAD_SIZE; | ||
133 | 146 | ||
134 | #ifndef CONFIG_MMU | ||
135 | memset(&ti->cpu_context, 0, sizeof(struct cpu_context)); | 147 | memset(&ti->cpu_context, 0, sizeof(struct cpu_context)); |
136 | ti->cpu_context.r1 = (unsigned long)childregs; | 148 | ti->cpu_context.r1 = (unsigned long)childregs; |
149 | #ifndef CONFIG_MMU | ||
137 | ti->cpu_context.msr = (unsigned long)childregs->msr; | 150 | ti->cpu_context.msr = (unsigned long)childregs->msr; |
138 | #else | 151 | #else |
152 | childregs->msr |= MSR_UMS; | ||
139 | 153 | ||
140 | /* if creating a kernel thread then update the current reg (we don't | ||
141 | * want to use the parent's value when restoring by POP_STATE) */ | ||
142 | if (kernel_mode(regs)) | ||
143 | /* save new current on stack to use POP_STATE */ | ||
144 | childregs->CURRENT_TASK = (unsigned long)p; | ||
145 | /* if returning to user then use the parent's value of this register */ | ||
146 | |||
147 | /* if we're creating a new kernel thread then just zeroing all | ||
148 | * the registers. That's OK for a brand new thread.*/ | ||
149 | /* Pls. note that some of them will be restored in POP_STATE */ | ||
150 | if (kernel_mode(regs)) | ||
151 | memset(&ti->cpu_context, 0, sizeof(struct cpu_context)); | ||
152 | /* if this thread is created for fork/vfork/clone, then we want to | ||
153 | * restore all the parent's context */ | ||
154 | /* in addition to the registers which will be restored by POP_STATE */ | ||
155 | else { | ||
156 | ti->cpu_context = *(struct cpu_context *)regs; | ||
157 | childregs->msr |= MSR_UMS; | ||
158 | } | ||
159 | |||
160 | /* FIXME STATE_SAVE_PT_OFFSET; */ | ||
161 | ti->cpu_context.r1 = (unsigned long)childregs; | ||
162 | /* we should consider the fact that childregs is a copy of the parent | 154 | /* we should consider the fact that childregs is a copy of the parent |
163 | * regs which were saved immediately after entering the kernel state | 155 | * regs which were saved immediately after entering the kernel state |
164 | * before enabling VM. This MSR will be restored in switch_to and | 156 | * before enabling VM. This MSR will be restored in switch_to and |
@@ -209,29 +201,6 @@ unsigned long thread_saved_pc(struct task_struct *tsk) | |||
209 | } | 201 | } |
210 | #endif | 202 | #endif |
211 | 203 | ||
212 | static void kernel_thread_helper(int (*fn)(void *), void *arg) | ||
213 | { | ||
214 | fn(arg); | ||
215 | do_exit(-1); | ||
216 | } | ||
217 | |||
218 | int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags) | ||
219 | { | ||
220 | struct pt_regs regs; | ||
221 | |||
222 | memset(®s, 0, sizeof(regs)); | ||
223 | /* store them in non-volatile registers */ | ||
224 | regs.r5 = (unsigned long)fn; | ||
225 | regs.r6 = (unsigned long)arg; | ||
226 | local_save_flags(regs.msr); | ||
227 | regs.pc = (unsigned long)kernel_thread_helper; | ||
228 | regs.pt_mode = 1; | ||
229 | |||
230 | return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, | ||
231 | ®s, 0, NULL, NULL); | ||
232 | } | ||
233 | EXPORT_SYMBOL_GPL(kernel_thread); | ||
234 | |||
235 | unsigned long get_wchan(struct task_struct *p) | 204 | unsigned long get_wchan(struct task_struct *p) |
236 | { | 205 | { |
237 | /* TBD (used by procfs) */ | 206 | /* TBD (used by procfs) */ |
@@ -246,6 +215,7 @@ void start_thread(struct pt_regs *regs, unsigned long pc, unsigned long usp) | |||
246 | regs->pt_mode = 0; | 215 | regs->pt_mode = 0; |
247 | #ifdef CONFIG_MMU | 216 | #ifdef CONFIG_MMU |
248 | regs->msr |= MSR_UMS; | 217 | regs->msr |= MSR_UMS; |
218 | regs->msr &= ~MSR_VM; | ||
249 | #endif | 219 | #endif |
250 | } | 220 | } |
251 | 221 | ||
diff --git a/arch/microblaze/kernel/sys_microblaze.c b/arch/microblaze/kernel/sys_microblaze.c index 404c0f24bd41..a6a7bae9f5c6 100644 --- a/arch/microblaze/kernel/sys_microblaze.c +++ b/arch/microblaze/kernel/sys_microblaze.c | |||
@@ -48,24 +48,6 @@ asmlinkage long microblaze_clone(int flags, unsigned long stack, | |||
48 | return do_fork(flags, stack, regs, 0, NULL, NULL); | 48 | return do_fork(flags, stack, regs, 0, NULL, NULL); |
49 | } | 49 | } |
50 | 50 | ||
51 | asmlinkage long microblaze_execve(const char __user *filenamei, | ||
52 | const char __user *const __user *argv, | ||
53 | const char __user *const __user *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 = do_execve(filename->name, argv, envp, regs); | ||
64 | putname(filename); | ||
65 | out: | ||
66 | return error; | ||
67 | } | ||
68 | |||
69 | asmlinkage long sys_mmap(unsigned long addr, unsigned long len, | 51 | asmlinkage long sys_mmap(unsigned long addr, unsigned long len, |
70 | unsigned long prot, unsigned long flags, | 52 | unsigned long prot, unsigned long flags, |
71 | unsigned long fd, off_t pgoff) | 53 | unsigned long fd, off_t pgoff) |
@@ -75,24 +57,3 @@ asmlinkage long sys_mmap(unsigned long addr, unsigned long len, | |||
75 | 57 | ||
76 | return sys_mmap_pgoff(addr, len, prot, flags, fd, pgoff >> PAGE_SHIFT); | 58 | return sys_mmap_pgoff(addr, len, prot, flags, fd, pgoff >> PAGE_SHIFT); |
77 | } | 59 | } |
78 | |||
79 | /* | ||
80 | * Do a system call from kernel instead of calling sys_execve so we | ||
81 | * end up with proper pt_regs. | ||
82 | */ | ||
83 | int kernel_execve(const char *filename, | ||
84 | const char *const argv[], | ||
85 | const char *const envp[]) | ||
86 | { | ||
87 | register const char *__a __asm__("r5") = filename; | ||
88 | register const void *__b __asm__("r6") = argv; | ||
89 | register const void *__c __asm__("r7") = envp; | ||
90 | register unsigned long __syscall __asm__("r12") = __NR_execve; | ||
91 | register unsigned long __ret __asm__("r3"); | ||
92 | __asm__ __volatile__ ("brki r14, 0x8" | ||
93 | : "=r" (__ret), "=r" (__syscall) | ||
94 | : "1" (__syscall), "r" (__a), "r" (__b), "r" (__c) | ||
95 | : "r4", "r8", "r9", | ||
96 | "r10", "r11", "r14", "cc", "memory"); | ||
97 | return __ret; | ||
98 | } | ||
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index dba9390d37cf..4183e62f178c 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig | |||
@@ -40,6 +40,8 @@ config MIPS | |||
40 | select HAVE_MOD_ARCH_SPECIFIC | 40 | select HAVE_MOD_ARCH_SPECIFIC |
41 | select MODULES_USE_ELF_REL | 41 | select MODULES_USE_ELF_REL |
42 | select MODULES_USE_ELF_RELA if 64BIT | 42 | select MODULES_USE_ELF_RELA if 64BIT |
43 | select GENERIC_KERNEL_THREAD | ||
44 | select GENERIC_KERNEL_EXECVE | ||
43 | 45 | ||
44 | menu "Machine selection" | 46 | menu "Machine selection" |
45 | 47 | ||
diff --git a/arch/mips/include/asm/processor.h b/arch/mips/include/asm/processor.h index 5e33fabe354d..d28c41e0887c 100644 --- a/arch/mips/include/asm/processor.h +++ b/arch/mips/include/asm/processor.h | |||
@@ -310,8 +310,6 @@ struct task_struct; | |||
310 | /* Free all resources held by a thread. */ | 310 | /* Free all resources held by a thread. */ |
311 | #define release_thread(thread) do { } while(0) | 311 | #define release_thread(thread) do { } while(0) |
312 | 312 | ||
313 | extern long kernel_thread(int (*fn)(void *), void * arg, unsigned long flags); | ||
314 | |||
315 | extern unsigned long thread_saved_pc(struct task_struct *tsk); | 313 | extern unsigned long thread_saved_pc(struct task_struct *tsk); |
316 | 314 | ||
317 | /* | 315 | /* |
diff --git a/arch/mips/include/asm/ptrace.h b/arch/mips/include/asm/ptrace.h index 4f5da948a777..cec5e125f7e4 100644 --- a/arch/mips/include/asm/ptrace.h +++ b/arch/mips/include/asm/ptrace.h | |||
@@ -61,4 +61,10 @@ static inline void die_if_kernel(const char *str, struct pt_regs *regs) | |||
61 | die(str, regs); | 61 | die(str, regs); |
62 | } | 62 | } |
63 | 63 | ||
64 | #define current_pt_regs() \ | ||
65 | ({ \ | ||
66 | unsigned long sp = (unsigned long)__builtin_frame_address(0); \ | ||
67 | (struct pt_regs *)((sp | (THREAD_SIZE - 1)) + 1 - 32) - 1; \ | ||
68 | }) | ||
69 | |||
64 | #endif /* _ASM_PTRACE_H */ | 70 | #endif /* _ASM_PTRACE_H */ |
diff --git a/arch/mips/include/asm/unistd.h b/arch/mips/include/asm/unistd.h index 9e47cc11aa26..b306e2081cad 100644 --- a/arch/mips/include/asm/unistd.h +++ b/arch/mips/include/asm/unistd.h | |||
@@ -20,6 +20,7 @@ | |||
20 | #define __ARCH_OMIT_COMPAT_SYS_GETDENTS64 | 20 | #define __ARCH_OMIT_COMPAT_SYS_GETDENTS64 |
21 | #define __ARCH_WANT_OLD_READDIR | 21 | #define __ARCH_WANT_OLD_READDIR |
22 | #define __ARCH_WANT_SYS_ALARM | 22 | #define __ARCH_WANT_SYS_ALARM |
23 | #define __ARCH_WANT_SYS_EXECVE | ||
23 | #define __ARCH_WANT_SYS_GETHOSTNAME | 24 | #define __ARCH_WANT_SYS_GETHOSTNAME |
24 | #define __ARCH_WANT_SYS_IPC | 25 | #define __ARCH_WANT_SYS_IPC |
25 | #define __ARCH_WANT_SYS_PAUSE | 26 | #define __ARCH_WANT_SYS_PAUSE |
diff --git a/arch/mips/kernel/entry.S b/arch/mips/kernel/entry.S index a6c133212003..3320cb4ac1d4 100644 --- a/arch/mips/kernel/entry.S +++ b/arch/mips/kernel/entry.S | |||
@@ -65,6 +65,12 @@ need_resched: | |||
65 | b need_resched | 65 | b need_resched |
66 | #endif | 66 | #endif |
67 | 67 | ||
68 | FEXPORT(ret_from_kernel_thread) | ||
69 | jal schedule_tail # a0 = struct task_struct *prev | ||
70 | move a0, s1 | ||
71 | jal s0 | ||
72 | j syscall_exit | ||
73 | |||
68 | FEXPORT(ret_from_fork) | 74 | FEXPORT(ret_from_fork) |
69 | jal schedule_tail # a0 = struct task_struct *prev | 75 | jal schedule_tail # a0 = struct task_struct *prev |
70 | 76 | ||
diff --git a/arch/mips/kernel/linux32.c b/arch/mips/kernel/linux32.c index 3a21acedf882..8796dbc7e358 100644 --- a/arch/mips/kernel/linux32.c +++ b/arch/mips/kernel/linux32.c | |||
@@ -3,7 +3,6 @@ | |||
3 | * | 3 | * |
4 | * Copyright (C) 2000 Silicon Graphics, Inc. | 4 | * Copyright (C) 2000 Silicon Graphics, Inc. |
5 | * Written by Ulf Carlsson (ulfc@engr.sgi.com) | 5 | * Written by Ulf Carlsson (ulfc@engr.sgi.com) |
6 | * sys32_execve from ia64/ia32 code, Feb 2000, Kanoj Sarcar (kanoj@sgi.com) | ||
7 | */ | 6 | */ |
8 | #include <linux/compiler.h> | 7 | #include <linux/compiler.h> |
9 | #include <linux/mm.h> | 8 | #include <linux/mm.h> |
@@ -77,26 +76,6 @@ out: | |||
77 | return error; | 76 | return error; |
78 | } | 77 | } |
79 | 78 | ||
80 | /* | ||
81 | * sys_execve() executes a new program. | ||
82 | */ | ||
83 | asmlinkage int sys32_execve(nabi_no_regargs struct pt_regs regs) | ||
84 | { | ||
85 | int error; | ||
86 | struct filename *filename; | ||
87 | |||
88 | filename = getname(compat_ptr(regs.regs[4])); | ||
89 | error = PTR_ERR(filename); | ||
90 | if (IS_ERR(filename)) | ||
91 | goto out; | ||
92 | error = compat_do_execve(filename->name, compat_ptr(regs.regs[5]), | ||
93 | compat_ptr(regs.regs[6]), ®s); | ||
94 | putname(filename); | ||
95 | |||
96 | out: | ||
97 | return error; | ||
98 | } | ||
99 | |||
100 | #define RLIM_INFINITY32 0x7fffffff | 79 | #define RLIM_INFINITY32 0x7fffffff |
101 | #define RESOURCE32(x) ((x > RLIM_INFINITY32) ? RLIM_INFINITY32 : x) | 80 | #define RESOURCE32(x) ((x > RLIM_INFINITY32) ? RLIM_INFINITY32 : x) |
102 | 81 | ||
diff --git a/arch/mips/kernel/mips_ksyms.c b/arch/mips/kernel/mips_ksyms.c index 3fc1691110dc..2d9304c2b54c 100644 --- a/arch/mips/kernel/mips_ksyms.c +++ b/arch/mips/kernel/mips_ksyms.c | |||
@@ -32,8 +32,6 @@ EXPORT_SYMBOL(memset); | |||
32 | EXPORT_SYMBOL(memcpy); | 32 | EXPORT_SYMBOL(memcpy); |
33 | EXPORT_SYMBOL(memmove); | 33 | EXPORT_SYMBOL(memmove); |
34 | 34 | ||
35 | EXPORT_SYMBOL(kernel_thread); | ||
36 | |||
37 | /* | 35 | /* |
38 | * Functions that operate on entire pages. Mostly used by memory management. | 36 | * Functions that operate on entire pages. Mostly used by memory management. |
39 | */ | 37 | */ |
diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c index e9a5fd7277f4..d13720ac656f 100644 --- a/arch/mips/kernel/process.c +++ b/arch/mips/kernel/process.c | |||
@@ -84,6 +84,7 @@ void __noreturn cpu_idle(void) | |||
84 | } | 84 | } |
85 | 85 | ||
86 | asmlinkage void ret_from_fork(void); | 86 | asmlinkage void ret_from_fork(void); |
87 | asmlinkage void ret_from_kernel_thread(void); | ||
87 | 88 | ||
88 | void start_thread(struct pt_regs * regs, unsigned long pc, unsigned long sp) | 89 | void start_thread(struct pt_regs * regs, unsigned long pc, unsigned long sp) |
89 | { | 90 | { |
@@ -113,7 +114,7 @@ void flush_thread(void) | |||
113 | } | 114 | } |
114 | 115 | ||
115 | int copy_thread(unsigned long clone_flags, unsigned long usp, | 116 | int copy_thread(unsigned long clone_flags, unsigned long usp, |
116 | unsigned long unused, struct task_struct *p, struct pt_regs *regs) | 117 | unsigned long arg, struct task_struct *p, struct pt_regs *regs) |
117 | { | 118 | { |
118 | struct thread_info *ti = task_thread_info(p); | 119 | struct thread_info *ti = task_thread_info(p); |
119 | struct pt_regs *childregs; | 120 | struct pt_regs *childregs; |
@@ -136,19 +137,30 @@ int copy_thread(unsigned long clone_flags, unsigned long usp, | |||
136 | childregs = (struct pt_regs *) childksp - 1; | 137 | childregs = (struct pt_regs *) childksp - 1; |
137 | /* Put the stack after the struct pt_regs. */ | 138 | /* Put the stack after the struct pt_regs. */ |
138 | childksp = (unsigned long) childregs; | 139 | childksp = (unsigned long) childregs; |
140 | p->thread.cp0_status = read_c0_status() & ~(ST0_CU2|ST0_CU1); | ||
141 | if (unlikely(p->flags & PF_KTHREAD)) { | ||
142 | unsigned long status = p->thread.cp0_status; | ||
143 | memset(childregs, 0, sizeof(struct pt_regs)); | ||
144 | ti->addr_limit = KERNEL_DS; | ||
145 | p->thread.reg16 = usp; /* fn */ | ||
146 | p->thread.reg17 = arg; | ||
147 | p->thread.reg29 = childksp; | ||
148 | p->thread.reg31 = (unsigned long) ret_from_kernel_thread; | ||
149 | #if defined(CONFIG_CPU_R3000) || defined(CONFIG_CPU_TX39XX) | ||
150 | status = (status & ~(ST0_KUP | ST0_IEP | ST0_IEC)) | | ||
151 | ((status & (ST0_KUC | ST0_IEC)) << 2); | ||
152 | #else | ||
153 | status |= ST0_EXL; | ||
154 | #endif | ||
155 | childregs->cp0_status = status; | ||
156 | return 0; | ||
157 | } | ||
139 | *childregs = *regs; | 158 | *childregs = *regs; |
140 | childregs->regs[7] = 0; /* Clear error flag */ | 159 | childregs->regs[7] = 0; /* Clear error flag */ |
141 | |||
142 | childregs->regs[2] = 0; /* Child gets zero as return value */ | 160 | childregs->regs[2] = 0; /* Child gets zero as return value */ |
161 | childregs->regs[29] = usp; | ||
162 | ti->addr_limit = USER_DS; | ||
143 | 163 | ||
144 | if (childregs->cp0_status & ST0_CU0) { | ||
145 | childregs->regs[28] = (unsigned long) ti; | ||
146 | childregs->regs[29] = childksp; | ||
147 | ti->addr_limit = KERNEL_DS; | ||
148 | } else { | ||
149 | childregs->regs[29] = usp; | ||
150 | ti->addr_limit = USER_DS; | ||
151 | } | ||
152 | p->thread.reg29 = (unsigned long) childregs; | 164 | p->thread.reg29 = (unsigned long) childregs; |
153 | p->thread.reg31 = (unsigned long) ret_from_fork; | 165 | p->thread.reg31 = (unsigned long) ret_from_fork; |
154 | 166 | ||
@@ -156,7 +168,6 @@ int copy_thread(unsigned long clone_flags, unsigned long usp, | |||
156 | * New tasks lose permission to use the fpu. This accelerates context | 168 | * New tasks lose permission to use the fpu. This accelerates context |
157 | * switching for most programs since they don't use the fpu. | 169 | * switching for most programs since they don't use the fpu. |
158 | */ | 170 | */ |
159 | p->thread.cp0_status = read_c0_status() & ~(ST0_CU2|ST0_CU1); | ||
160 | childregs->cp0_status &= ~(ST0_CU2|ST0_CU1); | 171 | childregs->cp0_status &= ~(ST0_CU2|ST0_CU1); |
161 | 172 | ||
162 | #ifdef CONFIG_MIPS_MT_SMTC | 173 | #ifdef CONFIG_MIPS_MT_SMTC |
@@ -222,35 +233,6 @@ int dump_task_fpu(struct task_struct *t, elf_fpregset_t *fpr) | |||
222 | } | 233 | } |
223 | 234 | ||
224 | /* | 235 | /* |
225 | * Create a kernel thread | ||
226 | */ | ||
227 | static void __noreturn kernel_thread_helper(void *arg, int (*fn)(void *)) | ||
228 | { | ||
229 | do_exit(fn(arg)); | ||
230 | } | ||
231 | |||
232 | long kernel_thread(int (*fn)(void *), void *arg, unsigned long flags) | ||
233 | { | ||
234 | struct pt_regs regs; | ||
235 | |||
236 | memset(®s, 0, sizeof(regs)); | ||
237 | |||
238 | regs.regs[4] = (unsigned long) arg; | ||
239 | regs.regs[5] = (unsigned long) fn; | ||
240 | regs.cp0_epc = (unsigned long) kernel_thread_helper; | ||
241 | regs.cp0_status = read_c0_status(); | ||
242 | #if defined(CONFIG_CPU_R3000) || defined(CONFIG_CPU_TX39XX) | ||
243 | regs.cp0_status = (regs.cp0_status & ~(ST0_KUP | ST0_IEP | ST0_IEC)) | | ||
244 | ((regs.cp0_status & (ST0_KUC | ST0_IEC)) << 2); | ||
245 | #else | ||
246 | regs.cp0_status |= ST0_EXL; | ||
247 | #endif | ||
248 | |||
249 | /* Ok, create the new process.. */ | ||
250 | return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, ®s, 0, NULL, NULL); | ||
251 | } | ||
252 | |||
253 | /* | ||
254 | * | 236 | * |
255 | */ | 237 | */ |
256 | struct mips_frame_info { | 238 | struct mips_frame_info { |
diff --git a/arch/mips/kernel/scall64-n32.S b/arch/mips/kernel/scall64-n32.S index f6ba8381ee01..d27ca340d46d 100644 --- a/arch/mips/kernel/scall64-n32.S +++ b/arch/mips/kernel/scall64-n32.S | |||
@@ -167,7 +167,7 @@ EXPORT(sysn32_call_table) | |||
167 | PTR sys_getsockopt | 167 | PTR sys_getsockopt |
168 | PTR sys_clone /* 6055 */ | 168 | PTR sys_clone /* 6055 */ |
169 | PTR sys_fork | 169 | PTR sys_fork |
170 | PTR sys32_execve | 170 | PTR compat_sys_execve |
171 | PTR sys_exit | 171 | PTR sys_exit |
172 | PTR compat_sys_wait4 | 172 | PTR compat_sys_wait4 |
173 | PTR sys_kill /* 6060 */ | 173 | PTR sys_kill /* 6060 */ |
diff --git a/arch/mips/kernel/scall64-o32.S b/arch/mips/kernel/scall64-o32.S index 53c2d7245764..9601be6afa3d 100644 --- a/arch/mips/kernel/scall64-o32.S +++ b/arch/mips/kernel/scall64-o32.S | |||
@@ -203,7 +203,7 @@ sys_call_table: | |||
203 | PTR sys_creat | 203 | PTR sys_creat |
204 | PTR sys_link | 204 | PTR sys_link |
205 | PTR sys_unlink /* 4010 */ | 205 | PTR sys_unlink /* 4010 */ |
206 | PTR sys32_execve | 206 | PTR compat_sys_execve |
207 | PTR sys_chdir | 207 | PTR sys_chdir |
208 | PTR compat_sys_time | 208 | PTR compat_sys_time |
209 | PTR sys_mknod | 209 | PTR sys_mknod |
diff --git a/arch/mips/kernel/syscall.c b/arch/mips/kernel/syscall.c index 2bd561bc05ae..c611e2df7767 100644 --- a/arch/mips/kernel/syscall.c +++ b/arch/mips/kernel/syscall.c | |||
@@ -127,28 +127,6 @@ _sys_clone(nabi_no_regargs struct pt_regs regs) | |||
127 | parent_tidptr, child_tidptr); | 127 | parent_tidptr, child_tidptr); |
128 | } | 128 | } |
129 | 129 | ||
130 | /* | ||
131 | * sys_execve() executes a new program. | ||
132 | */ | ||
133 | asmlinkage int sys_execve(nabi_no_regargs struct pt_regs regs) | ||
134 | { | ||
135 | int error; | ||
136 | struct filename *filename; | ||
137 | |||
138 | filename = getname((const char __user *) (long)regs.regs[4]); | ||
139 | error = PTR_ERR(filename); | ||
140 | if (IS_ERR(filename)) | ||
141 | goto out; | ||
142 | error = do_execve(filename->name, | ||
143 | (const char __user *const __user *) (long)regs.regs[5], | ||
144 | (const char __user *const __user *) (long)regs.regs[6], | ||
145 | ®s); | ||
146 | putname(filename); | ||
147 | |||
148 | out: | ||
149 | return error; | ||
150 | } | ||
151 | |||
152 | SYSCALL_DEFINE1(set_thread_area, unsigned long, addr) | 130 | SYSCALL_DEFINE1(set_thread_area, unsigned long, addr) |
153 | { | 131 | { |
154 | struct thread_info *ti = task_thread_info(current); | 132 | struct thread_info *ti = task_thread_info(current); |
@@ -313,34 +291,3 @@ asmlinkage void bad_stack(void) | |||
313 | { | 291 | { |
314 | do_exit(SIGSEGV); | 292 | do_exit(SIGSEGV); |
315 | } | 293 | } |
316 | |||
317 | /* | ||
318 | * Do a system call from kernel instead of calling sys_execve so we | ||
319 | * end up with proper pt_regs. | ||
320 | */ | ||
321 | int kernel_execve(const char *filename, | ||
322 | const char *const argv[], | ||
323 | const char *const envp[]) | ||
324 | { | ||
325 | register unsigned long __a0 asm("$4") = (unsigned long) filename; | ||
326 | register unsigned long __a1 asm("$5") = (unsigned long) argv; | ||
327 | register unsigned long __a2 asm("$6") = (unsigned long) envp; | ||
328 | register unsigned long __a3 asm("$7"); | ||
329 | unsigned long __v0; | ||
330 | |||
331 | __asm__ volatile (" \n" | ||
332 | " .set noreorder \n" | ||
333 | " li $2, %5 # __NR_execve \n" | ||
334 | " syscall \n" | ||
335 | " move %0, $2 \n" | ||
336 | " .set reorder \n" | ||
337 | : "=&r" (__v0), "=r" (__a3) | ||
338 | : "r" (__a0), "r" (__a1), "r" (__a2), "i" (__NR_execve) | ||
339 | : "$2", "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15", "$24", | ||
340 | "memory"); | ||
341 | |||
342 | if (__a3 == 0) | ||
343 | return __v0; | ||
344 | |||
345 | return -__v0; | ||
346 | } | ||
diff --git a/arch/mn10300/Kconfig b/arch/mn10300/Kconfig index 04669fac117b..72471744a912 100644 --- a/arch/mn10300/Kconfig +++ b/arch/mn10300/Kconfig | |||
@@ -9,6 +9,7 @@ config MN10300 | |||
9 | select HAVE_NMI_WATCHDOG if MN10300_WD_TIMER | 9 | select HAVE_NMI_WATCHDOG if MN10300_WD_TIMER |
10 | select GENERIC_CLOCKEVENTS | 10 | select GENERIC_CLOCKEVENTS |
11 | select GENERIC_KERNEL_THREAD | 11 | select GENERIC_KERNEL_THREAD |
12 | select GENERIC_KERNEL_EXECVE | ||
12 | select MODULES_USE_ELF_RELA | 13 | select MODULES_USE_ELF_RELA |
13 | 14 | ||
14 | config AM33_2 | 15 | config AM33_2 |
diff --git a/arch/mn10300/include/asm/unistd.h b/arch/mn10300/include/asm/unistd.h index 55bbec1887e9..9711d51b0212 100644 --- a/arch/mn10300/include/asm/unistd.h +++ b/arch/mn10300/include/asm/unistd.h | |||
@@ -44,7 +44,6 @@ | |||
44 | #define __ARCH_WANT_SYS_RT_SIGACTION | 44 | #define __ARCH_WANT_SYS_RT_SIGACTION |
45 | #define __ARCH_WANT_SYS_RT_SIGSUSPEND | 45 | #define __ARCH_WANT_SYS_RT_SIGSUSPEND |
46 | #define __ARCH_WANT_SYS_EXECVE | 46 | #define __ARCH_WANT_SYS_EXECVE |
47 | #define __ARCH_WANT_KERNEL_EXECVE | ||
48 | 47 | ||
49 | /* | 48 | /* |
50 | * "Conditional" syscalls | 49 | * "Conditional" syscalls |
diff --git a/arch/mn10300/kernel/entry.S b/arch/mn10300/kernel/entry.S index 0c631d34c8d7..68fcab8f8f6f 100644 --- a/arch/mn10300/kernel/entry.S +++ b/arch/mn10300/kernel/entry.S | |||
@@ -60,13 +60,8 @@ ENTRY(ret_from_kernel_thread) | |||
60 | mov (REG_D0,fp),d0 | 60 | mov (REG_D0,fp),d0 |
61 | mov (REG_A0,fp),a0 | 61 | mov (REG_A0,fp),a0 |
62 | calls (a0) | 62 | calls (a0) |
63 | jmp sys_exit | ||
64 | |||
65 | ENTRY(ret_from_kernel_execve) | ||
66 | add -12,d0 /* pt_regs -> frame */ | ||
67 | mov d0,sp | ||
68 | GET_THREAD_INFO a2 | ||
69 | clr d0 | 63 | clr d0 |
64 | mov d0,(REG_D0,fp) | ||
70 | jmp syscall_exit | 65 | jmp syscall_exit |
71 | 66 | ||
72 | ############################################################################### | 67 | ############################################################################### |
diff --git a/arch/openrisc/Kconfig b/arch/openrisc/Kconfig index 05f2ba41ff1a..e7f1a2993f78 100644 --- a/arch/openrisc/Kconfig +++ b/arch/openrisc/Kconfig | |||
@@ -22,6 +22,8 @@ config OPENRISC | |||
22 | select GENERIC_STRNCPY_FROM_USER | 22 | select GENERIC_STRNCPY_FROM_USER |
23 | select GENERIC_STRNLEN_USER | 23 | select GENERIC_STRNLEN_USER |
24 | select MODULES_USE_ELF_RELA | 24 | select MODULES_USE_ELF_RELA |
25 | select GENERIC_KERNEL_THREAD | ||
26 | select GENERIC_KERNEL_EXECVE | ||
25 | 27 | ||
26 | config MMU | 28 | config MMU |
27 | def_bool y | 29 | def_bool y |
diff --git a/arch/openrisc/include/uapi/asm/unistd.h b/arch/openrisc/include/uapi/asm/unistd.h index 437bdbb61b14..5db7bc0fa5a7 100644 --- a/arch/openrisc/include/uapi/asm/unistd.h +++ b/arch/openrisc/include/uapi/asm/unistd.h | |||
@@ -20,6 +20,8 @@ | |||
20 | 20 | ||
21 | #define sys_mmap2 sys_mmap_pgoff | 21 | #define sys_mmap2 sys_mmap_pgoff |
22 | 22 | ||
23 | #define __ARCH_WANT_SYS_EXECVE | ||
24 | |||
23 | #include <asm-generic/unistd.h> | 25 | #include <asm-generic/unistd.h> |
24 | 26 | ||
25 | #define __NR_or1k_atomic __NR_arch_specific_syscall | 27 | #define __NR_or1k_atomic __NR_arch_specific_syscall |
diff --git a/arch/openrisc/kernel/entry.S b/arch/openrisc/kernel/entry.S index ddfcaa828b0e..c60a09df323f 100644 --- a/arch/openrisc/kernel/entry.S +++ b/arch/openrisc/kernel/entry.S | |||
@@ -894,6 +894,16 @@ ENTRY(ret_from_fork) | |||
894 | l.jal schedule_tail | 894 | l.jal schedule_tail |
895 | l.nop | 895 | l.nop |
896 | 896 | ||
897 | /* Check if we are a kernel thread */ | ||
898 | l.sfeqi r20,0 | ||
899 | l.bf 1f | ||
900 | l.nop | ||
901 | |||
902 | /* ...we are a kernel thread so invoke the requested callback */ | ||
903 | l.jalr r20 | ||
904 | l.or r3,r22,r0 | ||
905 | |||
906 | 1: | ||
897 | /* _syscall_returns expect r11 to contain return value */ | 907 | /* _syscall_returns expect r11 to contain return value */ |
898 | l.lwz r11,PT_GPR11(r1) | 908 | l.lwz r11,PT_GPR11(r1) |
899 | 909 | ||
@@ -915,26 +925,6 @@ ENTRY(ret_from_fork) | |||
915 | l.j _syscall_return | 925 | l.j _syscall_return |
916 | l.nop | 926 | l.nop |
917 | 927 | ||
918 | /* Since syscalls don't save call-clobbered registers, the args to | ||
919 | * kernel_thread_helper will need to be passed through callee-saved | ||
920 | * registers and copied to the parameter registers when the thread | ||
921 | * begins running. | ||
922 | * | ||
923 | * See arch/openrisc/kernel/process.c: | ||
924 | * The args are passed as follows: | ||
925 | * arg1 (r3) : passed in r20 | ||
926 | * arg2 (r4) : passed in r22 | ||
927 | */ | ||
928 | |||
929 | ENTRY(_kernel_thread_helper) | ||
930 | l.or r3,r20,r0 | ||
931 | l.or r4,r22,r0 | ||
932 | l.movhi r31,hi(kernel_thread_helper) | ||
933 | l.ori r31,r31,lo(kernel_thread_helper) | ||
934 | l.jr r31 | ||
935 | l.nop | ||
936 | |||
937 | |||
938 | /* ========================================================[ switch ] === */ | 928 | /* ========================================================[ switch ] === */ |
939 | 929 | ||
940 | /* | 930 | /* |
@@ -1044,8 +1034,13 @@ ENTRY(_switch) | |||
1044 | /* Unwind stack to pre-switch state */ | 1034 | /* Unwind stack to pre-switch state */ |
1045 | l.addi r1,r1,(INT_FRAME_SIZE) | 1035 | l.addi r1,r1,(INT_FRAME_SIZE) |
1046 | 1036 | ||
1047 | /* Return via the link-register back to where we 'came from', where that can be | 1037 | /* Return via the link-register back to where we 'came from', where |
1048 | * either schedule() or return_from_fork()... */ | 1038 | * that may be either schedule(), ret_from_fork(), or |
1039 | * ret_from_kernel_thread(). If we are returning to a new thread, | ||
1040 | * we are expected to have set up the arg to schedule_tail already, | ||
1041 | * hence we do so here unconditionally: | ||
1042 | */ | ||
1043 | l.lwz r3,TI_STACK(r3) /* Load 'prev' as schedule_tail arg */ | ||
1049 | l.jr r9 | 1044 | l.jr r9 |
1050 | l.nop | 1045 | l.nop |
1051 | 1046 | ||
@@ -1088,10 +1083,6 @@ ENTRY(sys_fork) | |||
1088 | l.j _fork_save_extra_regs_and_call | 1083 | l.j _fork_save_extra_regs_and_call |
1089 | l.addi r3,r1,0 | 1084 | l.addi r3,r1,0 |
1090 | 1085 | ||
1091 | ENTRY(sys_execve) | ||
1092 | l.j _sys_execve | ||
1093 | l.addi r6,r1,0 | ||
1094 | |||
1095 | ENTRY(sys_sigaltstack) | 1086 | ENTRY(sys_sigaltstack) |
1096 | l.j _sys_sigaltstack | 1087 | l.j _sys_sigaltstack |
1097 | l.addi r5,r1,0 | 1088 | l.addi r5,r1,0 |
diff --git a/arch/openrisc/kernel/process.c b/arch/openrisc/kernel/process.c index c35f3ab1a8d3..e0874b8e09e4 100644 --- a/arch/openrisc/kernel/process.c +++ b/arch/openrisc/kernel/process.c | |||
@@ -109,66 +109,82 @@ void release_thread(struct task_struct *dead_task) | |||
109 | */ | 109 | */ |
110 | extern asmlinkage void ret_from_fork(void); | 110 | extern asmlinkage void ret_from_fork(void); |
111 | 111 | ||
112 | /* | ||
113 | * copy_thread | ||
114 | * @clone_flags: flags | ||
115 | * @usp: user stack pointer or fn for kernel thread | ||
116 | * @arg: arg to fn for kernel thread; always NULL for userspace thread | ||
117 | * @p: the newly created task | ||
118 | * @regs: CPU context to copy for userspace thread; always NULL for kthread | ||
119 | * | ||
120 | * At the top of a newly initialized kernel stack are two stacked pt_reg | ||
121 | * structures. The first (topmost) is the userspace context of the thread. | ||
122 | * The second is the kernelspace context of the thread. | ||
123 | * | ||
124 | * A kernel thread will not be returning to userspace, so the topmost pt_regs | ||
125 | * struct can be uninitialized; it _does_ need to exist, though, because | ||
126 | * a kernel thread can become a userspace thread by doing a kernel_execve, in | ||
127 | * which case the topmost context will be initialized and used for 'returning' | ||
128 | * to userspace. | ||
129 | * | ||
130 | * The second pt_reg struct needs to be initialized to 'return' to | ||
131 | * ret_from_fork. A kernel thread will need to set r20 to the address of | ||
132 | * a function to call into (with arg in r22); userspace threads need to set | ||
133 | * r20 to NULL in which case ret_from_fork will just continue a return to | ||
134 | * userspace. | ||
135 | * | ||
136 | * A kernel thread 'fn' may return; this is effectively what happens when | ||
137 | * kernel_execve is called. In that case, the userspace pt_regs must have | ||
138 | * been initialized (which kernel_execve takes care of, see start_thread | ||
139 | * below); ret_from_fork will then continue its execution causing the | ||
140 | * 'kernel thread' to return to userspace as a userspace thread. | ||
141 | */ | ||
142 | |||
112 | int | 143 | int |
113 | copy_thread(unsigned long clone_flags, unsigned long usp, | 144 | copy_thread(unsigned long clone_flags, unsigned long usp, |
114 | unsigned long unused, struct task_struct *p, struct pt_regs *regs) | 145 | unsigned long arg, struct task_struct *p, struct pt_regs *regs) |
115 | { | 146 | { |
116 | struct pt_regs *childregs; | 147 | struct pt_regs *userregs; |
117 | struct pt_regs *kregs; | 148 | struct pt_regs *kregs; |
118 | unsigned long sp = (unsigned long)task_stack_page(p) + THREAD_SIZE; | 149 | unsigned long sp = (unsigned long)task_stack_page(p) + THREAD_SIZE; |
119 | struct thread_info *ti; | ||
120 | unsigned long top_of_kernel_stack; | 150 | unsigned long top_of_kernel_stack; |
121 | 151 | ||
122 | top_of_kernel_stack = sp; | 152 | top_of_kernel_stack = sp; |
123 | 153 | ||
124 | p->set_child_tid = p->clear_child_tid = NULL; | 154 | p->set_child_tid = p->clear_child_tid = NULL; |
125 | 155 | ||
126 | /* Copy registers */ | 156 | /* Locate userspace context on stack... */ |
127 | /* redzone */ | 157 | sp -= STACK_FRAME_OVERHEAD; /* redzone */ |
128 | sp -= STACK_FRAME_OVERHEAD; | ||
129 | sp -= sizeof(struct pt_regs); | 158 | sp -= sizeof(struct pt_regs); |
130 | childregs = (struct pt_regs *)sp; | 159 | userregs = (struct pt_regs *) sp; |
131 | 160 | ||
132 | /* Copy parent registers */ | 161 | /* ...and kernel context */ |
133 | *childregs = *regs; | 162 | sp -= STACK_FRAME_OVERHEAD; /* redzone */ |
163 | sp -= sizeof(struct pt_regs); | ||
164 | kregs = (struct pt_regs *)sp; | ||
134 | 165 | ||
135 | if ((childregs->sr & SPR_SR_SM) == 1) { | 166 | if (unlikely(p->flags & PF_KTHREAD)) { |
136 | /* for kernel thread, set `current_thread_info' | 167 | memset(kregs, 0, sizeof(struct pt_regs)); |
137 | * and stackptr in new task | 168 | kregs->gpr[20] = usp; /* fn, kernel thread */ |
138 | */ | 169 | kregs->gpr[22] = arg; |
139 | childregs->sp = (unsigned long)task_stack_page(p) + THREAD_SIZE; | ||
140 | childregs->gpr[10] = (unsigned long)task_thread_info(p); | ||
141 | } else { | 170 | } else { |
142 | childregs->sp = usp; | 171 | *userregs = *regs; |
143 | } | ||
144 | |||
145 | childregs->gpr[11] = 0; /* Result from fork() */ | ||
146 | 172 | ||
147 | /* | 173 | userregs->sp = usp; |
148 | * The way this works is that at some point in the future | 174 | userregs->gpr[11] = 0; /* Result from fork() */ |
149 | * some task will call _switch to switch to the new task. | ||
150 | * That will pop off the stack frame created below and start | ||
151 | * the new task running at ret_from_fork. The new task will | ||
152 | * do some house keeping and then return from the fork or clone | ||
153 | * system call, using the stack frame created above. | ||
154 | */ | ||
155 | /* redzone */ | ||
156 | sp -= STACK_FRAME_OVERHEAD; | ||
157 | sp -= sizeof(struct pt_regs); | ||
158 | kregs = (struct pt_regs *)sp; | ||
159 | 175 | ||
160 | ti = task_thread_info(p); | 176 | kregs->gpr[20] = 0; /* Userspace thread */ |
161 | ti->ksp = sp; | 177 | } |
162 | 178 | ||
163 | /* kregs->sp must store the location of the 'pre-switch' kernel stack | 179 | /* |
164 | * pointer... for a newly forked process, this is simply the top of | 180 | * _switch wants the kernel stack page in pt_regs->sp so that it |
165 | * the kernel stack. | 181 | * can restore it to thread_info->ksp... see _switch for details. |
166 | */ | 182 | */ |
167 | kregs->sp = top_of_kernel_stack; | 183 | kregs->sp = top_of_kernel_stack; |
168 | kregs->gpr[3] = (unsigned long)current; /* arg to schedule_tail */ | ||
169 | kregs->gpr[10] = (unsigned long)task_thread_info(p); | ||
170 | kregs->gpr[9] = (unsigned long)ret_from_fork; | 184 | kregs->gpr[9] = (unsigned long)ret_from_fork; |
171 | 185 | ||
186 | task_thread_info(p)->ksp = (unsigned long)kregs; | ||
187 | |||
172 | return 0; | 188 | return 0; |
173 | } | 189 | } |
174 | 190 | ||
@@ -177,16 +193,14 @@ copy_thread(unsigned long clone_flags, unsigned long usp, | |||
177 | */ | 193 | */ |
178 | void start_thread(struct pt_regs *regs, unsigned long pc, unsigned long sp) | 194 | void start_thread(struct pt_regs *regs, unsigned long pc, unsigned long sp) |
179 | { | 195 | { |
180 | unsigned long sr = regs->sr & ~SPR_SR_SM; | 196 | unsigned long sr = mfspr(SPR_SR) & ~SPR_SR_SM; |
181 | 197 | ||
182 | set_fs(USER_DS); | 198 | set_fs(USER_DS); |
183 | memset(regs->gpr, 0, sizeof(regs->gpr)); | 199 | memset(regs, 0, sizeof(struct pt_regs)); |
184 | 200 | ||
185 | regs->pc = pc; | 201 | regs->pc = pc; |
186 | regs->sr = sr; | 202 | regs->sr = sr; |
187 | regs->sp = sp; | 203 | regs->sp = sp; |
188 | |||
189 | /* printk("start thread, ksp = %lx\n", current_thread_info()->ksp);*/ | ||
190 | } | 204 | } |
191 | 205 | ||
192 | /* Fill in the fpu structure for a core dump. */ | 206 | /* Fill in the fpu structure for a core dump. */ |
@@ -237,74 +251,9 @@ void dump_elf_thread(elf_greg_t *dest, struct pt_regs* regs) | |||
237 | dest[35] = 0; | 251 | dest[35] = 0; |
238 | } | 252 | } |
239 | 253 | ||
240 | extern void _kernel_thread_helper(void); | ||
241 | |||
242 | void __noreturn kernel_thread_helper(int (*fn) (void *), void *arg) | ||
243 | { | ||
244 | do_exit(fn(arg)); | ||
245 | } | ||
246 | |||
247 | /* | ||
248 | * Create a kernel thread. | ||
249 | */ | ||
250 | int kernel_thread(int (*fn) (void *), void *arg, unsigned long flags) | ||
251 | { | ||
252 | struct pt_regs regs; | ||
253 | |||
254 | memset(®s, 0, sizeof(regs)); | ||
255 | |||
256 | regs.gpr[20] = (unsigned long)fn; | ||
257 | regs.gpr[22] = (unsigned long)arg; | ||
258 | regs.sr = mfspr(SPR_SR); | ||
259 | regs.pc = (unsigned long)_kernel_thread_helper; | ||
260 | |||
261 | return do_fork(flags | CLONE_VM | CLONE_UNTRACED, | ||
262 | 0, ®s, 0, NULL, NULL); | ||
263 | } | ||
264 | |||
265 | /* | ||
266 | * sys_execve() executes a new program. | ||
267 | */ | ||
268 | asmlinkage long _sys_execve(const char __user *name, | ||
269 | const char __user * const __user *argv, | ||
270 | const char __user * const __user *envp, | ||
271 | struct pt_regs *regs) | ||
272 | { | ||
273 | int error; | ||
274 | struct filename *filename; | ||
275 | |||
276 | filename = getname(name); | ||
277 | error = PTR_ERR(filename); | ||
278 | |||
279 | if (IS_ERR(filename)) | ||
280 | goto out; | ||
281 | |||
282 | error = do_execve(filename->name, argv, envp, regs); | ||
283 | putname(filename); | ||
284 | |||
285 | out: | ||
286 | return error; | ||
287 | } | ||
288 | |||
289 | unsigned long get_wchan(struct task_struct *p) | 254 | unsigned long get_wchan(struct task_struct *p) |
290 | { | 255 | { |
291 | /* TODO */ | 256 | /* TODO */ |
292 | 257 | ||
293 | return 0; | 258 | return 0; |
294 | } | 259 | } |
295 | |||
296 | int kernel_execve(const char *filename, char *const argv[], char *const envp[]) | ||
297 | { | ||
298 | register long __res asm("r11") = __NR_execve; | ||
299 | register long __a asm("r3") = (long)(filename); | ||
300 | register long __b asm("r4") = (long)(argv); | ||
301 | register long __c asm("r5") = (long)(envp); | ||
302 | __asm__ volatile ("l.sys 1" | ||
303 | : "=r" (__res), "=r"(__a), "=r"(__b), "=r"(__c) | ||
304 | : "0"(__res), "1"(__a), "2"(__b), "3"(__c) | ||
305 | : "r6", "r7", "r8", "r12", "r13", "r15", | ||
306 | "r17", "r19", "r21", "r23", "r25", "r27", | ||
307 | "r29", "r31"); | ||
308 | __asm__ volatile ("l.nop"); | ||
309 | return __res; | ||
310 | } | ||
diff --git a/arch/parisc/Kconfig b/arch/parisc/Kconfig index 11def45b98c5..0aec70c35614 100644 --- a/arch/parisc/Kconfig +++ b/arch/parisc/Kconfig | |||
@@ -22,6 +22,8 @@ config PARISC | |||
22 | select GENERIC_STRNCPY_FROM_USER | 22 | select GENERIC_STRNCPY_FROM_USER |
23 | select HAVE_MOD_ARCH_SPECIFIC | 23 | select HAVE_MOD_ARCH_SPECIFIC |
24 | select MODULES_USE_ELF_RELA | 24 | select MODULES_USE_ELF_RELA |
25 | select GENERIC_KERNEL_THREAD | ||
26 | select GENERIC_KERNEL_EXECVE | ||
25 | 27 | ||
26 | help | 28 | help |
27 | The PA-RISC microprocessor is designed by Hewlett-Packard and used | 29 | The PA-RISC microprocessor is designed by Hewlett-Packard and used |
diff --git a/arch/parisc/include/asm/unistd.h b/arch/parisc/include/asm/unistd.h index 541639c3f607..55512e26b0c2 100644 --- a/arch/parisc/include/asm/unistd.h +++ b/arch/parisc/include/asm/unistd.h | |||
@@ -163,6 +163,7 @@ type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5) \ | |||
163 | #define __ARCH_WANT_SYS_RT_SIGACTION | 163 | #define __ARCH_WANT_SYS_RT_SIGACTION |
164 | #define __ARCH_WANT_SYS_RT_SIGSUSPEND | 164 | #define __ARCH_WANT_SYS_RT_SIGSUSPEND |
165 | #define __ARCH_WANT_COMPAT_SYS_RT_SIGSUSPEND | 165 | #define __ARCH_WANT_COMPAT_SYS_RT_SIGSUSPEND |
166 | #define __ARCH_WANT_SYS_EXECVE | ||
166 | 167 | ||
167 | #endif /* __ASSEMBLY__ */ | 168 | #endif /* __ASSEMBLY__ */ |
168 | 169 | ||
diff --git a/arch/parisc/kernel/entry.S b/arch/parisc/kernel/entry.S index 18670a078849..c9a9abd4bc58 100644 --- a/arch/parisc/kernel/entry.S +++ b/arch/parisc/kernel/entry.S | |||
@@ -708,59 +708,9 @@ ENTRY(end_fault_vector) | |||
708 | .import do_cpu_irq_mask,code | 708 | .import do_cpu_irq_mask,code |
709 | 709 | ||
710 | /* | 710 | /* |
711 | * r26 = function to be called | ||
712 | * r25 = argument to pass in | ||
713 | * r24 = flags for do_fork() | ||
714 | * | ||
715 | * Kernel threads don't ever return, so they don't need | ||
716 | * a true register context. We just save away the arguments | ||
717 | * for copy_thread/ret_ to properly set up the child. | ||
718 | */ | ||
719 | |||
720 | #define CLONE_VM 0x100 /* Must agree with <linux/sched.h> */ | ||
721 | #define CLONE_UNTRACED 0x00800000 | ||
722 | |||
723 | .import do_fork | ||
724 | ENTRY(__kernel_thread) | ||
725 | STREG %r2, -RP_OFFSET(%r30) | ||
726 | |||
727 | copy %r30, %r1 | ||
728 | ldo PT_SZ_ALGN(%r30),%r30 | ||
729 | #ifdef CONFIG_64BIT | ||
730 | /* Yo, function pointers in wide mode are little structs... -PB */ | ||
731 | ldd 24(%r26), %r2 | ||
732 | STREG %r2, PT_GR27(%r1) /* Store childs %dp */ | ||
733 | ldd 16(%r26), %r26 | ||
734 | |||
735 | STREG %r22, PT_GR22(%r1) /* save r22 (arg5) */ | ||
736 | copy %r0, %r22 /* user_tid */ | ||
737 | #endif | ||
738 | STREG %r26, PT_GR26(%r1) /* Store function & argument for child */ | ||
739 | STREG %r25, PT_GR25(%r1) | ||
740 | ldil L%CLONE_UNTRACED, %r26 | ||
741 | ldo CLONE_VM(%r26), %r26 /* Force CLONE_VM since only init_mm */ | ||
742 | or %r26, %r24, %r26 /* will have kernel mappings. */ | ||
743 | ldi 1, %r25 /* stack_start, signals kernel thread */ | ||
744 | stw %r0, -52(%r30) /* user_tid */ | ||
745 | #ifdef CONFIG_64BIT | ||
746 | ldo -16(%r30),%r29 /* Reference param save area */ | ||
747 | #endif | ||
748 | BL do_fork, %r2 | ||
749 | copy %r1, %r24 /* pt_regs */ | ||
750 | |||
751 | /* Parent Returns here */ | ||
752 | |||
753 | LDREG -PT_SZ_ALGN-RP_OFFSET(%r30), %r2 | ||
754 | ldo -PT_SZ_ALGN(%r30), %r30 | ||
755 | bv %r0(%r2) | ||
756 | nop | ||
757 | ENDPROC(__kernel_thread) | ||
758 | |||
759 | /* | ||
760 | * Child Returns here | 711 | * Child Returns here |
761 | * | 712 | * |
762 | * copy_thread moved args from temp save area set up above | 713 | * copy_thread moved args into task save area. |
763 | * into task save area. | ||
764 | */ | 714 | */ |
765 | 715 | ||
766 | ENTRY(ret_from_kernel_thread) | 716 | ENTRY(ret_from_kernel_thread) |
@@ -769,51 +719,17 @@ ENTRY(ret_from_kernel_thread) | |||
769 | BL schedule_tail, %r2 | 719 | BL schedule_tail, %r2 |
770 | nop | 720 | nop |
771 | 721 | ||
772 | LDREG TI_TASK-THREAD_SZ_ALGN(%r30), %r1 | 722 | LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30), %r1 |
773 | LDREG TASK_PT_GR25(%r1), %r26 | 723 | LDREG TASK_PT_GR25(%r1), %r26 |
774 | #ifdef CONFIG_64BIT | 724 | #ifdef CONFIG_64BIT |
775 | LDREG TASK_PT_GR27(%r1), %r27 | 725 | LDREG TASK_PT_GR27(%r1), %r27 |
776 | LDREG TASK_PT_GR22(%r1), %r22 | ||
777 | #endif | 726 | #endif |
778 | LDREG TASK_PT_GR26(%r1), %r1 | 727 | LDREG TASK_PT_GR26(%r1), %r1 |
779 | ble 0(%sr7, %r1) | 728 | ble 0(%sr7, %r1) |
780 | copy %r31, %r2 | 729 | copy %r31, %r2 |
781 | 730 | b finish_child_return | |
782 | #ifdef CONFIG_64BIT | ||
783 | ldo -16(%r30),%r29 /* Reference param save area */ | ||
784 | loadgp /* Thread could have been in a module */ | ||
785 | #endif | ||
786 | #ifndef CONFIG_64BIT | ||
787 | b sys_exit | ||
788 | #else | ||
789 | load32 sys_exit, %r1 | ||
790 | bv %r0(%r1) | ||
791 | #endif | ||
792 | ldi 0, %r26 | ||
793 | ENDPROC(ret_from_kernel_thread) | ||
794 | |||
795 | .import sys_execve, code | ||
796 | ENTRY(__execve) | ||
797 | copy %r2, %r15 | ||
798 | copy %r30, %r16 | ||
799 | ldo PT_SZ_ALGN(%r30), %r30 | ||
800 | STREG %r26, PT_GR26(%r16) | ||
801 | STREG %r25, PT_GR25(%r16) | ||
802 | STREG %r24, PT_GR24(%r16) | ||
803 | #ifdef CONFIG_64BIT | ||
804 | ldo -16(%r30),%r29 /* Reference param save area */ | ||
805 | #endif | ||
806 | BL sys_execve, %r2 | ||
807 | copy %r16, %r26 | ||
808 | |||
809 | cmpib,=,n 0,%r28,intr_return /* forward */ | ||
810 | |||
811 | /* yes, this will trap and die. */ | ||
812 | copy %r15, %r2 | ||
813 | copy %r16, %r30 | ||
814 | bv %r0(%r2) | ||
815 | nop | 731 | nop |
816 | ENDPROC(__execve) | 732 | ENDPROC(ret_from_kernel_thread) |
817 | 733 | ||
818 | 734 | ||
819 | /* | 735 | /* |
@@ -1776,49 +1692,27 @@ ENTRY(sys_fork_wrapper) | |||
1776 | LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30), %r1 | 1692 | LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30), %r1 |
1777 | ldo TASK_REGS(%r1),%r1 | 1693 | ldo TASK_REGS(%r1),%r1 |
1778 | reg_save %r1 | 1694 | reg_save %r1 |
1779 | mfctl %cr27, %r3 | 1695 | mfctl %cr27, %r28 |
1780 | STREG %r3, PT_CR27(%r1) | 1696 | STREG %r28, PT_CR27(%r1) |
1781 | |||
1782 | STREG %r2,-RP_OFFSET(%r30) | ||
1783 | ldo FRAME_SIZE(%r30),%r30 | ||
1784 | #ifdef CONFIG_64BIT | ||
1785 | ldo -16(%r30),%r29 /* Reference param save area */ | ||
1786 | #endif | ||
1787 | |||
1788 | /* These are call-clobbered registers and therefore | ||
1789 | also syscall-clobbered (we hope). */ | ||
1790 | STREG %r2,PT_GR19(%r1) /* save for child */ | ||
1791 | STREG %r30,PT_GR21(%r1) | ||
1792 | 1697 | ||
1793 | LDREG PT_GR30(%r1),%r25 | 1698 | LDREG PT_GR30(%r1),%r25 |
1794 | copy %r1,%r24 | 1699 | copy %r1,%r24 |
1795 | BL sys_clone,%r2 | 1700 | b sys_clone |
1796 | ldi SIGCHLD,%r26 | 1701 | ldi SIGCHLD,%r26 |
1797 | |||
1798 | LDREG -RP_OFFSET-FRAME_SIZE(%r30),%r2 | ||
1799 | wrapper_exit: | ||
1800 | ldo -FRAME_SIZE(%r30),%r30 /* get the stackframe */ | ||
1801 | LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r1 | ||
1802 | ldo TASK_REGS(%r1),%r1 /* get pt regs */ | ||
1803 | |||
1804 | LDREG PT_CR27(%r1), %r3 | ||
1805 | mtctl %r3, %cr27 | ||
1806 | reg_restore %r1 | ||
1807 | |||
1808 | /* strace expects syscall # to be preserved in r20 */ | ||
1809 | ldi __NR_fork,%r20 | ||
1810 | bv %r0(%r2) | ||
1811 | STREG %r20,PT_GR20(%r1) | ||
1812 | ENDPROC(sys_fork_wrapper) | 1702 | ENDPROC(sys_fork_wrapper) |
1813 | 1703 | ||
1814 | /* Set the return value for the child */ | 1704 | /* Set the return value for the child */ |
1815 | ENTRY(child_return) | 1705 | ENTRY(child_return) |
1816 | BL schedule_tail, %r2 | 1706 | BL schedule_tail, %r2 |
1817 | nop | 1707 | nop |
1708 | finish_child_return: | ||
1709 | LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30), %r1 | ||
1710 | ldo TASK_REGS(%r1),%r1 /* get pt regs */ | ||
1818 | 1711 | ||
1819 | LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE-FRAME_SIZE(%r30), %r1 | 1712 | LDREG PT_CR27(%r1), %r3 |
1820 | LDREG TASK_PT_GR19(%r1),%r2 | 1713 | mtctl %r3, %cr27 |
1821 | b wrapper_exit | 1714 | reg_restore %r1 |
1715 | b syscall_exit | ||
1822 | copy %r0,%r28 | 1716 | copy %r0,%r28 |
1823 | ENDPROC(child_return) | 1717 | ENDPROC(child_return) |
1824 | 1718 | ||
@@ -1827,23 +1721,10 @@ ENTRY(sys_clone_wrapper) | |||
1827 | LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r1 | 1721 | LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r1 |
1828 | ldo TASK_REGS(%r1),%r1 /* get pt regs */ | 1722 | ldo TASK_REGS(%r1),%r1 /* get pt regs */ |
1829 | reg_save %r1 | 1723 | reg_save %r1 |
1830 | mfctl %cr27, %r3 | 1724 | mfctl %cr27, %r28 |
1831 | STREG %r3, PT_CR27(%r1) | 1725 | STREG %r28, PT_CR27(%r1) |
1832 | 1726 | b sys_clone | |
1833 | STREG %r2,-RP_OFFSET(%r30) | ||
1834 | ldo FRAME_SIZE(%r30),%r30 | ||
1835 | #ifdef CONFIG_64BIT | ||
1836 | ldo -16(%r30),%r29 /* Reference param save area */ | ||
1837 | #endif | ||
1838 | |||
1839 | /* WARNING - Clobbers r19 and r21, userspace must save these! */ | ||
1840 | STREG %r2,PT_GR19(%r1) /* save for child */ | ||
1841 | STREG %r30,PT_GR21(%r1) | ||
1842 | BL sys_clone,%r2 | ||
1843 | copy %r1,%r24 | 1727 | copy %r1,%r24 |
1844 | |||
1845 | b wrapper_exit | ||
1846 | LDREG -RP_OFFSET-FRAME_SIZE(%r30),%r2 | ||
1847 | ENDPROC(sys_clone_wrapper) | 1728 | ENDPROC(sys_clone_wrapper) |
1848 | 1729 | ||
1849 | 1730 | ||
@@ -1851,72 +1732,14 @@ ENTRY(sys_vfork_wrapper) | |||
1851 | LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r1 | 1732 | LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r1 |
1852 | ldo TASK_REGS(%r1),%r1 /* get pt regs */ | 1733 | ldo TASK_REGS(%r1),%r1 /* get pt regs */ |
1853 | reg_save %r1 | 1734 | reg_save %r1 |
1854 | mfctl %cr27, %r3 | 1735 | mfctl %cr27, %r28 |
1855 | STREG %r3, PT_CR27(%r1) | 1736 | STREG %r28, PT_CR27(%r1) |
1856 | 1737 | ||
1857 | STREG %r2,-RP_OFFSET(%r30) | 1738 | b sys_vfork |
1858 | ldo FRAME_SIZE(%r30),%r30 | ||
1859 | #ifdef CONFIG_64BIT | ||
1860 | ldo -16(%r30),%r29 /* Reference param save area */ | ||
1861 | #endif | ||
1862 | |||
1863 | STREG %r2,PT_GR19(%r1) /* save for child */ | ||
1864 | STREG %r30,PT_GR21(%r1) | ||
1865 | |||
1866 | BL sys_vfork,%r2 | ||
1867 | copy %r1,%r26 | 1739 | copy %r1,%r26 |
1868 | |||
1869 | b wrapper_exit | ||
1870 | LDREG -RP_OFFSET-FRAME_SIZE(%r30),%r2 | ||
1871 | ENDPROC(sys_vfork_wrapper) | 1740 | ENDPROC(sys_vfork_wrapper) |
1872 | 1741 | ||
1873 | 1742 | ||
1874 | .macro execve_wrapper execve | ||
1875 | LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r1 | ||
1876 | ldo TASK_REGS(%r1),%r1 /* get pt regs */ | ||
1877 | |||
1878 | /* | ||
1879 | * Do we need to save/restore r3-r18 here? | ||
1880 | * I don't think so. why would new thread need old | ||
1881 | * threads registers? | ||
1882 | */ | ||
1883 | |||
1884 | /* %arg0 - %arg3 are already saved for us. */ | ||
1885 | |||
1886 | STREG %r2,-RP_OFFSET(%r30) | ||
1887 | ldo FRAME_SIZE(%r30),%r30 | ||
1888 | #ifdef CONFIG_64BIT | ||
1889 | ldo -16(%r30),%r29 /* Reference param save area */ | ||
1890 | #endif | ||
1891 | BL \execve,%r2 | ||
1892 | copy %r1,%arg0 | ||
1893 | |||
1894 | ldo -FRAME_SIZE(%r30),%r30 | ||
1895 | LDREG -RP_OFFSET(%r30),%r2 | ||
1896 | |||
1897 | /* If exec succeeded we need to load the args */ | ||
1898 | |||
1899 | ldo -1024(%r0),%r1 | ||
1900 | cmpb,>>= %r28,%r1,error_\execve | ||
1901 | copy %r2,%r19 | ||
1902 | |||
1903 | error_\execve: | ||
1904 | bv %r0(%r19) | ||
1905 | nop | ||
1906 | .endm | ||
1907 | |||
1908 | .import sys_execve | ||
1909 | ENTRY(sys_execve_wrapper) | ||
1910 | execve_wrapper sys_execve | ||
1911 | ENDPROC(sys_execve_wrapper) | ||
1912 | |||
1913 | #ifdef CONFIG_64BIT | ||
1914 | .import sys32_execve | ||
1915 | ENTRY(sys32_execve_wrapper) | ||
1916 | execve_wrapper sys32_execve | ||
1917 | ENDPROC(sys32_execve_wrapper) | ||
1918 | #endif | ||
1919 | |||
1920 | ENTRY(sys_rt_sigreturn_wrapper) | 1743 | ENTRY(sys_rt_sigreturn_wrapper) |
1921 | LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r26 | 1744 | LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r26 |
1922 | ldo TASK_REGS(%r26),%r26 /* get pt regs */ | 1745 | ldo TASK_REGS(%r26),%r26 /* get pt regs */ |
diff --git a/arch/parisc/kernel/process.c b/arch/parisc/kernel/process.c index cbc37216bf90..38db36f64307 100644 --- a/arch/parisc/kernel/process.c +++ b/arch/parisc/kernel/process.c | |||
@@ -52,6 +52,7 @@ | |||
52 | 52 | ||
53 | #include <asm/io.h> | 53 | #include <asm/io.h> |
54 | #include <asm/asm-offsets.h> | 54 | #include <asm/asm-offsets.h> |
55 | #include <asm/assembly.h> | ||
55 | #include <asm/pdc.h> | 56 | #include <asm/pdc.h> |
56 | #include <asm/pdc_chassis.h> | 57 | #include <asm/pdc_chassis.h> |
57 | #include <asm/pgalloc.h> | 58 | #include <asm/pgalloc.h> |
@@ -165,23 +166,6 @@ void (*pm_power_off)(void) = machine_power_off; | |||
165 | EXPORT_SYMBOL(pm_power_off); | 166 | EXPORT_SYMBOL(pm_power_off); |
166 | 167 | ||
167 | /* | 168 | /* |
168 | * Create a kernel thread | ||
169 | */ | ||
170 | |||
171 | extern pid_t __kernel_thread(int (*fn)(void *), void *arg, unsigned long flags); | ||
172 | pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags) | ||
173 | { | ||
174 | |||
175 | /* | ||
176 | * FIXME: Once we are sure we don't need any debug here, | ||
177 | * kernel_thread can become a #define. | ||
178 | */ | ||
179 | |||
180 | return __kernel_thread(fn, arg, flags); | ||
181 | } | ||
182 | EXPORT_SYMBOL(kernel_thread); | ||
183 | |||
184 | /* | ||
185 | * Free current thread data structures etc.. | 169 | * Free current thread data structures etc.. |
186 | */ | 170 | */ |
187 | void exit_thread(void) | 171 | void exit_thread(void) |
@@ -256,8 +240,8 @@ sys_vfork(struct pt_regs *regs) | |||
256 | 240 | ||
257 | int | 241 | int |
258 | copy_thread(unsigned long clone_flags, unsigned long usp, | 242 | copy_thread(unsigned long clone_flags, unsigned long usp, |
259 | unsigned long unused, /* in ia64 this is "user_stack_size" */ | 243 | unsigned long arg, |
260 | struct task_struct * p, struct pt_regs * pregs) | 244 | struct task_struct *p, struct pt_regs *pregs) |
261 | { | 245 | { |
262 | struct pt_regs * cregs = &(p->thread.regs); | 246 | struct pt_regs * cregs = &(p->thread.regs); |
263 | void *stack = task_stack_page(p); | 247 | void *stack = task_stack_page(p); |
@@ -270,48 +254,32 @@ copy_thread(unsigned long clone_flags, unsigned long usp, | |||
270 | #ifdef CONFIG_HPUX | 254 | #ifdef CONFIG_HPUX |
271 | extern void * const hpux_child_return; | 255 | extern void * const hpux_child_return; |
272 | #endif | 256 | #endif |
257 | if (unlikely(p->flags & PF_KTHREAD)) { | ||
258 | memset(cregs, 0, sizeof(struct pt_regs)); | ||
259 | if (!usp) /* idle thread */ | ||
260 | return 0; | ||
273 | 261 | ||
274 | *cregs = *pregs; | ||
275 | |||
276 | /* Set the return value for the child. Note that this is not | ||
277 | actually restored by the syscall exit path, but we put it | ||
278 | here for consistency in case of signals. */ | ||
279 | cregs->gr[28] = 0; /* child */ | ||
280 | |||
281 | /* | ||
282 | * We need to differentiate between a user fork and a | ||
283 | * kernel fork. We can't use user_mode, because the | ||
284 | * the syscall path doesn't save iaoq. Right now | ||
285 | * We rely on the fact that kernel_thread passes | ||
286 | * in zero for usp. | ||
287 | */ | ||
288 | if (usp == 1) { | ||
289 | /* kernel thread */ | 262 | /* kernel thread */ |
290 | cregs->ksp = (unsigned long)stack + THREAD_SZ_ALGN; | ||
291 | /* Must exit via ret_from_kernel_thread in order | 263 | /* Must exit via ret_from_kernel_thread in order |
292 | * to call schedule_tail() | 264 | * to call schedule_tail() |
293 | */ | 265 | */ |
266 | cregs->ksp = (unsigned long)stack + THREAD_SZ_ALGN + FRAME_SIZE; | ||
294 | cregs->kpc = (unsigned long) &ret_from_kernel_thread; | 267 | cregs->kpc = (unsigned long) &ret_from_kernel_thread; |
295 | /* | 268 | /* |
296 | * Copy function and argument to be called from | 269 | * Copy function and argument to be called from |
297 | * ret_from_kernel_thread. | 270 | * ret_from_kernel_thread. |
298 | */ | 271 | */ |
299 | #ifdef CONFIG_64BIT | 272 | #ifdef CONFIG_64BIT |
300 | cregs->gr[27] = pregs->gr[27]; | 273 | cregs->gr[27] = ((unsigned long *)usp)[3]; |
274 | cregs->gr[26] = ((unsigned long *)usp)[2]; | ||
275 | #else | ||
276 | cregs->gr[26] = usp; | ||
301 | #endif | 277 | #endif |
302 | cregs->gr[26] = pregs->gr[26]; | 278 | cregs->gr[25] = arg; |
303 | cregs->gr[25] = pregs->gr[25]; | ||
304 | } else { | 279 | } else { |
305 | /* user thread */ | 280 | /* user thread */ |
306 | /* | ||
307 | * Note that the fork wrappers are responsible | ||
308 | * for setting gr[21]. | ||
309 | */ | ||
310 | |||
311 | /* Use same stack depth as parent */ | ||
312 | cregs->ksp = (unsigned long)stack | ||
313 | + (pregs->gr[21] & (THREAD_SIZE - 1)); | ||
314 | cregs->gr[30] = usp; | 281 | cregs->gr[30] = usp; |
282 | cregs->ksp = (unsigned long)stack + THREAD_SZ_ALGN + FRAME_SIZE; | ||
315 | if (personality(p->personality) == PER_HPUX) { | 283 | if (personality(p->personality) == PER_HPUX) { |
316 | #ifdef CONFIG_HPUX | 284 | #ifdef CONFIG_HPUX |
317 | cregs->kpc = (unsigned long) &hpux_child_return; | 285 | cregs->kpc = (unsigned long) &hpux_child_return; |
@@ -323,8 +291,7 @@ copy_thread(unsigned long clone_flags, unsigned long usp, | |||
323 | } | 291 | } |
324 | /* Setup thread TLS area from the 4th parameter in clone */ | 292 | /* Setup thread TLS area from the 4th parameter in clone */ |
325 | if (clone_flags & CLONE_SETTLS) | 293 | if (clone_flags & CLONE_SETTLS) |
326 | cregs->cr27 = pregs->gr[23]; | 294 | cregs->cr27 = pregs->gr[23]; |
327 | |||
328 | } | 295 | } |
329 | 296 | ||
330 | return 0; | 297 | return 0; |
@@ -335,39 +302,6 @@ unsigned long thread_saved_pc(struct task_struct *t) | |||
335 | return t->thread.regs.kpc; | 302 | return t->thread.regs.kpc; |
336 | } | 303 | } |
337 | 304 | ||
338 | /* | ||
339 | * sys_execve() executes a new program. | ||
340 | */ | ||
341 | |||
342 | asmlinkage int sys_execve(struct pt_regs *regs) | ||
343 | { | ||
344 | int error; | ||
345 | struct filename *filename; | ||
346 | |||
347 | filename = getname((const char __user *) regs->gr[26]); | ||
348 | error = PTR_ERR(filename); | ||
349 | if (IS_ERR(filename)) | ||
350 | goto out; | ||
351 | error = do_execve(filename->name, | ||
352 | (const char __user *const __user *) regs->gr[25], | ||
353 | (const char __user *const __user *) regs->gr[24], | ||
354 | regs); | ||
355 | putname(filename); | ||
356 | out: | ||
357 | |||
358 | return error; | ||
359 | } | ||
360 | |||
361 | extern int __execve(const char *filename, | ||
362 | const char *const argv[], | ||
363 | const char *const envp[], struct task_struct *task); | ||
364 | int kernel_execve(const char *filename, | ||
365 | const char *const argv[], | ||
366 | const char *const envp[]) | ||
367 | { | ||
368 | return __execve(filename, argv, envp, current); | ||
369 | } | ||
370 | |||
371 | unsigned long | 305 | unsigned long |
372 | get_wchan(struct task_struct *p) | 306 | get_wchan(struct task_struct *p) |
373 | { | 307 | { |
diff --git a/arch/parisc/kernel/sys_parisc32.c b/arch/parisc/kernel/sys_parisc32.c index bf5b93a885d3..9cfdaa19ab63 100644 --- a/arch/parisc/kernel/sys_parisc32.c +++ b/arch/parisc/kernel/sys_parisc32.c | |||
@@ -53,28 +53,6 @@ | |||
53 | #define DBG(x) | 53 | #define DBG(x) |
54 | #endif | 54 | #endif |
55 | 55 | ||
56 | /* | ||
57 | * sys32_execve() executes a new program. | ||
58 | */ | ||
59 | |||
60 | asmlinkage int sys32_execve(struct pt_regs *regs) | ||
61 | { | ||
62 | int error; | ||
63 | struct filename *filename; | ||
64 | |||
65 | DBG(("sys32_execve(%p) r26 = 0x%lx\n", regs, regs->gr[26])); | ||
66 | filename = getname((const char __user *) regs->gr[26]); | ||
67 | error = PTR_ERR(filename); | ||
68 | if (IS_ERR(filename)) | ||
69 | goto out; | ||
70 | error = compat_do_execve(filename->name, compat_ptr(regs->gr[25]), | ||
71 | compat_ptr(regs->gr[24]), regs); | ||
72 | putname(filename); | ||
73 | out: | ||
74 | |||
75 | return error; | ||
76 | } | ||
77 | |||
78 | asmlinkage long sys32_unimplemented(int r26, int r25, int r24, int r23, | 56 | asmlinkage long sys32_unimplemented(int r26, int r25, int r24, int r23, |
79 | int r22, int r21, int r20) | 57 | int r22, int r21, int r20) |
80 | { | 58 | { |
diff --git a/arch/parisc/kernel/syscall_table.S b/arch/parisc/kernel/syscall_table.S index 3735abd7f8f6..cb2da96d6ab9 100644 --- a/arch/parisc/kernel/syscall_table.S +++ b/arch/parisc/kernel/syscall_table.S | |||
@@ -66,7 +66,7 @@ | |||
66 | ENTRY_SAME(creat) | 66 | ENTRY_SAME(creat) |
67 | ENTRY_SAME(link) | 67 | ENTRY_SAME(link) |
68 | ENTRY_SAME(unlink) /* 10 */ | 68 | ENTRY_SAME(unlink) /* 10 */ |
69 | ENTRY_DIFF(execve_wrapper) | 69 | ENTRY_COMP(execve) |
70 | ENTRY_SAME(chdir) | 70 | ENTRY_SAME(chdir) |
71 | /* See comments in kernel/time.c!!! Maybe we don't need this? */ | 71 | /* See comments in kernel/time.c!!! Maybe we don't need this? */ |
72 | ENTRY_COMP(time) | 72 | ENTRY_COMP(time) |
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index a902a5c1c76a..5af5aa707176 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig | |||
@@ -144,6 +144,7 @@ config PPC | |||
144 | select GENERIC_KERNEL_THREAD | 144 | select GENERIC_KERNEL_THREAD |
145 | select HAVE_MOD_ARCH_SPECIFIC | 145 | select HAVE_MOD_ARCH_SPECIFIC |
146 | select MODULES_USE_ELF_RELA | 146 | select MODULES_USE_ELF_RELA |
147 | select GENERIC_KERNEL_EXECVE | ||
147 | 148 | ||
148 | config EARLY_PRINTK | 149 | config EARLY_PRINTK |
149 | bool | 150 | bool |
diff --git a/arch/powerpc/include/asm/unistd.h b/arch/powerpc/include/asm/unistd.h index 921dce6d8445..280068cfff2e 100644 --- a/arch/powerpc/include/asm/unistd.h +++ b/arch/powerpc/include/asm/unistd.h | |||
@@ -56,7 +56,6 @@ | |||
56 | #define __ARCH_WANT_COMPAT_SYS_SENDFILE | 56 | #define __ARCH_WANT_COMPAT_SYS_SENDFILE |
57 | #endif | 57 | #endif |
58 | #define __ARCH_WANT_SYS_EXECVE | 58 | #define __ARCH_WANT_SYS_EXECVE |
59 | #define __ARCH_WANT_KERNEL_EXECVE | ||
60 | 59 | ||
61 | /* | 60 | /* |
62 | * "Conditional" syscalls | 61 | * "Conditional" syscalls |
diff --git a/arch/powerpc/kernel/entry_32.S b/arch/powerpc/kernel/entry_32.S index 9499385676e7..d22e73e4618b 100644 --- a/arch/powerpc/kernel/entry_32.S +++ b/arch/powerpc/kernel/entry_32.S | |||
@@ -444,11 +444,6 @@ ret_from_kernel_thread: | |||
444 | PPC440EP_ERR42 | 444 | PPC440EP_ERR42 |
445 | blrl | 445 | blrl |
446 | li r3,0 | 446 | li r3,0 |
447 | b do_exit # no return | ||
448 | |||
449 | .globl __ret_from_kernel_execve | ||
450 | __ret_from_kernel_execve: | ||
451 | addi r1,r3,-STACK_FRAME_OVERHEAD | ||
452 | b ret_from_syscall | 447 | b ret_from_syscall |
453 | 448 | ||
454 | /* Traced system call support */ | 449 | /* Traced system call support */ |
diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S index 56e0ff0878b5..e9a906c27234 100644 --- a/arch/powerpc/kernel/entry_64.S +++ b/arch/powerpc/kernel/entry_64.S | |||
@@ -373,17 +373,11 @@ _GLOBAL(ret_from_fork) | |||
373 | _GLOBAL(ret_from_kernel_thread) | 373 | _GLOBAL(ret_from_kernel_thread) |
374 | bl .schedule_tail | 374 | bl .schedule_tail |
375 | REST_NVGPRS(r1) | 375 | REST_NVGPRS(r1) |
376 | REST_GPR(2,r1) | 376 | ld r14, 0(r14) |
377 | mtlr r14 | 377 | mtlr r14 |
378 | mr r3,r15 | 378 | mr r3,r15 |
379 | blrl | 379 | blrl |
380 | li r3,0 | 380 | li r3,0 |
381 | b .do_exit # no return | ||
382 | |||
383 | _GLOBAL(__ret_from_kernel_execve) | ||
384 | addi r1,r3,-STACK_FRAME_OVERHEAD | ||
385 | li r10,1 | ||
386 | std r10,SOFTE(r1) | ||
387 | b syscall_exit | 381 | b syscall_exit |
388 | 382 | ||
389 | .section ".toc","aw" | 383 | .section ".toc","aw" |
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c index ba48233500f6..f6d244db9203 100644 --- a/arch/powerpc/kernel/process.c +++ b/arch/powerpc/kernel/process.c | |||
@@ -745,25 +745,24 @@ int copy_thread(unsigned long clone_flags, unsigned long usp, | |||
745 | /* Copy registers */ | 745 | /* Copy registers */ |
746 | sp -= sizeof(struct pt_regs); | 746 | sp -= sizeof(struct pt_regs); |
747 | childregs = (struct pt_regs *) sp; | 747 | childregs = (struct pt_regs *) sp; |
748 | if (!regs) { | 748 | if (unlikely(p->flags & PF_KTHREAD)) { |
749 | /* for kernel thread, set `current' and stackptr in new task */ | 749 | struct thread_info *ti = (void *)task_stack_page(p); |
750 | memset(childregs, 0, sizeof(struct pt_regs)); | 750 | memset(childregs, 0, sizeof(struct pt_regs)); |
751 | childregs->gpr[1] = sp + sizeof(struct pt_regs); | 751 | childregs->gpr[1] = sp + sizeof(struct pt_regs); |
752 | childregs->gpr[14] = usp; /* function */ | ||
752 | #ifdef CONFIG_PPC64 | 753 | #ifdef CONFIG_PPC64 |
753 | childregs->gpr[14] = *(unsigned long *)usp; | ||
754 | childregs->gpr[2] = ((unsigned long *)usp)[1], | ||
755 | clear_tsk_thread_flag(p, TIF_32BIT); | 754 | clear_tsk_thread_flag(p, TIF_32BIT); |
756 | #else | 755 | childregs->softe = 1; |
757 | childregs->gpr[14] = usp; /* function */ | ||
758 | childregs->gpr[2] = (unsigned long) p; | ||
759 | #endif | 756 | #endif |
760 | childregs->gpr[15] = arg; | 757 | childregs->gpr[15] = arg; |
761 | p->thread.regs = NULL; /* no user register state */ | 758 | p->thread.regs = NULL; /* no user register state */ |
759 | ti->flags |= _TIF_RESTOREALL; | ||
762 | f = ret_from_kernel_thread; | 760 | f = ret_from_kernel_thread; |
763 | } else { | 761 | } else { |
764 | CHECK_FULL_REGS(regs); | 762 | CHECK_FULL_REGS(regs); |
765 | *childregs = *regs; | 763 | *childregs = *regs; |
766 | childregs->gpr[1] = usp; | 764 | if (usp) |
765 | childregs->gpr[1] = usp; | ||
767 | p->thread.regs = childregs; | 766 | p->thread.regs = childregs; |
768 | childregs->gpr[3] = 0; /* Result from fork() */ | 767 | childregs->gpr[3] = 0; /* Result from fork() */ |
769 | if (clone_flags & CLONE_SETTLS) { | 768 | if (clone_flags & CLONE_SETTLS) { |
@@ -1027,22 +1026,11 @@ int get_unalign_ctl(struct task_struct *tsk, unsigned long adr) | |||
1027 | return put_user(tsk->thread.align_ctl, (unsigned int __user *)adr); | 1026 | return put_user(tsk->thread.align_ctl, (unsigned int __user *)adr); |
1028 | } | 1027 | } |
1029 | 1028 | ||
1030 | #define TRUNC_PTR(x) ((typeof(x))(((unsigned long)(x)) & 0xffffffff)) | ||
1031 | |||
1032 | int sys_clone(unsigned long clone_flags, unsigned long usp, | 1029 | int sys_clone(unsigned long clone_flags, unsigned long usp, |
1033 | int __user *parent_tidp, void __user *child_threadptr, | 1030 | int __user *parent_tidp, void __user *child_threadptr, |
1034 | int __user *child_tidp, int p6, | 1031 | int __user *child_tidp, int p6, |
1035 | struct pt_regs *regs) | 1032 | struct pt_regs *regs) |
1036 | { | 1033 | { |
1037 | CHECK_FULL_REGS(regs); | ||
1038 | if (usp == 0) | ||
1039 | usp = regs->gpr[1]; /* stack pointer for child */ | ||
1040 | #ifdef CONFIG_PPC64 | ||
1041 | if (is_32bit_task()) { | ||
1042 | parent_tidp = TRUNC_PTR(parent_tidp); | ||
1043 | child_tidp = TRUNC_PTR(child_tidp); | ||
1044 | } | ||
1045 | #endif | ||
1046 | return do_fork(clone_flags, usp, regs, 0, parent_tidp, child_tidp); | 1034 | return do_fork(clone_flags, usp, regs, 0, parent_tidp, child_tidp); |
1047 | } | 1035 | } |
1048 | 1036 | ||
@@ -1050,28 +1038,17 @@ int sys_fork(unsigned long p1, unsigned long p2, unsigned long p3, | |||
1050 | unsigned long p4, unsigned long p5, unsigned long p6, | 1038 | unsigned long p4, unsigned long p5, unsigned long p6, |
1051 | struct pt_regs *regs) | 1039 | struct pt_regs *regs) |
1052 | { | 1040 | { |
1053 | CHECK_FULL_REGS(regs); | 1041 | return do_fork(SIGCHLD, 0, regs, 0, NULL, NULL); |
1054 | return do_fork(SIGCHLD, regs->gpr[1], regs, 0, NULL, NULL); | ||
1055 | } | 1042 | } |
1056 | 1043 | ||
1057 | int sys_vfork(unsigned long p1, unsigned long p2, unsigned long p3, | 1044 | int sys_vfork(unsigned long p1, unsigned long p2, unsigned long p3, |
1058 | unsigned long p4, unsigned long p5, unsigned long p6, | 1045 | unsigned long p4, unsigned long p5, unsigned long p6, |
1059 | struct pt_regs *regs) | 1046 | struct pt_regs *regs) |
1060 | { | 1047 | { |
1061 | CHECK_FULL_REGS(regs); | 1048 | return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, 0, |
1062 | return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->gpr[1], | ||
1063 | regs, 0, NULL, NULL); | 1049 | regs, 0, NULL, NULL); |
1064 | } | 1050 | } |
1065 | 1051 | ||
1066 | void __ret_from_kernel_execve(struct pt_regs *normal) | ||
1067 | __noreturn; | ||
1068 | |||
1069 | void ret_from_kernel_execve(struct pt_regs *normal) | ||
1070 | { | ||
1071 | set_thread_flag(TIF_RESTOREALL); | ||
1072 | __ret_from_kernel_execve(normal); | ||
1073 | } | ||
1074 | |||
1075 | static inline int valid_irq_stack(unsigned long sp, struct task_struct *p, | 1052 | static inline int valid_irq_stack(unsigned long sp, struct task_struct *p, |
1076 | unsigned long nbytes) | 1053 | unsigned long nbytes) |
1077 | { | 1054 | { |
diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index d385f396dfee..a163784e72c8 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig | |||
@@ -138,6 +138,7 @@ config S390 | |||
138 | select KTIME_SCALAR if 32BIT | 138 | select KTIME_SCALAR if 32BIT |
139 | select HAVE_ARCH_SECCOMP_FILTER | 139 | select HAVE_ARCH_SECCOMP_FILTER |
140 | select GENERIC_KERNEL_THREAD | 140 | select GENERIC_KERNEL_THREAD |
141 | select GENERIC_KERNEL_EXECVE | ||
141 | select HAVE_MOD_ARCH_SPECIFIC | 142 | select HAVE_MOD_ARCH_SPECIFIC |
142 | select MODULES_USE_ELF_RELA | 143 | select MODULES_USE_ELF_RELA |
143 | 144 | ||
diff --git a/arch/s390/include/asm/unistd.h b/arch/s390/include/asm/unistd.h index bbbae41fa9a5..ccbcab7742cd 100644 --- a/arch/s390/include/asm/unistd.h +++ b/arch/s390/include/asm/unistd.h | |||
@@ -54,7 +54,6 @@ | |||
54 | # define __ARCH_WANT_COMPAT_SYS_RT_SIGSUSPEND | 54 | # define __ARCH_WANT_COMPAT_SYS_RT_SIGSUSPEND |
55 | # endif | 55 | # endif |
56 | #define __ARCH_WANT_SYS_EXECVE | 56 | #define __ARCH_WANT_SYS_EXECVE |
57 | #define __ARCH_WANT_KERNEL_EXECVE | ||
58 | 57 | ||
59 | /* | 58 | /* |
60 | * "Conditional" syscalls | 59 | * "Conditional" syscalls |
diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S index ef46f66bc0d6..aa8f2ba6289b 100644 --- a/arch/s390/kernel/entry.S +++ b/arch/s390/kernel/entry.S | |||
@@ -330,40 +330,18 @@ ENTRY(ret_from_fork) | |||
330 | la %r11,STACK_FRAME_OVERHEAD(%r15) | 330 | la %r11,STACK_FRAME_OVERHEAD(%r15) |
331 | l %r12,__LC_THREAD_INFO | 331 | l %r12,__LC_THREAD_INFO |
332 | l %r13,__LC_SVC_NEW_PSW+4 | 332 | l %r13,__LC_SVC_NEW_PSW+4 |
333 | tm __PT_PSW+1(%r11),0x01 # forking a kernel thread ? | ||
334 | je 1f | ||
335 | l %r1,BASED(.Lschedule_tail) | 333 | l %r1,BASED(.Lschedule_tail) |
336 | basr %r14,%r1 # call schedule_tail | 334 | basr %r14,%r1 # call schedule_tail |
337 | TRACE_IRQS_ON | 335 | TRACE_IRQS_ON |
338 | ssm __LC_SVC_NEW_PSW # reenable interrupts | 336 | ssm __LC_SVC_NEW_PSW # reenable interrupts |
339 | j sysc_tracenogo | 337 | tm __PT_PSW+1(%r11),0x01 # forking a kernel thread ? |
340 | 338 | jne sysc_tracenogo | |
341 | 1: # it's a kernel thread | 339 | # it's a kernel thread |
342 | st %r15,__PT_R15(%r11) # store stack pointer for new kthread | 340 | lm %r9,%r10,__PT_R9(%r11) # load gprs |
343 | l %r1,BASED(.Lschedule_tail) | ||
344 | basr %r14,%r1 # call schedule_tail | ||
345 | TRACE_IRQS_ON | ||
346 | ssm __LC_SVC_NEW_PSW # reenable interrupts | ||
347 | lm %r9,%r11,__PT_R9(%r11) # load gprs | ||
348 | ENTRY(kernel_thread_starter) | 341 | ENTRY(kernel_thread_starter) |
349 | la %r2,0(%r10) | 342 | la %r2,0(%r10) |
350 | basr %r14,%r9 | 343 | basr %r14,%r9 |
351 | la %r2,0 | 344 | j sysc_tracenogo |
352 | br %r11 # do_exit | ||
353 | |||
354 | # | ||
355 | # kernel_execve function needs to deal with pt_regs that is not | ||
356 | # at the usual place | ||
357 | # | ||
358 | ENTRY(ret_from_kernel_execve) | ||
359 | ssm __LC_PGM_NEW_PSW # disable I/O and ext. interrupts | ||
360 | lr %r15,%r2 | ||
361 | lr %r11,%r2 | ||
362 | ahi %r15,-STACK_FRAME_OVERHEAD | ||
363 | xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) | ||
364 | l %r12,__LC_THREAD_INFO | ||
365 | ssm __LC_SVC_NEW_PSW # reenable interrupts | ||
366 | j sysc_return | ||
367 | 345 | ||
368 | /* | 346 | /* |
369 | * Program check handler routine | 347 | * Program check handler routine |
diff --git a/arch/s390/kernel/entry64.S b/arch/s390/kernel/entry64.S index 07d8de353984..499e95e90f38 100644 --- a/arch/s390/kernel/entry64.S +++ b/arch/s390/kernel/entry64.S | |||
@@ -352,33 +352,17 @@ sysc_tracenogo: | |||
352 | ENTRY(ret_from_fork) | 352 | ENTRY(ret_from_fork) |
353 | la %r11,STACK_FRAME_OVERHEAD(%r15) | 353 | la %r11,STACK_FRAME_OVERHEAD(%r15) |
354 | lg %r12,__LC_THREAD_INFO | 354 | lg %r12,__LC_THREAD_INFO |
355 | tm __PT_PSW+1(%r11),0x01 # forking a kernel thread ? | ||
356 | je 1f | ||
357 | brasl %r14,schedule_tail | 355 | brasl %r14,schedule_tail |
358 | TRACE_IRQS_ON | 356 | TRACE_IRQS_ON |
359 | ssm __LC_SVC_NEW_PSW # reenable interrupts | 357 | ssm __LC_SVC_NEW_PSW # reenable interrupts |
360 | j sysc_tracenogo | 358 | tm __PT_PSW+1(%r11),0x01 # forking a kernel thread ? |
361 | 1: # it's a kernel thread | 359 | jne sysc_tracenogo |
362 | stg %r15,__PT_R15(%r11) # store stack pointer for new kthread | 360 | # it's a kernel thread |
363 | brasl %r14,schedule_tail | 361 | lmg %r9,%r10,__PT_R9(%r11) # load gprs |
364 | TRACE_IRQS_ON | ||
365 | ssm __LC_SVC_NEW_PSW # reenable interrupts | ||
366 | lmg %r9,%r11,__PT_R9(%r11) # load gprs | ||
367 | ENTRY(kernel_thread_starter) | 362 | ENTRY(kernel_thread_starter) |
368 | la %r2,0(%r10) | 363 | la %r2,0(%r10) |
369 | basr %r14,%r9 | 364 | basr %r14,%r9 |
370 | la %r2,0 | 365 | j sysc_tracenogo |
371 | br %r11 # do_exit | ||
372 | |||
373 | ENTRY(ret_from_kernel_execve) | ||
374 | ssm __LC_PGM_NEW_PSW # disable I/O and ext. interrupts | ||
375 | lgr %r15,%r2 | ||
376 | lgr %r11,%r2 | ||
377 | aghi %r15,-STACK_FRAME_OVERHEAD | ||
378 | xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15) | ||
379 | lg %r12,__LC_THREAD_INFO | ||
380 | ssm __LC_SVC_NEW_PSW # reenable interrupts | ||
381 | j sysc_return | ||
382 | 366 | ||
383 | /* | 367 | /* |
384 | * Program check handler routine | 368 | * Program check handler routine |
diff --git a/arch/score/Kconfig b/arch/score/Kconfig index 4f93a431a45a..a285e78fb9c5 100644 --- a/arch/score/Kconfig +++ b/arch/score/Kconfig | |||
@@ -13,6 +13,8 @@ config SCORE | |||
13 | select GENERIC_CLOCKEVENTS | 13 | select GENERIC_CLOCKEVENTS |
14 | select HAVE_MOD_ARCH_SPECIFIC | 14 | select HAVE_MOD_ARCH_SPECIFIC |
15 | select MODULES_USE_ELF_REL | 15 | select MODULES_USE_ELF_REL |
16 | select GENERIC_KERNEL_THREAD | ||
17 | select GENERIC_KERNEL_EXECVE | ||
16 | 18 | ||
17 | choice | 19 | choice |
18 | prompt "System type" | 20 | prompt "System type" |
diff --git a/arch/score/include/asm/processor.h b/arch/score/include/asm/processor.h index ab3aceb54209..d9a922d8711b 100644 --- a/arch/score/include/asm/processor.h +++ b/arch/score/include/asm/processor.h | |||
@@ -13,7 +13,6 @@ struct task_struct; | |||
13 | */ | 13 | */ |
14 | extern void (*cpu_wait)(void); | 14 | extern void (*cpu_wait)(void); |
15 | 15 | ||
16 | extern long kernel_thread(int (*fn)(void *), void *arg, unsigned long flags); | ||
17 | extern unsigned long thread_saved_pc(struct task_struct *tsk); | 16 | extern unsigned long thread_saved_pc(struct task_struct *tsk); |
18 | extern void start_thread(struct pt_regs *regs, | 17 | extern void start_thread(struct pt_regs *regs, |
19 | unsigned long pc, unsigned long sp); | 18 | unsigned long pc, unsigned long sp); |
diff --git a/arch/score/include/asm/syscalls.h b/arch/score/include/asm/syscalls.h index 1dd5e0d6b0c3..8d332534342f 100644 --- a/arch/score/include/asm/syscalls.h +++ b/arch/score/include/asm/syscalls.h | |||
@@ -2,7 +2,6 @@ | |||
2 | #define _ASM_SCORE_SYSCALLS_H | 2 | #define _ASM_SCORE_SYSCALLS_H |
3 | 3 | ||
4 | asmlinkage long score_clone(struct pt_regs *regs); | 4 | asmlinkage long score_clone(struct pt_regs *regs); |
5 | asmlinkage long score_execve(struct pt_regs *regs); | ||
6 | asmlinkage long score_sigaltstack(struct pt_regs *regs); | 5 | asmlinkage long score_sigaltstack(struct pt_regs *regs); |
7 | asmlinkage long score_rt_sigreturn(struct pt_regs *regs); | 6 | asmlinkage long score_rt_sigreturn(struct pt_regs *regs); |
8 | 7 | ||
diff --git a/arch/score/include/asm/unistd.h b/arch/score/include/asm/unistd.h index a862384e9c16..b006ca435120 100644 --- a/arch/score/include/asm/unistd.h +++ b/arch/score/include/asm/unistd.h | |||
@@ -4,5 +4,6 @@ | |||
4 | #define __ARCH_WANT_SYSCALL_NO_FLAGS | 4 | #define __ARCH_WANT_SYSCALL_NO_FLAGS |
5 | #define __ARCH_WANT_SYSCALL_OFF_T | 5 | #define __ARCH_WANT_SYSCALL_OFF_T |
6 | #define __ARCH_WANT_SYSCALL_DEPRECATED | 6 | #define __ARCH_WANT_SYSCALL_DEPRECATED |
7 | #define __ARCH_WANT_SYS_EXECVE | ||
7 | 8 | ||
8 | #include <asm-generic/unistd.h> | 9 | #include <asm-generic/unistd.h> |
diff --git a/arch/score/kernel/entry.S b/arch/score/kernel/entry.S index 83bb96079c43..da9901088bbb 100644 --- a/arch/score/kernel/entry.S +++ b/arch/score/kernel/entry.S | |||
@@ -278,6 +278,13 @@ need_resched: | |||
278 | nop | 278 | nop |
279 | #endif | 279 | #endif |
280 | 280 | ||
281 | ENTRY(ret_from_kernel_thread) | ||
282 | bl schedule_tail # r4=struct task_struct *prev | ||
283 | nop | ||
284 | mv r4, r13 | ||
285 | brl r12 | ||
286 | j syscall_exit | ||
287 | |||
281 | ENTRY(ret_from_fork) | 288 | ENTRY(ret_from_fork) |
282 | bl schedule_tail # r4=struct task_struct *prev | 289 | bl schedule_tail # r4=struct task_struct *prev |
283 | 290 | ||
@@ -480,11 +487,6 @@ illegal_syscall: | |||
480 | sw r9, [r0, PT_R7] | 487 | sw r9, [r0, PT_R7] |
481 | j syscall_return | 488 | j syscall_return |
482 | 489 | ||
483 | ENTRY(sys_execve) | ||
484 | mv r4, r0 | ||
485 | la r8, score_execve | ||
486 | br r8 | ||
487 | |||
488 | ENTRY(sys_clone) | 490 | ENTRY(sys_clone) |
489 | mv r4, r0 | 491 | mv r4, r0 |
490 | la r8, score_clone | 492 | la r8, score_clone |
diff --git a/arch/score/kernel/process.c b/arch/score/kernel/process.c index 637970cfd3f4..6f311cf64b99 100644 --- a/arch/score/kernel/process.c +++ b/arch/score/kernel/process.c | |||
@@ -60,6 +60,7 @@ void __noreturn cpu_idle(void) | |||
60 | } | 60 | } |
61 | 61 | ||
62 | void ret_from_fork(void); | 62 | void ret_from_fork(void); |
63 | void ret_from_kernel_thread(void); | ||
63 | 64 | ||
64 | void start_thread(struct pt_regs *regs, unsigned long pc, unsigned long sp) | 65 | void start_thread(struct pt_regs *regs, unsigned long pc, unsigned long sp) |
65 | { | 66 | { |
@@ -86,29 +87,27 @@ void flush_thread(void) {} | |||
86 | * set up the kernel stack and exception frames for a new process | 87 | * set up the kernel stack and exception frames for a new process |
87 | */ | 88 | */ |
88 | int copy_thread(unsigned long clone_flags, unsigned long usp, | 89 | int copy_thread(unsigned long clone_flags, unsigned long usp, |
89 | unsigned long unused, | 90 | unsigned long arg, |
90 | struct task_struct *p, struct pt_regs *regs) | 91 | struct task_struct *p, struct pt_regs *regs) |
91 | { | 92 | { |
92 | struct thread_info *ti = task_thread_info(p); | 93 | struct thread_info *ti = task_thread_info(p); |
93 | struct pt_regs *childregs = task_pt_regs(p); | 94 | struct pt_regs *childregs = task_pt_regs(p); |
94 | 95 | ||
95 | p->set_child_tid = NULL; | 96 | p->thread.reg0 = (unsigned long) childregs; |
96 | p->clear_child_tid = NULL; | 97 | if (unlikely(!regs)) { |
97 | 98 | memset(childregs, 0, sizeof(struct pt_regs)); | |
98 | *childregs = *regs; | 99 | p->thread->reg12 = usp; |
99 | childregs->regs[7] = 0; /* Clear error flag */ | 100 | p->thread->reg13 = arg; |
100 | childregs->regs[4] = 0; /* Child gets zero as return value */ | 101 | p->thread.reg3 = (unsigned long) ret_from_kernel_thread; |
101 | regs->regs[4] = p->pid; | ||
102 | |||
103 | if (childregs->cp0_psr & 0x8) { /* test kernel fork or user fork */ | ||
104 | childregs->regs[0] = usp; /* user fork */ | ||
105 | } else { | 102 | } else { |
106 | childregs->regs[28] = (unsigned long) ti; /* kernel fork */ | 103 | *childregs = *regs; |
107 | childregs->regs[0] = (unsigned long) childregs; | 104 | childregs->regs[7] = 0; /* Clear error flag */ |
105 | childregs->regs[4] = 0; /* Child gets zero as return value */ | ||
106 | childregs->regs[0] = usp; /* user fork */ | ||
107 | regs->regs[4] = p->pid; /* WTF? */ | ||
108 | p->thread.reg3 = (unsigned long) ret_from_fork; | ||
108 | } | 109 | } |
109 | 110 | ||
110 | p->thread.reg0 = (unsigned long) childregs; | ||
111 | p->thread.reg3 = (unsigned long) ret_from_fork; | ||
112 | p->thread.cp0_psr = 0; | 111 | p->thread.cp0_psr = 0; |
113 | 112 | ||
114 | return 0; | 113 | return 0; |
@@ -120,32 +119,6 @@ int dump_fpu(struct pt_regs *regs, elf_fpregset_t *r) | |||
120 | return 1; | 119 | return 1; |
121 | } | 120 | } |
122 | 121 | ||
123 | static void __noreturn | ||
124 | kernel_thread_helper(void *unused0, int (*fn)(void *), | ||
125 | void *arg, void *unused1) | ||
126 | { | ||
127 | do_exit(fn(arg)); | ||
128 | } | ||
129 | |||
130 | /* | ||
131 | * Create a kernel thread. | ||
132 | */ | ||
133 | long kernel_thread(int (*fn)(void *), void *arg, unsigned long flags) | ||
134 | { | ||
135 | struct pt_regs regs; | ||
136 | |||
137 | memset(®s, 0, sizeof(regs)); | ||
138 | |||
139 | regs.regs[6] = (unsigned long) arg; | ||
140 | regs.regs[5] = (unsigned long) fn; | ||
141 | regs.cp0_epc = (unsigned long) kernel_thread_helper; | ||
142 | regs.cp0_psr = (regs.cp0_psr & ~(0x1|0x4|0x8)) | \ | ||
143 | ((regs.cp0_psr & 0x3) << 2); | ||
144 | |||
145 | return do_fork(flags | CLONE_VM | CLONE_UNTRACED, \ | ||
146 | 0, ®s, 0, NULL, NULL); | ||
147 | } | ||
148 | |||
149 | unsigned long thread_saved_pc(struct task_struct *tsk) | 122 | unsigned long thread_saved_pc(struct task_struct *tsk) |
150 | { | 123 | { |
151 | return task_pt_regs(tsk)->cp0_epc; | 124 | return task_pt_regs(tsk)->cp0_epc; |
diff --git a/arch/score/kernel/sys_score.c b/arch/score/kernel/sys_score.c index d45cf00a3351..c54434c2fd9d 100644 --- a/arch/score/kernel/sys_score.c +++ b/arch/score/kernel/sys_score.c | |||
@@ -83,57 +83,3 @@ score_vfork(struct pt_regs *regs) | |||
83 | return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, | 83 | return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, |
84 | regs->regs[0], regs, 0, NULL, NULL); | 84 | regs->regs[0], regs, 0, NULL, NULL); |
85 | } | 85 | } |
86 | |||
87 | /* | ||
88 | * sys_execve() executes a new program. | ||
89 | * This is called indirectly via a small wrapper | ||
90 | */ | ||
91 | asmlinkage long | ||
92 | score_execve(struct pt_regs *regs) | ||
93 | { | ||
94 | int error; | ||
95 | struct filename *filename; | ||
96 | |||
97 | filename = getname((char __user*)regs->regs[4]); | ||
98 | error = PTR_ERR(filename); | ||
99 | if (IS_ERR(filename)) | ||
100 | return error; | ||
101 | |||
102 | error = do_execve(filename->name, | ||
103 | (const char __user *const __user *)regs->regs[5], | ||
104 | (const char __user *const __user *)regs->regs[6], | ||
105 | regs); | ||
106 | |||
107 | putname(filename); | ||
108 | return error; | ||
109 | } | ||
110 | |||
111 | /* | ||
112 | * Do a system call from kernel instead of calling sys_execve so we | ||
113 | * end up with proper pt_regs. | ||
114 | */ | ||
115 | asmlinkage | ||
116 | int kernel_execve(const char *filename, | ||
117 | const char *const argv[], | ||
118 | const char *const envp[]) | ||
119 | { | ||
120 | register unsigned long __r4 asm("r4") = (unsigned long) filename; | ||
121 | register unsigned long __r5 asm("r5") = (unsigned long) argv; | ||
122 | register unsigned long __r6 asm("r6") = (unsigned long) envp; | ||
123 | register unsigned long __r7 asm("r7"); | ||
124 | |||
125 | __asm__ __volatile__ (" \n" | ||
126 | "ldi r27, %5 \n" | ||
127 | "syscall \n" | ||
128 | "mv %0, r4 \n" | ||
129 | "mv %1, r7 \n" | ||
130 | : "=&r" (__r4), "=r" (__r7) | ||
131 | : "r" (__r4), "r" (__r5), "r" (__r6), "i" (__NR_execve) | ||
132 | : "r8", "r9", "r10", "r11", "r22", "r23", "r24", "r25", | ||
133 | "r26", "r27", "memory"); | ||
134 | |||
135 | if (__r7 == 0) | ||
136 | return __r4; | ||
137 | |||
138 | return -__r4; | ||
139 | } | ||
diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig index babc2b826c5c..8451317eed58 100644 --- a/arch/sh/Kconfig +++ b/arch/sh/Kconfig | |||
@@ -40,6 +40,8 @@ config SUPERH | |||
40 | select GENERIC_STRNLEN_USER | 40 | select GENERIC_STRNLEN_USER |
41 | select HAVE_MOD_ARCH_SPECIFIC if DWARF_UNWINDER | 41 | select HAVE_MOD_ARCH_SPECIFIC if DWARF_UNWINDER |
42 | select MODULES_USE_ELF_RELA | 42 | select MODULES_USE_ELF_RELA |
43 | select GENERIC_KERNEL_THREAD | ||
44 | select GENERIC_KERNEL_EXECVE | ||
43 | help | 45 | help |
44 | The SuperH is a RISC processor targeted for use in embedded systems | 46 | The SuperH is a RISC processor targeted for use in embedded systems |
45 | and consumer electronics; it was also used in the Sega Dreamcast | 47 | and consumer electronics; it was also used in the Sega Dreamcast |
diff --git a/arch/sh/include/asm/processor_32.h b/arch/sh/include/asm/processor_32.h index b6311fd2d066..b1320d55ca30 100644 --- a/arch/sh/include/asm/processor_32.h +++ b/arch/sh/include/asm/processor_32.h | |||
@@ -126,11 +126,6 @@ extern void start_thread(struct pt_regs *regs, unsigned long new_pc, unsigned lo | |||
126 | /* Free all resources held by a thread. */ | 126 | /* Free all resources held by a thread. */ |
127 | extern void release_thread(struct task_struct *); | 127 | extern void release_thread(struct task_struct *); |
128 | 128 | ||
129 | /* | ||
130 | * create a kernel thread without removing it from tasklists | ||
131 | */ | ||
132 | extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags); | ||
133 | |||
134 | /* Copy and release all segment info associated with a VM */ | 129 | /* Copy and release all segment info associated with a VM */ |
135 | #define copy_segments(p, mm) do { } while(0) | 130 | #define copy_segments(p, mm) do { } while(0) |
136 | #define release_segments(mm) do { } while(0) | 131 | #define release_segments(mm) do { } while(0) |
diff --git a/arch/sh/include/asm/processor_64.h b/arch/sh/include/asm/processor_64.h index cd6029fb2c01..1ee8946f0952 100644 --- a/arch/sh/include/asm/processor_64.h +++ b/arch/sh/include/asm/processor_64.h | |||
@@ -159,11 +159,6 @@ struct mm_struct; | |||
159 | 159 | ||
160 | /* Free all resources held by a thread. */ | 160 | /* Free all resources held by a thread. */ |
161 | extern void release_thread(struct task_struct *); | 161 | extern void release_thread(struct task_struct *); |
162 | /* | ||
163 | * create a kernel thread without removing it from tasklists | ||
164 | */ | ||
165 | extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags); | ||
166 | |||
167 | 162 | ||
168 | /* Copy and release all segment info associated with a VM */ | 163 | /* Copy and release all segment info associated with a VM */ |
169 | #define copy_segments(p, mm) do { } while (0) | 164 | #define copy_segments(p, mm) do { } while (0) |
diff --git a/arch/sh/include/asm/syscalls_32.h b/arch/sh/include/asm/syscalls_32.h index 6c1fa559753c..d2f89f1741f4 100644 --- a/arch/sh/include/asm/syscalls_32.h +++ b/arch/sh/include/asm/syscalls_32.h | |||
@@ -19,10 +19,6 @@ asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp, | |||
19 | asmlinkage int sys_vfork(unsigned long r4, unsigned long r5, | 19 | asmlinkage int sys_vfork(unsigned long r4, unsigned long r5, |
20 | unsigned long r6, unsigned long r7, | 20 | unsigned long r6, unsigned long r7, |
21 | struct pt_regs __regs); | 21 | struct pt_regs __regs); |
22 | asmlinkage int sys_execve(const char __user *ufilename, | ||
23 | const char __user *const __user *uargv, | ||
24 | const char __user *const __user *uenvp, | ||
25 | unsigned long r7, struct pt_regs __regs); | ||
26 | asmlinkage int sys_sigsuspend(old_sigset_t mask); | 22 | asmlinkage int sys_sigsuspend(old_sigset_t mask); |
27 | asmlinkage int sys_sigaction(int sig, const struct old_sigaction __user *act, | 23 | asmlinkage int sys_sigaction(int sig, const struct old_sigaction __user *act, |
28 | struct old_sigaction __user *oact); | 24 | struct old_sigaction __user *oact); |
diff --git a/arch/sh/include/asm/syscalls_64.h b/arch/sh/include/asm/syscalls_64.h index ee519f41d950..3fedd9f1fab5 100644 --- a/arch/sh/include/asm/syscalls_64.h +++ b/arch/sh/include/asm/syscalls_64.h | |||
@@ -21,10 +21,6 @@ asmlinkage int sys_vfork(unsigned long r2, unsigned long r3, | |||
21 | unsigned long r4, unsigned long r5, | 21 | unsigned long r4, unsigned long r5, |
22 | unsigned long r6, unsigned long r7, | 22 | unsigned long r6, unsigned long r7, |
23 | struct pt_regs *pregs); | 23 | struct pt_regs *pregs); |
24 | asmlinkage int sys_execve(const char *ufilename, char **uargv, | ||
25 | char **uenvp, unsigned long r5, | ||
26 | unsigned long r6, unsigned long r7, | ||
27 | struct pt_regs *pregs); | ||
28 | 24 | ||
29 | /* Misc syscall related bits */ | 25 | /* Misc syscall related bits */ |
30 | asmlinkage long long do_syscall_trace_enter(struct pt_regs *regs); | 26 | asmlinkage long long do_syscall_trace_enter(struct pt_regs *regs); |
diff --git a/arch/sh/include/asm/unistd.h b/arch/sh/include/asm/unistd.h index 38956dfa76f7..f1f4775766a6 100644 --- a/arch/sh/include/asm/unistd.h +++ b/arch/sh/include/asm/unistd.h | |||
@@ -28,6 +28,7 @@ | |||
28 | # define __ARCH_WANT_SYS_SIGPENDING | 28 | # define __ARCH_WANT_SYS_SIGPENDING |
29 | # define __ARCH_WANT_SYS_SIGPROCMASK | 29 | # define __ARCH_WANT_SYS_SIGPROCMASK |
30 | # define __ARCH_WANT_SYS_RT_SIGACTION | 30 | # define __ARCH_WANT_SYS_RT_SIGACTION |
31 | # define __ARCH_WANT_SYS_EXECVE | ||
31 | 32 | ||
32 | /* | 33 | /* |
33 | * "Conditional" syscalls | 34 | * "Conditional" syscalls |
diff --git a/arch/sh/kernel/Makefile b/arch/sh/kernel/Makefile index 88571ff8eeec..f259b37874e9 100644 --- a/arch/sh/kernel/Makefile +++ b/arch/sh/kernel/Makefile | |||
@@ -16,7 +16,7 @@ obj-y := debugtraps.o dma-nommu.o dumpstack.o \ | |||
16 | machvec.o nmi_debug.o process.o \ | 16 | machvec.o nmi_debug.o process.o \ |
17 | process_$(BITS).o ptrace.o ptrace_$(BITS).o \ | 17 | process_$(BITS).o ptrace.o ptrace_$(BITS).o \ |
18 | reboot.o return_address.o \ | 18 | reboot.o return_address.o \ |
19 | setup.o signal_$(BITS).o sys_sh.o sys_sh$(BITS).o \ | 19 | setup.o signal_$(BITS).o sys_sh.o \ |
20 | syscalls_$(BITS).o time.o topology.o traps.o \ | 20 | syscalls_$(BITS).o time.o topology.o traps.o \ |
21 | traps_$(BITS).o unwinder.o | 21 | traps_$(BITS).o unwinder.o |
22 | 22 | ||
@@ -25,6 +25,7 @@ obj-y += iomap.o | |||
25 | obj-$(CONFIG_HAS_IOPORT) += ioport.o | 25 | obj-$(CONFIG_HAS_IOPORT) += ioport.o |
26 | endif | 26 | endif |
27 | 27 | ||
28 | obj-$(CONFIG_SUPERH32) += sys_sh32.o | ||
28 | obj-y += cpu/ | 29 | obj-y += cpu/ |
29 | obj-$(CONFIG_VSYSCALL) += vsyscall/ | 30 | obj-$(CONFIG_VSYSCALL) += vsyscall/ |
30 | obj-$(CONFIG_SMP) += smp.o | 31 | obj-$(CONFIG_SMP) += smp.o |
diff --git a/arch/sh/kernel/cpu/sh5/entry.S b/arch/sh/kernel/cpu/sh5/entry.S index 7e605b95592a..0c8d0377d40b 100644 --- a/arch/sh/kernel/cpu/sh5/entry.S +++ b/arch/sh/kernel/cpu/sh5/entry.S | |||
@@ -1228,6 +1228,25 @@ ret_from_fork: | |||
1228 | pta ret_from_syscall, tr0 | 1228 | pta ret_from_syscall, tr0 |
1229 | blink tr0, ZERO | 1229 | blink tr0, ZERO |
1230 | 1230 | ||
1231 | .global ret_from_kernel_thread | ||
1232 | ret_from_kernel_thread: | ||
1233 | |||
1234 | movi schedule_tail,r5 | ||
1235 | ori r5, 1, r5 | ||
1236 | ptabs r5, tr0 | ||
1237 | blink tr0, LINK | ||
1238 | |||
1239 | ld.q SP, FRAME_R(2), r2 | ||
1240 | ld.q SP, FRAME_R(3), r3 | ||
1241 | ptabs r3, tr0 | ||
1242 | blink tr0, LINK | ||
1243 | |||
1244 | ld.q SP, FRAME_S(FSPC), r2 | ||
1245 | addi r2, 4, r2 /* Move PC, being pre-execution event */ | ||
1246 | st.q SP, FRAME_S(FSPC), r2 | ||
1247 | pta ret_from_syscall, tr0 | ||
1248 | blink tr0, ZERO | ||
1249 | |||
1231 | syscall_allowed: | 1250 | syscall_allowed: |
1232 | /* Use LINK to deflect the exit point, default is syscall_ret */ | 1251 | /* Use LINK to deflect the exit point, default is syscall_ret */ |
1233 | pta syscall_ret, tr0 | 1252 | pta syscall_ret, tr0 |
diff --git a/arch/sh/kernel/entry-common.S b/arch/sh/kernel/entry-common.S index b96489d8b27d..9b6e4beeb296 100644 --- a/arch/sh/kernel/entry-common.S +++ b/arch/sh/kernel/entry-common.S | |||
@@ -297,6 +297,19 @@ ret_from_fork: | |||
297 | mov r0, r4 | 297 | mov r0, r4 |
298 | bra syscall_exit | 298 | bra syscall_exit |
299 | nop | 299 | nop |
300 | |||
301 | .align 2 | ||
302 | .globl ret_from_kernel_thread | ||
303 | ret_from_kernel_thread: | ||
304 | mov.l 1f, r8 | ||
305 | jsr @r8 | ||
306 | mov r0, r4 | ||
307 | mov.l @(OFF_R5,r15), r5 ! fn | ||
308 | jsr @r5 | ||
309 | mov.l @(OFF_R4,r15), r4 ! arg | ||
310 | bra syscall_exit | ||
311 | nop | ||
312 | |||
300 | .align 2 | 313 | .align 2 |
301 | 1: .long schedule_tail | 314 | 1: .long schedule_tail |
302 | 315 | ||
diff --git a/arch/sh/kernel/process_32.c b/arch/sh/kernel/process_32.c index ba7345f37bc9..fce8029de922 100644 --- a/arch/sh/kernel/process_32.c +++ b/arch/sh/kernel/process_32.c | |||
@@ -68,38 +68,6 @@ void show_regs(struct pt_regs * regs) | |||
68 | show_code(regs); | 68 | show_code(regs); |
69 | } | 69 | } |
70 | 70 | ||
71 | /* | ||
72 | * Create a kernel thread | ||
73 | */ | ||
74 | __noreturn void kernel_thread_helper(void *arg, int (*fn)(void *)) | ||
75 | { | ||
76 | do_exit(fn(arg)); | ||
77 | } | ||
78 | |||
79 | /* Don't use this in BL=1(cli). Or else, CPU resets! */ | ||
80 | int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) | ||
81 | { | ||
82 | struct pt_regs regs; | ||
83 | int pid; | ||
84 | |||
85 | memset(®s, 0, sizeof(regs)); | ||
86 | regs.regs[4] = (unsigned long)arg; | ||
87 | regs.regs[5] = (unsigned long)fn; | ||
88 | |||
89 | regs.pc = (unsigned long)kernel_thread_helper; | ||
90 | regs.sr = SR_MD; | ||
91 | #if defined(CONFIG_SH_FPU) | ||
92 | regs.sr |= SR_FD; | ||
93 | #endif | ||
94 | |||
95 | /* Ok, create the new process.. */ | ||
96 | pid = do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, | ||
97 | ®s, 0, NULL, NULL); | ||
98 | |||
99 | return pid; | ||
100 | } | ||
101 | EXPORT_SYMBOL(kernel_thread); | ||
102 | |||
103 | void start_thread(struct pt_regs *regs, unsigned long new_pc, | 71 | void start_thread(struct pt_regs *regs, unsigned long new_pc, |
104 | unsigned long new_sp) | 72 | unsigned long new_sp) |
105 | { | 73 | { |
@@ -157,9 +125,10 @@ int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu) | |||
157 | EXPORT_SYMBOL(dump_fpu); | 125 | EXPORT_SYMBOL(dump_fpu); |
158 | 126 | ||
159 | asmlinkage void ret_from_fork(void); | 127 | asmlinkage void ret_from_fork(void); |
128 | asmlinkage void ret_from_kernel_thread(void); | ||
160 | 129 | ||
161 | int copy_thread(unsigned long clone_flags, unsigned long usp, | 130 | int copy_thread(unsigned long clone_flags, unsigned long usp, |
162 | unsigned long unused, | 131 | unsigned long arg, |
163 | struct task_struct *p, struct pt_regs *regs) | 132 | struct task_struct *p, struct pt_regs *regs) |
164 | { | 133 | { |
165 | struct thread_info *ti = task_thread_info(p); | 134 | struct thread_info *ti = task_thread_info(p); |
@@ -177,29 +146,34 @@ int copy_thread(unsigned long clone_flags, unsigned long usp, | |||
177 | } | 146 | } |
178 | #endif | 147 | #endif |
179 | 148 | ||
180 | childregs = task_pt_regs(p); | 149 | memset(p->thread.ptrace_bps, 0, sizeof(p->thread.ptrace_bps)); |
181 | *childregs = *regs; | ||
182 | 150 | ||
183 | if (user_mode(regs)) { | 151 | childregs = task_pt_regs(p); |
184 | childregs->regs[15] = usp; | 152 | p->thread.sp = (unsigned long) childregs; |
185 | ti->addr_limit = USER_DS; | 153 | if (unlikely(p->flags & PF_KTHREAD)) { |
186 | } else { | 154 | memset(childregs, 0, sizeof(struct pt_regs)); |
187 | childregs->regs[15] = (unsigned long)childregs; | 155 | p->thread.pc = (unsigned long) ret_from_kernel_thread; |
156 | childregs->regs[4] = arg; | ||
157 | childregs->regs[5] = usp; | ||
158 | childregs->sr = SR_MD; | ||
159 | #if defined(CONFIG_SH_FPU) | ||
160 | childregs->sr |= SR_FD; | ||
161 | #endif | ||
188 | ti->addr_limit = KERNEL_DS; | 162 | ti->addr_limit = KERNEL_DS; |
189 | ti->status &= ~TS_USEDFPU; | 163 | ti->status &= ~TS_USEDFPU; |
190 | p->fpu_counter = 0; | 164 | p->fpu_counter = 0; |
165 | return 0; | ||
191 | } | 166 | } |
167 | *childregs = *regs; | ||
168 | |||
169 | childregs->regs[15] = usp; | ||
170 | ti->addr_limit = USER_DS; | ||
192 | 171 | ||
193 | if (clone_flags & CLONE_SETTLS) | 172 | if (clone_flags & CLONE_SETTLS) |
194 | childregs->gbr = childregs->regs[0]; | 173 | childregs->gbr = childregs->regs[0]; |
195 | 174 | ||
196 | childregs->regs[0] = 0; /* Set return value for child */ | 175 | childregs->regs[0] = 0; /* Set return value for child */ |
197 | |||
198 | p->thread.sp = (unsigned long) childregs; | ||
199 | p->thread.pc = (unsigned long) ret_from_fork; | 176 | p->thread.pc = (unsigned long) ret_from_fork; |
200 | |||
201 | memset(p->thread.ptrace_bps, 0, sizeof(p->thread.ptrace_bps)); | ||
202 | |||
203 | return 0; | 177 | return 0; |
204 | } | 178 | } |
205 | 179 | ||
@@ -288,29 +262,6 @@ asmlinkage int sys_vfork(unsigned long r4, unsigned long r5, | |||
288 | 0, NULL, NULL); | 262 | 0, NULL, NULL); |
289 | } | 263 | } |
290 | 264 | ||
291 | /* | ||
292 | * sys_execve() executes a new program. | ||
293 | */ | ||
294 | asmlinkage int sys_execve(const char __user *ufilename, | ||
295 | const char __user *const __user *uargv, | ||
296 | const char __user *const __user *uenvp, | ||
297 | unsigned long r7, struct pt_regs __regs) | ||
298 | { | ||
299 | struct pt_regs *regs = RELOC_HIDE(&__regs, 0); | ||
300 | int error; | ||
301 | struct filename *filename; | ||
302 | |||
303 | filename = getname(ufilename); | ||
304 | error = PTR_ERR(filename); | ||
305 | if (IS_ERR(filename)) | ||
306 | goto out; | ||
307 | |||
308 | error = do_execve(filename->name, uargv, uenvp, regs); | ||
309 | putname(filename); | ||
310 | out: | ||
311 | return error; | ||
312 | } | ||
313 | |||
314 | unsigned long get_wchan(struct task_struct *p) | 265 | unsigned long get_wchan(struct task_struct *p) |
315 | { | 266 | { |
316 | unsigned long pc; | 267 | unsigned long pc; |
diff --git a/arch/sh/kernel/process_64.c b/arch/sh/kernel/process_64.c index 98a709f0c3c4..3a0f3fd3bb58 100644 --- a/arch/sh/kernel/process_64.c +++ b/arch/sh/kernel/process_64.c | |||
@@ -285,39 +285,6 @@ void show_regs(struct pt_regs *regs) | |||
285 | } | 285 | } |
286 | 286 | ||
287 | /* | 287 | /* |
288 | * Create a kernel thread | ||
289 | */ | ||
290 | __noreturn void kernel_thread_helper(void *arg, int (*fn)(void *)) | ||
291 | { | ||
292 | do_exit(fn(arg)); | ||
293 | } | ||
294 | |||
295 | /* | ||
296 | * This is the mechanism for creating a new kernel thread. | ||
297 | * | ||
298 | * NOTE! Only a kernel-only process(ie the swapper or direct descendants | ||
299 | * who haven't done an "execve()") should use this: it will work within | ||
300 | * a system call from a "real" process, but the process memory space will | ||
301 | * not be freed until both the parent and the child have exited. | ||
302 | */ | ||
303 | int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) | ||
304 | { | ||
305 | struct pt_regs regs; | ||
306 | |||
307 | memset(®s, 0, sizeof(regs)); | ||
308 | regs.regs[2] = (unsigned long)arg; | ||
309 | regs.regs[3] = (unsigned long)fn; | ||
310 | |||
311 | regs.pc = (unsigned long)kernel_thread_helper; | ||
312 | regs.sr = (1 << 30); | ||
313 | |||
314 | /* Ok, create the new process.. */ | ||
315 | return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, | ||
316 | ®s, 0, NULL, NULL); | ||
317 | } | ||
318 | EXPORT_SYMBOL(kernel_thread); | ||
319 | |||
320 | /* | ||
321 | * Free current thread data structures etc.. | 288 | * Free current thread data structures etc.. |
322 | */ | 289 | */ |
323 | void exit_thread(void) | 290 | void exit_thread(void) |
@@ -401,15 +368,17 @@ int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu) | |||
401 | EXPORT_SYMBOL(dump_fpu); | 368 | EXPORT_SYMBOL(dump_fpu); |
402 | 369 | ||
403 | asmlinkage void ret_from_fork(void); | 370 | asmlinkage void ret_from_fork(void); |
371 | asmlinkage void ret_from_kernel_thread(void); | ||
404 | 372 | ||
405 | int copy_thread(unsigned long clone_flags, unsigned long usp, | 373 | int copy_thread(unsigned long clone_flags, unsigned long usp, |
406 | unsigned long unused, | 374 | unsigned long arg, |
407 | struct task_struct *p, struct pt_regs *regs) | 375 | struct task_struct *p, struct pt_regs *regs) |
408 | { | 376 | { |
409 | struct pt_regs *childregs; | 377 | struct pt_regs *childregs; |
410 | 378 | ||
411 | #ifdef CONFIG_SH_FPU | 379 | #ifdef CONFIG_SH_FPU |
412 | if(last_task_used_math == current) { | 380 | /* can't happen for a kernel thread */ |
381 | if (last_task_used_math == current) { | ||
413 | enable_fpu(); | 382 | enable_fpu(); |
414 | save_fpu(current); | 383 | save_fpu(current); |
415 | disable_fpu(); | 384 | disable_fpu(); |
@@ -419,7 +388,17 @@ int copy_thread(unsigned long clone_flags, unsigned long usp, | |||
419 | #endif | 388 | #endif |
420 | /* Copy from sh version */ | 389 | /* Copy from sh version */ |
421 | childregs = (struct pt_regs *)(THREAD_SIZE + task_stack_page(p)) - 1; | 390 | childregs = (struct pt_regs *)(THREAD_SIZE + task_stack_page(p)) - 1; |
391 | p->thread.sp = (unsigned long) childregs; | ||
422 | 392 | ||
393 | if (unlikely(p->flags & PF_KTHREAD)) { | ||
394 | memset(childregs, 0, sizeof(struct pt_regs)); | ||
395 | childregs->regs[2] = (unsigned long)arg; | ||
396 | childregs->regs[3] = (unsigned long)fn; | ||
397 | childregs->sr = (1 << 30); /* not user_mode */ | ||
398 | childregs->sr |= SR_FD; /* Invalidate FPU flag */ | ||
399 | p->thread.pc = (unsigned long) ret_from_kernel_thread; | ||
400 | return 0; | ||
401 | } | ||
423 | *childregs = *regs; | 402 | *childregs = *regs; |
424 | 403 | ||
425 | /* | 404 | /* |
@@ -428,19 +407,12 @@ int copy_thread(unsigned long clone_flags, unsigned long usp, | |||
428 | * 32-bit wide and context switch must take care | 407 | * 32-bit wide and context switch must take care |
429 | * of NEFF sign extension. | 408 | * of NEFF sign extension. |
430 | */ | 409 | */ |
431 | if (user_mode(regs)) { | 410 | childregs->regs[15] = neff_sign_extend(usp); |
432 | childregs->regs[15] = neff_sign_extend(usp); | 411 | p->thread.uregs = childregs; |
433 | p->thread.uregs = childregs; | ||
434 | } else { | ||
435 | childregs->regs[15] = | ||
436 | neff_sign_extend((unsigned long)task_stack_page(p) + | ||
437 | THREAD_SIZE); | ||
438 | } | ||
439 | 412 | ||
440 | childregs->regs[9] = 0; /* Set return value for child */ | 413 | childregs->regs[9] = 0; /* Set return value for child */ |
441 | childregs->sr |= SR_FD; /* Invalidate FPU flag */ | 414 | childregs->sr |= SR_FD; /* Invalidate FPU flag */ |
442 | 415 | ||
443 | p->thread.sp = (unsigned long) childregs; | ||
444 | p->thread.pc = (unsigned long) ret_from_fork; | 416 | p->thread.pc = (unsigned long) ret_from_fork; |
445 | 417 | ||
446 | return 0; | 418 | return 0; |
@@ -482,31 +454,6 @@ asmlinkage int sys_vfork(unsigned long r2, unsigned long r3, | |||
482 | return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, pregs->regs[15], pregs, 0, 0, 0); | 454 | return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, pregs->regs[15], pregs, 0, 0, 0); |
483 | } | 455 | } |
484 | 456 | ||
485 | /* | ||
486 | * sys_execve() executes a new program. | ||
487 | */ | ||
488 | asmlinkage int sys_execve(const char *ufilename, char **uargv, | ||
489 | char **uenvp, unsigned long r5, | ||
490 | unsigned long r6, unsigned long r7, | ||
491 | struct pt_regs *pregs) | ||
492 | { | ||
493 | int error; | ||
494 | struct filename *filename; | ||
495 | |||
496 | filename = getname((char __user *)ufilename); | ||
497 | error = PTR_ERR(filename); | ||
498 | if (IS_ERR(filename)) | ||
499 | goto out; | ||
500 | |||
501 | error = do_execve(filename->name, | ||
502 | (const char __user *const __user *)uargv, | ||
503 | (const char __user *const __user *)uenvp, | ||
504 | pregs); | ||
505 | putname(filename); | ||
506 | out: | ||
507 | return error; | ||
508 | } | ||
509 | |||
510 | #ifdef CONFIG_FRAME_POINTER | 457 | #ifdef CONFIG_FRAME_POINTER |
511 | static int in_sh64_switch_to(unsigned long pc) | 458 | static int in_sh64_switch_to(unsigned long pc) |
512 | { | 459 | { |
diff --git a/arch/sh/kernel/sys_sh32.c b/arch/sh/kernel/sys_sh32.c index f56b6fe5c5d0..497bab3a0401 100644 --- a/arch/sh/kernel/sys_sh32.c +++ b/arch/sh/kernel/sys_sh32.c | |||
@@ -60,27 +60,3 @@ asmlinkage int sys_fadvise64_64_wrapper(int fd, u32 offset0, u32 offset1, | |||
60 | (u64)len0 << 32 | len1, advice); | 60 | (u64)len0 << 32 | len1, advice); |
61 | #endif | 61 | #endif |
62 | } | 62 | } |
63 | |||
64 | #if defined(CONFIG_CPU_SH2) || defined(CONFIG_CPU_SH2A) | ||
65 | #define SYSCALL_ARG3 "trapa #0x23" | ||
66 | #else | ||
67 | #define SYSCALL_ARG3 "trapa #0x13" | ||
68 | #endif | ||
69 | |||
70 | /* | ||
71 | * Do a system call from kernel instead of calling sys_execve so we | ||
72 | * end up with proper pt_regs. | ||
73 | */ | ||
74 | int kernel_execve(const char *filename, | ||
75 | const char *const argv[], | ||
76 | const char *const envp[]) | ||
77 | { | ||
78 | register long __sc0 __asm__ ("r3") = __NR_execve; | ||
79 | register long __sc4 __asm__ ("r4") = (long) filename; | ||
80 | register long __sc5 __asm__ ("r5") = (long) argv; | ||
81 | register long __sc6 __asm__ ("r6") = (long) envp; | ||
82 | __asm__ __volatile__ (SYSCALL_ARG3 : "=z" (__sc0) | ||
83 | : "0" (__sc0), "r" (__sc4), "r" (__sc5), "r" (__sc6) | ||
84 | : "memory"); | ||
85 | return __sc0; | ||
86 | } | ||
diff --git a/arch/sh/kernel/sys_sh64.c b/arch/sh/kernel/sys_sh64.c deleted file mode 100644 index c5a38c4bf410..000000000000 --- a/arch/sh/kernel/sys_sh64.c +++ /dev/null | |||
@@ -1,50 +0,0 @@ | |||
1 | /* | ||
2 | * arch/sh/kernel/sys_sh64.c | ||
3 | * | ||
4 | * Copyright (C) 2000, 2001 Paolo Alberelli | ||
5 | * | ||
6 | * This file contains various random system calls that | ||
7 | * have a non-standard calling sequence on the Linux/SH5 | ||
8 | * platform. | ||
9 | * | ||
10 | * This file is subject to the terms and conditions of the GNU General Public | ||
11 | * License. See the file "COPYING" in the main directory of this archive | ||
12 | * for more details. | ||
13 | */ | ||
14 | #include <linux/errno.h> | ||
15 | #include <linux/rwsem.h> | ||
16 | #include <linux/sched.h> | ||
17 | #include <linux/mm.h> | ||
18 | #include <linux/fs.h> | ||
19 | #include <linux/smp.h> | ||
20 | #include <linux/sem.h> | ||
21 | #include <linux/msg.h> | ||
22 | #include <linux/shm.h> | ||
23 | #include <linux/stat.h> | ||
24 | #include <linux/mman.h> | ||
25 | #include <linux/file.h> | ||
26 | #include <linux/syscalls.h> | ||
27 | #include <linux/ipc.h> | ||
28 | #include <asm/uaccess.h> | ||
29 | #include <asm/ptrace.h> | ||
30 | #include <asm/unistd.h> | ||
31 | |||
32 | /* | ||
33 | * Do a system call from kernel instead of calling sys_execve so we | ||
34 | * end up with proper pt_regs. | ||
35 | */ | ||
36 | int kernel_execve(const char *filename, | ||
37 | const char *const argv[], | ||
38 | const char *const envp[]) | ||
39 | { | ||
40 | register unsigned long __sc0 __asm__ ("r9") = ((0x13 << 16) | __NR_execve); | ||
41 | register unsigned long __sc2 __asm__ ("r2") = (unsigned long) filename; | ||
42 | register unsigned long __sc3 __asm__ ("r3") = (unsigned long) argv; | ||
43 | register unsigned long __sc4 __asm__ ("r4") = (unsigned long) envp; | ||
44 | __asm__ __volatile__ ("trapa %1 !\t\t\t execve(%2,%3,%4)" | ||
45 | : "=r" (__sc0) | ||
46 | : "r" (__sc0), "r" (__sc2), "r" (__sc3), "r" (__sc4) ); | ||
47 | __asm__ __volatile__ ("!dummy %0 %1 %2 %3" | ||
48 | : : "r" (__sc0), "r" (__sc2), "r" (__sc3), "r" (__sc4) : "memory"); | ||
49 | return __sc0; | ||
50 | } | ||
diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig index 9f2edb5c5551..0c7d365fa402 100644 --- a/arch/sparc/Kconfig +++ b/arch/sparc/Kconfig | |||
@@ -41,6 +41,8 @@ config SPARC | |||
41 | select GENERIC_STRNCPY_FROM_USER | 41 | select GENERIC_STRNCPY_FROM_USER |
42 | select GENERIC_STRNLEN_USER | 42 | select GENERIC_STRNLEN_USER |
43 | select MODULES_USE_ELF_RELA | 43 | select MODULES_USE_ELF_RELA |
44 | select GENERIC_KERNEL_THREAD | ||
45 | select GENERIC_KERNEL_EXECVE | ||
44 | 46 | ||
45 | config SPARC32 | 47 | config SPARC32 |
46 | def_bool !64BIT | 48 | def_bool !64BIT |
diff --git a/arch/sparc/include/asm/processor_32.h b/arch/sparc/include/asm/processor_32.h index f74ac9ee33a8..c1e01914fd98 100644 --- a/arch/sparc/include/asm/processor_32.h +++ b/arch/sparc/include/asm/processor_32.h | |||
@@ -106,7 +106,6 @@ static inline void start_thread(struct pt_regs * regs, unsigned long pc, | |||
106 | 106 | ||
107 | /* Free all resources held by a thread. */ | 107 | /* Free all resources held by a thread. */ |
108 | #define release_thread(tsk) do { } while(0) | 108 | #define release_thread(tsk) do { } while(0) |
109 | extern pid_t kernel_thread(int (*fn)(void *), void * arg, unsigned long flags); | ||
110 | 109 | ||
111 | extern unsigned long get_wchan(struct task_struct *); | 110 | extern unsigned long get_wchan(struct task_struct *); |
112 | 111 | ||
diff --git a/arch/sparc/include/asm/processor_64.h b/arch/sparc/include/asm/processor_64.h index 721e25f0e2ea..cce72ce4c334 100644 --- a/arch/sparc/include/asm/processor_64.h +++ b/arch/sparc/include/asm/processor_64.h | |||
@@ -94,6 +94,7 @@ struct thread_struct { | |||
94 | #ifndef __ASSEMBLY__ | 94 | #ifndef __ASSEMBLY__ |
95 | 95 | ||
96 | #include <linux/types.h> | 96 | #include <linux/types.h> |
97 | #include <asm/fpumacro.h> | ||
97 | 98 | ||
98 | /* Return saved PC of a blocked thread. */ | 99 | /* Return saved PC of a blocked thread. */ |
99 | struct task_struct; | 100 | struct task_struct; |
@@ -143,6 +144,10 @@ do { \ | |||
143 | : \ | 144 | : \ |
144 | : "r" (regs), "r" (sp - sizeof(struct reg_window) - STACK_BIAS), \ | 145 | : "r" (regs), "r" (sp - sizeof(struct reg_window) - STACK_BIAS), \ |
145 | "i" ((const unsigned long)(&((struct pt_regs *)0)->u_regs[0]))); \ | 146 | "i" ((const unsigned long)(&((struct pt_regs *)0)->u_regs[0]))); \ |
147 | fprs_write(0); \ | ||
148 | current_thread_info()->xfsr[0] = 0; \ | ||
149 | current_thread_info()->fpsaved[0] = 0; \ | ||
150 | regs->tstate &= ~TSTATE_PEF; \ | ||
146 | } while (0) | 151 | } while (0) |
147 | 152 | ||
148 | #define start_thread32(regs, pc, sp) \ | 153 | #define start_thread32(regs, pc, sp) \ |
@@ -183,13 +188,15 @@ do { \ | |||
183 | : \ | 188 | : \ |
184 | : "r" (regs), "r" (sp - sizeof(struct reg_window32)), \ | 189 | : "r" (regs), "r" (sp - sizeof(struct reg_window32)), \ |
185 | "i" ((const unsigned long)(&((struct pt_regs *)0)->u_regs[0]))); \ | 190 | "i" ((const unsigned long)(&((struct pt_regs *)0)->u_regs[0]))); \ |
191 | fprs_write(0); \ | ||
192 | current_thread_info()->xfsr[0] = 0; \ | ||
193 | current_thread_info()->fpsaved[0] = 0; \ | ||
194 | regs->tstate &= ~TSTATE_PEF; \ | ||
186 | } while (0) | 195 | } while (0) |
187 | 196 | ||
188 | /* Free all resources held by a thread. */ | 197 | /* Free all resources held by a thread. */ |
189 | #define release_thread(tsk) do { } while (0) | 198 | #define release_thread(tsk) do { } while (0) |
190 | 199 | ||
191 | extern pid_t kernel_thread(int (*fn)(void *), void * arg, unsigned long flags); | ||
192 | |||
193 | extern unsigned long get_wchan(struct task_struct *task); | 200 | extern unsigned long get_wchan(struct task_struct *task); |
194 | 201 | ||
195 | #define task_pt_regs(tsk) (task_thread_info(tsk)->kregs) | 202 | #define task_pt_regs(tsk) (task_thread_info(tsk)->kregs) |
diff --git a/arch/sparc/include/asm/ptrace.h b/arch/sparc/include/asm/ptrace.h index da43bdc62294..bdfafd7af46f 100644 --- a/arch/sparc/include/asm/ptrace.h +++ b/arch/sparc/include/asm/ptrace.h | |||
@@ -32,6 +32,9 @@ static inline bool pt_regs_clear_syscall(struct pt_regs *regs) | |||
32 | #define arch_ptrace_stop(exit_code, info) \ | 32 | #define arch_ptrace_stop(exit_code, info) \ |
33 | synchronize_user_stack() | 33 | synchronize_user_stack() |
34 | 34 | ||
35 | #define current_pt_regs() \ | ||
36 | ((struct pt_regs *)((unsigned long)current_thread_info() + THREAD_SIZE) - 1) | ||
37 | |||
35 | struct global_reg_snapshot { | 38 | struct global_reg_snapshot { |
36 | unsigned long tstate; | 39 | unsigned long tstate; |
37 | unsigned long tpc; | 40 | unsigned long tpc; |
@@ -55,9 +58,7 @@ union global_cpu_snapshot { | |||
55 | 58 | ||
56 | extern union global_cpu_snapshot global_cpu_snapshot[NR_CPUS]; | 59 | extern union global_cpu_snapshot global_cpu_snapshot[NR_CPUS]; |
57 | 60 | ||
58 | #define force_successful_syscall_return() \ | 61 | #define force_successful_syscall_return() set_thread_noerror(1) |
59 | do { current_thread_info()->syscall_noerror = 1; \ | ||
60 | } while (0) | ||
61 | #define user_mode(regs) (!((regs)->tstate & TSTATE_PRIV)) | 62 | #define user_mode(regs) (!((regs)->tstate & TSTATE_PRIV)) |
62 | #define instruction_pointer(regs) ((regs)->tpc) | 63 | #define instruction_pointer(regs) ((regs)->tpc) |
63 | #define instruction_pointer_set(regs, val) ((regs)->tpc = (val)) | 64 | #define instruction_pointer_set(regs, val) ((regs)->tpc = (val)) |
@@ -100,6 +101,9 @@ static inline bool pt_regs_clear_syscall(struct pt_regs *regs) | |||
100 | #define arch_ptrace_stop(exit_code, info) \ | 101 | #define arch_ptrace_stop(exit_code, info) \ |
101 | synchronize_user_stack() | 102 | synchronize_user_stack() |
102 | 103 | ||
104 | #define current_pt_regs() \ | ||
105 | ((struct pt_regs *)((unsigned long)current_thread_info() + THREAD_SIZE) - 1) | ||
106 | |||
103 | #define user_mode(regs) (!((regs)->psr & PSR_PS)) | 107 | #define user_mode(regs) (!((regs)->psr & PSR_PS)) |
104 | #define instruction_pointer(regs) ((regs)->pc) | 108 | #define instruction_pointer(regs) ((regs)->pc) |
105 | #define user_stack_pointer(regs) ((regs)->u_regs[UREG_FP]) | 109 | #define user_stack_pointer(regs) ((regs)->u_regs[UREG_FP]) |
diff --git a/arch/sparc/include/asm/switch_to_64.h b/arch/sparc/include/asm/switch_to_64.h index 7923c4a2be38..cad36f56fa03 100644 --- a/arch/sparc/include/asm/switch_to_64.h +++ b/arch/sparc/include/asm/switch_to_64.h | |||
@@ -23,7 +23,7 @@ do { flush_tlb_pending(); \ | |||
23 | /* If you are tempted to conditionalize the following */ \ | 23 | /* If you are tempted to conditionalize the following */ \ |
24 | /* so that ASI is only written if it changes, think again. */ \ | 24 | /* so that ASI is only written if it changes, think again. */ \ |
25 | __asm__ __volatile__("wr %%g0, %0, %%asi" \ | 25 | __asm__ __volatile__("wr %%g0, %0, %%asi" \ |
26 | : : "r" (__thread_flag_byte_ptr(task_thread_info(next))[TI_FLAG_BYTE_CURRENT_DS]));\ | 26 | : : "r" (task_thread_info(next)->current_ds));\ |
27 | trap_block[current_thread_info()->cpu].thread = \ | 27 | trap_block[current_thread_info()->cpu].thread = \ |
28 | task_thread_info(next); \ | 28 | task_thread_info(next); \ |
29 | __asm__ __volatile__( \ | 29 | __asm__ __volatile__( \ |
diff --git a/arch/sparc/include/asm/syscalls.h b/arch/sparc/include/asm/syscalls.h index 45a43f637a14..bf8972adea17 100644 --- a/arch/sparc/include/asm/syscalls.h +++ b/arch/sparc/include/asm/syscalls.h | |||
@@ -8,6 +8,4 @@ extern asmlinkage long sparc_do_fork(unsigned long clone_flags, | |||
8 | struct pt_regs *regs, | 8 | struct pt_regs *regs, |
9 | unsigned long stack_size); | 9 | unsigned long stack_size); |
10 | 10 | ||
11 | extern asmlinkage int sparc_execve(struct pt_regs *regs); | ||
12 | |||
13 | #endif /* _SPARC64_SYSCALLS_H */ | 11 | #endif /* _SPARC64_SYSCALLS_H */ |
diff --git a/arch/sparc/include/asm/thread_info_64.h b/arch/sparc/include/asm/thread_info_64.h index a3fe4dcc0aa6..269bd92313df 100644 --- a/arch/sparc/include/asm/thread_info_64.h +++ b/arch/sparc/include/asm/thread_info_64.h | |||
@@ -14,12 +14,12 @@ | |||
14 | #define TI_FLAG_FAULT_CODE_SHIFT 56 | 14 | #define TI_FLAG_FAULT_CODE_SHIFT 56 |
15 | #define TI_FLAG_BYTE_WSTATE 1 | 15 | #define TI_FLAG_BYTE_WSTATE 1 |
16 | #define TI_FLAG_WSTATE_SHIFT 48 | 16 | #define TI_FLAG_WSTATE_SHIFT 48 |
17 | #define TI_FLAG_BYTE_CWP 2 | 17 | #define TI_FLAG_BYTE_NOERROR 2 |
18 | #define TI_FLAG_CWP_SHIFT 40 | 18 | #define TI_FLAG_BYTE_NOERROR_SHIFT 40 |
19 | #define TI_FLAG_BYTE_CURRENT_DS 3 | 19 | #define TI_FLAG_BYTE_FPDEPTH 3 |
20 | #define TI_FLAG_CURRENT_DS_SHIFT 32 | 20 | #define TI_FLAG_FPDEPTH_SHIFT 32 |
21 | #define TI_FLAG_BYTE_FPDEPTH 4 | 21 | #define TI_FLAG_BYTE_CWP 4 |
22 | #define TI_FLAG_FPDEPTH_SHIFT 24 | 22 | #define TI_FLAG_CWP_SHIFT 24 |
23 | #define TI_FLAG_BYTE_WSAVED 5 | 23 | #define TI_FLAG_BYTE_WSAVED 5 |
24 | #define TI_FLAG_WSAVED_SHIFT 16 | 24 | #define TI_FLAG_WSAVED_SHIFT 16 |
25 | 25 | ||
@@ -47,7 +47,7 @@ struct thread_info { | |||
47 | struct exec_domain *exec_domain; | 47 | struct exec_domain *exec_domain; |
48 | int preempt_count; /* 0 => preemptable, <0 => BUG */ | 48 | int preempt_count; /* 0 => preemptable, <0 => BUG */ |
49 | __u8 new_child; | 49 | __u8 new_child; |
50 | __u8 syscall_noerror; | 50 | __u8 current_ds; |
51 | __u16 cpu; | 51 | __u16 cpu; |
52 | 52 | ||
53 | unsigned long *utraps; | 53 | unsigned long *utraps; |
@@ -74,9 +74,9 @@ struct thread_info { | |||
74 | #define TI_FAULT_CODE (TI_FLAGS + TI_FLAG_BYTE_FAULT_CODE) | 74 | #define TI_FAULT_CODE (TI_FLAGS + TI_FLAG_BYTE_FAULT_CODE) |
75 | #define TI_WSTATE (TI_FLAGS + TI_FLAG_BYTE_WSTATE) | 75 | #define TI_WSTATE (TI_FLAGS + TI_FLAG_BYTE_WSTATE) |
76 | #define TI_CWP (TI_FLAGS + TI_FLAG_BYTE_CWP) | 76 | #define TI_CWP (TI_FLAGS + TI_FLAG_BYTE_CWP) |
77 | #define TI_CURRENT_DS (TI_FLAGS + TI_FLAG_BYTE_CURRENT_DS) | ||
78 | #define TI_FPDEPTH (TI_FLAGS + TI_FLAG_BYTE_FPDEPTH) | 77 | #define TI_FPDEPTH (TI_FLAGS + TI_FLAG_BYTE_FPDEPTH) |
79 | #define TI_WSAVED (TI_FLAGS + TI_FLAG_BYTE_WSAVED) | 78 | #define TI_WSAVED (TI_FLAGS + TI_FLAG_BYTE_WSAVED) |
79 | #define TI_SYS_NOERROR (TI_FLAGS + TI_FLAG_BYTE_NOERROR) | ||
80 | #define TI_FPSAVED 0x00000010 | 80 | #define TI_FPSAVED 0x00000010 |
81 | #define TI_KSP 0x00000018 | 81 | #define TI_KSP 0x00000018 |
82 | #define TI_FAULT_ADDR 0x00000020 | 82 | #define TI_FAULT_ADDR 0x00000020 |
@@ -84,7 +84,7 @@ struct thread_info { | |||
84 | #define TI_EXEC_DOMAIN 0x00000030 | 84 | #define TI_EXEC_DOMAIN 0x00000030 |
85 | #define TI_PRE_COUNT 0x00000038 | 85 | #define TI_PRE_COUNT 0x00000038 |
86 | #define TI_NEW_CHILD 0x0000003c | 86 | #define TI_NEW_CHILD 0x0000003c |
87 | #define TI_SYS_NOERROR 0x0000003d | 87 | #define TI_CURRENT_DS 0x0000003d |
88 | #define TI_CPU 0x0000003e | 88 | #define TI_CPU 0x0000003e |
89 | #define TI_UTRAPS 0x00000040 | 89 | #define TI_UTRAPS 0x00000040 |
90 | #define TI_REG_WINDOW 0x00000048 | 90 | #define TI_REG_WINDOW 0x00000048 |
@@ -121,7 +121,7 @@ struct thread_info { | |||
121 | #define INIT_THREAD_INFO(tsk) \ | 121 | #define INIT_THREAD_INFO(tsk) \ |
122 | { \ | 122 | { \ |
123 | .task = &tsk, \ | 123 | .task = &tsk, \ |
124 | .flags = ((unsigned long)ASI_P) << TI_FLAG_CURRENT_DS_SHIFT, \ | 124 | .current_ds = ASI_P, \ |
125 | .exec_domain = &default_exec_domain, \ | 125 | .exec_domain = &default_exec_domain, \ |
126 | .preempt_count = INIT_PREEMPT_COUNT, \ | 126 | .preempt_count = INIT_PREEMPT_COUNT, \ |
127 | .restart_block = { \ | 127 | .restart_block = { \ |
@@ -153,13 +153,12 @@ register struct thread_info *current_thread_info_reg asm("g6"); | |||
153 | #define set_thread_wstate(val) (__cur_thread_flag_byte_ptr[TI_FLAG_BYTE_WSTATE] = (val)) | 153 | #define set_thread_wstate(val) (__cur_thread_flag_byte_ptr[TI_FLAG_BYTE_WSTATE] = (val)) |
154 | #define get_thread_cwp() (__cur_thread_flag_byte_ptr[TI_FLAG_BYTE_CWP]) | 154 | #define get_thread_cwp() (__cur_thread_flag_byte_ptr[TI_FLAG_BYTE_CWP]) |
155 | #define set_thread_cwp(val) (__cur_thread_flag_byte_ptr[TI_FLAG_BYTE_CWP] = (val)) | 155 | #define set_thread_cwp(val) (__cur_thread_flag_byte_ptr[TI_FLAG_BYTE_CWP] = (val)) |
156 | #define get_thread_current_ds() (__cur_thread_flag_byte_ptr[TI_FLAG_BYTE_CURRENT_DS]) | 156 | #define get_thread_noerror() (__cur_thread_flag_byte_ptr[TI_FLAG_BYTE_NOERROR]) |
157 | #define set_thread_current_ds(val) (__cur_thread_flag_byte_ptr[TI_FLAG_BYTE_CURRENT_DS] = (val)) | 157 | #define set_thread_noerror(val) (__cur_thread_flag_byte_ptr[TI_FLAG_BYTE_NOERROR] = (val)) |
158 | #define get_thread_fpdepth() (__cur_thread_flag_byte_ptr[TI_FLAG_BYTE_FPDEPTH]) | 158 | #define get_thread_fpdepth() (__cur_thread_flag_byte_ptr[TI_FLAG_BYTE_FPDEPTH]) |
159 | #define set_thread_fpdepth(val) (__cur_thread_flag_byte_ptr[TI_FLAG_BYTE_FPDEPTH] = (val)) | 159 | #define set_thread_fpdepth(val) (__cur_thread_flag_byte_ptr[TI_FLAG_BYTE_FPDEPTH] = (val)) |
160 | #define get_thread_wsaved() (__cur_thread_flag_byte_ptr[TI_FLAG_BYTE_WSAVED]) | 160 | #define get_thread_wsaved() (__cur_thread_flag_byte_ptr[TI_FLAG_BYTE_WSAVED]) |
161 | #define set_thread_wsaved(val) (__cur_thread_flag_byte_ptr[TI_FLAG_BYTE_WSAVED] = (val)) | 161 | #define set_thread_wsaved(val) (__cur_thread_flag_byte_ptr[TI_FLAG_BYTE_WSAVED] = (val)) |
162 | |||
163 | #endif /* !(__ASSEMBLY__) */ | 162 | #endif /* !(__ASSEMBLY__) */ |
164 | 163 | ||
165 | /* | 164 | /* |
diff --git a/arch/sparc/include/asm/uaccess_64.h b/arch/sparc/include/asm/uaccess_64.h index 73083e1d38d9..e562d3caee57 100644 --- a/arch/sparc/include/asm/uaccess_64.h +++ b/arch/sparc/include/asm/uaccess_64.h | |||
@@ -38,14 +38,14 @@ | |||
38 | #define VERIFY_READ 0 | 38 | #define VERIFY_READ 0 |
39 | #define VERIFY_WRITE 1 | 39 | #define VERIFY_WRITE 1 |
40 | 40 | ||
41 | #define get_fs() ((mm_segment_t) { get_thread_current_ds() }) | 41 | #define get_fs() ((mm_segment_t){(current_thread_info()->current_ds)}) |
42 | #define get_ds() (KERNEL_DS) | 42 | #define get_ds() (KERNEL_DS) |
43 | 43 | ||
44 | #define segment_eq(a,b) ((a).seg == (b).seg) | 44 | #define segment_eq(a,b) ((a).seg == (b).seg) |
45 | 45 | ||
46 | #define set_fs(val) \ | 46 | #define set_fs(val) \ |
47 | do { \ | 47 | do { \ |
48 | set_thread_current_ds((val).seg); \ | 48 | current_thread_info()->current_ds =(val).seg; \ |
49 | __asm__ __volatile__ ("wr %%g0, %0, %%asi" : : "r" ((val).seg)); \ | 49 | __asm__ __volatile__ ("wr %%g0, %0, %%asi" : : "r" ((val).seg)); \ |
50 | } while(0) | 50 | } while(0) |
51 | 51 | ||
diff --git a/arch/sparc/include/asm/unistd.h b/arch/sparc/include/asm/unistd.h index 0ecea6ed943e..c3e5d8b64171 100644 --- a/arch/sparc/include/asm/unistd.h +++ b/arch/sparc/include/asm/unistd.h | |||
@@ -46,6 +46,7 @@ | |||
46 | #define __ARCH_WANT_COMPAT_SYS_RT_SIGSUSPEND | 46 | #define __ARCH_WANT_COMPAT_SYS_RT_SIGSUSPEND |
47 | #define __ARCH_WANT_COMPAT_SYS_SENDFILE | 47 | #define __ARCH_WANT_COMPAT_SYS_SENDFILE |
48 | #endif | 48 | #endif |
49 | #define __ARCH_WANT_SYS_EXECVE | ||
49 | 50 | ||
50 | /* | 51 | /* |
51 | * "Conditional" syscalls | 52 | * "Conditional" syscalls |
diff --git a/arch/sparc/kernel/entry.S b/arch/sparc/kernel/entry.S index dcaa1cf0de40..21fd1a8f47d2 100644 --- a/arch/sparc/kernel/entry.S +++ b/arch/sparc/kernel/entry.S | |||
@@ -806,23 +806,10 @@ sys_nis_syscall: | |||
806 | call c_sys_nis_syscall | 806 | call c_sys_nis_syscall |
807 | mov %l5, %o7 | 807 | mov %l5, %o7 |
808 | 808 | ||
809 | .align 4 | ||
810 | .globl sys_execve | ||
811 | sys_execve: | ||
812 | mov %o7, %l5 | ||
813 | add %sp, STACKFRAME_SZ, %o0 ! pt_regs *regs arg | ||
814 | call sparc_execve | ||
815 | mov %l5, %o7 | ||
816 | |||
817 | .globl sunos_execv | ||
818 | sunos_execv: | 809 | sunos_execv: |
819 | st %g0, [%sp + STACKFRAME_SZ + PT_I2] | 810 | .globl sunos_execv |
820 | 811 | b sys_execve | |
821 | call sparc_execve | 812 | clr %i2 |
822 | add %sp, STACKFRAME_SZ, %o0 | ||
823 | |||
824 | b ret_sys_call | ||
825 | ld [%sp + STACKFRAME_SZ + PT_I0], %o0 | ||
826 | 813 | ||
827 | .align 4 | 814 | .align 4 |
828 | .globl sys_sparc_pipe | 815 | .globl sys_sparc_pipe |
@@ -959,17 +946,9 @@ flush_patch_four: | |||
959 | .align 4 | 946 | .align 4 |
960 | linux_sparc_ni_syscall: | 947 | linux_sparc_ni_syscall: |
961 | sethi %hi(sys_ni_syscall), %l7 | 948 | sethi %hi(sys_ni_syscall), %l7 |
962 | b syscall_is_too_hard | 949 | b do_syscall |
963 | or %l7, %lo(sys_ni_syscall), %l7 | 950 | or %l7, %lo(sys_ni_syscall), %l7 |
964 | 951 | ||
965 | linux_fast_syscall: | ||
966 | andn %l7, 3, %l7 | ||
967 | mov %i0, %o0 | ||
968 | mov %i1, %o1 | ||
969 | mov %i2, %o2 | ||
970 | jmpl %l7 + %g0, %g0 | ||
971 | mov %i3, %o3 | ||
972 | |||
973 | linux_syscall_trace: | 952 | linux_syscall_trace: |
974 | add %sp, STACKFRAME_SZ, %o0 | 953 | add %sp, STACKFRAME_SZ, %o0 |
975 | call syscall_trace | 954 | call syscall_trace |
@@ -991,6 +970,23 @@ ret_from_fork: | |||
991 | b ret_sys_call | 970 | b ret_sys_call |
992 | ld [%sp + STACKFRAME_SZ + PT_I0], %o0 | 971 | ld [%sp + STACKFRAME_SZ + PT_I0], %o0 |
993 | 972 | ||
973 | .globl ret_from_kernel_thread | ||
974 | ret_from_kernel_thread: | ||
975 | call schedule_tail | ||
976 | ld [%g3 + TI_TASK], %o0 | ||
977 | ld [%sp + STACKFRAME_SZ + PT_G1], %l0 | ||
978 | call %l0 | ||
979 | ld [%sp + STACKFRAME_SZ + PT_G2], %o0 | ||
980 | rd %psr, %l1 | ||
981 | ld [%sp + STACKFRAME_SZ + PT_PSR], %l0 | ||
982 | andn %l0, PSR_CWP, %l0 | ||
983 | nop | ||
984 | and %l1, PSR_CWP, %l1 | ||
985 | or %l0, %l1, %l0 | ||
986 | st %l0, [%sp + STACKFRAME_SZ + PT_PSR] | ||
987 | b ret_sys_call | ||
988 | mov 0, %o0 | ||
989 | |||
994 | /* Linux native system calls enter here... */ | 990 | /* Linux native system calls enter here... */ |
995 | .align 4 | 991 | .align 4 |
996 | .globl linux_sparc_syscall | 992 | .globl linux_sparc_syscall |
@@ -1002,11 +998,8 @@ linux_sparc_syscall: | |||
1002 | bgeu linux_sparc_ni_syscall | 998 | bgeu linux_sparc_ni_syscall |
1003 | sll %g1, 2, %l4 | 999 | sll %g1, 2, %l4 |
1004 | ld [%l7 + %l4], %l7 | 1000 | ld [%l7 + %l4], %l7 |
1005 | andcc %l7, 1, %g0 | ||
1006 | bne linux_fast_syscall | ||
1007 | /* Just do first insn from SAVE_ALL in the delay slot */ | ||
1008 | 1001 | ||
1009 | syscall_is_too_hard: | 1002 | do_syscall: |
1010 | SAVE_ALL_HEAD | 1003 | SAVE_ALL_HEAD |
1011 | rd %wim, %l3 | 1004 | rd %wim, %l3 |
1012 | 1005 | ||
diff --git a/arch/sparc/kernel/etrap_64.S b/arch/sparc/kernel/etrap_64.S index 786b185e6e3f..1276ca2567ba 100644 --- a/arch/sparc/kernel/etrap_64.S +++ b/arch/sparc/kernel/etrap_64.S | |||
@@ -92,8 +92,10 @@ etrap_save: save %g2, -STACK_BIAS, %sp | |||
92 | rdpr %wstate, %g2 | 92 | rdpr %wstate, %g2 |
93 | wrpr %g0, 0, %canrestore | 93 | wrpr %g0, 0, %canrestore |
94 | sll %g2, 3, %g2 | 94 | sll %g2, 3, %g2 |
95 | |||
96 | /* Set TI_SYS_FPDEPTH to 1 and clear TI_SYS_NOERROR. */ | ||
95 | mov 1, %l5 | 97 | mov 1, %l5 |
96 | stb %l5, [%l6 + TI_FPDEPTH] | 98 | sth %l5, [%l6 + TI_SYS_NOERROR] |
97 | 99 | ||
98 | wrpr %g3, 0, %otherwin | 100 | wrpr %g3, 0, %otherwin |
99 | wrpr %g2, 0, %wstate | 101 | wrpr %g2, 0, %wstate |
@@ -152,7 +154,9 @@ etrap_save: save %g2, -STACK_BIAS, %sp | |||
152 | add %l6, TI_FPSAVED + 1, %l4 | 154 | add %l6, TI_FPSAVED + 1, %l4 |
153 | srl %l5, 1, %l3 | 155 | srl %l5, 1, %l3 |
154 | add %l5, 2, %l5 | 156 | add %l5, 2, %l5 |
155 | stb %l5, [%l6 + TI_FPDEPTH] | 157 | |
158 | /* Set TI_SYS_FPDEPTH to %l5 and clear TI_SYS_NOERROR. */ | ||
159 | sth %l5, [%l6 + TI_SYS_NOERROR] | ||
156 | ba,pt %xcc, 2b | 160 | ba,pt %xcc, 2b |
157 | stb %g0, [%l4 + %l3] | 161 | stb %g0, [%l4 + %l3] |
158 | nop | 162 | nop |
diff --git a/arch/sparc/kernel/process_32.c b/arch/sparc/kernel/process_32.c index 487bffb36f5e..bf4c6addce7b 100644 --- a/arch/sparc/kernel/process_32.c +++ b/arch/sparc/kernel/process_32.c | |||
@@ -316,9 +316,10 @@ asmlinkage int sparc_do_fork(unsigned long clone_flags, | |||
316 | * XXX See comment above sys_vfork in sparc64. todo. | 316 | * XXX See comment above sys_vfork in sparc64. todo. |
317 | */ | 317 | */ |
318 | extern void ret_from_fork(void); | 318 | extern void ret_from_fork(void); |
319 | extern void ret_from_kernel_thread(void); | ||
319 | 320 | ||
320 | int copy_thread(unsigned long clone_flags, unsigned long sp, | 321 | int copy_thread(unsigned long clone_flags, unsigned long sp, |
321 | unsigned long unused, | 322 | unsigned long arg, |
322 | struct task_struct *p, struct pt_regs *regs) | 323 | struct task_struct *p, struct pt_regs *regs) |
323 | { | 324 | { |
324 | struct thread_info *ti = task_thread_info(p); | 325 | struct thread_info *ti = task_thread_info(p); |
@@ -336,16 +337,13 @@ int copy_thread(unsigned long clone_flags, unsigned long sp, | |||
336 | } | 337 | } |
337 | 338 | ||
338 | /* | 339 | /* |
339 | * p->thread_info new_stack childregs | 340 | * p->thread_info new_stack childregs stack bottom |
340 | * ! ! ! {if(PSR_PS) } | 341 | * ! ! ! ! |
341 | * V V (stk.fr.) V (pt_regs) { (stk.fr.) } | 342 | * V V (stk.fr.) V (pt_regs) V |
342 | * +----- - - - - - ------+===========+============={+==========}+ | 343 | * +----- - - - - - ------+===========+=============+ |
343 | */ | 344 | */ |
344 | new_stack = task_stack_page(p) + THREAD_SIZE; | 345 | new_stack = task_stack_page(p) + THREAD_SIZE; |
345 | if (regs->psr & PSR_PS) | ||
346 | new_stack -= STACKFRAME_SZ; | ||
347 | new_stack -= STACKFRAME_SZ + TRACEREG_SZ; | 346 | new_stack -= STACKFRAME_SZ + TRACEREG_SZ; |
348 | memcpy(new_stack, (char *)regs - STACKFRAME_SZ, STACKFRAME_SZ + TRACEREG_SZ); | ||
349 | childregs = (struct pt_regs *) (new_stack + STACKFRAME_SZ); | 347 | childregs = (struct pt_regs *) (new_stack + STACKFRAME_SZ); |
350 | 348 | ||
351 | /* | 349 | /* |
@@ -356,55 +354,58 @@ int copy_thread(unsigned long clone_flags, unsigned long sp, | |||
356 | * Thus, kpsr|=PSR_PIL. | 354 | * Thus, kpsr|=PSR_PIL. |
357 | */ | 355 | */ |
358 | ti->ksp = (unsigned long) new_stack; | 356 | ti->ksp = (unsigned long) new_stack; |
357 | p->thread.kregs = childregs; | ||
358 | |||
359 | if (unlikely(p->flags & PF_KTHREAD)) { | ||
360 | extern int nwindows; | ||
361 | unsigned long psr; | ||
362 | memset(new_stack, 0, STACKFRAME_SZ + TRACEREG_SZ); | ||
363 | p->thread.flags |= SPARC_FLAG_KTHREAD; | ||
364 | p->thread.current_ds = KERNEL_DS; | ||
365 | ti->kpc = (((unsigned long) ret_from_kernel_thread) - 0x8); | ||
366 | childregs->u_regs[UREG_G1] = sp; /* function */ | ||
367 | childregs->u_regs[UREG_G2] = arg; | ||
368 | psr = childregs->psr = get_psr(); | ||
369 | ti->kpsr = psr | PSR_PIL; | ||
370 | ti->kwim = 1 << (((psr & PSR_CWP) + 1) % nwindows); | ||
371 | return 0; | ||
372 | } | ||
373 | memcpy(new_stack, (char *)regs - STACKFRAME_SZ, STACKFRAME_SZ + TRACEREG_SZ); | ||
374 | childregs->u_regs[UREG_FP] = sp; | ||
375 | p->thread.flags &= ~SPARC_FLAG_KTHREAD; | ||
376 | p->thread.current_ds = USER_DS; | ||
359 | ti->kpc = (((unsigned long) ret_from_fork) - 0x8); | 377 | ti->kpc = (((unsigned long) ret_from_fork) - 0x8); |
360 | ti->kpsr = current->thread.fork_kpsr | PSR_PIL; | 378 | ti->kpsr = current->thread.fork_kpsr | PSR_PIL; |
361 | ti->kwim = current->thread.fork_kwim; | 379 | ti->kwim = current->thread.fork_kwim; |
362 | 380 | ||
363 | if(regs->psr & PSR_PS) { | 381 | if (sp != regs->u_regs[UREG_FP]) { |
364 | extern struct pt_regs fake_swapper_regs; | 382 | struct sparc_stackf __user *childstack; |
383 | struct sparc_stackf __user *parentstack; | ||
365 | 384 | ||
366 | p->thread.kregs = &fake_swapper_regs; | 385 | /* |
367 | new_stack += STACKFRAME_SZ + TRACEREG_SZ; | 386 | * This is a clone() call with supplied user stack. |
368 | childregs->u_regs[UREG_FP] = (unsigned long) new_stack; | 387 | * Set some valid stack frames to give to the child. |
369 | p->thread.flags |= SPARC_FLAG_KTHREAD; | 388 | */ |
370 | p->thread.current_ds = KERNEL_DS; | 389 | childstack = (struct sparc_stackf __user *) |
371 | memcpy(new_stack, (void *)regs->u_regs[UREG_FP], STACKFRAME_SZ); | 390 | (sp & ~0xfUL); |
372 | childregs->u_regs[UREG_G6] = (unsigned long) ti; | 391 | parentstack = (struct sparc_stackf __user *) |
373 | } else { | 392 | regs->u_regs[UREG_FP]; |
374 | p->thread.kregs = childregs; | ||
375 | childregs->u_regs[UREG_FP] = sp; | ||
376 | p->thread.flags &= ~SPARC_FLAG_KTHREAD; | ||
377 | p->thread.current_ds = USER_DS; | ||
378 | |||
379 | if (sp != regs->u_regs[UREG_FP]) { | ||
380 | struct sparc_stackf __user *childstack; | ||
381 | struct sparc_stackf __user *parentstack; | ||
382 | |||
383 | /* | ||
384 | * This is a clone() call with supplied user stack. | ||
385 | * Set some valid stack frames to give to the child. | ||
386 | */ | ||
387 | childstack = (struct sparc_stackf __user *) | ||
388 | (sp & ~0xfUL); | ||
389 | parentstack = (struct sparc_stackf __user *) | ||
390 | regs->u_regs[UREG_FP]; | ||
391 | 393 | ||
392 | #if 0 | 394 | #if 0 |
393 | printk("clone: parent stack:\n"); | 395 | printk("clone: parent stack:\n"); |
394 | show_stackframe(parentstack); | 396 | show_stackframe(parentstack); |
395 | #endif | 397 | #endif |
396 | 398 | ||
397 | childstack = clone_stackframe(childstack, parentstack); | 399 | childstack = clone_stackframe(childstack, parentstack); |
398 | if (!childstack) | 400 | if (!childstack) |
399 | return -EFAULT; | 401 | return -EFAULT; |
400 | 402 | ||
401 | #if 0 | 403 | #if 0 |
402 | printk("clone: child stack:\n"); | 404 | printk("clone: child stack:\n"); |
403 | show_stackframe(childstack); | 405 | show_stackframe(childstack); |
404 | #endif | 406 | #endif |
405 | 407 | ||
406 | childregs->u_regs[UREG_FP] = (unsigned long)childstack; | 408 | childregs->u_regs[UREG_FP] = (unsigned long)childstack; |
407 | } | ||
408 | } | 409 | } |
409 | 410 | ||
410 | #ifdef CONFIG_SMP | 411 | #ifdef CONFIG_SMP |
@@ -475,69 +476,6 @@ int dump_fpu (struct pt_regs * regs, elf_fpregset_t * fpregs) | |||
475 | return 1; | 476 | return 1; |
476 | } | 477 | } |
477 | 478 | ||
478 | /* | ||
479 | * sparc_execve() executes a new program after the asm stub has set | ||
480 | * things up for us. This should basically do what I want it to. | ||
481 | */ | ||
482 | asmlinkage int sparc_execve(struct pt_regs *regs) | ||
483 | { | ||
484 | int error, base = 0; | ||
485 | struct filename *filename; | ||
486 | |||
487 | /* Check for indirect call. */ | ||
488 | if(regs->u_regs[UREG_G1] == 0) | ||
489 | base = 1; | ||
490 | |||
491 | filename = getname((char __user *)regs->u_regs[base + UREG_I0]); | ||
492 | error = PTR_ERR(filename); | ||
493 | if(IS_ERR(filename)) | ||
494 | goto out; | ||
495 | error = do_execve(filename->name, | ||
496 | (const char __user *const __user *) | ||
497 | regs->u_regs[base + UREG_I1], | ||
498 | (const char __user *const __user *) | ||
499 | regs->u_regs[base + UREG_I2], | ||
500 | regs); | ||
501 | putname(filename); | ||
502 | out: | ||
503 | return error; | ||
504 | } | ||
505 | |||
506 | /* | ||
507 | * This is the mechanism for creating a new kernel thread. | ||
508 | * | ||
509 | * NOTE! Only a kernel-only process(ie the swapper or direct descendants | ||
510 | * who haven't done an "execve()") should use this: it will work within | ||
511 | * a system call from a "real" process, but the process memory space will | ||
512 | * not be freed until both the parent and the child have exited. | ||
513 | */ | ||
514 | pid_t kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) | ||
515 | { | ||
516 | long retval; | ||
517 | |||
518 | __asm__ __volatile__("mov %4, %%g2\n\t" /* Set aside fn ptr... */ | ||
519 | "mov %5, %%g3\n\t" /* and arg. */ | ||
520 | "mov %1, %%g1\n\t" | ||
521 | "mov %2, %%o0\n\t" /* Clone flags. */ | ||
522 | "mov 0, %%o1\n\t" /* usp arg == 0 */ | ||
523 | "t 0x10\n\t" /* Linux/Sparc clone(). */ | ||
524 | "cmp %%o1, 0\n\t" | ||
525 | "be 1f\n\t" /* The parent, just return. */ | ||
526 | " nop\n\t" /* Delay slot. */ | ||
527 | "jmpl %%g2, %%o7\n\t" /* Call the function. */ | ||
528 | " mov %%g3, %%o0\n\t" /* Get back the arg in delay. */ | ||
529 | "mov %3, %%g1\n\t" | ||
530 | "t 0x10\n\t" /* Linux/Sparc exit(). */ | ||
531 | /* Notreached by child. */ | ||
532 | "1: mov %%o0, %0\n\t" : | ||
533 | "=r" (retval) : | ||
534 | "i" (__NR_clone), "r" (flags | CLONE_VM | CLONE_UNTRACED), | ||
535 | "i" (__NR_exit), "r" (fn), "r" (arg) : | ||
536 | "g1", "g2", "g3", "o0", "o1", "memory", "cc"); | ||
537 | return retval; | ||
538 | } | ||
539 | EXPORT_SYMBOL(kernel_thread); | ||
540 | |||
541 | unsigned long get_wchan(struct task_struct *task) | 479 | unsigned long get_wchan(struct task_struct *task) |
542 | { | 480 | { |
543 | unsigned long pc, fp, bias = 0; | 481 | unsigned long pc, fp, bias = 0; |
diff --git a/arch/sparc/kernel/process_64.c b/arch/sparc/kernel/process_64.c index c6e0c2910043..dff54f46728d 100644 --- a/arch/sparc/kernel/process_64.c +++ b/arch/sparc/kernel/process_64.c | |||
@@ -622,64 +622,55 @@ asmlinkage long sparc_do_fork(unsigned long clone_flags, | |||
622 | * Child --> %o0 == parents pid, %o1 == 1 | 622 | * Child --> %o0 == parents pid, %o1 == 1 |
623 | */ | 623 | */ |
624 | int copy_thread(unsigned long clone_flags, unsigned long sp, | 624 | int copy_thread(unsigned long clone_flags, unsigned long sp, |
625 | unsigned long unused, | 625 | unsigned long arg, |
626 | struct task_struct *p, struct pt_regs *regs) | 626 | struct task_struct *p, struct pt_regs *regs) |
627 | { | 627 | { |
628 | struct thread_info *t = task_thread_info(p); | 628 | struct thread_info *t = task_thread_info(p); |
629 | struct sparc_stackf *parent_sf; | 629 | struct sparc_stackf *parent_sf; |
630 | unsigned long child_stack_sz; | 630 | unsigned long child_stack_sz; |
631 | char *child_trap_frame; | 631 | char *child_trap_frame; |
632 | int kernel_thread; | ||
633 | |||
634 | kernel_thread = (regs->tstate & TSTATE_PRIV) ? 1 : 0; | ||
635 | parent_sf = ((struct sparc_stackf *) regs) - 1; | ||
636 | 632 | ||
637 | /* Calculate offset to stack_frame & pt_regs */ | 633 | /* Calculate offset to stack_frame & pt_regs */ |
638 | child_stack_sz = ((STACKFRAME_SZ + TRACEREG_SZ) + | 634 | child_stack_sz = (STACKFRAME_SZ + TRACEREG_SZ); |
639 | (kernel_thread ? STACKFRAME_SZ : 0)); | ||
640 | child_trap_frame = (task_stack_page(p) + | 635 | child_trap_frame = (task_stack_page(p) + |
641 | (THREAD_SIZE - child_stack_sz)); | 636 | (THREAD_SIZE - child_stack_sz)); |
642 | memcpy(child_trap_frame, parent_sf, child_stack_sz); | ||
643 | 637 | ||
644 | t->flags = (t->flags & ~((0xffUL << TI_FLAG_CWP_SHIFT) | | ||
645 | (0xffUL << TI_FLAG_CURRENT_DS_SHIFT))) | | ||
646 | (((regs->tstate + 1) & TSTATE_CWP) << TI_FLAG_CWP_SHIFT); | ||
647 | t->new_child = 1; | 638 | t->new_child = 1; |
648 | t->ksp = ((unsigned long) child_trap_frame) - STACK_BIAS; | 639 | t->ksp = ((unsigned long) child_trap_frame) - STACK_BIAS; |
649 | t->kregs = (struct pt_regs *) (child_trap_frame + | 640 | t->kregs = (struct pt_regs *) (child_trap_frame + |
650 | sizeof(struct sparc_stackf)); | 641 | sizeof(struct sparc_stackf)); |
651 | t->fpsaved[0] = 0; | 642 | t->fpsaved[0] = 0; |
652 | 643 | ||
653 | if (kernel_thread) { | 644 | if (unlikely(p->flags & PF_KTHREAD)) { |
654 | struct sparc_stackf *child_sf = (struct sparc_stackf *) | 645 | memset(child_trap_frame, 0, child_stack_sz); |
655 | (child_trap_frame + (STACKFRAME_SZ + TRACEREG_SZ)); | 646 | __thread_flag_byte_ptr(t)[TI_FLAG_BYTE_CWP] = |
656 | 647 | (current_pt_regs()->tstate + 1) & TSTATE_CWP; | |
657 | /* Zero terminate the stack backtrace. */ | 648 | t->current_ds = ASI_P; |
658 | child_sf->fp = NULL; | 649 | t->kregs->u_regs[UREG_G1] = sp; /* function */ |
659 | t->kregs->u_regs[UREG_FP] = | 650 | t->kregs->u_regs[UREG_G2] = arg; |
660 | ((unsigned long) child_sf) - STACK_BIAS; | 651 | return 0; |
652 | } | ||
661 | 653 | ||
662 | t->flags |= ((long)ASI_P << TI_FLAG_CURRENT_DS_SHIFT); | 654 | parent_sf = ((struct sparc_stackf *) regs) - 1; |
663 | t->kregs->u_regs[UREG_G6] = (unsigned long) t; | 655 | memcpy(child_trap_frame, parent_sf, child_stack_sz); |
664 | t->kregs->u_regs[UREG_G4] = (unsigned long) t->task; | 656 | if (t->flags & _TIF_32BIT) { |
665 | } else { | 657 | sp &= 0x00000000ffffffffUL; |
666 | if (t->flags & _TIF_32BIT) { | 658 | regs->u_regs[UREG_FP] &= 0x00000000ffffffffUL; |
667 | sp &= 0x00000000ffffffffUL; | ||
668 | regs->u_regs[UREG_FP] &= 0x00000000ffffffffUL; | ||
669 | } | ||
670 | t->kregs->u_regs[UREG_FP] = sp; | ||
671 | t->flags |= ((long)ASI_AIUS << TI_FLAG_CURRENT_DS_SHIFT); | ||
672 | if (sp != regs->u_regs[UREG_FP]) { | ||
673 | unsigned long csp; | ||
674 | |||
675 | csp = clone_stackframe(sp, regs->u_regs[UREG_FP]); | ||
676 | if (!csp) | ||
677 | return -EFAULT; | ||
678 | t->kregs->u_regs[UREG_FP] = csp; | ||
679 | } | ||
680 | if (t->utraps) | ||
681 | t->utraps[0]++; | ||
682 | } | 659 | } |
660 | t->kregs->u_regs[UREG_FP] = sp; | ||
661 | __thread_flag_byte_ptr(t)[TI_FLAG_BYTE_CWP] = | ||
662 | (regs->tstate + 1) & TSTATE_CWP; | ||
663 | t->current_ds = ASI_AIUS; | ||
664 | if (sp != regs->u_regs[UREG_FP]) { | ||
665 | unsigned long csp; | ||
666 | |||
667 | csp = clone_stackframe(sp, regs->u_regs[UREG_FP]); | ||
668 | if (!csp) | ||
669 | return -EFAULT; | ||
670 | t->kregs->u_regs[UREG_FP] = csp; | ||
671 | } | ||
672 | if (t->utraps) | ||
673 | t->utraps[0]++; | ||
683 | 674 | ||
684 | /* Set the return value for the child. */ | 675 | /* Set the return value for the child. */ |
685 | t->kregs->u_regs[UREG_I0] = current->pid; | 676 | t->kregs->u_regs[UREG_I0] = current->pid; |
@@ -694,45 +685,6 @@ int copy_thread(unsigned long clone_flags, unsigned long sp, | |||
694 | return 0; | 685 | return 0; |
695 | } | 686 | } |
696 | 687 | ||
697 | /* | ||
698 | * This is the mechanism for creating a new kernel thread. | ||
699 | * | ||
700 | * NOTE! Only a kernel-only process(ie the swapper or direct descendants | ||
701 | * who haven't done an "execve()") should use this: it will work within | ||
702 | * a system call from a "real" process, but the process memory space will | ||
703 | * not be freed until both the parent and the child have exited. | ||
704 | */ | ||
705 | pid_t kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) | ||
706 | { | ||
707 | long retval; | ||
708 | |||
709 | /* If the parent runs before fn(arg) is called by the child, | ||
710 | * the input registers of this function can be clobbered. | ||
711 | * So we stash 'fn' and 'arg' into global registers which | ||
712 | * will not be modified by the parent. | ||
713 | */ | ||
714 | __asm__ __volatile__("mov %4, %%g2\n\t" /* Save FN into global */ | ||
715 | "mov %5, %%g3\n\t" /* Save ARG into global */ | ||
716 | "mov %1, %%g1\n\t" /* Clone syscall nr. */ | ||
717 | "mov %2, %%o0\n\t" /* Clone flags. */ | ||
718 | "mov 0, %%o1\n\t" /* usp arg == 0 */ | ||
719 | "t 0x6d\n\t" /* Linux/Sparc clone(). */ | ||
720 | "brz,a,pn %%o1, 1f\n\t" /* Parent, just return. */ | ||
721 | " mov %%o0, %0\n\t" | ||
722 | "jmpl %%g2, %%o7\n\t" /* Call the function. */ | ||
723 | " mov %%g3, %%o0\n\t" /* Set arg in delay. */ | ||
724 | "mov %3, %%g1\n\t" | ||
725 | "t 0x6d\n\t" /* Linux/Sparc exit(). */ | ||
726 | /* Notreached by child. */ | ||
727 | "1:" : | ||
728 | "=r" (retval) : | ||
729 | "i" (__NR_clone), "r" (flags | CLONE_VM | CLONE_UNTRACED), | ||
730 | "i" (__NR_exit), "r" (fn), "r" (arg) : | ||
731 | "g1", "g2", "g3", "o0", "o1", "memory", "cc"); | ||
732 | return retval; | ||
733 | } | ||
734 | EXPORT_SYMBOL(kernel_thread); | ||
735 | |||
736 | typedef struct { | 688 | typedef struct { |
737 | union { | 689 | union { |
738 | unsigned int pr_regs[32]; | 690 | unsigned int pr_regs[32]; |
@@ -799,41 +751,6 @@ int dump_fpu (struct pt_regs * regs, elf_fpregset_t * fpregs) | |||
799 | } | 751 | } |
800 | EXPORT_SYMBOL(dump_fpu); | 752 | EXPORT_SYMBOL(dump_fpu); |
801 | 753 | ||
802 | /* | ||
803 | * sparc_execve() executes a new program after the asm stub has set | ||
804 | * things up for us. This should basically do what I want it to. | ||
805 | */ | ||
806 | asmlinkage int sparc_execve(struct pt_regs *regs) | ||
807 | { | ||
808 | int error, base = 0; | ||
809 | struct filename *filename; | ||
810 | |||
811 | /* User register window flush is done by entry.S */ | ||
812 | |||
813 | /* Check for indirect call. */ | ||
814 | if (regs->u_regs[UREG_G1] == 0) | ||
815 | base = 1; | ||
816 | |||
817 | filename = getname((char __user *)regs->u_regs[base + UREG_I0]); | ||
818 | error = PTR_ERR(filename); | ||
819 | if (IS_ERR(filename)) | ||
820 | goto out; | ||
821 | error = do_execve(filename->name, | ||
822 | (const char __user *const __user *) | ||
823 | regs->u_regs[base + UREG_I1], | ||
824 | (const char __user *const __user *) | ||
825 | regs->u_regs[base + UREG_I2], regs); | ||
826 | putname(filename); | ||
827 | if (!error) { | ||
828 | fprs_write(0); | ||
829 | current_thread_info()->xfsr[0] = 0; | ||
830 | current_thread_info()->fpsaved[0] = 0; | ||
831 | regs->tstate &= ~TSTATE_PEF; | ||
832 | } | ||
833 | out: | ||
834 | return error; | ||
835 | } | ||
836 | |||
837 | unsigned long get_wchan(struct task_struct *task) | 754 | unsigned long get_wchan(struct task_struct *task) |
838 | { | 755 | { |
839 | unsigned long pc, fp, bias = 0; | 756 | unsigned long pc, fp, bias = 0; |
diff --git a/arch/sparc/kernel/sys_sparc32.c b/arch/sparc/kernel/sys_sparc32.c index c3239811a1b5..03c7e929ec34 100644 --- a/arch/sparc/kernel/sys_sparc32.c +++ b/arch/sparc/kernel/sys_sparc32.c | |||
@@ -396,42 +396,6 @@ asmlinkage long compat_sys_rt_sigaction(int sig, | |||
396 | return ret; | 396 | return ret; |
397 | } | 397 | } |
398 | 398 | ||
399 | /* | ||
400 | * sparc32_execve() executes a new program after the asm stub has set | ||
401 | * things up for us. This should basically do what I want it to. | ||
402 | */ | ||
403 | asmlinkage long sparc32_execve(struct pt_regs *regs) | ||
404 | { | ||
405 | int error, base = 0; | ||
406 | struct filename *filename; | ||
407 | |||
408 | /* User register window flush is done by entry.S */ | ||
409 | |||
410 | /* Check for indirect call. */ | ||
411 | if ((u32)regs->u_regs[UREG_G1] == 0) | ||
412 | base = 1; | ||
413 | |||
414 | filename = getname(compat_ptr(regs->u_regs[base + UREG_I0])); | ||
415 | error = PTR_ERR(filename); | ||
416 | if (IS_ERR(filename)) | ||
417 | goto out; | ||
418 | |||
419 | error = compat_do_execve(filename->name, | ||
420 | compat_ptr(regs->u_regs[base + UREG_I1]), | ||
421 | compat_ptr(regs->u_regs[base + UREG_I2]), regs); | ||
422 | |||
423 | putname(filename); | ||
424 | |||
425 | if (!error) { | ||
426 | fprs_write(0); | ||
427 | current_thread_info()->xfsr[0] = 0; | ||
428 | current_thread_info()->fpsaved[0] = 0; | ||
429 | regs->tstate &= ~TSTATE_PEF; | ||
430 | } | ||
431 | out: | ||
432 | return error; | ||
433 | } | ||
434 | |||
435 | #ifdef CONFIG_MODULES | 399 | #ifdef CONFIG_MODULES |
436 | 400 | ||
437 | asmlinkage long sys32_init_module(void __user *umod, u32 len, | 401 | asmlinkage long sys32_init_module(void __user *umod, u32 len, |
diff --git a/arch/sparc/kernel/sys_sparc_32.c b/arch/sparc/kernel/sys_sparc_32.c index 0c9b31b22e07..a8e6eb0a11d5 100644 --- a/arch/sparc/kernel/sys_sparc_32.c +++ b/arch/sparc/kernel/sys_sparc_32.c | |||
@@ -258,27 +258,3 @@ out: | |||
258 | up_read(&uts_sem); | 258 | up_read(&uts_sem); |
259 | return err; | 259 | return err; |
260 | } | 260 | } |
261 | |||
262 | /* | ||
263 | * Do a system call from kernel instead of calling sys_execve so we | ||
264 | * end up with proper pt_regs. | ||
265 | */ | ||
266 | int kernel_execve(const char *filename, | ||
267 | const char *const argv[], | ||
268 | const char *const envp[]) | ||
269 | { | ||
270 | long __res; | ||
271 | register long __g1 __asm__ ("g1") = __NR_execve; | ||
272 | register long __o0 __asm__ ("o0") = (long)(filename); | ||
273 | register long __o1 __asm__ ("o1") = (long)(argv); | ||
274 | register long __o2 __asm__ ("o2") = (long)(envp); | ||
275 | asm volatile ("t 0x10\n\t" | ||
276 | "bcc 1f\n\t" | ||
277 | "mov %%o0, %0\n\t" | ||
278 | "sub %%g0, %%o0, %0\n\t" | ||
279 | "1:\n\t" | ||
280 | : "=r" (__res), "=&r" (__o0) | ||
281 | : "1" (__o0), "r" (__o1), "r" (__o2), "r" (__g1) | ||
282 | : "cc"); | ||
283 | return __res; | ||
284 | } | ||
diff --git a/arch/sparc/kernel/sys_sparc_64.c b/arch/sparc/kernel/sys_sparc_64.c index 878ef3d5fec5..51b85feb8b97 100644 --- a/arch/sparc/kernel/sys_sparc_64.c +++ b/arch/sparc/kernel/sys_sparc_64.c | |||
@@ -730,28 +730,6 @@ SYSCALL_DEFINE5(rt_sigaction, int, sig, const struct sigaction __user *, act, | |||
730 | return ret; | 730 | return ret; |
731 | } | 731 | } |
732 | 732 | ||
733 | /* | ||
734 | * Do a system call from kernel instead of calling sys_execve so we | ||
735 | * end up with proper pt_regs. | ||
736 | */ | ||
737 | int kernel_execve(const char *filename, | ||
738 | const char *const argv[], | ||
739 | const char *const envp[]) | ||
740 | { | ||
741 | long __res; | ||
742 | register long __g1 __asm__ ("g1") = __NR_execve; | ||
743 | register long __o0 __asm__ ("o0") = (long)(filename); | ||
744 | register long __o1 __asm__ ("o1") = (long)(argv); | ||
745 | register long __o2 __asm__ ("o2") = (long)(envp); | ||
746 | asm volatile ("t 0x6d\n\t" | ||
747 | "sub %%g0, %%o0, %0\n\t" | ||
748 | "movcc %%xcc, %%o0, %0\n\t" | ||
749 | : "=r" (__res), "=&r" (__o0) | ||
750 | : "1" (__o0), "r" (__o1), "r" (__o2), "r" (__g1) | ||
751 | : "cc"); | ||
752 | return __res; | ||
753 | } | ||
754 | |||
755 | asmlinkage long sys_kern_features(void) | 733 | asmlinkage long sys_kern_features(void) |
756 | { | 734 | { |
757 | return KERN_FEATURE_MIXED_MODE_STACK; | 735 | return KERN_FEATURE_MIXED_MODE_STACK; |
diff --git a/arch/sparc/kernel/syscalls.S b/arch/sparc/kernel/syscalls.S index 7f5f65d0b3fd..2ef41e67f0be 100644 --- a/arch/sparc/kernel/syscalls.S +++ b/arch/sparc/kernel/syscalls.S | |||
@@ -1,23 +1,19 @@ | |||
1 | /* SunOS's execv() call only specifies the argv argument, the | 1 | /* SunOS's execv() call only specifies the argv argument, the |
2 | * environment settings are the same as the calling processes. | 2 | * environment settings are the same as the calling processes. |
3 | */ | 3 | */ |
4 | sys_execve: | 4 | sys64_execve: |
5 | sethi %hi(sparc_execve), %g1 | 5 | set sys_execve, %g1 |
6 | ba,pt %xcc, execve_merge | 6 | jmpl %g1, %g0 |
7 | or %g1, %lo(sparc_execve), %g1 | 7 | flushw |
8 | 8 | ||
9 | #ifdef CONFIG_COMPAT | 9 | #ifdef CONFIG_COMPAT |
10 | sunos_execv: | 10 | sunos_execv: |
11 | stx %g0, [%sp + PTREGS_OFF + PT_V9_I2] | 11 | mov %g0, %o2 |
12 | sys32_execve: | 12 | sys32_execve: |
13 | sethi %hi(sparc32_execve), %g1 | 13 | set compat_sys_execve, %g1 |
14 | or %g1, %lo(sparc32_execve), %g1 | ||
15 | #endif | ||
16 | |||
17 | execve_merge: | ||
18 | flushw | ||
19 | jmpl %g1, %g0 | 14 | jmpl %g1, %g0 |
20 | add %sp, PTREGS_OFF, %o0 | 15 | flushw |
16 | #endif | ||
21 | 17 | ||
22 | .align 32 | 18 | .align 32 |
23 | sys_sparc_pipe: | 19 | sys_sparc_pipe: |
@@ -112,11 +108,16 @@ sys_clone: | |||
112 | ret_from_syscall: | 108 | ret_from_syscall: |
113 | /* Clear current_thread_info()->new_child. */ | 109 | /* Clear current_thread_info()->new_child. */ |
114 | stb %g0, [%g6 + TI_NEW_CHILD] | 110 | stb %g0, [%g6 + TI_NEW_CHILD] |
115 | ldx [%g6 + TI_FLAGS], %l0 | ||
116 | call schedule_tail | 111 | call schedule_tail |
117 | mov %g7, %o0 | 112 | mov %g7, %o0 |
113 | ldx [%sp + PTREGS_OFF + PT_V9_I0], %o0 | ||
114 | brnz,pt %o0, ret_sys_call | ||
115 | ldx [%g6 + TI_FLAGS], %l0 | ||
116 | ldx [%sp + PTREGS_OFF + PT_V9_G1], %l1 | ||
117 | call %l1 | ||
118 | ldx [%sp + PTREGS_OFF + PT_V9_G2], %o0 | ||
118 | ba,pt %xcc, ret_sys_call | 119 | ba,pt %xcc, ret_sys_call |
119 | ldx [%sp + PTREGS_OFF + PT_V9_I0], %o0 | 120 | mov 0, %o0 |
120 | 121 | ||
121 | .globl sparc_exit | 122 | .globl sparc_exit |
122 | .type sparc_exit,#function | 123 | .type sparc_exit,#function |
@@ -222,7 +223,6 @@ ret_sys_call: | |||
222 | ldx [%sp + PTREGS_OFF + PT_V9_TNPC], %l1 ! pc = npc | 223 | ldx [%sp + PTREGS_OFF + PT_V9_TNPC], %l1 ! pc = npc |
223 | 224 | ||
224 | 2: | 225 | 2: |
225 | stb %g0, [%g6 + TI_SYS_NOERROR] | ||
226 | /* System call success, clear Carry condition code. */ | 226 | /* System call success, clear Carry condition code. */ |
227 | andn %g3, %g2, %g3 | 227 | andn %g3, %g2, %g3 |
228 | 3: | 228 | 3: |
diff --git a/arch/sparc/kernel/systbls_64.S b/arch/sparc/kernel/systbls_64.S index 1c9af9fa38e9..ebb7f5fc58fb 100644 --- a/arch/sparc/kernel/systbls_64.S +++ b/arch/sparc/kernel/systbls_64.S | |||
@@ -107,7 +107,7 @@ sys_call_table: | |||
107 | /*40*/ .word sys_newlstat, sys_dup, sys_sparc_pipe, sys_times, sys_nis_syscall | 107 | /*40*/ .word sys_newlstat, sys_dup, sys_sparc_pipe, sys_times, sys_nis_syscall |
108 | .word sys_umount, sys_setgid, sys_getgid, sys_signal, sys_geteuid | 108 | .word sys_umount, sys_setgid, sys_getgid, sys_signal, sys_geteuid |
109 | /*50*/ .word sys_getegid, sys_acct, sys_memory_ordering, sys_nis_syscall, sys_ioctl | 109 | /*50*/ .word sys_getegid, sys_acct, sys_memory_ordering, sys_nis_syscall, sys_ioctl |
110 | .word sys_reboot, sys_nis_syscall, sys_symlink, sys_readlink, sys_execve | 110 | .word sys_reboot, sys_nis_syscall, sys_symlink, sys_readlink, sys64_execve |
111 | /*60*/ .word sys_umask, sys_chroot, sys_newfstat, sys_fstat64, sys_getpagesize | 111 | /*60*/ .word sys_umask, sys_chroot, sys_newfstat, sys_fstat64, sys_getpagesize |
112 | .word sys_msync, sys_vfork, sys_pread64, sys_pwrite64, sys_nis_syscall | 112 | .word sys_msync, sys_vfork, sys_pread64, sys_pwrite64, sys_nis_syscall |
113 | /*70*/ .word sys_nis_syscall, sys_mmap, sys_nis_syscall, sys_64_munmap, sys_mprotect | 113 | /*70*/ .word sys_nis_syscall, sys_mmap, sys_nis_syscall, sys_64_munmap, sys_mprotect |
diff --git a/arch/sparc/kernel/traps_64.c b/arch/sparc/kernel/traps_64.c index b66a77968f35..e7ecf1507d90 100644 --- a/arch/sparc/kernel/traps_64.c +++ b/arch/sparc/kernel/traps_64.c | |||
@@ -2688,8 +2688,8 @@ void __init trap_init(void) | |||
2688 | TI_PRE_COUNT != offsetof(struct thread_info, | 2688 | TI_PRE_COUNT != offsetof(struct thread_info, |
2689 | preempt_count) || | 2689 | preempt_count) || |
2690 | TI_NEW_CHILD != offsetof(struct thread_info, new_child) || | 2690 | TI_NEW_CHILD != offsetof(struct thread_info, new_child) || |
2691 | TI_SYS_NOERROR != offsetof(struct thread_info, | 2691 | TI_CURRENT_DS != offsetof(struct thread_info, |
2692 | syscall_noerror) || | 2692 | current_ds) || |
2693 | TI_RESTART_BLOCK != offsetof(struct thread_info, | 2693 | TI_RESTART_BLOCK != offsetof(struct thread_info, |
2694 | restart_block) || | 2694 | restart_block) || |
2695 | TI_KUNA_REGS != offsetof(struct thread_info, | 2695 | TI_KUNA_REGS != offsetof(struct thread_info, |
diff --git a/arch/sparc/mm/init_64.c b/arch/sparc/mm/init_64.c index 9e28a118e6a4..85be1ca539b2 100644 --- a/arch/sparc/mm/init_64.c +++ b/arch/sparc/mm/init_64.c | |||
@@ -624,7 +624,7 @@ static void __init inherit_prom_mappings(void) | |||
624 | void prom_world(int enter) | 624 | void prom_world(int enter) |
625 | { | 625 | { |
626 | if (!enter) | 626 | if (!enter) |
627 | set_fs((mm_segment_t) { get_thread_current_ds() }); | 627 | set_fs(get_fs()); |
628 | 628 | ||
629 | __asm__ __volatile__("flushw"); | 629 | __asm__ __volatile__("flushw"); |
630 | } | 630 | } |
diff --git a/arch/tile/Kconfig b/arch/tile/Kconfig index 875d008828b8..ea7f61e8bc9e 100644 --- a/arch/tile/Kconfig +++ b/arch/tile/Kconfig | |||
@@ -21,6 +21,8 @@ config TILE | |||
21 | select ARCH_HAVE_NMI_SAFE_CMPXCHG | 21 | select ARCH_HAVE_NMI_SAFE_CMPXCHG |
22 | select GENERIC_CLOCKEVENTS | 22 | select GENERIC_CLOCKEVENTS |
23 | select MODULES_USE_ELF_RELA | 23 | select MODULES_USE_ELF_RELA |
24 | select GENERIC_KERNEL_THREAD | ||
25 | select GENERIC_KERNEL_EXECVE | ||
24 | 26 | ||
25 | # FIXME: investigate whether we need/want these options. | 27 | # FIXME: investigate whether we need/want these options. |
26 | # select HAVE_IOREMAP_PROT | 28 | # select HAVE_IOREMAP_PROT |
diff --git a/arch/tile/include/asm/compat.h b/arch/tile/include/asm/compat.h index 3063e6fc8daa..ca61fb4296b3 100644 --- a/arch/tile/include/asm/compat.h +++ b/arch/tile/include/asm/compat.h | |||
@@ -275,18 +275,14 @@ extern int compat_setup_rt_frame(int sig, struct k_sigaction *ka, | |||
275 | struct compat_sigaction; | 275 | struct compat_sigaction; |
276 | struct compat_siginfo; | 276 | struct compat_siginfo; |
277 | struct compat_sigaltstack; | 277 | struct compat_sigaltstack; |
278 | long compat_sys_execve(const char __user *path, | ||
279 | compat_uptr_t __user *argv, | ||
280 | compat_uptr_t __user *envp, struct pt_regs *); | ||
281 | long compat_sys_rt_sigaction(int sig, struct compat_sigaction __user *act, | 278 | long compat_sys_rt_sigaction(int sig, struct compat_sigaction __user *act, |
282 | struct compat_sigaction __user *oact, | 279 | struct compat_sigaction __user *oact, |
283 | size_t sigsetsize); | 280 | size_t sigsetsize); |
284 | long compat_sys_rt_sigqueueinfo(int pid, int sig, | 281 | long compat_sys_rt_sigqueueinfo(int pid, int sig, |
285 | struct compat_siginfo __user *uinfo); | 282 | struct compat_siginfo __user *uinfo); |
286 | long compat_sys_rt_sigreturn(struct pt_regs *); | 283 | long compat_sys_rt_sigreturn(void); |
287 | long compat_sys_sigaltstack(const struct compat_sigaltstack __user *uss_ptr, | 284 | long compat_sys_sigaltstack(const struct compat_sigaltstack __user *uss_ptr, |
288 | struct compat_sigaltstack __user *uoss_ptr, | 285 | struct compat_sigaltstack __user *uoss_ptr); |
289 | struct pt_regs *); | ||
290 | long compat_sys_truncate64(char __user *filename, u32 dummy, u32 low, u32 high); | 286 | long compat_sys_truncate64(char __user *filename, u32 dummy, u32 low, u32 high); |
291 | long compat_sys_ftruncate64(unsigned int fd, u32 dummy, u32 low, u32 high); | 287 | long compat_sys_ftruncate64(unsigned int fd, u32 dummy, u32 low, u32 high); |
292 | long compat_sys_pread64(unsigned int fd, char __user *ubuf, size_t count, | 288 | long compat_sys_pread64(unsigned int fd, char __user *ubuf, size_t count, |
@@ -303,12 +299,7 @@ long compat_sys_fallocate(int fd, int mode, | |||
303 | long compat_sys_sched_rr_get_interval(compat_pid_t pid, | 299 | long compat_sys_sched_rr_get_interval(compat_pid_t pid, |
304 | struct compat_timespec __user *interval); | 300 | struct compat_timespec __user *interval); |
305 | 301 | ||
306 | /* These are the intvec_64.S trampolines. */ | 302 | /* Assembly trampoline to avoid clobbering r0. */ |
307 | long _compat_sys_execve(const char __user *path, | ||
308 | const compat_uptr_t __user *argv, | ||
309 | const compat_uptr_t __user *envp); | ||
310 | long _compat_sys_sigaltstack(const struct compat_sigaltstack __user *uss_ptr, | ||
311 | struct compat_sigaltstack __user *uoss_ptr); | ||
312 | long _compat_sys_rt_sigreturn(void); | 303 | long _compat_sys_rt_sigreturn(void); |
313 | 304 | ||
314 | #endif /* _ASM_TILE_COMPAT_H */ | 305 | #endif /* _ASM_TILE_COMPAT_H */ |
diff --git a/arch/tile/include/asm/elf.h b/arch/tile/include/asm/elf.h index f8ccf08f6934..b73e1039c911 100644 --- a/arch/tile/include/asm/elf.h +++ b/arch/tile/include/asm/elf.h | |||
@@ -148,6 +148,7 @@ extern int arch_setup_additional_pages(struct linux_binprm *bprm, | |||
148 | #define compat_start_thread(regs, ip, usp) do { \ | 148 | #define compat_start_thread(regs, ip, usp) do { \ |
149 | regs->pc = ptr_to_compat_reg((void *)(ip)); \ | 149 | regs->pc = ptr_to_compat_reg((void *)(ip)); \ |
150 | regs->sp = ptr_to_compat_reg((void *)(usp)); \ | 150 | regs->sp = ptr_to_compat_reg((void *)(usp)); \ |
151 | single_step_execve(); \ | ||
151 | } while (0) | 152 | } while (0) |
152 | 153 | ||
153 | /* | 154 | /* |
diff --git a/arch/tile/include/asm/processor.h b/arch/tile/include/asm/processor.h index 8c4dd9ff91eb..879073e76586 100644 --- a/arch/tile/include/asm/processor.h +++ b/arch/tile/include/asm/processor.h | |||
@@ -211,6 +211,7 @@ static inline void start_thread(struct pt_regs *regs, | |||
211 | { | 211 | { |
212 | regs->pc = pc; | 212 | regs->pc = pc; |
213 | regs->sp = usp; | 213 | regs->sp = usp; |
214 | single_step_execve(); | ||
214 | } | 215 | } |
215 | 216 | ||
216 | /* Free all resources held by a thread. */ | 217 | /* Free all resources held by a thread. */ |
@@ -239,6 +240,9 @@ unsigned long get_wchan(struct task_struct *p); | |||
239 | #define KSTK_TOP(task) (task_ksp0(task) - STACK_TOP_DELTA) | 240 | #define KSTK_TOP(task) (task_ksp0(task) - STACK_TOP_DELTA) |
240 | #define task_pt_regs(task) \ | 241 | #define task_pt_regs(task) \ |
241 | ((struct pt_regs *)(task_ksp0(task) - KSTK_PTREGS_GAP) - 1) | 242 | ((struct pt_regs *)(task_ksp0(task) - KSTK_PTREGS_GAP) - 1) |
243 | #define current_pt_regs() \ | ||
244 | ((struct pt_regs *)((stack_pointer | (THREAD_SIZE - 1)) - \ | ||
245 | (KSTK_PTREGS_GAP - 1)) - 1) | ||
242 | #define task_sp(task) (task_pt_regs(task)->sp) | 246 | #define task_sp(task) (task_pt_regs(task)->sp) |
243 | #define task_pc(task) (task_pt_regs(task)->pc) | 247 | #define task_pc(task) (task_pt_regs(task)->pc) |
244 | /* Aliases for pc and sp (used in fs/proc/array.c) */ | 248 | /* Aliases for pc and sp (used in fs/proc/array.c) */ |
diff --git a/arch/tile/include/asm/switch_to.h b/arch/tile/include/asm/switch_to.h index 1d48c5fee8b7..b8f888cbe6b0 100644 --- a/arch/tile/include/asm/switch_to.h +++ b/arch/tile/include/asm/switch_to.h | |||
@@ -68,7 +68,10 @@ extern unsigned long get_switch_to_pc(void); | |||
68 | /* Support function for forking a new task. */ | 68 | /* Support function for forking a new task. */ |
69 | void ret_from_fork(void); | 69 | void ret_from_fork(void); |
70 | 70 | ||
71 | /* Called from ret_from_fork() when a new process starts up. */ | 71 | /* Support function for forking a new kernel thread. */ |
72 | void ret_from_kernel_thread(void *fn, void *arg); | ||
73 | |||
74 | /* Called from ret_from_xxx() when a new process starts up. */ | ||
72 | struct task_struct *sim_notify_fork(struct task_struct *prev); | 75 | struct task_struct *sim_notify_fork(struct task_struct *prev); |
73 | 76 | ||
74 | #endif /* !__ASSEMBLY__ */ | 77 | #endif /* !__ASSEMBLY__ */ |
diff --git a/arch/tile/include/asm/syscalls.h b/arch/tile/include/asm/syscalls.h index 06f0464cfed9..369696d63e7b 100644 --- a/arch/tile/include/asm/syscalls.h +++ b/arch/tile/include/asm/syscalls.h | |||
@@ -51,8 +51,7 @@ long sys_cacheflush(unsigned long addr, unsigned long len, | |||
51 | 51 | ||
52 | #ifndef __tilegx__ | 52 | #ifndef __tilegx__ |
53 | /* mm/fault.c */ | 53 | /* mm/fault.c */ |
54 | long sys_cmpxchg_badaddr(unsigned long address, struct pt_regs *); | 54 | long sys_cmpxchg_badaddr(unsigned long address); |
55 | long _sys_cmpxchg_badaddr(unsigned long address); | ||
56 | #endif | 55 | #endif |
57 | 56 | ||
58 | #ifdef CONFIG_COMPAT | 57 | #ifdef CONFIG_COMPAT |
@@ -63,14 +62,23 @@ long sys_truncate64(const char __user *path, loff_t length); | |||
63 | long sys_ftruncate64(unsigned int fd, loff_t length); | 62 | long sys_ftruncate64(unsigned int fd, loff_t length); |
64 | #endif | 63 | #endif |
65 | 64 | ||
65 | /* Provide versions of standard syscalls that use current_pt_regs(). */ | ||
66 | long sys_clone(unsigned long clone_flags, unsigned long newsp, | ||
67 | void __user *parent_tid, void __user *child_tid); | ||
68 | long sys_execve(const char __user *filename, | ||
69 | const char __user *const __user *argv, | ||
70 | const char __user *const __user *envp); | ||
71 | long sys_rt_sigreturn(void); | ||
72 | long sys_sigaltstack(const stack_t __user *, stack_t __user *); | ||
73 | #define sys_clone sys_clone | ||
74 | #define sys_execve sys_execve | ||
75 | #define sys_rt_sigreturn sys_rt_sigreturn | ||
76 | #define sys_sigaltstack sys_sigaltstack | ||
77 | |||
66 | /* These are the intvec*.S trampolines. */ | 78 | /* These are the intvec*.S trampolines. */ |
67 | long _sys_sigaltstack(const stack_t __user *, stack_t __user *); | ||
68 | long _sys_rt_sigreturn(void); | 79 | long _sys_rt_sigreturn(void); |
69 | long _sys_clone(unsigned long clone_flags, unsigned long newsp, | 80 | long _sys_clone(unsigned long clone_flags, unsigned long newsp, |
70 | void __user *parent_tid, void __user *child_tid); | 81 | void __user *parent_tid, void __user *child_tid); |
71 | long _sys_execve(const char __user *filename, | ||
72 | const char __user *const __user *argv, | ||
73 | const char __user *const __user *envp); | ||
74 | 82 | ||
75 | #include <asm-generic/syscalls.h> | 83 | #include <asm-generic/syscalls.h> |
76 | 84 | ||
diff --git a/arch/tile/include/asm/unistd.h b/arch/tile/include/asm/unistd.h index 6e032a0a268e..dab827dc8acb 100644 --- a/arch/tile/include/asm/unistd.h +++ b/arch/tile/include/asm/unistd.h | |||
@@ -16,4 +16,5 @@ | |||
16 | #define __ARCH_WANT_SYS_LLSEEK | 16 | #define __ARCH_WANT_SYS_LLSEEK |
17 | #endif | 17 | #endif |
18 | #define __ARCH_WANT_SYS_NEWFSTATAT | 18 | #define __ARCH_WANT_SYS_NEWFSTATAT |
19 | #define __ARCH_WANT_SYS_EXECVE | ||
19 | #include <uapi/asm/unistd.h> | 20 | #include <uapi/asm/unistd.h> |
diff --git a/arch/tile/kernel/compat.c b/arch/tile/kernel/compat.c index d67459b9ac2a..a2e805569d5d 100644 --- a/arch/tile/kernel/compat.c +++ b/arch/tile/kernel/compat.c | |||
@@ -102,10 +102,9 @@ long compat_sys_sched_rr_get_interval(compat_pid_t pid, | |||
102 | #define compat_sys_fadvise64_64 sys32_fadvise64_64 | 102 | #define compat_sys_fadvise64_64 sys32_fadvise64_64 |
103 | #define compat_sys_readahead sys32_readahead | 103 | #define compat_sys_readahead sys32_readahead |
104 | 104 | ||
105 | /* Call the trampolines to manage pt_regs where necessary. */ | 105 | /* Call the assembly trampolines where necessary. */ |
106 | #define compat_sys_execve _compat_sys_execve | ||
107 | #define compat_sys_sigaltstack _compat_sys_sigaltstack | ||
108 | #define compat_sys_rt_sigreturn _compat_sys_rt_sigreturn | 106 | #define compat_sys_rt_sigreturn _compat_sys_rt_sigreturn |
107 | #undef sys_clone | ||
109 | #define sys_clone _sys_clone | 108 | #define sys_clone _sys_clone |
110 | 109 | ||
111 | /* | 110 | /* |
diff --git a/arch/tile/kernel/compat_signal.c b/arch/tile/kernel/compat_signal.c index 08b4fe1717bb..2e4cc69224a6 100644 --- a/arch/tile/kernel/compat_signal.c +++ b/arch/tile/kernel/compat_signal.c | |||
@@ -197,8 +197,7 @@ int copy_siginfo_from_user32(siginfo_t *to, struct compat_siginfo __user *from) | |||
197 | } | 197 | } |
198 | 198 | ||
199 | long compat_sys_sigaltstack(const struct compat_sigaltstack __user *uss_ptr, | 199 | long compat_sys_sigaltstack(const struct compat_sigaltstack __user *uss_ptr, |
200 | struct compat_sigaltstack __user *uoss_ptr, | 200 | struct compat_sigaltstack __user *uoss_ptr) |
201 | struct pt_regs *regs) | ||
202 | { | 201 | { |
203 | stack_t uss, uoss; | 202 | stack_t uss, uoss; |
204 | int ret; | 203 | int ret; |
@@ -219,7 +218,7 @@ long compat_sys_sigaltstack(const struct compat_sigaltstack __user *uss_ptr, | |||
219 | set_fs(KERNEL_DS); | 218 | set_fs(KERNEL_DS); |
220 | ret = do_sigaltstack(uss_ptr ? (stack_t __user __force *)&uss : NULL, | 219 | ret = do_sigaltstack(uss_ptr ? (stack_t __user __force *)&uss : NULL, |
221 | (stack_t __user __force *)&uoss, | 220 | (stack_t __user __force *)&uoss, |
222 | (unsigned long)compat_ptr(regs->sp)); | 221 | (unsigned long)compat_ptr(current_pt_regs()->sp)); |
223 | set_fs(seg); | 222 | set_fs(seg); |
224 | if (ret >= 0 && uoss_ptr) { | 223 | if (ret >= 0 && uoss_ptr) { |
225 | if (!access_ok(VERIFY_WRITE, uoss_ptr, sizeof(*uoss_ptr)) || | 224 | if (!access_ok(VERIFY_WRITE, uoss_ptr, sizeof(*uoss_ptr)) || |
@@ -232,8 +231,9 @@ long compat_sys_sigaltstack(const struct compat_sigaltstack __user *uss_ptr, | |||
232 | } | 231 | } |
233 | 232 | ||
234 | /* The assembly shim for this function arranges to ignore the return value. */ | 233 | /* The assembly shim for this function arranges to ignore the return value. */ |
235 | long compat_sys_rt_sigreturn(struct pt_regs *regs) | 234 | long compat_sys_rt_sigreturn(void) |
236 | { | 235 | { |
236 | struct pt_regs *regs = current_pt_regs(); | ||
237 | struct compat_rt_sigframe __user *frame = | 237 | struct compat_rt_sigframe __user *frame = |
238 | (struct compat_rt_sigframe __user *) compat_ptr(regs->sp); | 238 | (struct compat_rt_sigframe __user *) compat_ptr(regs->sp); |
239 | sigset_t set; | 239 | sigset_t set; |
@@ -248,7 +248,7 @@ long compat_sys_rt_sigreturn(struct pt_regs *regs) | |||
248 | if (restore_sigcontext(regs, &frame->uc.uc_mcontext)) | 248 | if (restore_sigcontext(regs, &frame->uc.uc_mcontext)) |
249 | goto badframe; | 249 | goto badframe; |
250 | 250 | ||
251 | if (compat_sys_sigaltstack(&frame->uc.uc_stack, NULL, regs) != 0) | 251 | if (compat_sys_sigaltstack(&frame->uc.uc_stack, NULL) == -EFAULT) |
252 | goto badframe; | 252 | goto badframe; |
253 | 253 | ||
254 | return 0; | 254 | return 0; |
diff --git a/arch/tile/kernel/entry.S b/arch/tile/kernel/entry.S index c31637baff28..f116cb0bce20 100644 --- a/arch/tile/kernel/entry.S +++ b/arch/tile/kernel/entry.S | |||
@@ -28,17 +28,6 @@ STD_ENTRY(current_text_addr) | |||
28 | STD_ENDPROC(current_text_addr) | 28 | STD_ENDPROC(current_text_addr) |
29 | 29 | ||
30 | /* | 30 | /* |
31 | * Implement execve(). The i386 code has a note that forking from kernel | ||
32 | * space results in no copy on write until the execve, so we should be | ||
33 | * careful not to write to the stack here. | ||
34 | */ | ||
35 | STD_ENTRY(kernel_execve) | ||
36 | moveli TREG_SYSCALL_NR_NAME, __NR_execve | ||
37 | swint1 | ||
38 | jrp lr | ||
39 | STD_ENDPROC(kernel_execve) | ||
40 | |||
41 | /* | ||
42 | * We don't run this function directly, but instead copy it to a page | 31 | * We don't run this function directly, but instead copy it to a page |
43 | * we map into every user process. See vdso_setup(). | 32 | * we map into every user process. See vdso_setup(). |
44 | * | 33 | * |
diff --git a/arch/tile/kernel/intvec_32.S b/arch/tile/kernel/intvec_32.S index 6943515100f8..f212bf7cea86 100644 --- a/arch/tile/kernel/intvec_32.S +++ b/arch/tile/kernel/intvec_32.S | |||
@@ -1291,6 +1291,21 @@ STD_ENTRY(ret_from_fork) | |||
1291 | } | 1291 | } |
1292 | STD_ENDPROC(ret_from_fork) | 1292 | STD_ENDPROC(ret_from_fork) |
1293 | 1293 | ||
1294 | STD_ENTRY(ret_from_kernel_thread) | ||
1295 | jal sim_notify_fork | ||
1296 | jal schedule_tail | ||
1297 | FEEDBACK_REENTER(ret_from_fork) | ||
1298 | { | ||
1299 | move r0, r31 | ||
1300 | jalr r30 | ||
1301 | } | ||
1302 | FEEDBACK_REENTER(ret_from_kernel_thread) | ||
1303 | { | ||
1304 | movei r30, 0 /* not an NMI */ | ||
1305 | j .Lresume_userspace /* jump into middle of interrupt_return */ | ||
1306 | } | ||
1307 | STD_ENDPROC(ret_from_kernel_thread) | ||
1308 | |||
1294 | /* | 1309 | /* |
1295 | * Code for ill interrupt. | 1310 | * Code for ill interrupt. |
1296 | */ | 1311 | */ |
@@ -1437,15 +1452,6 @@ STD_ENTRY_LOCAL(bad_intr) | |||
1437 | panic "Unhandled interrupt %#x: PC %#lx" | 1452 | panic "Unhandled interrupt %#x: PC %#lx" |
1438 | STD_ENDPROC(bad_intr) | 1453 | STD_ENDPROC(bad_intr) |
1439 | 1454 | ||
1440 | /* Put address of pt_regs in reg and jump. */ | ||
1441 | #define PTREGS_SYSCALL(x, reg) \ | ||
1442 | STD_ENTRY(_##x); \ | ||
1443 | { \ | ||
1444 | PTREGS_PTR(reg, PTREGS_OFFSET_BASE); \ | ||
1445 | j x \ | ||
1446 | }; \ | ||
1447 | STD_ENDPROC(_##x) | ||
1448 | |||
1449 | /* | 1455 | /* |
1450 | * Special-case sigreturn to not write r0 to the stack on return. | 1456 | * Special-case sigreturn to not write r0 to the stack on return. |
1451 | * This is technically more efficient, but it also avoids difficulties | 1457 | * This is technically more efficient, but it also avoids difficulties |
@@ -1461,12 +1467,9 @@ STD_ENTRY_LOCAL(bad_intr) | |||
1461 | }; \ | 1467 | }; \ |
1462 | STD_ENDPROC(_##x) | 1468 | STD_ENDPROC(_##x) |
1463 | 1469 | ||
1464 | PTREGS_SYSCALL(sys_execve, r3) | ||
1465 | PTREGS_SYSCALL(sys_sigaltstack, r2) | ||
1466 | PTREGS_SYSCALL_SIGRETURN(sys_rt_sigreturn, r0) | 1470 | PTREGS_SYSCALL_SIGRETURN(sys_rt_sigreturn, r0) |
1467 | PTREGS_SYSCALL(sys_cmpxchg_badaddr, r1) | ||
1468 | 1471 | ||
1469 | /* Save additional callee-saves to pt_regs, put address in r4 and jump. */ | 1472 | /* Save additional callee-saves to pt_regs and jump to standard function. */ |
1470 | STD_ENTRY(_sys_clone) | 1473 | STD_ENTRY(_sys_clone) |
1471 | push_extra_callee_saves r4 | 1474 | push_extra_callee_saves r4 |
1472 | j sys_clone | 1475 | j sys_clone |
diff --git a/arch/tile/kernel/intvec_64.S b/arch/tile/kernel/intvec_64.S index 7c06d597ffd0..54bc9a6678e8 100644 --- a/arch/tile/kernel/intvec_64.S +++ b/arch/tile/kernel/intvec_64.S | |||
@@ -1150,6 +1150,21 @@ STD_ENTRY(ret_from_fork) | |||
1150 | } | 1150 | } |
1151 | STD_ENDPROC(ret_from_fork) | 1151 | STD_ENDPROC(ret_from_fork) |
1152 | 1152 | ||
1153 | STD_ENTRY(ret_from_kernel_thread) | ||
1154 | jal sim_notify_fork | ||
1155 | jal schedule_tail | ||
1156 | FEEDBACK_REENTER(ret_from_fork) | ||
1157 | { | ||
1158 | move r0, r31 | ||
1159 | jalr r30 | ||
1160 | } | ||
1161 | FEEDBACK_REENTER(ret_from_kernel_thread) | ||
1162 | { | ||
1163 | movei r30, 0 /* not an NMI */ | ||
1164 | j .Lresume_userspace /* jump into middle of interrupt_return */ | ||
1165 | } | ||
1166 | STD_ENDPROC(ret_from_kernel_thread) | ||
1167 | |||
1153 | /* Various stub interrupt handlers and syscall handlers */ | 1168 | /* Various stub interrupt handlers and syscall handlers */ |
1154 | 1169 | ||
1155 | STD_ENTRY_LOCAL(_kernel_double_fault) | 1170 | STD_ENTRY_LOCAL(_kernel_double_fault) |
@@ -1166,15 +1181,6 @@ STD_ENTRY_LOCAL(bad_intr) | |||
1166 | panic "Unhandled interrupt %#x: PC %#lx" | 1181 | panic "Unhandled interrupt %#x: PC %#lx" |
1167 | STD_ENDPROC(bad_intr) | 1182 | STD_ENDPROC(bad_intr) |
1168 | 1183 | ||
1169 | /* Put address of pt_regs in reg and jump. */ | ||
1170 | #define PTREGS_SYSCALL(x, reg) \ | ||
1171 | STD_ENTRY(_##x); \ | ||
1172 | { \ | ||
1173 | PTREGS_PTR(reg, PTREGS_OFFSET_BASE); \ | ||
1174 | j x \ | ||
1175 | }; \ | ||
1176 | STD_ENDPROC(_##x) | ||
1177 | |||
1178 | /* | 1184 | /* |
1179 | * Special-case sigreturn to not write r0 to the stack on return. | 1185 | * Special-case sigreturn to not write r0 to the stack on return. |
1180 | * This is technically more efficient, but it also avoids difficulties | 1186 | * This is technically more efficient, but it also avoids difficulties |
@@ -1190,16 +1196,12 @@ STD_ENTRY_LOCAL(bad_intr) | |||
1190 | }; \ | 1196 | }; \ |
1191 | STD_ENDPROC(_##x) | 1197 | STD_ENDPROC(_##x) |
1192 | 1198 | ||
1193 | PTREGS_SYSCALL(sys_execve, r3) | ||
1194 | PTREGS_SYSCALL(sys_sigaltstack, r2) | ||
1195 | PTREGS_SYSCALL_SIGRETURN(sys_rt_sigreturn, r0) | 1199 | PTREGS_SYSCALL_SIGRETURN(sys_rt_sigreturn, r0) |
1196 | #ifdef CONFIG_COMPAT | 1200 | #ifdef CONFIG_COMPAT |
1197 | PTREGS_SYSCALL(compat_sys_execve, r3) | ||
1198 | PTREGS_SYSCALL(compat_sys_sigaltstack, r2) | ||
1199 | PTREGS_SYSCALL_SIGRETURN(compat_sys_rt_sigreturn, r0) | 1201 | PTREGS_SYSCALL_SIGRETURN(compat_sys_rt_sigreturn, r0) |
1200 | #endif | 1202 | #endif |
1201 | 1203 | ||
1202 | /* Save additional callee-saves to pt_regs, put address in r4 and jump. */ | 1204 | /* Save additional callee-saves to pt_regs and jump to standard function. */ |
1203 | STD_ENTRY(_sys_clone) | 1205 | STD_ENTRY(_sys_clone) |
1204 | push_extra_callee_saves r4 | 1206 | push_extra_callee_saves r4 |
1205 | j sys_clone | 1207 | j sys_clone |
diff --git a/arch/tile/kernel/process.c b/arch/tile/kernel/process.c index 307d010696c9..1c20029d2f5a 100644 --- a/arch/tile/kernel/process.c +++ b/arch/tile/kernel/process.c | |||
@@ -157,24 +157,44 @@ void arch_release_thread_info(struct thread_info *info) | |||
157 | static void save_arch_state(struct thread_struct *t); | 157 | static void save_arch_state(struct thread_struct *t); |
158 | 158 | ||
159 | int copy_thread(unsigned long clone_flags, unsigned long sp, | 159 | int copy_thread(unsigned long clone_flags, unsigned long sp, |
160 | unsigned long stack_size, | 160 | unsigned long arg, |
161 | struct task_struct *p, struct pt_regs *regs) | 161 | struct task_struct *p, struct pt_regs *unused) |
162 | { | 162 | { |
163 | struct pt_regs *childregs; | 163 | struct pt_regs *childregs = task_pt_regs(p); |
164 | unsigned long ksp; | 164 | unsigned long ksp; |
165 | unsigned long *callee_regs; | ||
165 | 166 | ||
166 | /* | 167 | /* |
167 | * When creating a new kernel thread we pass sp as zero. | 168 | * Set up the stack and stack pointer appropriately for the |
168 | * Assign it to a reasonable value now that we have the stack. | 169 | * new child to find itself woken up in __switch_to(). |
170 | * The callee-saved registers must be on the stack to be read; | ||
171 | * the new task will then jump to assembly support to handle | ||
172 | * calling schedule_tail(), etc., and (for userspace tasks) | ||
173 | * returning to the context set up in the pt_regs. | ||
169 | */ | 174 | */ |
170 | if (sp == 0 && regs->ex1 == PL_ICS_EX1(KERNEL_PL, 0)) | 175 | ksp = (unsigned long) childregs; |
171 | sp = KSTK_TOP(p); | 176 | ksp -= C_ABI_SAVE_AREA_SIZE; /* interrupt-entry save area */ |
177 | ((long *)ksp)[0] = ((long *)ksp)[1] = 0; | ||
178 | ksp -= CALLEE_SAVED_REGS_COUNT * sizeof(unsigned long); | ||
179 | callee_regs = (unsigned long *)ksp; | ||
180 | ksp -= C_ABI_SAVE_AREA_SIZE; /* __switch_to() save area */ | ||
181 | ((long *)ksp)[0] = ((long *)ksp)[1] = 0; | ||
182 | p->thread.ksp = ksp; | ||
172 | 183 | ||
173 | /* | 184 | /* Record the pid of the task that created this one. */ |
174 | * Do not clone step state from the parent; each thread | 185 | p->thread.creator_pid = current->pid; |
175 | * must make its own lazily. | 186 | |
176 | */ | 187 | if (unlikely(p->flags & PF_KTHREAD)) { |
177 | task_thread_info(p)->step_state = NULL; | 188 | /* kernel thread */ |
189 | memset(childregs, 0, sizeof(struct pt_regs)); | ||
190 | memset(&callee_regs[2], 0, | ||
191 | (CALLEE_SAVED_REGS_COUNT - 2) * sizeof(unsigned long)); | ||
192 | callee_regs[0] = sp; /* r30 = function */ | ||
193 | callee_regs[1] = arg; /* r31 = arg */ | ||
194 | childregs->ex1 = PL_ICS_EX1(KERNEL_PL, 0); | ||
195 | p->thread.pc = (unsigned long) ret_from_kernel_thread; | ||
196 | return 0; | ||
197 | } | ||
178 | 198 | ||
179 | /* | 199 | /* |
180 | * Start new thread in ret_from_fork so it schedules properly | 200 | * Start new thread in ret_from_fork so it schedules properly |
@@ -182,46 +202,33 @@ int copy_thread(unsigned long clone_flags, unsigned long sp, | |||
182 | */ | 202 | */ |
183 | p->thread.pc = (unsigned long) ret_from_fork; | 203 | p->thread.pc = (unsigned long) ret_from_fork; |
184 | 204 | ||
185 | /* Save user stack top pointer so we can ID the stack vm area later. */ | 205 | /* |
186 | p->thread.usp0 = sp; | 206 | * Do not clone step state from the parent; each thread |
187 | 207 | * must make its own lazily. | |
188 | /* Record the pid of the process that created this one. */ | 208 | */ |
189 | p->thread.creator_pid = current->pid; | 209 | task_thread_info(p)->step_state = NULL; |
190 | 210 | ||
191 | /* | 211 | /* |
192 | * Copy the registers onto the kernel stack so the | 212 | * Copy the registers onto the kernel stack so the |
193 | * return-from-interrupt code will reload it into registers. | 213 | * return-from-interrupt code will reload it into registers. |
194 | */ | 214 | */ |
195 | childregs = task_pt_regs(p); | 215 | *childregs = *current_pt_regs(); |
196 | *childregs = *regs; | ||
197 | childregs->regs[0] = 0; /* return value is zero */ | 216 | childregs->regs[0] = 0; /* return value is zero */ |
198 | childregs->sp = sp; /* override with new user stack pointer */ | 217 | if (sp) |
218 | childregs->sp = sp; /* override with new user stack pointer */ | ||
219 | memcpy(callee_regs, &childregs->regs[CALLEE_SAVED_FIRST_REG], | ||
220 | CALLEE_SAVED_REGS_COUNT * sizeof(unsigned long)); | ||
221 | |||
222 | /* Save user stack top pointer so we can ID the stack vm area later. */ | ||
223 | p->thread.usp0 = childregs->sp; | ||
199 | 224 | ||
200 | /* | 225 | /* |
201 | * If CLONE_SETTLS is set, set "tp" in the new task to "r4", | 226 | * If CLONE_SETTLS is set, set "tp" in the new task to "r4", |
202 | * which is passed in as arg #5 to sys_clone(). | 227 | * which is passed in as arg #5 to sys_clone(). |
203 | */ | 228 | */ |
204 | if (clone_flags & CLONE_SETTLS) | 229 | if (clone_flags & CLONE_SETTLS) |
205 | childregs->tp = regs->regs[4]; | 230 | childregs->tp = childregs->regs[4]; |
206 | 231 | ||
207 | /* | ||
208 | * Copy the callee-saved registers from the passed pt_regs struct | ||
209 | * into the context-switch callee-saved registers area. | ||
210 | * This way when we start the interrupt-return sequence, the | ||
211 | * callee-save registers will be correctly in registers, which | ||
212 | * is how we assume the compiler leaves them as we start doing | ||
213 | * the normal return-from-interrupt path after calling C code. | ||
214 | * Zero out the C ABI save area to mark the top of the stack. | ||
215 | */ | ||
216 | ksp = (unsigned long) childregs; | ||
217 | ksp -= C_ABI_SAVE_AREA_SIZE; /* interrupt-entry save area */ | ||
218 | ((long *)ksp)[0] = ((long *)ksp)[1] = 0; | ||
219 | ksp -= CALLEE_SAVED_REGS_COUNT * sizeof(unsigned long); | ||
220 | memcpy((void *)ksp, ®s->regs[CALLEE_SAVED_FIRST_REG], | ||
221 | CALLEE_SAVED_REGS_COUNT * sizeof(unsigned long)); | ||
222 | ksp -= C_ABI_SAVE_AREA_SIZE; /* __switch_to() save area */ | ||
223 | ((long *)ksp)[0] = ((long *)ksp)[1] = 0; | ||
224 | p->thread.ksp = ksp; | ||
225 | 232 | ||
226 | #if CHIP_HAS_TILE_DMA() | 233 | #if CHIP_HAS_TILE_DMA() |
227 | /* | 234 | /* |
@@ -578,61 +585,13 @@ int do_work_pending(struct pt_regs *regs, u32 thread_info_flags) | |||
578 | } | 585 | } |
579 | 586 | ||
580 | /* Note there is an implicit fifth argument if (clone_flags & CLONE_SETTLS). */ | 587 | /* Note there is an implicit fifth argument if (clone_flags & CLONE_SETTLS). */ |
581 | SYSCALL_DEFINE5(clone, unsigned long, clone_flags, unsigned long, newsp, | 588 | SYSCALL_DEFINE4(clone, unsigned long, clone_flags, unsigned long, newsp, |
582 | void __user *, parent_tidptr, void __user *, child_tidptr, | 589 | void __user *, parent_tidptr, void __user *, child_tidptr) |
583 | struct pt_regs *, regs) | ||
584 | { | 590 | { |
585 | if (!newsp) | 591 | return do_fork(clone_flags, newsp, current_pt_regs(), 0, |
586 | newsp = regs->sp; | ||
587 | return do_fork(clone_flags, newsp, regs, 0, | ||
588 | parent_tidptr, child_tidptr); | 592 | parent_tidptr, child_tidptr); |
589 | } | 593 | } |
590 | 594 | ||
591 | /* | ||
592 | * sys_execve() executes a new program. | ||
593 | */ | ||
594 | SYSCALL_DEFINE4(execve, const char __user *, path, | ||
595 | const char __user *const __user *, argv, | ||
596 | const char __user *const __user *, envp, | ||
597 | struct pt_regs *, regs) | ||
598 | { | ||
599 | long error; | ||
600 | struct filename *filename; | ||
601 | |||
602 | filename = getname(path); | ||
603 | error = PTR_ERR(filename); | ||
604 | if (IS_ERR(filename)) | ||
605 | goto out; | ||
606 | error = do_execve(filename->name, argv, envp, regs); | ||
607 | putname(filename); | ||
608 | if (error == 0) | ||
609 | single_step_execve(); | ||
610 | out: | ||
611 | return error; | ||
612 | } | ||
613 | |||
614 | #ifdef CONFIG_COMPAT | ||
615 | long compat_sys_execve(const char __user *path, | ||
616 | compat_uptr_t __user *argv, | ||
617 | compat_uptr_t __user *envp, | ||
618 | struct pt_regs *regs) | ||
619 | { | ||
620 | long error; | ||
621 | struct filename *filename; | ||
622 | |||
623 | filename = getname(path); | ||
624 | error = PTR_ERR(filename); | ||
625 | if (IS_ERR(filename)) | ||
626 | goto out; | ||
627 | error = compat_do_execve(filename->name, argv, envp, regs); | ||
628 | putname(filename); | ||
629 | if (error == 0) | ||
630 | single_step_execve(); | ||
631 | out: | ||
632 | return error; | ||
633 | } | ||
634 | #endif | ||
635 | |||
636 | unsigned long get_wchan(struct task_struct *p) | 595 | unsigned long get_wchan(struct task_struct *p) |
637 | { | 596 | { |
638 | struct KBacktraceIterator kbt; | 597 | struct KBacktraceIterator kbt; |
@@ -650,37 +609,6 @@ unsigned long get_wchan(struct task_struct *p) | |||
650 | return 0; | 609 | return 0; |
651 | } | 610 | } |
652 | 611 | ||
653 | /* | ||
654 | * We pass in lr as zero (cleared in kernel_thread) and the caller | ||
655 | * part of the backtrace ABI on the stack also zeroed (in copy_thread) | ||
656 | * so that backtraces will stop with this function. | ||
657 | * Note that we don't use r0, since copy_thread() clears it. | ||
658 | */ | ||
659 | static void start_kernel_thread(int dummy, int (*fn)(int), int arg) | ||
660 | { | ||
661 | do_exit(fn(arg)); | ||
662 | } | ||
663 | |||
664 | /* | ||
665 | * Create a kernel thread | ||
666 | */ | ||
667 | int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) | ||
668 | { | ||
669 | struct pt_regs regs; | ||
670 | |||
671 | memset(®s, 0, sizeof(regs)); | ||
672 | regs.ex1 = PL_ICS_EX1(KERNEL_PL, 0); /* run at kernel PL, no ICS */ | ||
673 | regs.pc = (long) start_kernel_thread; | ||
674 | regs.flags = PT_FLAGS_CALLER_SAVES; /* need to restore r1 and r2 */ | ||
675 | regs.regs[1] = (long) fn; /* function pointer */ | ||
676 | regs.regs[2] = (long) arg; /* parameter register */ | ||
677 | |||
678 | /* Ok, create the new process.. */ | ||
679 | return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, ®s, | ||
680 | 0, NULL, NULL); | ||
681 | } | ||
682 | EXPORT_SYMBOL(kernel_thread); | ||
683 | |||
684 | /* Flush thread state. */ | 612 | /* Flush thread state. */ |
685 | void flush_thread(void) | 613 | void flush_thread(void) |
686 | { | 614 | { |
diff --git a/arch/tile/kernel/signal.c b/arch/tile/kernel/signal.c index 67efb656d104..657a7ace4ab4 100644 --- a/arch/tile/kernel/signal.c +++ b/arch/tile/kernel/signal.c | |||
@@ -37,10 +37,10 @@ | |||
37 | 37 | ||
38 | #define DEBUG_SIG 0 | 38 | #define DEBUG_SIG 0 |
39 | 39 | ||
40 | SYSCALL_DEFINE3(sigaltstack, const stack_t __user *, uss, | 40 | SYSCALL_DEFINE2(sigaltstack, const stack_t __user *, uss, |
41 | stack_t __user *, uoss, struct pt_regs *, regs) | 41 | stack_t __user *, uoss) |
42 | { | 42 | { |
43 | return do_sigaltstack(uss, uoss, regs->sp); | 43 | return do_sigaltstack(uss, uoss, current_pt_regs()->sp); |
44 | } | 44 | } |
45 | 45 | ||
46 | 46 | ||
@@ -83,8 +83,9 @@ void signal_fault(const char *type, struct pt_regs *regs, | |||
83 | } | 83 | } |
84 | 84 | ||
85 | /* The assembly shim for this function arranges to ignore the return value. */ | 85 | /* The assembly shim for this function arranges to ignore the return value. */ |
86 | SYSCALL_DEFINE1(rt_sigreturn, struct pt_regs *, regs) | 86 | SYSCALL_DEFINE0(rt_sigreturn) |
87 | { | 87 | { |
88 | struct pt_regs *regs = current_pt_regs(); | ||
88 | struct rt_sigframe __user *frame = | 89 | struct rt_sigframe __user *frame = |
89 | (struct rt_sigframe __user *)(regs->sp); | 90 | (struct rt_sigframe __user *)(regs->sp); |
90 | sigset_t set; | 91 | sigset_t set; |
diff --git a/arch/tile/kernel/sys.c b/arch/tile/kernel/sys.c index b08095b402d6..02ff5c0ef775 100644 --- a/arch/tile/kernel/sys.c +++ b/arch/tile/kernel/sys.c | |||
@@ -106,14 +106,11 @@ SYSCALL_DEFINE6(mmap, unsigned long, addr, unsigned long, len, | |||
106 | #define sys_readahead sys32_readahead | 106 | #define sys_readahead sys32_readahead |
107 | #endif | 107 | #endif |
108 | 108 | ||
109 | /* Call the trampolines to manage pt_regs where necessary. */ | 109 | /* Call the assembly trampolines where necessary. */ |
110 | #define sys_execve _sys_execve | 110 | #undef sys_rt_sigreturn |
111 | #define sys_sigaltstack _sys_sigaltstack | ||
112 | #define sys_rt_sigreturn _sys_rt_sigreturn | 111 | #define sys_rt_sigreturn _sys_rt_sigreturn |
112 | #undef sys_clone | ||
113 | #define sys_clone _sys_clone | 113 | #define sys_clone _sys_clone |
114 | #ifndef __tilegx__ | ||
115 | #define sys_cmpxchg_badaddr _sys_cmpxchg_badaddr | ||
116 | #endif | ||
117 | 114 | ||
118 | /* | 115 | /* |
119 | * Note that we can't include <linux/unistd.h> here since the header | 116 | * Note that we can't include <linux/unistd.h> here since the header |
diff --git a/arch/tile/mm/fault.c b/arch/tile/mm/fault.c index fe811fa5f1b9..3d2b81c163a6 100644 --- a/arch/tile/mm/fault.c +++ b/arch/tile/mm/fault.c | |||
@@ -70,9 +70,10 @@ static noinline void force_sig_info_fault(const char *type, int si_signo, | |||
70 | * Synthesize the fault a PL0 process would get by doing a word-load of | 70 | * Synthesize the fault a PL0 process would get by doing a word-load of |
71 | * an unaligned address or a high kernel address. | 71 | * an unaligned address or a high kernel address. |
72 | */ | 72 | */ |
73 | SYSCALL_DEFINE2(cmpxchg_badaddr, unsigned long, address, | 73 | SYSCALL_DEFINE1(cmpxchg_badaddr, unsigned long, address) |
74 | struct pt_regs *, regs) | ||
75 | { | 74 | { |
75 | struct pt_regs *regs = current_pt_regs(); | ||
76 | |||
76 | if (address >= PAGE_OFFSET) | 77 | if (address >= PAGE_OFFSET) |
77 | force_sig_info_fault("atomic segfault", SIGSEGV, SEGV_MAPERR, | 78 | force_sig_info_fault("atomic segfault", SIGSEGV, SEGV_MAPERR, |
78 | address, INT_DTLB_MISS, current, regs); | 79 | address, INT_DTLB_MISS, current, regs); |