diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2012-09-12 18:32:42 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2012-09-30 23:31:19 -0400 |
commit | 58254e1002a82eb383c5977ad9fd5a451b91fe29 (patch) | |
tree | e03b441b252ec3630ceedbe266311c0a24812fd9 /arch/powerpc | |
parent | f322220d6159455da2b5a8a596d802c8695fed30 (diff) |
powerpc: split ret_from_fork
... and get rid of in-kernel syscalls in kernel_thread()
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'arch/powerpc')
-rw-r--r-- | arch/powerpc/Kconfig | 1 | ||||
-rw-r--r-- | arch/powerpc/include/asm/processor.h | 3 | ||||
-rw-r--r-- | arch/powerpc/kernel/entry_32.S | 11 | ||||
-rw-r--r-- | arch/powerpc/kernel/entry_64.S | 10 | ||||
-rw-r--r-- | arch/powerpc/kernel/misc_32.S | 33 | ||||
-rw-r--r-- | arch/powerpc/kernel/misc_64.S | 34 | ||||
-rw-r--r-- | arch/powerpc/kernel/ppc_ksyms.c | 1 | ||||
-rw-r--r-- | arch/powerpc/kernel/process.c | 34 |
8 files changed, 43 insertions, 84 deletions
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 352f416269ce..6e5a0979c085 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig | |||
@@ -139,6 +139,7 @@ config PPC | |||
139 | select GENERIC_CLOCKEVENTS | 139 | select GENERIC_CLOCKEVENTS |
140 | select GENERIC_STRNCPY_FROM_USER | 140 | select GENERIC_STRNCPY_FROM_USER |
141 | select GENERIC_STRNLEN_USER | 141 | select GENERIC_STRNLEN_USER |
142 | select GENERIC_KERNEL_THREAD | ||
142 | 143 | ||
143 | config EARLY_PRINTK | 144 | config EARLY_PRINTK |
144 | bool | 145 | bool |
diff --git a/arch/powerpc/include/asm/processor.h b/arch/powerpc/include/asm/processor.h index 54b73a28c205..5376453d90cc 100644 --- a/arch/powerpc/include/asm/processor.h +++ b/arch/powerpc/include/asm/processor.h | |||
@@ -74,9 +74,6 @@ struct task_struct; | |||
74 | void start_thread(struct pt_regs *regs, unsigned long fdptr, unsigned long sp); | 74 | void start_thread(struct pt_regs *regs, unsigned long fdptr, unsigned long sp); |
75 | void release_thread(struct task_struct *); | 75 | void release_thread(struct task_struct *); |
76 | 76 | ||
77 | /* Create a new kernel thread. */ | ||
78 | extern long kernel_thread(int (*fn)(void *), void *arg, unsigned long flags); | ||
79 | |||
80 | /* Lazy FPU handling on uni-processor */ | 77 | /* Lazy FPU handling on uni-processor */ |
81 | extern struct task_struct *last_task_used_math; | 78 | extern struct task_struct *last_task_used_math; |
82 | extern struct task_struct *last_task_used_altivec; | 79 | extern struct task_struct *last_task_used_altivec; |
diff --git a/arch/powerpc/kernel/entry_32.S b/arch/powerpc/kernel/entry_32.S index ead5016b02d0..6eb330a87c36 100644 --- a/arch/powerpc/kernel/entry_32.S +++ b/arch/powerpc/kernel/entry_32.S | |||
@@ -435,6 +435,17 @@ ret_from_fork: | |||
435 | li r3,0 | 435 | li r3,0 |
436 | b ret_from_syscall | 436 | b ret_from_syscall |
437 | 437 | ||
438 | .globl ret_from_kernel_thread | ||
439 | ret_from_kernel_thread: | ||
440 | REST_NVGPRS(r1) | ||
441 | bl schedule_tail | ||
442 | mtlr r14 | ||
443 | mr r3,r15 | ||
444 | PPC440EP_ERR42 | ||
445 | blrl | ||
446 | li r3,0 | ||
447 | b do_exit # no return | ||
448 | |||
438 | /* Traced system call support */ | 449 | /* Traced system call support */ |
439 | syscall_dotrace: | 450 | syscall_dotrace: |
440 | SAVE_NVGPRS(r1) | 451 | SAVE_NVGPRS(r1) |
diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S index b40e0b4815b3..d7f4fafc7515 100644 --- a/arch/powerpc/kernel/entry_64.S +++ b/arch/powerpc/kernel/entry_64.S | |||
@@ -370,6 +370,16 @@ _GLOBAL(ret_from_fork) | |||
370 | li r3,0 | 370 | li r3,0 |
371 | b syscall_exit | 371 | b syscall_exit |
372 | 372 | ||
373 | _GLOBAL(ret_from_kernel_thread) | ||
374 | bl .schedule_tail | ||
375 | REST_NVGPRS(r1) | ||
376 | REST_GPR(2,r1) | ||
377 | mtlr r14 | ||
378 | mr r3,r15 | ||
379 | blrl | ||
380 | li r3,0 | ||
381 | b .do_exit # no return | ||
382 | |||
373 | .section ".toc","aw" | 383 | .section ".toc","aw" |
374 | DSCR_DEFAULT: | 384 | DSCR_DEFAULT: |
375 | .tc dscr_default[TC],dscr_default | 385 | .tc dscr_default[TC],dscr_default |
diff --git a/arch/powerpc/kernel/misc_32.S b/arch/powerpc/kernel/misc_32.S index 407e293aad2f..19e096bd0e73 100644 --- a/arch/powerpc/kernel/misc_32.S +++ b/arch/powerpc/kernel/misc_32.S | |||
@@ -663,39 +663,6 @@ _GLOBAL(abs) | |||
663 | sub r3,r3,r4 | 663 | sub r3,r3,r4 |
664 | blr | 664 | blr |
665 | 665 | ||
666 | /* | ||
667 | * Create a kernel thread | ||
668 | * kernel_thread(fn, arg, flags) | ||
669 | */ | ||
670 | _GLOBAL(kernel_thread) | ||
671 | stwu r1,-16(r1) | ||
672 | stw r30,8(r1) | ||
673 | stw r31,12(r1) | ||
674 | mr r30,r3 /* function */ | ||
675 | mr r31,r4 /* argument */ | ||
676 | ori r3,r5,CLONE_VM /* flags */ | ||
677 | oris r3,r3,CLONE_UNTRACED>>16 | ||
678 | li r4,0 /* new sp (unused) */ | ||
679 | li r0,__NR_clone | ||
680 | sc | ||
681 | bns+ 1f /* did system call indicate error? */ | ||
682 | neg r3,r3 /* if so, make return code negative */ | ||
683 | 1: cmpwi 0,r3,0 /* parent or child? */ | ||
684 | bne 2f /* return if parent */ | ||
685 | li r0,0 /* make top-level stack frame */ | ||
686 | stwu r0,-16(r1) | ||
687 | mtlr r30 /* fn addr in lr */ | ||
688 | mr r3,r31 /* load arg and call fn */ | ||
689 | PPC440EP_ERR42 | ||
690 | blrl | ||
691 | li r0,__NR_exit /* exit if function returns */ | ||
692 | li r3,0 | ||
693 | sc | ||
694 | 2: lwz r30,8(r1) | ||
695 | lwz r31,12(r1) | ||
696 | addi r1,r1,16 | ||
697 | blr | ||
698 | |||
699 | #ifdef CONFIG_SMP | 666 | #ifdef CONFIG_SMP |
700 | _GLOBAL(start_secondary_resume) | 667 | _GLOBAL(start_secondary_resume) |
701 | /* Reset stack */ | 668 | /* Reset stack */ |
diff --git a/arch/powerpc/kernel/misc_64.S b/arch/powerpc/kernel/misc_64.S index 565b78625a32..5cfa8008693b 100644 --- a/arch/powerpc/kernel/misc_64.S +++ b/arch/powerpc/kernel/misc_64.S | |||
@@ -407,40 +407,6 @@ _GLOBAL(scom970_write) | |||
407 | 407 | ||
408 | 408 | ||
409 | /* | 409 | /* |
410 | * Create a kernel thread | ||
411 | * kernel_thread(fn, arg, flags) | ||
412 | */ | ||
413 | _GLOBAL(kernel_thread) | ||
414 | std r29,-24(r1) | ||
415 | std r30,-16(r1) | ||
416 | stdu r1,-STACK_FRAME_OVERHEAD(r1) | ||
417 | mr r29,r3 | ||
418 | mr r30,r4 | ||
419 | ori r3,r5,CLONE_VM /* flags */ | ||
420 | oris r3,r3,(CLONE_UNTRACED>>16) | ||
421 | li r4,0 /* new sp (unused) */ | ||
422 | li r0,__NR_clone | ||
423 | sc | ||
424 | bns+ 1f /* did system call indicate error? */ | ||
425 | neg r3,r3 /* if so, make return code negative */ | ||
426 | 1: cmpdi 0,r3,0 /* parent or child? */ | ||
427 | bne 2f /* return if parent */ | ||
428 | li r0,0 | ||
429 | stdu r0,-STACK_FRAME_OVERHEAD(r1) | ||
430 | ld r2,8(r29) | ||
431 | ld r29,0(r29) | ||
432 | mtlr r29 /* fn addr in lr */ | ||
433 | mr r3,r30 /* load arg and call fn */ | ||
434 | blrl | ||
435 | li r0,__NR_exit /* exit after child exits */ | ||
436 | li r3,0 | ||
437 | sc | ||
438 | 2: addi r1,r1,STACK_FRAME_OVERHEAD | ||
439 | ld r29,-24(r1) | ||
440 | ld r30,-16(r1) | ||
441 | blr | ||
442 | |||
443 | /* | ||
444 | * disable_kernel_fp() | 410 | * disable_kernel_fp() |
445 | * Disable the FPU. | 411 | * Disable the FPU. |
446 | */ | 412 | */ |
diff --git a/arch/powerpc/kernel/ppc_ksyms.c b/arch/powerpc/kernel/ppc_ksyms.c index 3e4031581c65..19e4288d8486 100644 --- a/arch/powerpc/kernel/ppc_ksyms.c +++ b/arch/powerpc/kernel/ppc_ksyms.c | |||
@@ -94,7 +94,6 @@ EXPORT_SYMBOL(pci_dram_offset); | |||
94 | #endif /* CONFIG_PCI */ | 94 | #endif /* CONFIG_PCI */ |
95 | 95 | ||
96 | EXPORT_SYMBOL(start_thread); | 96 | EXPORT_SYMBOL(start_thread); |
97 | EXPORT_SYMBOL(kernel_thread); | ||
98 | 97 | ||
99 | EXPORT_SYMBOL(giveup_fpu); | 98 | EXPORT_SYMBOL(giveup_fpu); |
100 | #ifdef CONFIG_ALTIVEC | 99 | #ifdef CONFIG_ALTIVEC |
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c index 1a1f2ddfb581..3b06898fa175 100644 --- a/arch/powerpc/kernel/process.c +++ b/arch/powerpc/kernel/process.c | |||
@@ -734,30 +734,39 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src) | |||
734 | extern unsigned long dscr_default; /* defined in arch/powerpc/kernel/sysfs.c */ | 734 | extern unsigned long dscr_default; /* defined in arch/powerpc/kernel/sysfs.c */ |
735 | 735 | ||
736 | int copy_thread(unsigned long clone_flags, unsigned long usp, | 736 | int copy_thread(unsigned long clone_flags, unsigned long usp, |
737 | unsigned long unused, struct task_struct *p, | 737 | unsigned long arg, struct task_struct *p, |
738 | struct pt_regs *regs) | 738 | struct pt_regs *regs) |
739 | { | 739 | { |
740 | struct pt_regs *childregs, *kregs; | 740 | struct pt_regs *childregs, *kregs; |
741 | extern void ret_from_fork(void); | 741 | extern void ret_from_fork(void); |
742 | extern void ret_from_kernel_thread(void); | ||
743 | void (*f)(void); | ||
742 | unsigned long sp = (unsigned long)task_stack_page(p) + THREAD_SIZE; | 744 | unsigned long sp = (unsigned long)task_stack_page(p) + THREAD_SIZE; |
743 | 745 | ||
744 | CHECK_FULL_REGS(regs); | ||
745 | /* Copy registers */ | 746 | /* Copy registers */ |
746 | sp -= sizeof(struct pt_regs); | 747 | sp -= sizeof(struct pt_regs); |
747 | childregs = (struct pt_regs *) sp; | 748 | childregs = (struct pt_regs *) sp; |
748 | *childregs = *regs; | 749 | if (!regs) { |
749 | if ((childregs->msr & MSR_PR) == 0) { | ||
750 | /* for kernel thread, set `current' and stackptr in new task */ | 750 | /* for kernel thread, set `current' and stackptr in new task */ |
751 | memset(childregs, 0, sizeof(struct pt_regs)); | ||
751 | childregs->gpr[1] = sp + sizeof(struct pt_regs); | 752 | childregs->gpr[1] = sp + sizeof(struct pt_regs); |
752 | #ifdef CONFIG_PPC32 | 753 | #ifdef CONFIG_PPC64 |
753 | childregs->gpr[2] = (unsigned long) p; | 754 | childregs->gpr[14] = *(unsigned long *)usp; |
754 | #else | 755 | childregs->gpr[2] = ((unsigned long *)usp)[1], |
755 | clear_tsk_thread_flag(p, TIF_32BIT); | 756 | clear_tsk_thread_flag(p, TIF_32BIT); |
757 | #else | ||
758 | childregs->gpr[14] = usp; /* function */ | ||
759 | childregs->gpr[2] = (unsigned long) p; | ||
756 | #endif | 760 | #endif |
761 | childregs->gpr[15] = arg; | ||
757 | p->thread.regs = NULL; /* no user register state */ | 762 | p->thread.regs = NULL; /* no user register state */ |
763 | f = ret_from_kernel_thread; | ||
758 | } else { | 764 | } else { |
765 | CHECK_FULL_REGS(regs); | ||
766 | *childregs = *regs; | ||
759 | childregs->gpr[1] = usp; | 767 | childregs->gpr[1] = usp; |
760 | p->thread.regs = childregs; | 768 | p->thread.regs = childregs; |
769 | childregs->gpr[3] = 0; /* Result from fork() */ | ||
761 | if (clone_flags & CLONE_SETTLS) { | 770 | if (clone_flags & CLONE_SETTLS) { |
762 | #ifdef CONFIG_PPC64 | 771 | #ifdef CONFIG_PPC64 |
763 | if (!is_32bit_task()) | 772 | if (!is_32bit_task()) |
@@ -766,8 +775,9 @@ int copy_thread(unsigned long clone_flags, unsigned long usp, | |||
766 | #endif | 775 | #endif |
767 | childregs->gpr[2] = childregs->gpr[6]; | 776 | childregs->gpr[2] = childregs->gpr[6]; |
768 | } | 777 | } |
778 | |||
779 | f = ret_from_fork; | ||
769 | } | 780 | } |
770 | childregs->gpr[3] = 0; /* Result from fork() */ | ||
771 | sp -= STACK_FRAME_OVERHEAD; | 781 | sp -= STACK_FRAME_OVERHEAD; |
772 | 782 | ||
773 | /* | 783 | /* |
@@ -806,19 +816,17 @@ int copy_thread(unsigned long clone_flags, unsigned long usp, | |||
806 | p->thread.dscr = current->thread.dscr; | 816 | p->thread.dscr = current->thread.dscr; |
807 | } | 817 | } |
808 | #endif | 818 | #endif |
809 | |||
810 | /* | 819 | /* |
811 | * The PPC64 ABI makes use of a TOC to contain function | 820 | * The PPC64 ABI makes use of a TOC to contain function |
812 | * pointers. The function (ret_from_except) is actually a pointer | 821 | * pointers. The function (ret_from_except) is actually a pointer |
813 | * to the TOC entry. The first entry is a pointer to the actual | 822 | * to the TOC entry. The first entry is a pointer to the actual |
814 | * function. | 823 | * function. |
815 | */ | 824 | */ |
816 | #ifdef CONFIG_PPC64 | 825 | #ifdef CONFIG_PPC64 |
817 | kregs->nip = *((unsigned long *)ret_from_fork); | 826 | kregs->nip = *((unsigned long *)f); |
818 | #else | 827 | #else |
819 | kregs->nip = (unsigned long)ret_from_fork; | 828 | kregs->nip = (unsigned long)f; |
820 | #endif | 829 | #endif |
821 | |||
822 | return 0; | 830 | return 0; |
823 | } | 831 | } |
824 | 832 | ||