diff options
Diffstat (limited to 'arch/sh/kernel/process_64.c')
-rw-r--r-- | arch/sh/kernel/process_64.c | 60 |
1 files changed, 16 insertions, 44 deletions
diff --git a/arch/sh/kernel/process_64.c b/arch/sh/kernel/process_64.c index 98a709f0c3c4..fd338b030fd9 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; |