aboutsummaryrefslogtreecommitdiffstats
path: root/arch/m68k
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2012-10-21 16:41:46 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2012-11-28 22:44:46 -0500
commit20ecc91c3230b747cd13d9a2f43a45f6445a3906 (patch)
tree3892c3eafe47e78f153549158c24d26cf1b7ecc8 /arch/m68k
parentdfe09ae0e5fe40679af05b1ba810d469844c97b3 (diff)
m68k: sanitize copy_thread(), fork/vfork/clone wrappers, switch to generic fork/vfork
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'arch/m68k')
-rw-r--r--arch/m68k/include/asm/unistd.h2
-rw-r--r--arch/m68k/kernel/entry.S23
-rw-r--r--arch/m68k/kernel/process.c86
-rw-r--r--arch/m68k/kernel/syscalltable.S6
4 files changed, 46 insertions, 71 deletions
diff --git a/arch/m68k/include/asm/unistd.h b/arch/m68k/include/asm/unistd.h
index 0aa165405966..a021d67cdd72 100644
--- a/arch/m68k/include/asm/unistd.h
+++ b/arch/m68k/include/asm/unistd.h
@@ -32,6 +32,8 @@
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_SYS_FORK
36#define __ARCH_WANT_SYS_VFORK
35 37
36/* 38/*
37 * "Conditional" syscalls 39 * "Conditional" syscalls
diff --git a/arch/m68k/kernel/entry.S b/arch/m68k/kernel/entry.S
index 45b2f293f8cf..a78f5649e8de 100644
--- a/arch/m68k/kernel/entry.S
+++ b/arch/m68k/kernel/entry.S
@@ -44,34 +44,29 @@
44 44
45.globl system_call, buserr, trap, resume 45.globl system_call, buserr, trap, resume
46.globl sys_call_table 46.globl sys_call_table
47.globl sys_fork, sys_clone, sys_vfork 47.globl __sys_fork, __sys_clone, __sys_vfork
48.globl ret_from_interrupt, bad_interrupt 48.globl ret_from_interrupt, bad_interrupt
49.globl auto_irqhandler_fixup 49.globl auto_irqhandler_fixup
50.globl user_irqvec_fixup 50.globl user_irqvec_fixup
51 51
52.text 52.text
53ENTRY(sys_fork) 53ENTRY(__sys_fork)
54 SAVE_SWITCH_STACK 54 SAVE_SWITCH_STACK
55 pea %sp@(SWITCH_STACK_SIZE) 55 jbsr sys_fork
56 jbsr m68k_fork 56 lea %sp@(24),%sp
57 addql #4,%sp
58 RESTORE_SWITCH_STACK
59 rts 57 rts
60 58
61ENTRY(sys_clone) 59ENTRY(__sys_clone)
62 SAVE_SWITCH_STACK 60 SAVE_SWITCH_STACK
63 pea %sp@(SWITCH_STACK_SIZE) 61 pea %sp@(SWITCH_STACK_SIZE)
64 jbsr m68k_clone 62 jbsr m68k_clone
65 addql #4,%sp 63 lea %sp@(28),%sp
66 RESTORE_SWITCH_STACK
67 rts 64 rts
68 65
69ENTRY(sys_vfork) 66ENTRY(__sys_vfork)
70 SAVE_SWITCH_STACK 67 SAVE_SWITCH_STACK
71 pea %sp@(SWITCH_STACK_SIZE) 68 jbsr sys_vfork
72 jbsr m68k_vfork 69 lea %sp@(24),%sp
73 addql #4,%sp
74 RESTORE_SWITCH_STACK
75 rts 70 rts
76 71
77ENTRY(sys_sigreturn) 72ENTRY(sys_sigreturn)
diff --git a/arch/m68k/kernel/process.c b/arch/m68k/kernel/process.c
index c51bb172e14d..aa9b11000273 100644
--- a/arch/m68k/kernel/process.c
+++ b/arch/m68k/kernel/process.c
@@ -136,57 +136,36 @@ void flush_thread(void)
136} 136}
137 137
138/* 138/*
139 * "m68k_fork()".. By the time we get here, the 139 * Why not generic sys_clone, you ask? m68k passes all arguments on stack.
140 * non-volatile registers have also been saved on the 140 * And we need all registers saved, which means a bunch of stuff pushed
141 * stack. We do some ugly pointer stuff here.. (see 141 * on top of pt_regs, which means that sys_clone() arguments would be
142 * also copy_thread) 142 * buried. We could, of course, copy them, but it's too costly for no
143 * good reason - generic clone() would have to copy them *again* for
144 * do_fork() anyway. So in this case it's actually better to pass pt_regs *
145 * and extract arguments for do_fork() from there. Eventually we might
146 * go for calling do_fork() directly from the wrapper, but only after we
147 * are finished with do_fork() prototype conversion.
143 */ 148 */
144
145asmlinkage int m68k_fork(struct pt_regs *regs)
146{
147#ifdef CONFIG_MMU
148 return do_fork(SIGCHLD, rdusp(), regs, 0, NULL, NULL);
149#else
150 return -EINVAL;
151#endif
152}
153
154asmlinkage int m68k_vfork(struct pt_regs *regs)
155{
156 return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), regs, 0,
157 NULL, NULL);
158}
159
160asmlinkage int m68k_clone(struct pt_regs *regs) 149asmlinkage int m68k_clone(struct pt_regs *regs)
161{ 150{
162 unsigned long clone_flags; 151 /* regs will be equal to current_pt_regs() */
163 unsigned long newsp; 152 return do_fork(regs->d1, regs->d2, regs, 0,
164 int __user *parent_tidptr, *child_tidptr; 153 (int __user *)regs->d3, (int __user *)regs->d4);
165
166 /* syscall2 puts clone_flags in d1 and usp in d2 */
167 clone_flags = regs->d1;
168 newsp = regs->d2;
169 parent_tidptr = (int __user *)regs->d3;
170 child_tidptr = (int __user *)regs->d4;
171 if (!newsp)
172 newsp = rdusp();
173 return do_fork(clone_flags, newsp, regs, 0,
174 parent_tidptr, child_tidptr);
175} 154}
176 155
177int copy_thread(unsigned long clone_flags, unsigned long usp, 156int copy_thread(unsigned long clone_flags, unsigned long usp,
178 unsigned long arg, 157 unsigned long arg,
179 struct task_struct * p, struct pt_regs * regs) 158 struct task_struct * p, struct pt_regs * unused)
180{ 159{
181 struct pt_regs * childregs; 160 struct fork_frame {
182 struct switch_stack *childstack; 161 struct switch_stack sw;
162 struct pt_regs regs;
163 } *frame;
183 164
184 childregs = (struct pt_regs *) (task_stack_page(p) + THREAD_SIZE) - 1; 165 frame = (struct fork_frame *) (task_stack_page(p) + THREAD_SIZE) - 1;
185 childstack = ((struct switch_stack *) childregs) - 1;
186 166
187 p->thread.usp = usp; 167 p->thread.ksp = (unsigned long)frame;
188 p->thread.ksp = (unsigned long)childstack; 168 p->thread.esp0 = (unsigned long)&frame->regs;
189 p->thread.esp0 = (unsigned long)childregs;
190 169
191 /* 170 /*
192 * Must save the current SFC/DFC value, NOT the value when 171 * Must save the current SFC/DFC value, NOT the value when
@@ -194,25 +173,24 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,
194 */ 173 */
195 p->thread.fs = get_fs().seg; 174 p->thread.fs = get_fs().seg;
196 175
197 if (unlikely(!regs)) { 176 if (unlikely(p->flags & PF_KTHREAD)) {
198 /* kernel thread */ 177 /* kernel thread */
199 memset(childstack, 0, 178 memset(frame, 0, sizeof(struct fork_frame));
200 sizeof(struct switch_stack) + sizeof(struct pt_regs)); 179 frame->regs.sr = PS_S;
201 childregs->sr = PS_S; 180 frame->sw.a3 = usp; /* function */
202 childstack->a3 = usp; /* function */ 181 frame->sw.d7 = arg;
203 childstack->d7 = arg; 182 frame->sw.retpc = (unsigned long)ret_from_kernel_thread;
204 childstack->retpc = (unsigned long)ret_from_kernel_thread;
205 p->thread.usp = 0; 183 p->thread.usp = 0;
206 return 0; 184 return 0;
207 } 185 }
208 *childregs = *regs; 186 memcpy(frame, container_of(current_pt_regs(), struct fork_frame, regs),
209 childregs->d0 = 0; 187 sizeof(struct fork_frame));
210 188 frame->regs.d0 = 0;
211 *childstack = ((struct switch_stack *) regs)[-1]; 189 frame->sw.retpc = (unsigned long)ret_from_fork;
212 childstack->retpc = (unsigned long)ret_from_fork; 190 p->thread.usp = usp ?: rdusp();
213 191
214 if (clone_flags & CLONE_SETTLS) 192 if (clone_flags & CLONE_SETTLS)
215 task_thread_info(p)->tp_value = regs->d5; 193 task_thread_info(p)->tp_value = frame->regs.d5;
216 194
217#ifdef CONFIG_FPU 195#ifdef CONFIG_FPU
218 if (!FPU_IS_EMU) { 196 if (!FPU_IS_EMU) {
diff --git a/arch/m68k/kernel/syscalltable.S b/arch/m68k/kernel/syscalltable.S
index 4fc2e29b771b..c30da5b3f2db 100644
--- a/arch/m68k/kernel/syscalltable.S
+++ b/arch/m68k/kernel/syscalltable.S
@@ -22,7 +22,7 @@ ALIGN
22ENTRY(sys_call_table) 22ENTRY(sys_call_table)
23 .long sys_restart_syscall /* 0 - old "setup()" system call, used for restarting */ 23 .long sys_restart_syscall /* 0 - old "setup()" system call, used for restarting */
24 .long sys_exit 24 .long sys_exit
25 .long sys_fork 25 .long __sys_fork
26 .long sys_read 26 .long sys_read
27 .long sys_write 27 .long sys_write
28 .long sys_open /* 5 */ 28 .long sys_open /* 5 */
@@ -140,7 +140,7 @@ ENTRY(sys_call_table)
140 .long sys_ipc 140 .long sys_ipc
141 .long sys_fsync 141 .long sys_fsync
142 .long sys_sigreturn 142 .long sys_sigreturn
143 .long sys_clone /* 120 */ 143 .long __sys_clone /* 120 */
144 .long sys_setdomainname 144 .long sys_setdomainname
145 .long sys_newuname 145 .long sys_newuname
146 .long sys_cacheflush /* modify_ldt for i386 */ 146 .long sys_cacheflush /* modify_ldt for i386 */
@@ -210,7 +210,7 @@ ENTRY(sys_call_table)
210 .long sys_sendfile 210 .long sys_sendfile
211 .long sys_ni_syscall /* streams1 */ 211 .long sys_ni_syscall /* streams1 */
212 .long sys_ni_syscall /* streams2 */ 212 .long sys_ni_syscall /* streams2 */
213 .long sys_vfork /* 190 */ 213 .long __sys_vfork /* 190 */
214 .long sys_getrlimit 214 .long sys_getrlimit
215 .long sys_mmap2 215 .long sys_mmap2
216 .long sys_truncate64 216 .long sys_truncate64