frv: split ret_from_fork, simplify kernel_thread() a lot
Al Viro [Wed, 19 Sep 2012 02:18:51 +0000 (22:18 -0400)]
Acked-by: David Howells <dhowells@redhat.com>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>

arch/frv/kernel/Makefile
arch/frv/kernel/entry.S
arch/frv/kernel/frv_ksyms.c
arch/frv/kernel/kernel_thread.S [deleted file]
arch/frv/kernel/process.c

index ad4087b..7b10bc1 100644 (file)
@@ -7,7 +7,7 @@ heads-$(CONFIG_MMU)             := head-mmu-fr451.o
 
 extra-y:= head.o vmlinux.lds
 
-obj-y := $(heads-y) entry.o entry-table.o break.o switch_to.o kernel_thread.o \
+obj-y := $(heads-y) entry.o entry-table.o break.o switch_to.o \
         kernel_execve.o process.o traps.o ptrace.o signal.o dma.o \
         sys_frv.o time.o setup.o frv_ksyms.o \
         debug-stub.o irq.o sleep.o uaccess.o
index 7d5e000..7a88613 100644 (file)
@@ -863,6 +863,14 @@ ret_from_fork:
        setlos.p        #0,gr8
        bra             __syscall_exit
 
+       .globl          ret_from_kernel_thread
+ret_from_kernel_thread:
+       lddi.p          @(gr28,#REG_GR(8)),gr20
+       call            schedule_tail
+       or.p            gr20,gr20,gr8
+       calll           @(gr21,gr0)
+       bra             sys_exit
+
 ###################################################################################################
 #
 # Return to user mode is not as complex as all this looks,
index a89803b..86c516d 100644 (file)
@@ -30,7 +30,6 @@ EXPORT_SYMBOL(ip_fast_csum);
 EXPORT_SYMBOL(local_irq_count);
 EXPORT_SYMBOL(local_bh_count);
 #endif
-EXPORT_SYMBOL(kernel_thread);
 
 EXPORT_SYMBOL(__res_bus_clock_speed_HZ);
 EXPORT_SYMBOL(__page_offset);
diff --git a/arch/frv/kernel/kernel_thread.S b/arch/frv/kernel/kernel_thread.S
deleted file mode 100644 (file)
index f0e5294..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-/* kernel_thread.S: kernel thread creation
- *
- * Copyright (C) 2003 Red Hat, Inc. All Rights Reserved.
- * Written by David Howells (dhowells@redhat.com)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-
-#include <linux/linkage.h>
-#include <linux/kern_levels.h>
-#include <asm/unistd.h>
-
-#define CLONE_VM       0x00000100      /* set if VM shared between processes */
-
-       .section .rodata
-kernel_thread_emsg:
-       .asciz  KERN_ERR "failed to create kernel thread: error=%d\n"
-
-       .text
-       .balign         4
-
-###############################################################################
-#
-# Create a kernel thread
-#
-# int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
-#
-###############################################################################
-       .globl          kernel_thread
-       .type           kernel_thread,@function
-kernel_thread:
-       or.p            gr8,gr0,gr4
-       or              gr9,gr0,gr5
-
-       # start by forking the current process, but with shared VM
-       setlos.p        #__NR_clone,gr7         ; syscall number
-       ori             gr10,#CLONE_VM,gr8      ; first syscall arg     [clone_flags]
-       sethi.p         #0xe4e4,gr9             ; second syscall arg    [newsp]
-       setlo           #0xe4e4,gr9
-       setlos.p        #0,gr10                 ; third syscall arg     [parent_tidptr]
-       setlos          #0,gr11                 ; fourth syscall arg    [child_tidptr]
-       tira            gr0,#0
-       setlos.p        #4095,gr7
-       andcc           gr8,gr8,gr0,icc0
-       addcc.p         gr8,gr7,gr0,icc1
-       bnelr           icc0,#2
-       bc              icc1,#0,kernel_thread_error
-
-       # now invoke the work function
-       or              gr5,gr0,gr8
-       calll           @(gr4,gr0)
-
-       # and finally exit the thread
-       setlos          #__NR_exit,gr7          ; syscall number
-       tira            gr0,#0
-
-kernel_thread_error:
-       subi            sp,#8,sp
-       movsg           lr,gr4
-       sti             gr8,@(sp,#0)
-       sti.p           gr4,@(sp,#4)
-
-       or              gr8,gr0,gr9
-       sethi.p         %hi(kernel_thread_emsg),gr8
-       setlo           %lo(kernel_thread_emsg),gr8
-
-       call            printk
-
-       ldi             @(sp,#4),gr4
-       ldi             @(sp,#0),gr8
-       subi            sp,#8,sp
-       jmpl            @(gr4,gr0)
-
-       .size           kernel_thread,.-kernel_thread
index ff95f50..0f02dee 100644 (file)
@@ -37,6 +37,7 @@
 #include "local.h"
 
 asmlinkage void ret_from_fork(void);
+asmlinkage void ret_from_kernel_thread(void);
 
 #include <asm/pgalloc.h>
 
@@ -172,29 +173,21 @@ int copy_thread(unsigned long clone_flags,
                unsigned long usp, unsigned long topstk,
                struct task_struct *p, struct pt_regs *regs)
 {
-       struct pt_regs *childregs0, *childregs, *regs0;
+       struct pt_regs *childregs;
 
-       regs0 = __kernel_frame0_ptr;
-       childregs0 = (struct pt_regs *)
+       childregs = (struct pt_regs *)
                (task_stack_page(p) + THREAD_SIZE - FRV_FRAME0_SIZE);
-       childregs = childregs0;
 
        /* set up the userspace frame (the only place that the USP is stored) */
-       *childregs0 = *regs0;
-
-       childregs0->gr8         = 0;
-       childregs0->sp          = usp;
-       childregs0->next_frame  = NULL;
-
-       /* set up the return kernel frame if called from kernel_thread() */
-       if (regs != regs0) {
-               childregs--;
-               *childregs = *regs;
-               childregs->sp = (unsigned long) childregs0;
-               childregs->next_frame = childregs0;
-               childregs->gr15 = (unsigned long) task_thread_info(p);
-               childregs->gr29 = (unsigned long) p;
-       }
+       *childregs = *regs;
+
+       childregs->sp           = usp;
+       childregs->next_frame   = NULL;
+
+       if (unlikely(!user_mode(regs)))
+               p->thread.pc = (unsigned long) ret_from_kernel_thread;
+       else
+               p->thread.pc = (unsigned long) ret_from_fork;
 
        p->set_child_tid = p->clear_child_tid = NULL;
 
@@ -203,8 +196,7 @@ int copy_thread(unsigned long clone_flags,
        p->thread.sp     = (unsigned long) childregs;
        p->thread.fp     = 0;
        p->thread.lr     = 0;
-       p->thread.pc     = (unsigned long) ret_from_fork;
-       p->thread.frame0 = childregs0;
+       p->thread.frame0 = childregs;
 
        /* the new TLS pointer is passed in as arg #5 to sys_clone() */
        if (clone_flags & CLONE_SETTLS)
@@ -347,3 +339,13 @@ int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpregs)
               sizeof(current->thread.user->f));
        return 1;
 }
+
+int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
+{
+       struct pt_regs regs = {
+               .gr8 = (unsigned long)arg;
+               .gr9 = (unsigned long)fn;
+               .psr = PSR_S;
+       };
+       return do_fork(flags|CLONE_VM|CLONE_UNTRACED, 0, &regs, 0, NULL, NULL);
+}