diff options
Diffstat (limited to 'arch/m68k/kernel/process.c')
-rw-r--r-- | arch/m68k/kernel/process.c | 87 |
1 files changed, 32 insertions, 55 deletions
diff --git a/arch/m68k/kernel/process.c b/arch/m68k/kernel/process.c index c51bb172e14d..d538694ad208 100644 --- a/arch/m68k/kernel/process.c +++ b/arch/m68k/kernel/process.c | |||
@@ -136,57 +136,35 @@ 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 | |||
145 | asmlinkage 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 | |||
154 | asmlinkage 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 | |||
160 | asmlinkage int m68k_clone(struct pt_regs *regs) | 149 | asmlinkage 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, 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 | ||
177 | int copy_thread(unsigned long clone_flags, unsigned long usp, | 156 | int copy_thread(unsigned long clone_flags, unsigned long usp, |
178 | unsigned long arg, | 157 | unsigned long arg, struct task_struct *p) |
179 | struct task_struct * p, struct pt_regs * regs) | ||
180 | { | 158 | { |
181 | struct pt_regs * childregs; | 159 | struct fork_frame { |
182 | struct switch_stack *childstack; | 160 | struct switch_stack sw; |
161 | struct pt_regs regs; | ||
162 | } *frame; | ||
183 | 163 | ||
184 | childregs = (struct pt_regs *) (task_stack_page(p) + THREAD_SIZE) - 1; | 164 | frame = (struct fork_frame *) (task_stack_page(p) + THREAD_SIZE) - 1; |
185 | childstack = ((struct switch_stack *) childregs) - 1; | ||
186 | 165 | ||
187 | p->thread.usp = usp; | 166 | p->thread.ksp = (unsigned long)frame; |
188 | p->thread.ksp = (unsigned long)childstack; | 167 | p->thread.esp0 = (unsigned long)&frame->regs; |
189 | p->thread.esp0 = (unsigned long)childregs; | ||
190 | 168 | ||
191 | /* | 169 | /* |
192 | * Must save the current SFC/DFC value, NOT the value when | 170 | * Must save the current SFC/DFC value, NOT the value when |
@@ -194,25 +172,24 @@ int copy_thread(unsigned long clone_flags, unsigned long usp, | |||
194 | */ | 172 | */ |
195 | p->thread.fs = get_fs().seg; | 173 | p->thread.fs = get_fs().seg; |
196 | 174 | ||
197 | if (unlikely(!regs)) { | 175 | if (unlikely(p->flags & PF_KTHREAD)) { |
198 | /* kernel thread */ | 176 | /* kernel thread */ |
199 | memset(childstack, 0, | 177 | memset(frame, 0, sizeof(struct fork_frame)); |
200 | sizeof(struct switch_stack) + sizeof(struct pt_regs)); | 178 | frame->regs.sr = PS_S; |
201 | childregs->sr = PS_S; | 179 | frame->sw.a3 = usp; /* function */ |
202 | childstack->a3 = usp; /* function */ | 180 | frame->sw.d7 = arg; |
203 | childstack->d7 = arg; | 181 | frame->sw.retpc = (unsigned long)ret_from_kernel_thread; |
204 | childstack->retpc = (unsigned long)ret_from_kernel_thread; | ||
205 | p->thread.usp = 0; | 182 | p->thread.usp = 0; |
206 | return 0; | 183 | return 0; |
207 | } | 184 | } |
208 | *childregs = *regs; | 185 | memcpy(frame, container_of(current_pt_regs(), struct fork_frame, regs), |
209 | childregs->d0 = 0; | 186 | sizeof(struct fork_frame)); |
210 | 187 | frame->regs.d0 = 0; | |
211 | *childstack = ((struct switch_stack *) regs)[-1]; | 188 | frame->sw.retpc = (unsigned long)ret_from_fork; |
212 | childstack->retpc = (unsigned long)ret_from_fork; | 189 | p->thread.usp = usp ?: rdusp(); |
213 | 190 | ||
214 | if (clone_flags & CLONE_SETTLS) | 191 | if (clone_flags & CLONE_SETTLS) |
215 | task_thread_info(p)->tp_value = regs->d5; | 192 | task_thread_info(p)->tp_value = frame->regs.d5; |
216 | 193 | ||
217 | #ifdef CONFIG_FPU | 194 | #ifdef CONFIG_FPU |
218 | if (!FPU_IS_EMU) { | 195 | if (!FPU_IS_EMU) { |