diff options
Diffstat (limited to 'arch/m32r/kernel/process.c')
-rw-r--r-- | arch/m32r/kernel/process.c | 126 |
1 files changed, 17 insertions, 109 deletions
diff --git a/arch/m32r/kernel/process.c b/arch/m32r/kernel/process.c index e7366276ef30..765d0f57c787 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,88 +192,31 @@ 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) |
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 = *current_pt_regs(); | ||
210 | if (spu) | ||
211 | childregs->spu = spu; | ||
212 | childregs->r0 = 0; /* Child gets zero as return value */ | ||
213 | tsk->thread.lr = (unsigned long)ret_from_fork; | ||
214 | } | ||
241 | tsk->thread.sp = (unsigned long)childregs; | 215 | tsk->thread.sp = (unsigned long)childregs; |
242 | tsk->thread.lr = (unsigned long)ret_from_fork; | ||
243 | 216 | ||
244 | return 0; | 217 | return 0; |
245 | } | 218 | } |
246 | 219 | ||
247 | asmlinkage int sys_fork(unsigned long r0, unsigned long r1, unsigned long r2, | ||
248 | unsigned long r3, unsigned long r4, unsigned long r5, unsigned long r6, | ||
249 | struct pt_regs regs) | ||
250 | { | ||
251 | #ifdef CONFIG_MMU | ||
252 | return do_fork(SIGCHLD, regs.spu, ®s, 0, NULL, NULL); | ||
253 | #else | ||
254 | return -EINVAL; | ||
255 | #endif /* CONFIG_MMU */ | ||
256 | } | ||
257 | |||
258 | asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp, | ||
259 | unsigned long parent_tidptr, | ||
260 | unsigned long child_tidptr, | ||
261 | unsigned long r4, unsigned long r5, unsigned long r6, | ||
262 | struct pt_regs regs) | ||
263 | { | ||
264 | if (!newsp) | ||
265 | newsp = regs.spu; | ||
266 | |||
267 | return do_fork(clone_flags, newsp, ®s, 0, | ||
268 | (int __user *)parent_tidptr, (int __user *)child_tidptr); | ||
269 | } | ||
270 | |||
271 | /* | ||
272 | * This is trivial, and on the face of it looks like it | ||
273 | * could equally well be done in user mode. | ||
274 | * | ||
275 | * Not so, for quite unobvious reasons - register pressure. | ||
276 | * In user mode vfork() cannot have a stack frame, and if | ||
277 | * done by calling the "clone()" system call directly, you | ||
278 | * do not have enough call-clobbered registers to hold all | ||
279 | * the information you need. | ||
280 | */ | ||
281 | asmlinkage int sys_vfork(unsigned long r0, unsigned long r1, unsigned long r2, | ||
282 | unsigned long r3, unsigned long r4, unsigned long r5, unsigned long r6, | ||
283 | struct pt_regs regs) | ||
284 | { | ||
285 | return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs.spu, ®s, 0, | ||
286 | NULL, NULL); | ||
287 | } | ||
288 | |||
289 | /* | ||
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 | /* | 220 | /* |
313 | * These bracket the sleeping functions.. | 221 | * These bracket the sleeping functions.. |
314 | */ | 222 | */ |