powerpc: split ret_from_fork
authorAl Viro <viro@zeniv.linux.org.uk>
Wed, 12 Sep 2012 22:32:42 +0000 (18:32 -0400)
committerAl Viro <viro@zeniv.linux.org.uk>
Mon, 1 Oct 2012 03:31:19 +0000 (23:31 -0400)
... and get rid of in-kernel syscalls in kernel_thread()

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
arch/powerpc/Kconfig
arch/powerpc/include/asm/processor.h
arch/powerpc/kernel/entry_32.S
arch/powerpc/kernel/entry_64.S
arch/powerpc/kernel/misc_32.S
arch/powerpc/kernel/misc_64.S
arch/powerpc/kernel/ppc_ksyms.c
arch/powerpc/kernel/process.c

index 352f416269ce245c515e25e0cc5cbcf5a446d2a6..6e5a0979c085b9947e395a8a06dd7d3cae15d554 100644 (file)
@@ -139,6 +139,7 @@ config PPC
        select GENERIC_CLOCKEVENTS
        select GENERIC_STRNCPY_FROM_USER
        select GENERIC_STRNLEN_USER
+       select GENERIC_KERNEL_THREAD
 
 config EARLY_PRINTK
        bool
index 54b73a28c20579f4f6923e4f9711b5d7dc062205..5376453d90cc295f216e3db17b17264c22c2d0ce 100644 (file)
@@ -74,9 +74,6 @@ struct task_struct;
 void start_thread(struct pt_regs *regs, unsigned long fdptr, unsigned long sp);
 void release_thread(struct task_struct *);
 
-/* Create a new kernel thread. */
-extern long kernel_thread(int (*fn)(void *), void *arg, unsigned long flags);
-
 /* Lazy FPU handling on uni-processor */
 extern struct task_struct *last_task_used_math;
 extern struct task_struct *last_task_used_altivec;
index ead5016b02d020c32741e5f6d122736eb907d083..6eb330a87c3606c121c0c4de59c4237102246b80 100644 (file)
@@ -435,6 +435,17 @@ ret_from_fork:
        li      r3,0
        b       ret_from_syscall
 
+       .globl  ret_from_kernel_thread
+ret_from_kernel_thread:
+       REST_NVGPRS(r1)
+       bl      schedule_tail
+       mtlr    r14
+       mr      r3,r15
+       PPC440EP_ERR42
+       blrl
+       li      r3,0
+       b       do_exit         # no return
+
 /* Traced system call support */
 syscall_dotrace:
        SAVE_NVGPRS(r1)
index b40e0b4815b3f5297154fa9c6e8a66fa4ce7c574..d7f4fafc751533e16e1fc758643ffdfbd5c4fe90 100644 (file)
@@ -370,6 +370,16 @@ _GLOBAL(ret_from_fork)
        li      r3,0
        b       syscall_exit
 
+_GLOBAL(ret_from_kernel_thread)
+       bl      .schedule_tail
+       REST_NVGPRS(r1)
+       REST_GPR(2,r1)
+       mtlr    r14
+       mr      r3,r15
+       blrl
+       li      r3,0
+       b       .do_exit        # no return
+
        .section        ".toc","aw"
 DSCR_DEFAULT:
        .tc dscr_default[TC],dscr_default
index 407e293aad2fcad29c97be4d88961af12827f357..19e096bd0e73d8b9a530159a4b9b440efc25403f 100644 (file)
@@ -663,39 +663,6 @@ _GLOBAL(abs)
        sub     r3,r3,r4
        blr
 
-/*
- * Create a kernel thread
- *   kernel_thread(fn, arg, flags)
- */
-_GLOBAL(kernel_thread)
-       stwu    r1,-16(r1)
-       stw     r30,8(r1)
-       stw     r31,12(r1)
-       mr      r30,r3          /* function */
-       mr      r31,r4          /* argument */
-       ori     r3,r5,CLONE_VM  /* flags */
-       oris    r3,r3,CLONE_UNTRACED>>16
-       li      r4,0            /* new sp (unused) */
-       li      r0,__NR_clone
-       sc
-       bns+    1f              /* did system call indicate error? */
-       neg     r3,r3           /* if so, make return code negative */
-1:     cmpwi   0,r3,0          /* parent or child? */
-       bne     2f              /* return if parent */
-       li      r0,0            /* make top-level stack frame */
-       stwu    r0,-16(r1)
-       mtlr    r30             /* fn addr in lr */
-       mr      r3,r31          /* load arg and call fn */
-       PPC440EP_ERR42
-       blrl
-       li      r0,__NR_exit    /* exit if function returns */
-       li      r3,0
-       sc
-2:     lwz     r30,8(r1)
-       lwz     r31,12(r1)
-       addi    r1,r1,16
-       blr
-
 #ifdef CONFIG_SMP
 _GLOBAL(start_secondary_resume)
        /* Reset stack */
index 565b78625a32a149ce4959fb9610a46a82a5e04a..5cfa8008693b83aaae96dd4f5d91a7e8190d234b 100644 (file)
@@ -406,40 +406,6 @@ _GLOBAL(scom970_write)
 #endif /* CONFIG_CPU_FREQ_PMAC64 || CONFIG_CPU_FREQ_MAPLE */
 
 
-/*
- * Create a kernel thread
- *   kernel_thread(fn, arg, flags)
- */
-_GLOBAL(kernel_thread)
-       std     r29,-24(r1)
-       std     r30,-16(r1)
-       stdu    r1,-STACK_FRAME_OVERHEAD(r1)
-       mr      r29,r3
-       mr      r30,r4
-       ori     r3,r5,CLONE_VM  /* flags */
-       oris    r3,r3,(CLONE_UNTRACED>>16)
-       li      r4,0            /* new sp (unused) */
-       li      r0,__NR_clone
-       sc
-       bns+    1f              /* did system call indicate error? */
-       neg     r3,r3           /* if so, make return code negative */
-1:     cmpdi   0,r3,0          /* parent or child? */
-       bne     2f              /* return if parent */
-       li      r0,0
-       stdu    r0,-STACK_FRAME_OVERHEAD(r1)
-       ld      r2,8(r29)
-       ld      r29,0(r29)
-       mtlr    r29              /* fn addr in lr */
-       mr      r3,r30          /* load arg and call fn */
-       blrl
-       li      r0,__NR_exit    /* exit after child exits */
-        li     r3,0
-       sc
-2:     addi    r1,r1,STACK_FRAME_OVERHEAD
-       ld      r29,-24(r1)
-       ld      r30,-16(r1)
-       blr
-
 /*
  * disable_kernel_fp()
  * Disable the FPU.
index 3e4031581c65482bb9348b17c9509e630b710570..19e4288d84865e7b97f1a22a6fe099037b46aeef 100644 (file)
@@ -94,7 +94,6 @@ EXPORT_SYMBOL(pci_dram_offset);
 #endif /* CONFIG_PCI */
 
 EXPORT_SYMBOL(start_thread);
-EXPORT_SYMBOL(kernel_thread);
 
 EXPORT_SYMBOL(giveup_fpu);
 #ifdef CONFIG_ALTIVEC
index 1a1f2ddfb581a222fb5fe85a0d8983ef5ad7e2af..3b06898fa1754aaf8ca15361b8d81b0241533620 100644 (file)
@@ -734,30 +734,39 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
 extern unsigned long dscr_default; /* defined in arch/powerpc/kernel/sysfs.c */
 
 int copy_thread(unsigned long clone_flags, unsigned long usp,
-               unsigned long unused, struct task_struct *p,
+               unsigned long arg, struct task_struct *p,
                struct pt_regs *regs)
 {
        struct pt_regs *childregs, *kregs;
        extern void ret_from_fork(void);
+       extern void ret_from_kernel_thread(void);
+       void (*f)(void);
        unsigned long sp = (unsigned long)task_stack_page(p) + THREAD_SIZE;
 
-       CHECK_FULL_REGS(regs);
        /* Copy registers */
        sp -= sizeof(struct pt_regs);
        childregs = (struct pt_regs *) sp;
-       *childregs = *regs;
-       if ((childregs->msr & MSR_PR) == 0) {
+       if (!regs) {
                /* for kernel thread, set `current' and stackptr in new task */
+               memset(childregs, 0, sizeof(struct pt_regs));
                childregs->gpr[1] = sp + sizeof(struct pt_regs);
-#ifdef CONFIG_PPC32
-               childregs->gpr[2] = (unsigned long) p;
-#else
+#ifdef CONFIG_PPC64
+               childregs->gpr[14] = *(unsigned long *)usp;
+               childregs->gpr[2] = ((unsigned long *)usp)[1],
                clear_tsk_thread_flag(p, TIF_32BIT);
+#else
+               childregs->gpr[14] = usp;       /* function */
+               childregs->gpr[2] = (unsigned long) p;
 #endif
+               childregs->gpr[15] = arg;
                p->thread.regs = NULL;  /* no user register state */
+               f = ret_from_kernel_thread;
        } else {
+               CHECK_FULL_REGS(regs);
+               *childregs = *regs;
                childregs->gpr[1] = usp;
                p->thread.regs = childregs;
+               childregs->gpr[3] = 0;  /* Result from fork() */
                if (clone_flags & CLONE_SETTLS) {
 #ifdef CONFIG_PPC64
                        if (!is_32bit_task())
@@ -766,8 +775,9 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,
 #endif
                                childregs->gpr[2] = childregs->gpr[6];
                }
+
+               f = ret_from_fork;
        }
-       childregs->gpr[3] = 0;  /* Result from fork() */
        sp -= STACK_FRAME_OVERHEAD;
 
        /*
@@ -806,19 +816,17 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,
                p->thread.dscr = current->thread.dscr;
        }
 #endif
-
        /*
         * The PPC64 ABI makes use of a TOC to contain function 
         * pointers.  The function (ret_from_except) is actually a pointer
         * to the TOC entry.  The first entry is a pointer to the actual
         * function.
-        */
+        */
 #ifdef CONFIG_PPC64
-       kregs->nip = *((unsigned long *)ret_from_fork);
+       kregs->nip = *((unsigned long *)f);
 #else
-       kregs->nip = (unsigned long)ret_from_fork;
+       kregs->nip = (unsigned long)f;
 #endif
-
        return 0;
 }