Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/signal
Linus Torvalds [Wed, 12 Dec 2012 20:22:13 +0000 (12:22 -0800)]
Pull big execve/kernel_thread/fork unification series from Al Viro:
 "All architectures are converted to new model.  Quite a bit of that
  stuff is actually shared with architecture trees; in such cases it's
  literally shared branch pulled by both, not a cherry-pick.

  A lot of ugliness and black magic is gone (-3KLoC total in this one):

   - kernel_thread()/kernel_execve()/sys_execve() redesign.

     We don't do syscalls from kernel anymore for either kernel_thread()
     or kernel_execve():

     kernel_thread() is essentially clone(2) with callback run before we
     return to userland, the callbacks either never return or do
     successful do_execve() before returning.

     kernel_execve() is a wrapper for do_execve() - it doesn't need to
     do transition to user mode anymore.

     As a result kernel_thread() and kernel_execve() are
     arch-independent now - they live in kernel/fork.c and fs/exec.c
     resp.  sys_execve() is also in fs/exec.c and it's completely
     architecture-independent.

   - daemonize() is gone, along with its parts in fs/*.c

   - struct pt_regs * is no longer passed to do_fork/copy_process/
     copy_thread/do_execve/search_binary_handler/->load_binary/do_coredump.

   - sys_fork()/sys_vfork()/sys_clone() unified; some architectures
     still need wrappers (ones with callee-saved registers not saved in
     pt_regs on syscall entry), but the main part of those suckers is in
     kernel/fork.c now."

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/signal: (113 commits)
  do_coredump(): get rid of pt_regs argument
  print_fatal_signal(): get rid of pt_regs argument
  ptrace_signal(): get rid of unused arguments
  get rid of ptrace_signal_deliver() arguments
  new helper: signal_pt_regs()
  unify default ptrace_signal_deliver
  flagday: kill pt_regs argument of do_fork()
  death to idle_regs()
  don't pass regs to copy_process()
  flagday: don't pass regs to copy_thread()
  bfin: switch to generic vfork, get rid of pointless wrappers
  xtensa: switch to generic clone()
  openrisc: switch to use of generic fork and clone
  unicore32: switch to generic clone(2)
  score: switch to generic fork/vfork/clone
  c6x: sanitize copy_thread(), get rid of clone(2) wrapper, switch to generic clone()
  take sys_fork/sys_vfork/sys_clone prototypes to linux/syscalls.h
  mn10300: switch to generic fork/vfork/clone
  h8300: switch to generic fork/vfork/clone
  tile: switch to generic clone()
  ...

Conflicts:
arch/microblaze/include/asm/Kbuild

273 files changed:
arch/Kconfig
arch/alpha/include/asm/ptrace.h
arch/alpha/include/asm/signal.h
arch/alpha/include/asm/unistd.h
arch/alpha/kernel/binfmt_loader.c
arch/alpha/kernel/entry.S
arch/alpha/kernel/process.c
arch/alpha/kernel/signal.c
arch/alpha/kernel/systbls.S
arch/arm/Kconfig
arch/arm/include/asm/signal.h
arch/arm/include/asm/unistd.h
arch/arm/kernel/calls.S
arch/arm/kernel/entry-common.S
arch/arm/kernel/process.c
arch/arm/kernel/sys_arm.c
arch/arm64/Kconfig
arch/arm64/include/asm/syscalls.h
arch/arm64/include/asm/unistd.h
arch/arm64/include/asm/unistd32.h
arch/arm64/kernel/process.c
arch/arm64/kernel/sys.c
arch/arm64/kernel/sys_compat.c
arch/avr32/Kconfig
arch/avr32/include/asm/processor.h
arch/avr32/include/asm/signal.h
arch/avr32/include/asm/unistd.h
arch/avr32/kernel/Makefile
arch/avr32/kernel/entry-avr32b.S
arch/avr32/kernel/process.c
arch/avr32/kernel/sys_avr32.c [deleted file]
arch/avr32/kernel/syscall-stubs.S
arch/avr32/kernel/syscall_table.S
arch/blackfin/Kconfig
arch/blackfin/include/asm/processor.h
arch/blackfin/include/asm/unistd.h
arch/blackfin/kernel/entry.S
arch/blackfin/kernel/process.c
arch/blackfin/kernel/signal.c
arch/blackfin/mach-common/entry.S
arch/c6x/Kconfig
arch/c6x/include/asm/syscalls.h
arch/c6x/include/uapi/asm/unistd.h
arch/c6x/kernel/entry.S
arch/c6x/kernel/process.c
arch/cris/Kconfig
arch/cris/arch-v10/kernel/entry.S
arch/cris/arch-v10/kernel/process.c
arch/cris/arch-v32/kernel/entry.S
arch/cris/arch-v32/kernel/process.c
arch/cris/include/asm/processor.h
arch/cris/include/asm/signal.h
arch/cris/include/asm/unistd.h
arch/cris/kernel/crisksyms.c
arch/frv/include/asm/unistd.h
arch/frv/kernel/process.c
arch/h8300/Kconfig
arch/h8300/include/asm/processor.h
arch/h8300/include/asm/ptrace.h
arch/h8300/include/asm/signal.h
arch/h8300/include/asm/unistd.h
arch/h8300/kernel/entry.S
arch/h8300/kernel/h8300_ksyms.c
arch/h8300/kernel/process.c
arch/h8300/kernel/sys_h8300.c
arch/h8300/kernel/syscalls.S
arch/hexagon/Kconfig
arch/hexagon/include/asm/processor.h
arch/hexagon/include/asm/syscall.h
arch/hexagon/include/uapi/asm/ptrace.h
arch/hexagon/include/uapi/asm/unistd.h
arch/hexagon/kernel/Makefile
arch/hexagon/kernel/process.c
arch/hexagon/kernel/signal.c
arch/hexagon/kernel/syscall.c [deleted file]
arch/hexagon/kernel/vm_entry.S
arch/ia64/Kconfig
arch/ia64/include/asm/processor.h
arch/ia64/include/asm/signal.h
arch/ia64/include/asm/unistd.h
arch/ia64/kernel/entry.S
arch/ia64/kernel/head.S
arch/ia64/kernel/process.c
arch/ia64/kernel/smpboot.c
arch/m32r/Kconfig
arch/m32r/include/asm/processor.h
arch/m32r/include/asm/ptrace.h
arch/m32r/include/asm/signal.h
arch/m32r/include/asm/unistd.h
arch/m32r/kernel/entry.S
arch/m32r/kernel/m32r_ksyms.c
arch/m32r/kernel/process.c
arch/m32r/kernel/sys_m32r.c
arch/m68k/Kconfig
arch/m68k/include/asm/signal.h
arch/m68k/include/asm/unistd.h
arch/m68k/kernel/entry.S
arch/m68k/kernel/process.c
arch/m68k/kernel/signal.c
arch/m68k/kernel/syscalltable.S
arch/microblaze/Kconfig
arch/microblaze/include/asm/Kbuild
arch/microblaze/include/asm/processor.h
arch/microblaze/include/asm/syscalls.h [deleted file]
arch/microblaze/include/asm/unistd.h
arch/microblaze/kernel/entry-nommu.S
arch/microblaze/kernel/entry.S
arch/microblaze/kernel/process.c
arch/microblaze/kernel/sys_microblaze.c
arch/microblaze/kernel/syscall_table.S
arch/mips/Kconfig
arch/mips/include/asm/processor.h
arch/mips/include/asm/ptrace.h
arch/mips/include/asm/signal.h
arch/mips/include/asm/unistd.h
arch/mips/kernel/entry.S
arch/mips/kernel/linux32.c
arch/mips/kernel/mips_ksyms.c
arch/mips/kernel/process.c
arch/mips/kernel/scall64-n32.S
arch/mips/kernel/scall64-o32.S
arch/mips/kernel/syscall.c
arch/mn10300/Kconfig
arch/mn10300/include/asm/signal.h
arch/mn10300/include/asm/unistd.h
arch/mn10300/kernel/entry.S
arch/mn10300/kernel/process.c
arch/openrisc/Kconfig
arch/openrisc/include/asm/processor.h
arch/openrisc/include/asm/syscalls.h
arch/openrisc/include/uapi/asm/unistd.h
arch/openrisc/kernel/Makefile
arch/openrisc/kernel/entry.S
arch/openrisc/kernel/process.c
arch/openrisc/kernel/sys_or32.c [deleted file]
arch/parisc/Kconfig
arch/parisc/include/asm/processor.h
arch/parisc/include/asm/signal.h
arch/parisc/include/asm/unistd.h
arch/parisc/kernel/entry.S
arch/parisc/kernel/process.c
arch/parisc/kernel/sys_parisc32.c
arch/parisc/kernel/syscall_table.S
arch/powerpc/Kconfig
arch/powerpc/include/asm/signal.h
arch/powerpc/include/asm/syscalls.h
arch/powerpc/include/asm/unistd.h
arch/powerpc/kernel/entry_32.S
arch/powerpc/kernel/entry_64.S
arch/powerpc/kernel/process.c
arch/s390/Kconfig
arch/s390/include/asm/signal.h
arch/s390/include/asm/unistd.h
arch/s390/kernel/entry.S
arch/s390/kernel/entry.h
arch/s390/kernel/entry64.S
arch/s390/kernel/process.c
arch/score/Kconfig
arch/score/include/asm/processor.h
arch/score/include/asm/syscalls.h
arch/score/include/asm/unistd.h
arch/score/kernel/entry.S
arch/score/kernel/process.c
arch/score/kernel/sys_score.c
arch/sh/Kconfig
arch/sh/include/asm/processor_32.h
arch/sh/include/asm/processor_64.h
arch/sh/include/asm/syscalls_32.h
arch/sh/include/asm/syscalls_64.h
arch/sh/include/asm/unistd.h
arch/sh/kernel/Makefile
arch/sh/kernel/cpu/sh5/entry.S
arch/sh/kernel/entry-common.S
arch/sh/kernel/process_32.c
arch/sh/kernel/process_64.c
arch/sh/kernel/sys_sh32.c
arch/sh/kernel/sys_sh64.c [deleted file]
arch/sparc/Kconfig
arch/sparc/include/asm/processor_32.h
arch/sparc/include/asm/processor_64.h
arch/sparc/include/asm/ptrace.h
arch/sparc/include/asm/signal.h
arch/sparc/include/asm/switch_to_64.h
arch/sparc/include/asm/syscalls.h
arch/sparc/include/asm/thread_info_64.h
arch/sparc/include/asm/uaccess_64.h
arch/sparc/include/asm/unistd.h
arch/sparc/kernel/entry.S
arch/sparc/kernel/etrap_64.S
arch/sparc/kernel/process_32.c
arch/sparc/kernel/process_64.c
arch/sparc/kernel/sys_sparc32.c
arch/sparc/kernel/sys_sparc_32.c
arch/sparc/kernel/sys_sparc_64.c
arch/sparc/kernel/syscalls.S
arch/sparc/kernel/systbls_64.S
arch/sparc/kernel/traps_64.c
arch/sparc/mm/init_64.c
arch/tile/Kconfig
arch/tile/include/asm/compat.h
arch/tile/include/asm/elf.h
arch/tile/include/asm/processor.h
arch/tile/include/asm/switch_to.h
arch/tile/include/asm/syscalls.h
arch/tile/include/asm/unistd.h
arch/tile/kernel/compat.c
arch/tile/kernel/compat_signal.c
arch/tile/kernel/entry.S
arch/tile/kernel/intvec_32.S
arch/tile/kernel/intvec_64.S
arch/tile/kernel/process.c
arch/tile/kernel/signal.c
arch/tile/kernel/sys.c
arch/tile/mm/fault.c
arch/um/kernel/process.c
arch/um/kernel/syscall.c
arch/unicore32/include/uapi/asm/unistd.h
arch/unicore32/kernel/entry.S
arch/unicore32/kernel/process.c
arch/unicore32/kernel/sys.c
arch/x86/Kconfig
arch/x86/ia32/ia32_aout.c
arch/x86/ia32/ia32entry.S
arch/x86/ia32/sys_ia32.c
arch/x86/include/asm/processor.h
arch/x86/include/asm/signal.h
arch/x86/include/asm/sys_ia32.h
arch/x86/include/asm/syscalls.h
arch/x86/include/asm/unistd.h
arch/x86/kernel/cpu/common.c
arch/x86/kernel/entry_32.S
arch/x86/kernel/entry_64.S
arch/x86/kernel/process.c
arch/x86/kernel/process_32.c
arch/x86/kernel/process_64.c
arch/x86/syscalls/syscall_32.tbl
arch/x86/um/Kconfig
arch/x86/um/shared/sysdep/syscalls.h
arch/x86/um/sys_call_table_32.c
arch/x86/um/syscalls_32.c
arch/xtensa/Kconfig
arch/xtensa/include/asm/signal.h
arch/xtensa/include/asm/syscall.h
arch/xtensa/include/asm/unistd.h
arch/xtensa/include/uapi/asm/unistd.h
arch/xtensa/kernel/process.c
drivers/staging/gdm72xx/gdm_usb.c
fs/binfmt_aout.c
fs/binfmt_elf.c
fs/binfmt_elf_fdpic.c
fs/binfmt_em86.c
fs/binfmt_flat.c
fs/binfmt_misc.c
fs/binfmt_script.c
fs/binfmt_som.c
fs/coredump.c
fs/exec.c
fs/file.c
fs/fs_struct.c
include/asm-generic/signal.h
include/asm-generic/syscalls.h
include/linux/binfmts.h
include/linux/compat.h
include/linux/coredump.h
include/linux/fdtable.h
include/linux/fs_struct.h
include/linux/ptrace.h
include/linux/sched.h
include/linux/syscalls.h
kernel/auditsc.c
kernel/exit.c
kernel/fork.c
kernel/signal.c

index cc74aae..34884fa 100644 (file)
@@ -342,4 +342,18 @@ config MODULES_USE_ELF_REL
          Modules only use ELF REL relocations.  Modules with ELF RELA
          relocations will give an error.
 
+#
+# ABI hall of shame
+#
+config CLONE_BACKWARDS
+       bool
+       help
+         Architecture has tls passed as the 4th argument of clone(2),
+         not the 5th one.
+
+config CLONE_BACKWARDS2
+       bool
+       help
+         Architecture has the first two arguments of clone(2) swapped.
+
 source "kernel/gcov/Kconfig"
index b87755a..b4c5b2f 100644 (file)
@@ -78,6 +78,7 @@ struct switch_stack {
 
 #define current_pt_regs() \
   ((struct pt_regs *) ((char *)current_thread_info() + 2*PAGE_SIZE) - 1)
+#define signal_pt_regs current_pt_regs
 
 #define force_successful_syscall_return() (current_pt_regs()->r0 = 0)
 
index a938830..4555286 100644 (file)
@@ -164,9 +164,6 @@ struct sigstack {
 
 #ifdef __KERNEL__
 #include <asm/sigcontext.h>
-
-#define ptrace_signal_deliver(regs, cookie) do { } while (0)
-
 #endif
 
 #endif
index 7826e22..eb3a466 100644 (file)
 #define __ARCH_WANT_SYS_SIGPENDING
 #define __ARCH_WANT_SYS_RT_SIGSUSPEND
 #define __ARCH_WANT_SYS_EXECVE
+#define __ARCH_WANT_SYS_FORK
+#define __ARCH_WANT_SYS_VFORK
+#define __ARCH_WANT_SYS_CLONE
 
 /* "Conditional" syscalls.  What we want is
 
index d1f474d..9525660 100644 (file)
@@ -5,7 +5,7 @@
 #include <linux/binfmts.h>
 #include <linux/a.out.h>
 
-static int load_binary(struct linux_binprm *bprm, struct pt_regs *regs)
+static int load_binary(struct linux_binprm *bprm)
 {
        struct exec *eh = (struct exec *)bprm->buf;
        unsigned long loader;
@@ -37,7 +37,7 @@ static int load_binary(struct linux_binprm *bprm, struct pt_regs *regs)
        retval = prepare_binprm(bprm);
        if (retval < 0)
                return retval;
-       return search_binary_handler(bprm,regs);
+       return search_binary_handler(bprm);
 }
 
 static struct linux_binfmt loader_format = {
index a760783..f62a994 100644 (file)
@@ -612,47 +612,24 @@ ret_from_kernel_thread:
  * Special system calls.  Most of these are special in that they either
  * have to play switch_stack games or in some way use the pt_regs struct.
  */
-       .align  4
-       .globl  sys_fork
-       .ent    sys_fork
-sys_fork:
-       .prologue 0
-       mov     $sp, $21
-       bsr     $1, do_switch_stack
-       bis     $31, SIGCHLD, $16
-       mov     $31, $17
-       mov     $31, $18
-       mov     $31, $19
-       mov     $31, $20
-       jsr     $26, alpha_clone
-       bsr     $1, undo_switch_stack
-       ret
-.end sys_fork
 
+.macro fork_like name
        .align  4
-       .globl  sys_clone
-       .ent    sys_clone
-sys_clone:
+       .globl  alpha_\name
+       .ent    alpha_\name
+alpha_\name:
        .prologue 0
-       mov     $sp, $21
        bsr     $1, do_switch_stack
-       /* $16, $17, $18, $19, $20 come from the user.  */
-       jsr     $26, alpha_clone
-       bsr     $1, undo_switch_stack
+       jsr     $26, sys_\name
+       ldq     $26, 56($sp)
+       lda     $sp, SWITCH_STACK_SIZE($sp)
        ret
-.end sys_clone
+.end   alpha_\name
+.endm
 
-       .align  4
-       .globl  sys_vfork
-       .ent    sys_vfork
-sys_vfork:
-       .prologue 0
-       mov     $sp, $16
-       bsr     $1, do_switch_stack
-       jsr     $26, alpha_vfork
-       bsr     $1, undo_switch_stack
-       ret
-.end sys_vfork
+fork_like fork
+fork_like vfork
+fork_like clone
 
        .align  4
        .globl  sys_sigreturn
@@ -661,8 +638,6 @@ sys_sigreturn:
        .prologue 0
        lda     $9, ret_from_straced
        cmpult  $26, $9, $9
-       mov     $sp, $17
-       lda     $18, -SWITCH_STACK_SIZE($sp)
        lda     $sp, -SWITCH_STACK_SIZE($sp)
        jsr     $26, do_sigreturn
        bne     $9, 1f
@@ -678,8 +653,6 @@ sys_rt_sigreturn:
        .prologue 0
        lda     $9, ret_from_straced
        cmpult  $26, $9, $9
-       mov     $sp, $17
-       lda     $18, -SWITCH_STACK_SIZE($sp)
        lda     $sp, -SWITCH_STACK_SIZE($sp)
        jsr     $26, do_rt_sigreturn
        bne     $9, 1f
index 51987dc..b5d0d09 100644 (file)
@@ -235,51 +235,28 @@ release_thread(struct task_struct *dead_task)
 }
 
 /*
- * "alpha_clone()".. By the time we get here, the
- * non-volatile registers have also been saved on the
- * stack. We do some ugly pointer stuff here.. (see
- * also copy_thread)
- *
- * Notice that "fork()" is implemented in terms of clone,
- * with parameters (SIGCHLD, 0).
- */
-int
-alpha_clone(unsigned long clone_flags, unsigned long usp,
-           int __user *parent_tid, int __user *child_tid,
-           unsigned long tls_value, struct pt_regs *regs)
-{
-       if (!usp)
-               usp = rdusp();
-
-       return do_fork(clone_flags, usp, regs, 0, parent_tid, child_tid);
-}
-
-int
-alpha_vfork(struct pt_regs *regs)
-{
-       return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(),
-                      regs, 0, NULL, NULL);
-}
-
-/*
  * Copy an alpha thread..
  */
 
 int
 copy_thread(unsigned long clone_flags, unsigned long usp,
            unsigned long arg,
-           struct task_struct * p, struct pt_regs * regs)
+           struct task_struct *p)
 {
        extern void ret_from_fork(void);
        extern void ret_from_kernel_thread(void);
 
        struct thread_info *childti = task_thread_info(p);
        struct pt_regs *childregs = task_pt_regs(p);
+       struct pt_regs *regs = current_pt_regs();
        struct switch_stack *childstack, *stack;
        unsigned long settls;
 
        childstack = ((struct switch_stack *) childregs) - 1;
-       if (unlikely(!regs)) {
+       childti->pcb.ksp = (unsigned long) childstack;
+       childti->pcb.flags = 1; /* set FEN, clear everything else */
+
+       if (unlikely(p->flags & PF_KTHREAD)) {
                /* kernel thread */
                memset(childstack, 0,
                        sizeof(struct switch_stack) + sizeof(struct pt_regs));
@@ -288,12 +265,17 @@ copy_thread(unsigned long clone_flags, unsigned long usp,
                childstack->r10 = arg;
                childregs->hae = alpha_mv.hae_cache,
                childti->pcb.usp = 0;
-               childti->pcb.ksp = (unsigned long) childstack;
-               childti->pcb.flags = 1; /* set FEN, clear everything else */
                return 0;
        }
+       /* Note: if CLONE_SETTLS is not set, then we must inherit the
+          value from the parent, which will have been set by the block
+          copy in dup_task_struct.  This is non-intuitive, but is
+          required for proper operation in the case of a threaded
+          application calling fork.  */
+       if (clone_flags & CLONE_SETTLS)
+               childti->pcb.unique = regs->r20;
+       childti->pcb.usp = usp ?: rdusp();
        *childregs = *regs;
-       settls = regs->r20;
        childregs->r0 = 0;
        childregs->r19 = 0;
        childregs->r20 = 1;     /* OSF/1 has some strange fork() semantics.  */
@@ -301,22 +283,6 @@ copy_thread(unsigned long clone_flags, unsigned long usp,
        stack = ((struct switch_stack *) regs) - 1;
        *childstack = *stack;
        childstack->r26 = (unsigned long) ret_from_fork;
-       childti->pcb.usp = usp;
-       childti->pcb.ksp = (unsigned long) childstack;
-       childti->pcb.flags = 1; /* set FEN, clear everything else */
-
-       /* Set a new TLS for the child thread?  Peek back into the
-          syscall arguments that we saved on syscall entry.  Oops,
-          except we'd have clobbered it with the parent/child set
-          of r20.  Read the saved copy.  */
-       /* Note: if CLONE_SETTLS is not set, then we must inherit the
-          value from the parent, which will have been set by the block
-          copy in dup_task_struct.  This is non-intuitive, but is
-          required for proper operation in the case of a threaded
-          application calling fork.  */
-       if (clone_flags & CLONE_SETTLS)
-               childti->pcb.unique = settls;
-
        return 0;
 }
 
index 32575f8..336393c 100644 (file)
@@ -160,10 +160,10 @@ extern char compile_time_assert
 #define INSN_CALLSYS           0x00000083
 
 static long
-restore_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs,
-                  struct switch_stack *sw)
+restore_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs)
 {
        unsigned long usp;
+       struct switch_stack *sw = (struct switch_stack *)regs - 1;
        long i, err = __get_user(regs->pc, &sc->sc_pc);
 
        current_thread_info()->restart_block.fn = do_no_restart_syscall;
@@ -215,9 +215,9 @@ restore_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs,
    registers and transfer control from userland.  */
 
 asmlinkage void
-do_sigreturn(struct sigcontext __user *sc, struct pt_regs *regs,
-            struct switch_stack *sw)
+do_sigreturn(struct sigcontext __user *sc)
 {
+       struct pt_regs *regs = current_pt_regs();
        sigset_t set;
 
        /* Verify that it's a good sigcontext before using it */
@@ -228,7 +228,7 @@ do_sigreturn(struct sigcontext __user *sc, struct pt_regs *regs,
 
        set_current_blocked(&set);
 
-       if (restore_sigcontext(sc, regs, sw))
+       if (restore_sigcontext(sc, regs))
                goto give_sigsegv;
 
        /* Send SIGTRAP if we're single-stepping: */
@@ -249,9 +249,9 @@ give_sigsegv:
 }
 
 asmlinkage void
-do_rt_sigreturn(struct rt_sigframe __user *frame, struct pt_regs *regs,
-               struct switch_stack *sw)
+do_rt_sigreturn(struct rt_sigframe __user *frame)
 {
+       struct pt_regs *regs = current_pt_regs();
        sigset_t set;
 
        /* Verify that it's a good ucontext_t before using it */
@@ -262,7 +262,7 @@ do_rt_sigreturn(struct rt_sigframe __user *frame, struct pt_regs *regs,
 
        set_current_blocked(&set);
 
-       if (restore_sigcontext(&frame->uc.uc_mcontext, regs, sw))
+       if (restore_sigcontext(&frame->uc.uc_mcontext, regs))
                goto give_sigsegv;
 
        /* Send SIGTRAP if we're single-stepping: */
index 2ac6b45..4284ec7 100644 (file)
@@ -12,7 +12,7 @@
 sys_call_table:
        .quad alpha_ni_syscall                  /* 0 */
        .quad sys_exit
-       .quad sys_fork
+       .quad alpha_fork
        .quad sys_read
        .quad sys_write
        .quad alpha_ni_syscall                  /* 5 */
@@ -76,7 +76,7 @@ sys_call_table:
        .quad sys_getpgrp
        .quad sys_getpagesize
        .quad alpha_ni_syscall                  /* 65 */
-       .quad sys_vfork
+       .quad alpha_vfork
        .quad sys_newstat
        .quad sys_newlstat
        .quad alpha_ni_syscall
@@ -330,7 +330,7 @@ sys_call_table:
        .quad sys_ni_syscall                    /* 309: old get_kernel_syms */
        .quad sys_syslog                        /* 310 */
        .quad sys_reboot
-       .quad sys_clone
+       .quad alpha_clone
        .quad sys_uselib
        .quad sys_mlock
        .quad sys_munlock                       /* 315 */
index d7d7c2f..08330d9 100644 (file)
@@ -57,6 +57,7 @@ config ARM
        select SYS_SUPPORTS_APM_EMULATION
        select HAVE_MOD_ARCH_SPECIFIC if ARM_UNWIND
        select MODULES_USE_ELF_REL
+       select CLONE_BACKWARDS
        help
          The ARM series is a line of low-power-consumption RISC chip designs
          licensed by ARM Ltd and targeted at embedded applications and
index 5a7963d..9a0ea6a 100644 (file)
@@ -35,5 +35,4 @@ struct k_sigaction {
 };
 
 #include <asm/sigcontext.h>
-#define ptrace_signal_deliver(regs, cookie) do { } while (0)
 #endif
index 8f60b6e..7cd13cc 100644 (file)
@@ -42,6 +42,9 @@
 #define __ARCH_WANT_SYS_SOCKETCALL
 #endif
 #define __ARCH_WANT_SYS_EXECVE
+#define __ARCH_WANT_SYS_FORK
+#define __ARCH_WANT_SYS_VFORK
+#define __ARCH_WANT_SYS_CLONE
 
 /*
  * "Conditional" syscalls
index 831cd38..5935b6a 100644 (file)
@@ -11,7 +11,7 @@
  */
 /* 0 */                CALL(sys_restart_syscall)
                CALL(sys_exit)
-               CALL(sys_fork_wrapper)
+               CALL(sys_fork)
                CALL(sys_read)
                CALL(sys_write)
 /* 5 */                CALL(sys_open)
                CALL(OBSOLETE(ABI(sys_ipc, sys_oabi_ipc)))
                CALL(sys_fsync)
                CALL(sys_sigreturn_wrapper)
-/* 120 */      CALL(sys_clone_wrapper)
+/* 120 */      CALL(sys_clone)
                CALL(sys_setdomainname)
                CALL(sys_newuname)
                CALL(sys_ni_syscall)            /* modify_ldt */
                CALL(sys_sendfile)
                CALL(sys_ni_syscall)            /* getpmsg */
                CALL(sys_ni_syscall)            /* putpmsg */
-/* 190 */      CALL(sys_vfork_wrapper)
+/* 190 */      CALL(sys_vfork)
                CALL(sys_getrlimit)
                CALL(sys_mmap2)
                CALL(ABI(sys_truncate64, sys_oabi_truncate64))
index 804153c..a6c301e 100644 (file)
@@ -502,22 +502,6 @@ sys_syscall:
                b       sys_ni_syscall
 ENDPROC(sys_syscall)
 
-sys_fork_wrapper:
-               add     r0, sp, #S_OFF
-               b       sys_fork
-ENDPROC(sys_fork_wrapper)
-
-sys_vfork_wrapper:
-               add     r0, sp, #S_OFF
-               b       sys_vfork
-ENDPROC(sys_vfork_wrapper)
-
-sys_clone_wrapper:
-               add     ip, sp, #S_OFF
-               str     ip, [sp, #4]
-               b       sys_clone
-ENDPROC(sys_clone_wrapper)
-
 sys_sigreturn_wrapper:
                add     r0, sp, #S_OFF
                mov     why, #0         @ prevent syscall restart handling
index 44bc0b3..c6dec5f 100644 (file)
@@ -376,17 +376,18 @@ asmlinkage void ret_from_fork(void) __asm__("ret_from_fork");
 
 int
 copy_thread(unsigned long clone_flags, unsigned long stack_start,
-           unsigned long stk_sz, struct task_struct *p, struct pt_regs *regs)
+           unsigned long stk_sz, struct task_struct *p)
 {
        struct thread_info *thread = task_thread_info(p);
        struct pt_regs *childregs = task_pt_regs(p);
 
        memset(&thread->cpu_context, 0, sizeof(struct cpu_context_save));
 
-       if (likely(regs)) {
-               *childregs = *regs;
+       if (likely(!(p->flags & PF_KTHREAD))) {
+               *childregs = *current_pt_regs();
                childregs->ARM_r0 = 0;
-               childregs->ARM_sp = stack_start;
+               if (stack_start)
+                       childregs->ARM_sp = stack_start;
        } else {
                memset(childregs, 0, sizeof(struct pt_regs));
                thread->cpu_context.r4 = stk_sz;
@@ -399,7 +400,7 @@ copy_thread(unsigned long clone_flags, unsigned long stack_start,
        clear_ptrace_hw_breakpoint(p);
 
        if (clone_flags & CLONE_SETTLS)
-               thread->tp_value = regs->ARM_r3;
+               thread->tp_value = childregs->ARM_r3;
 
        thread_notify(THREAD_NOTIFY_COPY, thread);
 
index c2a898a..3151f56 100644 (file)
 #include <linux/uaccess.h>
 #include <linux/slab.h>
 
-/* Fork a new task - this creates a new program thread.
- * This is called indirectly via a small wrapper
- */
-asmlinkage int sys_fork(struct pt_regs *regs)
-{
-#ifdef CONFIG_MMU
-       return do_fork(SIGCHLD, regs->ARM_sp, regs, 0, NULL, NULL);
-#else
-       /* can not support in nommu mode */
-       return(-EINVAL);
-#endif
-}
-
-/* Clone a task - this clones the calling program thread.
- * This is called indirectly via a small wrapper
- */
-asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp,
-                        int __user *parent_tidptr, int tls_val,
-                        int __user *child_tidptr, struct pt_regs *regs)
-{
-       if (!newsp)
-               newsp = regs->ARM_sp;
-
-       return do_fork(clone_flags, newsp, regs, 0, parent_tidptr, child_tidptr);
-}
-
-asmlinkage int sys_vfork(struct pt_regs *regs)
-{
-       return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->ARM_sp, regs, 0, NULL, NULL);
-}
-
 /*
  * Since loff_t is a 64 bit type we avoid a lot of ABI hassle
  * with a different argument ordering.
index 2adf340..f9ccff9 100644 (file)
@@ -33,6 +33,7 @@ config ARM64
        select RTC_LIB
        select SPARSE_IRQ
        select SYSCTL_EXCEPTION_TRACE
+       select CLONE_BACKWARDS
        help
          ARM 64-bit (AArch64) Linux support.
 
index a1b00cd..20d63b2 100644 (file)
@@ -27,12 +27,6 @@ asmlinkage long sys_rt_sigreturn_wrapper(void);
 asmlinkage long sys_sigaltstack_wrapper(const stack_t __user *uss,
                                        stack_t __user *uoss);
 
-/*
- * AArch64 sys_clone implementation has a different prototype than the generic
- * one (additional TLS value argument).
- */
-#define sys_clone      sys_clone
-
 #include <asm-generic/syscalls.h>
 
 #endif /* __ASM_SYSCALLS_H */
index 43064a8..d69aeea 100644 (file)
@@ -24,6 +24,9 @@
 #define __ARCH_WANT_SYS_SIGPROCMASK
 #define __ARCH_WANT_COMPAT_SYS_RT_SIGSUSPEND
 #define __ARCH_WANT_COMPAT_SYS_SENDFILE
+#define __ARCH_WANT_SYS_FORK
+#define __ARCH_WANT_SYS_VFORK
 #endif
 #define __ARCH_WANT_SYS_EXECVE
+#define __ARCH_WANT_SYS_CLONE
 #include <uapi/asm/unistd.h>
index 50104e8..5843262 100644 (file)
@@ -23,7 +23,7 @@
 
 __SYSCALL(0,   sys_restart_syscall)
 __SYSCALL(1,   sys_exit)
-__SYSCALL(2,   compat_sys_fork)
+__SYSCALL(2,   sys_fork)
 __SYSCALL(3,   sys_read)
 __SYSCALL(4,   sys_write)
 __SYSCALL(5,   compat_sys_open)
@@ -211,7 +211,7 @@ __SYSCALL(186, compat_sys_sigaltstack_wrapper)
 __SYSCALL(187, compat_sys_sendfile)
 __SYSCALL(188, sys_ni_syscall)                 /* 188 reserved */
 __SYSCALL(189, sys_ni_syscall)                 /* 189 reserved */
-__SYSCALL(190, compat_sys_vfork)
+__SYSCALL(190, sys_vfork)
 __SYSCALL(191, compat_sys_getrlimit)           /* SuS compliant getrlimit */
 __SYSCALL(192, sys_mmap_pgoff)
 __SYSCALL(193, compat_sys_truncate64_wrapper)
index 8a5f334..cb0956b 100644 (file)
@@ -234,16 +234,15 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
 asmlinkage void ret_from_fork(void) asm("ret_from_fork");
 
 int copy_thread(unsigned long clone_flags, unsigned long stack_start,
-               unsigned long stk_sz, struct task_struct *p,
-               struct pt_regs *regs)
+               unsigned long stk_sz, struct task_struct *p)
 {
        struct pt_regs *childregs = task_pt_regs(p);
        unsigned long tls = p->thread.tp_value;
 
        memset(&p->thread.cpu_context, 0, sizeof(struct cpu_context));
 
-       if (likely(regs)) {
-               *childregs = *regs;
+       if (likely(!(p->flags & PF_KTHREAD))) {
+               *childregs = *current_pt_regs();
                childregs->regs[0] = 0;
                if (is_compat_thread(task_thread_info(p))) {
                        if (stack_start)
@@ -266,7 +265,7 @@ int copy_thread(unsigned long clone_flags, unsigned long stack_start,
                 * for the new thread.
                 */
                if (clone_flags & CLONE_SETTLS)
-                       tls = regs->regs[3];
+                       tls = childregs->regs[3];
        } else {
                memset(childregs, 0, sizeof(struct pt_regs));
                childregs->pstate = PSR_MODE_EL1h;
index 4364df8..8292a9b 100644 (file)
 #include <linux/slab.h>
 #include <linux/syscalls.h>
 
-/*
- * Clone a task - this clones the calling program thread.
- */
-asmlinkage long sys_clone(unsigned long clone_flags, unsigned long newsp,
-                         int __user *parent_tidptr, unsigned long tls_val,
-                         int __user *child_tidptr)
-{
-       return do_fork(clone_flags, newsp, current_pt_regs(), 0,
-                       parent_tidptr, child_tidptr);
-}
-
 asmlinkage long sys_mmap(unsigned long addr, unsigned long len,
                         unsigned long prot, unsigned long flags,
                         unsigned long fd, off_t off)
index 6fabc19..f7b05ed 100644 (file)
 #include <asm/cacheflush.h>
 #include <asm/unistd32.h>
 
-asmlinkage int compat_sys_fork(void)
-{
-       return do_fork(SIGCHLD, 0, current_pt_regs(), 0, NULL, NULL);
-}
-
-asmlinkage int compat_sys_vfork(void)
-{
-       return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, 0,
-                      current_pt_regs(), 0, NULL, NULL);
-}
-
 asmlinkage int compat_sys_sched_rr_get_interval(compat_pid_t pid,
                                                struct compat_timespec __user *interval)
 {
index c2bbc9a..202d71a 100644 (file)
@@ -17,6 +17,8 @@ config AVR32
        select GENERIC_CLOCKEVENTS
        select HAVE_MOD_ARCH_SPECIFIC
        select MODULES_USE_ELF_RELA
+       select GENERIC_KERNEL_THREAD
+       select GENERIC_KERNEL_EXECVE
        help
          AVR32 is a high-performance 32-bit RISC microprocessor core,
          designed for cost-sensitive embedded applications, with particular
index 87d8bac..48d71c5 100644 (file)
@@ -142,9 +142,6 @@ struct task_struct;
 /* Free all resources held by a thread */
 extern void release_thread(struct task_struct *);
 
-/* Create a kernel thread without removing it from tasklists */
-extern int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags);
-
 /* Return saved PC of a blocked thread */
 #define thread_saved_pc(tsk)    ((tsk)->thread.cpu_context.pc)
 
index 4d502fd..9326d18 100644 (file)
@@ -37,6 +37,4 @@ struct k_sigaction {
 #include <asm/sigcontext.h>
 #undef __HAVE_ARCH_SIG_BITOPS
 
-#define ptrace_signal_deliver(regs, cookie) do { } while (0)
-
 #endif
index 157b4bd..f05a980 100644 (file)
 #define __ARCH_WANT_SYS_GETPGRP
 #define __ARCH_WANT_SYS_RT_SIGACTION
 #define __ARCH_WANT_SYS_RT_SIGSUSPEND
+#define __ARCH_WANT_SYS_EXECVE
+#define __ARCH_WANT_SYS_FORK
+#define __ARCH_WANT_SYS_VFORK
+#define __ARCH_WANT_SYS_CLONE
 
 /*
  * "Conditional" syscalls
index 9e2c465..119a2e4 100644 (file)
@@ -7,7 +7,7 @@ extra-y                         := head.o vmlinux.lds
 obj-$(CONFIG_SUBARCH_AVR32B)   += entry-avr32b.o
 obj-y                          += syscall_table.o syscall-stubs.o irq.o
 obj-y                          += setup.o traps.o ocd.o ptrace.o
-obj-y                          += signal.o sys_avr32.o process.o time.o
+obj-y                          += signal.o process.o time.o
 obj-y                          += switch_to.o cpu.o
 obj-$(CONFIG_MODULES)          += module.o avr32_ksyms.o
 obj-$(CONFIG_KPROBES)          += kprobes.o
index df28841..9899d3c 100644 (file)
@@ -251,13 +251,15 @@ syscall_badsys:
        .global ret_from_fork
 ret_from_fork:
        call   schedule_tail
+       mov     r12, 0
+       rjmp    syscall_return
 
-       /* check for syscall tracing */
-       get_thread_info r0
-       ld.w    r1, r0[TI_flags]
-       andl    r1, _TIF_ALLWORK_MASK, COH
-       brne    syscall_exit_work
-       rjmp    syscall_exit_cont
+       .global ret_from_kernel_thread
+ret_from_kernel_thread:
+       call   schedule_tail
+       mov     r12, r0
+       mov     lr, r2  /* syscall_return */
+       mov     pc, r1
 
 syscall_trace_enter:
        pushm   r8-r12
index 1bb0a8a..fd78f58 100644 (file)
@@ -69,44 +69,6 @@ void machine_restart(char *cmd)
 }
 
 /*
- * PC is actually discarded when returning from a system call -- the
- * return address must be stored in LR. This function will make sure
- * LR points to do_exit before starting the thread.
- *
- * Also, when returning from fork(), r12 is 0, so we must copy the
- * argument as well.
- *
- *  r0 : The argument to the main thread function
- *  r1 : The address of do_exit
- *  r2 : The address of the main thread function
- */
-asmlinkage extern void kernel_thread_helper(void);
-__asm__("      .type   kernel_thread_helper, @function\n"
-       "kernel_thread_helper:\n"
-       "       mov     r12, r0\n"
-       "       mov     lr, r2\n"
-       "       mov     pc, r1\n"
-       "       .size   kernel_thread_helper, . - kernel_thread_helper");
-
-int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
-{
-       struct pt_regs regs;
-
-       memset(&regs, 0, sizeof(regs));
-
-       regs.r0 = (unsigned long)arg;
-       regs.r1 = (unsigned long)fn;
-       regs.r2 = (unsigned long)do_exit;
-       regs.lr = (unsigned long)kernel_thread_helper;
-       regs.pc = (unsigned long)kernel_thread_helper;
-       regs.sr = MODE_SUPERVISOR;
-
-       return do_fork(flags | CLONE_VM | CLONE_UNTRACED,
-                      0, &regs, 0, NULL, NULL);
-}
-EXPORT_SYMBOL(kernel_thread);
-
-/*
  * Free current thread data structures etc
  */
 void exit_thread(void)
@@ -332,26 +294,32 @@ int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu)
 }
 
 asmlinkage void ret_from_fork(void);
+asmlinkage void ret_from_kernel_thread(void);
+asmlinkage void syscall_return(void);
 
 int copy_thread(unsigned long clone_flags, unsigned long usp,
-               unsigned long unused,
-               struct task_struct *p, struct pt_regs *regs)
+               unsigned long arg,
+               struct task_struct *p)
 {
-       struct pt_regs *childregs;
-
-       childregs = ((struct pt_regs *)(THREAD_SIZE + (unsigned long)task_stack_page(p))) - 1;
-       *childregs = *regs;
-
-       if (user_mode(regs))
-               childregs->sp = usp;
-       else
-               childregs->sp = (unsigned long)task_stack_page(p) + THREAD_SIZE;
-
-       childregs->r12 = 0; /* Set return value for child */
+       struct pt_regs *childregs = task_pt_regs(p);
+
+       if (unlikely(p->flags & PF_KTHREAD)) {
+               memset(childregs, 0, sizeof(struct pt_regs));
+               p->thread.cpu_context.r0 = arg;
+               p->thread.cpu_context.r1 = usp; /* fn */
+               p->thread.cpu_context.r2 = syscall_return;
+               p->thread.cpu_context.pc = (unsigned long)ret_from_kernel_thread;
+               childregs->sr = MODE_SUPERVISOR;
+       } else {
+               *childregs = *current_pt_regs();
+               if (usp)
+                       childregs->sp = usp;
+               childregs->r12 = 0; /* Set return value for child */
+               p->thread.cpu_context.pc = (unsigned long)ret_from_fork;
+       }
 
        p->thread.cpu_context.sr = MODE_SUPERVISOR | SR_GM;
        p->thread.cpu_context.ksp = (unsigned long)childregs;
-       p->thread.cpu_context.pc = (unsigned long)ret_from_fork;
 
        clear_tsk_thread_flag(p, TIF_DEBUG);
        if ((clone_flags & CLONE_PTRACE) && test_thread_flag(TIF_DEBUG))
@@ -360,49 +328,6 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,
        return 0;
 }
 
-/* r12-r8 are dummy parameters to force the compiler to use the stack */
-asmlinkage int sys_fork(struct pt_regs *regs)
-{
-       return do_fork(SIGCHLD, regs->sp, regs, 0, NULL, NULL);
-}
-
-asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp,
-               void __user *parent_tidptr, void __user *child_tidptr,
-               struct pt_regs *regs)
-{
-       if (!newsp)
-               newsp = regs->sp;
-       return do_fork(clone_flags, newsp, regs, 0, parent_tidptr,
-                       child_tidptr);
-}
-
-asmlinkage int sys_vfork(struct pt_regs *regs)
-{
-       return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->sp, regs,
-                      0, NULL, NULL);
-}
-
-asmlinkage int sys_execve(const char __user *ufilename,
-                         const char __user *const __user *uargv,
-                         const char __user *const __user *uenvp,
-                         struct pt_regs *regs)
-{
-       int error;
-       struct filename *filename;
-
-       filename = getname(ufilename);
-       error = PTR_ERR(filename);
-       if (IS_ERR(filename))
-               goto out;
-
-       error = do_execve(filename->name, uargv, uenvp, regs);
-       putname(filename);
-
-out:
-       return error;
-}
-
-
 /*
  * This function is supposed to answer the question "who called
  * schedule()?"
diff --git a/arch/avr32/kernel/sys_avr32.c b/arch/avr32/kernel/sys_avr32.c
deleted file mode 100644 (file)
index 62635a0..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Copyright (C) 2004-2006 Atmel Corporation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-#include <linux/unistd.h>
-
-int kernel_execve(const char *file,
-                 const char *const *argv,
-                 const char *const *envp)
-{
-       register long scno asm("r8") = __NR_execve;
-       register long sc1 asm("r12") = (long)file;
-       register long sc2 asm("r11") = (long)argv;
-       register long sc3 asm("r10") = (long)envp;
-
-       asm volatile("scall"
-                    : "=r"(sc1)
-                    : "r"(scno), "0"(sc1), "r"(sc2), "r"(sc3)
-                    : "cc", "memory");
-       return sc1;
-}
index 0447a3e..275aab9 100644 (file)
@@ -32,30 +32,6 @@ __sys_rt_sigreturn:
        mov     r12, sp
        rjmp    sys_rt_sigreturn
 
-       .global __sys_fork
-       .type   __sys_fork,@function
-__sys_fork:
-       mov     r12, sp
-       rjmp    sys_fork
-
-       .global __sys_clone
-       .type   __sys_clone,@function
-__sys_clone:
-       mov     r8, sp
-       rjmp    sys_clone
-
-       .global __sys_vfork
-       .type   __sys_vfork,@function
-__sys_vfork:
-       mov     r12, sp
-       rjmp    sys_vfork
-
-       .global __sys_execve
-       .type   __sys_execve,@function
-__sys_execve:
-       mov     r9, sp
-       rjmp    sys_execve
-
        .global __sys_mmap2
        .type   __sys_mmap2,@function
 __sys_mmap2:
index 6eba535..f27bb87 100644 (file)
@@ -15,7 +15,7 @@
 sys_call_table:
        .long   sys_restart_syscall
        .long   sys_exit
-       .long   __sys_fork
+       .long   sys_fork
        .long   sys_read
        .long   sys_write
        .long   sys_open                /* 5 */
@@ -24,7 +24,7 @@ sys_call_table:
        .long   sys_creat
        .long   sys_link
        .long   sys_unlink              /* 10 */
-       .long   __sys_execve
+       .long   sys_execve
        .long   sys_chdir
        .long   sys_time
        .long   sys_mknod
@@ -57,7 +57,7 @@ sys_call_table:
        .long   sys_dup
        .long   sys_pipe
        .long   sys_times
-       .long   __sys_clone
+       .long   sys_clone
        .long   sys_brk                 /* 45 */
        .long   sys_setgid
        .long   sys_getgid
@@ -127,7 +127,7 @@ sys_call_table:
        .long   sys_newuname
        .long   sys_adjtimex
        .long   sys_mprotect
-       .long   __sys_vfork
+       .long   sys_vfork
        .long   sys_init_module         /* 115 */
        .long   sys_delete_module
        .long   sys_quotactl
index b6f3ad5..ab9ff40 100644 (file)
@@ -45,6 +45,8 @@ config BLACKFIN
        select ARCH_USES_GETTIMEOFFSET if !GENERIC_CLOCKEVENTS
        select HAVE_MOD_ARCH_SPECIFIC
        select MODULES_USE_ELF_RELA
+       select GENERIC_KERNEL_THREAD
+       select GENERIC_KERNEL_EXECVE
 
 config GENERIC_CSUM
        def_bool y
index 4ef7cfe..d0e72e9 100644 (file)
@@ -75,8 +75,6 @@ static inline void release_thread(struct task_struct *dead_task)
 {
 }
 
-extern int kernel_thread(int (*fn) (void *), void *arg, unsigned long flags);
-
 /*
  * Free current thread data structures etc..
  */
index 5b2a074..460514a 100644 (file)
 #define __ARCH_WANT_SYS_NICE
 #define __ARCH_WANT_SYS_RT_SIGACTION
 #define __ARCH_WANT_SYS_RT_SIGSUSPEND
+#define __ARCH_WANT_SYS_EXECVE
+#define __ARCH_WANT_SYS_VFORK
 
 /*
  * "Conditional" syscalls
index f33792c..4071265 100644 (file)
@@ -46,53 +46,14 @@ ENTRY(_ret_from_fork)
        SP += -12;
        pseudo_long_call _schedule_tail, p5;
        SP += 12;
-       r0 = [sp + PT_IPEND];
-       cc = bittst(r0,1);
-       if cc jump .Lin_kernel;
+       p1 = [sp++];
+       r0 = [sp++];
+       cc = p1 == 0;
+       if cc jump .Lfork;
+       sp += -12;
+       call (p1);
+       sp += 12;
+.Lfork:
        RESTORE_CONTEXT
        rti;
-.Lin_kernel:
-       bitclr(r0,1);
-       [sp + PT_IPEND] = r0;
-       /* do a 'fake' RTI by jumping to [RETI]
-        * to avoid clearing supervisor mode in child
-        */
-       r0 = [sp + PT_PC];
-       [sp + PT_P0] = r0;
-
-       RESTORE_ALL_SYS
-       jump (p0);
 ENDPROC(_ret_from_fork)
-
-ENTRY(_sys_vfork)
-       r0 = sp;
-       r0 += 24;
-       [--sp] = rets;
-       SP += -12;
-       pseudo_long_call _bfin_vfork, p2;
-       SP += 12;
-       rets = [sp++];
-       rts;
-ENDPROC(_sys_vfork)
-
-ENTRY(_sys_clone)
-       r0 = sp;
-       r0 += 24;
-       [--sp] = rets;
-       SP += -12;
-       pseudo_long_call _bfin_clone, p2;
-       SP += 12;
-       rets = [sp++];
-       rts;
-ENDPROC(_sys_clone)
-
-ENTRY(_sys_rt_sigreturn)
-       r0 = sp;
-       r0 += 24;
-       [--sp] = rets;
-       SP += -12;
-       pseudo_long_call _do_rt_sigreturn, p2;
-       SP += 12;
-       rets = [sp++];
-       rts;
-ENDPROC(_sys_rt_sigreturn)
index bb1cc72..3e16ad9 100644 (file)
@@ -102,40 +102,6 @@ void cpu_idle(void)
 }
 
 /*
- * This gets run with P1 containing the
- * function to call, and R1 containing
- * the "args".  Note P0 is clobbered on the way here.
- */
-void kernel_thread_helper(void);
-__asm__(".section .text\n"
-       ".align 4\n"
-       "_kernel_thread_helper:\n\t"
-       "\tsp += -12;\n\t"
-       "\tr0 = r1;\n\t" "\tcall (p1);\n\t" "\tcall _do_exit;\n" ".previous");
-
-/*
- * Create a kernel thread.
- */
-pid_t kernel_thread(int (*fn) (void *), void *arg, unsigned long flags)
-{
-       struct pt_regs regs;
-
-       memset(&regs, 0, sizeof(regs));
-
-       regs.r1 = (unsigned long)arg;
-       regs.p1 = (unsigned long)fn;
-       regs.pc = (unsigned long)kernel_thread_helper;
-       regs.orig_p0 = -1;
-       /* Set bit 2 to tell ret_from_fork we should be returning to kernel
-          mode.  */
-       regs.ipend = 0x8002;
-       __asm__ __volatile__("%0 = syscfg;":"=da"(regs.syscfg):);
-       return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, &regs, 0, NULL,
-                      NULL);
-}
-EXPORT_SYMBOL(kernel_thread);
-
-/*
  * Do necessary setup to start up a newly executed thread.
  *
  * pass the data segment into user programs if it exists,
@@ -161,70 +127,48 @@ void flush_thread(void)
 {
 }
 
-asmlinkage int bfin_vfork(struct pt_regs *regs)
-{
-       return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), regs, 0, NULL,
-                      NULL);
-}
-
-asmlinkage int bfin_clone(struct pt_regs *regs)
+asmlinkage int bfin_clone(unsigned long clone_flags, unsigned long newsp)
 {
-       unsigned long clone_flags;
-       unsigned long newsp;
-
 #ifdef __ARCH_SYNC_CORE_DCACHE
        if (current->nr_cpus_allowed == num_possible_cpus())
                set_cpus_allowed_ptr(current, cpumask_of(smp_processor_id()));
 #endif
-
-       /* syscall2 puts clone_flags in r0 and usp in r1 */
-       clone_flags = regs->r0;
-       newsp = regs->r1;
-       if (!newsp)
-               newsp = rdusp();
-       else
+       if (newsp)
                newsp -= 12;
-       return do_fork(clone_flags, newsp, regs, 0, NULL, NULL);
+       return do_fork(clone_flags, newsp, 0, NULL, NULL);
 }
 
 int
 copy_thread(unsigned long clone_flags,
            unsigned long usp, unsigned long topstk,
-           struct task_struct *p, struct pt_regs *regs)
+           struct task_struct *p)
 {
        struct pt_regs *childregs;
+       unsigned long *v;
 
        childregs = (struct pt_regs *) (task_stack_page(p) + THREAD_SIZE) - 1;
-       *childregs = *regs;
-       childregs->r0 = 0;
+       v = ((unsigned long *)childregs) - 2;
+       if (unlikely(p->flags & PF_KTHREAD)) {
+               memset(childregs, 0, sizeof(struct pt_regs));
+               v[0] = usp;
+               v[1] = topstk;
+               childregs->orig_p0 = -1;
+               childregs->ipend = 0x8000;
+               __asm__ __volatile__("%0 = syscfg;":"=da"(childregs->syscfg):);
+               p->thread.usp = 0;
+       } else {
+               *childregs = *current_pt_regs();
+               childregs->r0 = 0;
+               p->thread.usp = usp ? : rdusp();
+               v[0] = v[1] = 0;
+       }
 
-       p->thread.usp = usp;
-       p->thread.ksp = (unsigned long)childregs;
+       p->thread.ksp = (unsigned long)v;
        p->thread.pc = (unsigned long)ret_from_fork;
 
        return 0;
 }
 
-/*
- * sys_execve() executes a new program.
- */
-asmlinkage int sys_execve(const char __user *name,
-                         const char __user *const __user *argv,
-                         const char __user *const __user *envp)
-{
-       int error;
-       struct filename *filename;
-       struct pt_regs *regs = (struct pt_regs *)((&name) + 6);
-
-       filename = getname(name);
-       error = PTR_ERR(filename);
-       if (IS_ERR(filename))
-               return error;
-       error = do_execve(filename->name, argv, envp, regs);
-       putname(filename);
-       return error;
-}
-
 unsigned long get_wchan(struct task_struct *p)
 {
        unsigned long fp, pc;
index 6ed20a1..84b4be0 100644 (file)
@@ -82,9 +82,9 @@ rt_restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, int *p
        return err;
 }
 
-asmlinkage int do_rt_sigreturn(unsigned long __unused)
+asmlinkage int sys_rt_sigreturn(void)
 {
-       struct pt_regs *regs = (struct pt_regs *)__unused;
+       struct pt_regs *regs = current_pt_regs();
        unsigned long usp = rdusp();
        struct rt_sigframe *frame = (struct rt_sigframe *)(usp);
        sigset_t set;
index 1c3d2c5..86b5a09 100644 (file)
@@ -530,61 +530,6 @@ ENTRY(_trap) /* Exception: 4th entry into system event table(supervisor mode)*/
        jump .Lsyscall_really_exit;
 ENDPROC(_trap)
 
-ENTRY(_kernel_execve)
-       link SIZEOF_PTREGS;
-       p0 = sp;
-       r3 = SIZEOF_PTREGS / 4;
-       r4 = 0(x);
-.Lclear_regs:
-       [p0++] = r4;
-       r3 += -1;
-       cc = r3 == 0;
-       if !cc jump .Lclear_regs (bp);
-
-       p0 = sp;
-       sp += -16;
-       [sp + 12] = p0;
-       pseudo_long_call _do_execve, p5;
-       SP += 16;
-       cc = r0 == 0;
-       if ! cc jump .Lexecve_failed;
-       /* Success.  Copy our temporary pt_regs to the top of the kernel
-        * stack and do a normal exception return.
-        */
-       r1 = sp;
-       r0 = (-KERNEL_STACK_SIZE) (x);
-       r1 = r1 & r0;
-       p2 = r1;
-       p3 = [p2];
-       r0 = KERNEL_STACK_SIZE - 4 (z);
-       p1 = r0;
-       p1 = p1 + p2;
-
-       p0 = fp;
-       r4 = [p0--];
-       r3 = SIZEOF_PTREGS / 4;
-.Lcopy_regs:
-       r4 = [p0--];
-       [p1--] = r4;
-       r3 += -1;
-       cc = r3 == 0;
-       if ! cc jump .Lcopy_regs (bp);
-
-       r0 = (KERNEL_STACK_SIZE - SIZEOF_PTREGS) (z);
-       p1 = r0;
-       p1 = p1 + p2;
-       sp = p1;
-       r0 = syscfg;
-       [SP + PT_SYSCFG] = r0;
-       [p3 + (TASK_THREAD + THREAD_KSP)] = sp;
-
-       RESTORE_CONTEXT;
-       rti;
-.Lexecve_failed:
-       unlink;
-       rts;
-ENDPROC(_kernel_execve)
-
 ENTRY(_system_call)
        /* Store IPEND */
        p2.l = lo(IPEND);
@@ -1486,7 +1431,7 @@ ENTRY(_sys_call_table)
        .long _sys_ni_syscall   /* old sys_ipc */
        .long _sys_fsync
        .long _sys_ni_syscall   /* old sys_sigreturn */
-       .long _sys_clone                /* 120 */
+       .long _bfin_clone               /* 120 */
        .long _sys_setdomainname
        .long _sys_newuname
        .long _sys_ni_syscall   /* old sys_modify_ldt */
index aee1b56..66eab37 100644 (file)
@@ -18,6 +18,7 @@ config C6X
        select OF_EARLY_FLATTREE
        select GENERIC_CLOCKEVENTS
        select GENERIC_KERNEL_THREAD
+       select GENERIC_KERNEL_EXECVE
        select MODULES_USE_ELF_RELA
 
 config MMU
index e7b8991..df3d05f 100644 (file)
@@ -41,10 +41,6 @@ extern long sys_fallocate_c6x(int fd, int mode,
                              u32 len_lo, u32 len_hi);
 extern int sys_cache_sync(unsigned long s, unsigned long e);
 
-struct pt_regs;
-
-extern asmlinkage long sys_c6x_clone(struct pt_regs *regs);
-
 #include <asm-generic/syscalls.h>
 
 #endif /* __ASM_C6X_SYSCALLS_H */
index 4ff747d..f3987a8 100644 (file)
@@ -14,8 +14,8 @@
  *   more details.
  */
 
-#define __ARCH_WANT_KERNEL_EXECVE
 #define __ARCH_WANT_SYS_EXECVE
+#define __ARCH_WANT_SYS_CLONE
 
 /* Use the standard ABI for syscalls. */
 #include <asm-generic/unistd.h>
index 0ed6157..5239057 100644 (file)
@@ -415,19 +415,9 @@ ENTRY(ret_from_kernel_thread)
 0:
        B       .S2     B10                /* call fn */
        LDW     .D2T1   *+SP(REGS_A1+8),A4 /* get arg */
-       MVKL    .S2     sys_exit,B11
-       MVKH    .S2     sys_exit,B11
-       ADDKPC  .S2     0f,B3,1
-0:
-       BNOP    .S2     B11,5   /* jump to sys_exit */
+       ADDKPC  .S2     ret_from_fork_2,B3,3
 ENDPROC(ret_from_kernel_thread)
 
-ENTRY(ret_from_kernel_execve)
-       GET_THREAD_INFO A12
-       BNOP    .S2     syscall_exit,4
-       ADD     .D2X    A4,-8,SP
-ENDPROC(ret_from_kernel_execve)
-
        ;;
        ;; These are the interrupt handlers, responsible for calling c6x_do_IRQ()
        ;;
@@ -624,18 +614,6 @@ ENDPROC(sys_sigaltstack)
        ;; Special system calls
        ;; return address is in B3
        ;;
-ENTRY(sys_clone)
-       ADD     .D1X    SP,8,A4
-#ifdef CONFIG_C6X_BIG_KERNEL
- ||    MVKL    .S1     sys_c6x_clone,A0
-       MVKH    .S1     sys_c6x_clone,A0
-       BNOP    .S2X    A0,5
-#else
- ||    B       .S2     sys_c6x_clone
-       NOP     5
-#endif
-ENDPROC(sys_clone)
-
 ENTRY(sys_rt_sigreturn)
        ADD     .D1X    SP,8,A4
 #ifdef CONFIG_C6X_BIG_KERNEL
index 2770d9a..6434df4 100644 (file)
@@ -112,22 +112,6 @@ void exit_thread(void)
 {
 }
 
-SYSCALL_DEFINE1(c6x_clone, struct pt_regs *, regs)
-{
-       unsigned long clone_flags;
-       unsigned long newsp;
-
-       /* syscall puts clone_flags in A4 and usp in B4 */
-       clone_flags = regs->orig_a4;
-       if (regs->b4)
-               newsp = regs->b4;
-       else
-               newsp = regs->sp;
-
-       return do_fork(clone_flags, newsp, regs, 0, (int __user *)regs->a6,
-                      (int __user *)regs->b6);
-}
-
 /*
  * Do necessary setup to start up a newly executed thread.
  */
@@ -155,13 +139,13 @@ void start_thread(struct pt_regs *regs, unsigned int pc, unsigned long usp)
  */
 int copy_thread(unsigned long clone_flags, unsigned long usp,
                unsigned long ustk_size,
-               struct task_struct *p, struct pt_regs *regs)
+               struct task_struct *p)
 {
        struct pt_regs *childregs;
 
        childregs = task_pt_regs(p);
 
-       if (!regs) {
+       if (unlikely(p->flags & PF_KTHREAD)) {
                /* case of  __kernel_thread: we return to supervisor space */
                memset(childregs, 0, sizeof(struct pt_regs));
                childregs->sp = (unsigned long)(childregs + 1);
@@ -170,8 +154,9 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,
                childregs->a1 = ustk_size;      /* argument */
        } else {
                /* Otherwise use the given stack */
-               *childregs = *regs;
-               childregs->sp = usp;
+               *childregs = *current_pt_regs();
+               if (usp)
+                       childregs->sp = usp;
                p->thread.pc = (unsigned long) ret_from_fork;
        }
 
index a672444..0cac6a4 100644 (file)
@@ -49,6 +49,9 @@ config CRIS
        select GENERIC_SMP_IDLE_THREAD if ETRAX_ARCH_V32
        select GENERIC_CMOS_UPDATE
        select MODULES_USE_ELF_RELA
+       select GENERIC_KERNEL_THREAD
+       select GENERIC_KERNEL_EXECVE
+       select CLONE_BACKWARDS2
 
 config HZ
        int
index 592fbe9..897bba6 100644 (file)
@@ -35,6 +35,7 @@
        .globl system_call
        .globl ret_from_intr
        .globl ret_from_fork
+       .globl ret_from_kernel_thread
        .globl resume
        .globl multiple_interrupt
        .globl hwbreakpoint
@@ -81,7 +82,14 @@ ret_from_fork:
        jsr schedule_tail
        ba  ret_from_sys_call
        nop
-               
+
+ret_from_kernel_thread:
+       jsr schedule_tail
+       move.d  $r2, $r10       ; argument is here
+       jsr     $r1             ; call the payload
+       moveq   0, $r9          ; no syscall restarts, TYVM...
+       ba  ret_from_sys_call
+
 ret_from_intr:
        ;; check for resched if preemptive kernel or if we're going back to user-mode 
        ;; this test matches the user_regs(regs) macro
@@ -586,13 +594,6 @@ _ugdb_handle_breakpoint:
        ba      do_sigtrap              ; SIGTRAP the offending process. 
        pop     $dccr                   ; Restore dccr in delay slot.
 
-       .global kernel_execve
-kernel_execve:
-       move.d __NR_execve, $r9
-       break 13
-       ret
-       nop
-
        .data
 
 hw_bp_trigs:
index 15ac715..b101875 100644 (file)
@@ -17,6 +17,7 @@
 #include <arch/svinto.h>
 #include <linux/init.h>
 #include <arch/system.h>
+#include <linux/ptrace.h>
 
 #ifdef CONFIG_ETRAX_GPIO
 void etrax_gpio_wake_up_check(void); /* drivers/gpio.c */
@@ -81,31 +82,6 @@ unsigned long thread_saved_pc(struct task_struct *t)
        return task_pt_regs(t)->irp;
 }
 
-static void kernel_thread_helper(void* dummy, int (*fn)(void *), void * arg)
-{
-  fn(arg);
-  do_exit(-1); /* Should never be called, return bad exit value */
-}
-
-/*
- * Create a kernel thread
- */
-int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
-{
-       struct pt_regs regs;
-
-       memset(&regs, 0, sizeof(regs));
-
-        /* Don't use r10 since that is set to 0 in copy_thread */
-       regs.r11 = (unsigned long)fn;
-       regs.r12 = (unsigned long)arg;
-       regs.irp = (unsigned long)kernel_thread_helper;
-       regs.dccr = 1 << I_DCCR_BITNR;
-
-       /* Ok, create the new process.. */
-        return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, &regs, 0, NULL, NULL);
-}
-
 /* setup the child's kernel stack with a pt_regs and switch_stack on it.
  * it will be un-nested during _resume and _ret_from_sys_call when the
  * new thread is scheduled.
@@ -115,29 +91,34 @@ int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
  *
  */
 asmlinkage void ret_from_fork(void);
+asmlinkage void ret_from_kernel_thread(void);
 
 int copy_thread(unsigned long clone_flags, unsigned long usp,
-               unsigned long unused,
-               struct task_struct *p, struct pt_regs *regs)
+               unsigned long arg, struct task_struct *p)
 {
-       struct pt_regs * childregs;
-       struct switch_stack *swstack;
+       struct pt_regs *childregs = task_pt_regs(p);
+       struct switch_stack *swstack = ((struct switch_stack *)childregs) - 1;
        
        /* put the pt_regs structure at the end of the new kernel stack page and fix it up
         * remember that the task_struct doubles as the kernel stack for the task
         */
 
-       childregs = task_pt_regs(p);
-        
-       *childregs = *regs;  /* struct copy of pt_regs */
-        
-        p->set_child_tid = p->clear_child_tid = NULL;
+       if (unlikely(p->flags & PF_KTHREAD)) {
+               memset(swstack, 0,
+                       sizeof(struct switch_stack) + sizeof(struct pt_regs));
+               swstack->r1 = usp;
+               swstack->r2 = arg;
+               childregs->dccr = 1 << I_DCCR_BITNR;
+               swstack->return_ip = (unsigned long) ret_from_kernel_thread;
+               p->thread.ksp = (unsigned long) swstack;
+               p->thread.usp = 0;
+               return 0;
+       }
+       *childregs = *current_pt_regs();  /* struct copy of pt_regs */
 
         childregs->r10 = 0;  /* child returns 0 after a fork/clone */
-       
-       /* put the switch stack right below the pt_regs */
 
-       swstack = ((struct switch_stack *)childregs) - 1;
+       /* put the switch stack right below the pt_regs */
 
        swstack->r9 = 0; /* parameter to ret_from_sys_call, 0 == dont restart the syscall */
 
@@ -147,7 +128,7 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,
        
        /* fix the user-mode stackpointer */
 
-       p->thread.usp = usp;    
+       p->thread.usp = usp ?: rdusp();
 
        /* and the kernel-mode one */
 
@@ -161,70 +142,6 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,
        return 0;
 }
 
-/* 
- * Be aware of the "magic" 7th argument in the four system-calls below.
- * They need the latest stackframe, which is put as the 7th argument by
- * entry.S. The previous arguments are dummies or actually used, but need
- * to be defined to reach the 7th argument.
- *
- * N.B.: Another method to get the stackframe is to use current_regs(). But
- * it returns the latest stack-frame stacked when going from _user mode_ and
- * some of these (at least sys_clone) are called from kernel-mode sometimes
- * (for example during kernel_thread, above) and thus cannot use it. Thus,
- * to be sure not to get any surprises, we use the method for the other calls
- * as well.
- */
-
-asmlinkage int sys_fork(long r10, long r11, long r12, long r13, long mof, long srp,
-                       struct pt_regs *regs)
-{
-       return do_fork(SIGCHLD, rdusp(), regs, 0, NULL, NULL);
-}
-
-/* if newusp is 0, we just grab the old usp */
-/* FIXME: Is parent_tid/child_tid really third/fourth argument? Update lib? */
-asmlinkage int sys_clone(unsigned long newusp, unsigned long flags,
-                        int* parent_tid, int* child_tid, long mof, long srp,
-                        struct pt_regs *regs)
-{
-       if (!newusp)
-               newusp = rdusp();
-       return do_fork(flags, newusp, regs, 0, parent_tid, child_tid);
-}
-
-/* vfork is a system call in i386 because of register-pressure - maybe
- * we can remove it and handle it in libc but we put it here until then.
- */
-
-asmlinkage int sys_vfork(long r10, long r11, long r12, long r13, long mof, long srp,
-                        struct pt_regs *regs)
-{
-        return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), regs, 0, NULL, NULL);
-}
-
-/*
- * sys_execve() executes a new program.
- */
-asmlinkage int sys_execve(const char *fname,
-                         const char *const *argv,
-                         const char *const *envp,
-                         long r13, long mof, long srp, 
-                         struct pt_regs *regs)
-{
-       int error;
-       struct filename *filename;
-
-       filename = getname(fname);
-       error = PTR_ERR(filename);
-
-       if (IS_ERR(filename))
-               goto out;
-       error = do_execve(filename->name, argv, envp, regs);
-       putname(filename);
- out:
-       return error;
-}
-
 unsigned long get_wchan(struct task_struct *p)
 {
 #if 0
index c3ea469..faa6441 100644 (file)
@@ -31,6 +31,7 @@
        .globl system_call
        .globl ret_from_intr
        .globl ret_from_fork
+       .globl ret_from_kernel_thread
        .globl resume
        .globl multiple_interrupt
        .globl nmi_interrupt
@@ -84,6 +85,18 @@ ret_from_fork:
        nop
        .size   ret_from_fork, . - ret_from_fork
 
+       .type   ret_from_kernel_thread,@function
+ret_from_kernel_thread:
+       jsr schedule_tail
+       nop
+       move.d  $r2, $r10
+       jsr     $r1
+       nop
+       moveq   0, $r9                  ; no syscall restarts, TYVM...
+       ba  ret_from_sys_call
+       nop
+       .size   ret_from_kernel_thread, . - ret_from_kernel_thread
+
        .type   ret_from_intr,@function
 ret_from_intr:
        ;; Check for resched if preemptive kernel, or if we're going back to
@@ -531,15 +544,6 @@ _ugdb_handle_exception:
        ba      do_sigtrap              ; SIGTRAP the offending process.
        move.d  [$sp+], $r0             ; Restore R0 in delay slot.
 
-       .global kernel_execve
-       .type   kernel_execve,@function
-kernel_execve:
-       move.d __NR_execve, $r9
-       break 13
-       ret
-       nop
-       .size   kernel_execve, . - kernel_execve
-
        .data
 
        .section .rodata,"a"
index 4e99922..2b23ef0 100644 (file)
@@ -16,6 +16,7 @@
 #include <hwregs/reg_map.h>
 #include <hwregs/timer_defs.h>
 #include <hwregs/intr_vect_defs.h>
+#include <linux/ptrace.h>
 
 extern void stop_watchdog(void);
 
@@ -94,31 +95,6 @@ unsigned long thread_saved_pc(struct task_struct *t)
        return task_pt_regs(t)->erp;
 }
 
-static void
-kernel_thread_helper(void* dummy, int (*fn)(void *), void * arg)
-{
-       fn(arg);
-       do_exit(-1); /* Should never be called, return bad exit value. */
-}
-
-/* Create a kernel thread. */
-int
-kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
-{
-       struct pt_regs regs;
-
-       memset(&regs, 0, sizeof(regs));
-
-        /* Don't use r10 since that is set to 0 in copy_thread. */
-       regs.r11 = (unsigned long) fn;
-       regs.r12 = (unsigned long) arg;
-       regs.erp = (unsigned long) kernel_thread_helper;
-       regs.ccs = 1 << (I_CCS_BITNR + CCS_SHIFT);
-
-       /* Create the new process. */
-        return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, &regs, 0, NULL, NULL);
-}
-
 /*
  * Setup the child's kernel stack with a pt_regs and call switch_stack() on it.
  * It will be unnested during _resume and _ret_from_sys_call when the new thread
@@ -129,34 +105,42 @@ kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
  */
 
 extern asmlinkage void ret_from_fork(void);
+extern asmlinkage void ret_from_kernel_thread(void);
 
 int
 copy_thread(unsigned long clone_flags, unsigned long usp,
-       unsigned long unused,
-       struct task_struct *p, struct pt_regs *regs)
+       unsigned long arg, struct task_struct *p)
 {
-       struct pt_regs *childregs;
-       struct switch_stack *swstack;
+       struct pt_regs *childregs = task_pt_regs(p);
+       struct switch_stack *swstack = ((struct switch_stack *) childregs) - 1;
 
        /*
         * Put the pt_regs structure at the end of the new kernel stack page and
         * fix it up. Note: the task_struct doubles as the kernel stack for the
         * task.
         */
-       childregs = task_pt_regs(p);
-       *childregs = *regs;     /* Struct copy of pt_regs. */
-        p->set_child_tid = p->clear_child_tid = NULL;
+       if (unlikely(p->flags & PF_KTHREAD)) {
+               memset(swstack, 0,
+                       sizeof(struct switch_stack) + sizeof(struct pt_regs));
+               swstack->r1 = usp;
+               swstack->r2 = arg;
+               childregs->ccs = 1 << (I_CCS_BITNR + CCS_SHIFT);
+               swstack->return_ip = (unsigned long) ret_from_kernel_thread;
+               p->thread.ksp = (unsigned long) swstack;
+               p->thread.usp = 0;
+               return 0;
+       }
+       *childregs = *current_pt_regs();        /* Struct copy of pt_regs. */
         childregs->r10 = 0;    /* Child returns 0 after a fork/clone. */
 
        /* Set a new TLS ?
         * The TLS is in $mof because it is the 5th argument to sys_clone.
         */
        if (p->mm && (clone_flags & CLONE_SETTLS)) {
-               task_thread_info(p)->tls = regs->mof;
+               task_thread_info(p)->tls = childregs->mof;
        }
 
        /* Put the switch stack right below the pt_regs. */
-       swstack = ((struct switch_stack *) childregs) - 1;
 
        /* Parameter to ret_from_sys_call. 0 is don't restart the syscall. */
        swstack->r9 = 0;
@@ -168,76 +152,12 @@ copy_thread(unsigned long clone_flags, unsigned long usp,
        swstack->return_ip = (unsigned long) ret_from_fork;
 
        /* Fix the user-mode and kernel-mode stackpointer. */
-       p->thread.usp = usp;
+       p->thread.usp = usp ?: rdusp();
        p->thread.ksp = (unsigned long) swstack;
 
        return 0;
 }
 
-/*
- * Be aware of the "magic" 7th argument in the four system-calls below.
- * They need the latest stackframe, which is put as the 7th argument by
- * entry.S. The previous arguments are dummies or actually used, but need
- * to be defined to reach the 7th argument.
- *
- * N.B.: Another method to get the stackframe is to use current_regs(). But
- * it returns the latest stack-frame stacked when going from _user mode_ and
- * some of these (at least sys_clone) are called from kernel-mode sometimes
- * (for example during kernel_thread, above) and thus cannot use it. Thus,
- * to be sure not to get any surprises, we use the method for the other calls
- * as well.
- */
-asmlinkage int
-sys_fork(long r10, long r11, long r12, long r13, long mof, long srp,
-       struct pt_regs *regs)
-{
-       return do_fork(SIGCHLD, rdusp(), regs, 0, NULL, NULL);
-}
-
-/* FIXME: Is parent_tid/child_tid really third/fourth argument? Update lib? */
-asmlinkage int
-sys_clone(unsigned long newusp, unsigned long flags, int *parent_tid, int *child_tid,
-       unsigned long tls, long srp, struct pt_regs *regs)
-{
-       if (!newusp)
-               newusp = rdusp();
-
-       return do_fork(flags, newusp, regs, 0, parent_tid, child_tid);
-}
-
-/*
- * vfork is a system call in i386 because of register-pressure - maybe
- * we can remove it and handle it in libc but we put it here until then.
- */
-asmlinkage int
-sys_vfork(long r10, long r11, long r12, long r13, long mof, long srp,
-       struct pt_regs *regs)
-{
-       return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), regs, 0, NULL, NULL);
-}
-
-/* sys_execve() executes a new program. */
-asmlinkage int
-sys_execve(const char *fname,
-          const char *const *argv,
-          const char *const *envp, long r13, long mof, long srp,
-          struct pt_regs *regs)
-{
-       int error;
-       struct filename *filename;
-
-       filename = getname(fname);
-       error = PTR_ERR(filename);
-
-       if (IS_ERR(filename))
-               goto out;
-
-       error = do_execve(filename->name, argv, envp, regs);
-       putname(filename);
- out:
-       return error;
-}
-
 unsigned long
 get_wchan(struct task_struct *p)
 {
index ef4e1bc..675823f 100644 (file)
@@ -49,8 +49,6 @@ struct task_struct;
 #define task_pt_regs(task) user_regs(task_thread_info(task))
 #define current_regs() task_pt_regs(current)
 
-extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
-
 unsigned long get_wchan(struct task_struct *p);
 
 #define KSTK_ESP(tsk)   ((tsk) == current ? rdusp() : (tsk)->thread.usp)
index ea6af9a..72dbbf5 100644 (file)
@@ -152,12 +152,6 @@ typedef struct sigaltstack {
 
 #ifdef __KERNEL__
 #include <asm/sigcontext.h>
-
-/* here we could define asm-optimized sigaddset, sigdelset etc. operations. 
- * if we don't, generic ones are used from linux/signal.h
- */
-#define ptrace_signal_deliver(regs, cookie) do { } while (0)
-
 #endif /* __KERNEL__ */
 
 #endif
index 51873a4..f27b542 100644 (file)
 #define __ARCH_WANT_SYS_SIGPROCMASK
 #define __ARCH_WANT_SYS_RT_SIGACTION
 #define __ARCH_WANT_SYS_RT_SIGSUSPEND
+#define __ARCH_WANT_SYS_EXECVE
+#define __ARCH_WANT_SYS_FORK
+#define __ARCH_WANT_SYS_VFORK
+#define __ARCH_WANT_SYS_CLONE
 
 /*
  * "Conditional" syscalls
index 7ac000f..5868cee 100644 (file)
@@ -30,7 +30,6 @@ extern void __negdi2(void);
 extern void iounmap(volatile void * __iomem);
 
 /* Platform dependent support */
-EXPORT_SYMBOL(kernel_thread);
 EXPORT_SYMBOL(get_cmos_time);
 EXPORT_SYMBOL(loops_per_usec);
 
index 2358634..1807d8e 100644 (file)
@@ -30,6 +30,9 @@
 #define __ARCH_WANT_SYS_RT_SIGACTION
 #define __ARCH_WANT_SYS_RT_SIGSUSPEND
 #define __ARCH_WANT_SYS_EXECVE
+#define __ARCH_WANT_SYS_FORK
+#define __ARCH_WANT_SYS_VFORK
+#define __ARCH_WANT_SYS_CLONE
 
 /*
  * "Conditional" syscalls
index 7e33215..23916b2 100644 (file)
@@ -139,42 +139,12 @@ inline unsigned long user_stack(const struct pt_regs *regs)
        return user_mode(regs) ? regs->sp : 0;
 }
 
-asmlinkage int sys_fork(void)
-{
-#ifndef CONFIG_MMU
-       /* fork almost works, enough to trick you into looking elsewhere:-( */
-       return -EINVAL;
-#else
-       return do_fork(SIGCHLD, user_stack(__frame), __frame, 0, NULL, NULL);
-#endif
-}
-
-asmlinkage int sys_vfork(void)
-{
-       return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, user_stack(__frame), __frame, 0,
-                      NULL, NULL);
-}
-
-/*****************************************************************************/
-/*
- * clone a process
- * - tlsptr is retrieved by copy_thread()
- */
-asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp,
-                        int __user *parent_tidptr, int __user *child_tidptr,
-                        int __user *tlsptr)
-{
-       if (!newsp)
-               newsp = user_stack(__frame);
-       return do_fork(clone_flags, newsp, __frame, 0, parent_tidptr, child_tidptr);
-} /* end sys_clone() */
-
 /*
  * set up the kernel stack and exception frames for a new process
  */
 int copy_thread(unsigned long clone_flags,
                unsigned long usp, unsigned long arg,
-               struct task_struct *p, struct pt_regs *regs)
+               struct task_struct *p)
 {
        struct pt_regs *childregs;
 
@@ -182,9 +152,7 @@ int copy_thread(unsigned long clone_flags,
                (task_stack_page(p) + THREAD_SIZE - FRV_FRAME0_SIZE);
 
        /* set up the userspace frame (the only place that the USP is stored) */
-       *childregs = *__kernel_frame0_ptr;
-
-       p->set_child_tid = p->clear_child_tid = NULL;
+       *childregs = *current_pt_regs();
 
        p->thread.frame  = childregs;
        p->thread.curr   = p;
@@ -193,18 +161,15 @@ int copy_thread(unsigned long clone_flags,
        p->thread.lr     = 0;
        p->thread.frame0 = childregs;
 
-       if (unlikely(!regs)) {
+       if (unlikely(p->flags & PF_KTHREAD)) {
                childregs->gr9 = usp; /* function */
                childregs->gr8 = arg;
                p->thread.pc = (unsigned long) ret_from_kernel_thread;
                save_user_regs(p->thread.user);
                return 0;
        }
-
-       /* set up the userspace frame (the only place that the USP is stored) */
-       *childregs = *regs;
-
-       childregs->sp           = usp;
+       if (usp)
+               childregs->sp = usp;
        childregs->next_frame   = NULL;
 
        p->thread.pc = (unsigned long) ret_from_fork;
index 98fabd1..04bef4d 100644 (file)
@@ -8,6 +8,8 @@ config H8300
        select GENERIC_IRQ_SHOW
        select GENERIC_CPU_DEVICES
        select MODULES_USE_ELF_RELA
+       select GENERIC_KERNEL_THREAD
+       select GENERIC_KERNEL_EXECVE
 
 config SYMBOL_PREFIX
        string
index 4c9f6f8..4b0ca49 100644 (file)
@@ -107,8 +107,6 @@ static inline void release_thread(struct task_struct *dead_task)
 {
 }
 
-extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
-
 /*
  * Free current thread data structures etc..
  */
index d09c440..7468589 100644 (file)
@@ -60,6 +60,9 @@ struct pt_regs {
 #define user_mode(regs) (!((regs)->ccr & PS_S))
 #define instruction_pointer(regs) ((regs)->pc)
 #define profile_pc(regs) instruction_pointer(regs)
+#define current_pt_regs() ((struct pt_regs *) \
+       (THREAD_SIZE + (unsigned long)current_thread_info()) - 1)
+#define signal_pt_regs() ((struct pt_regs *)current->thread.esp0)
 #endif /* __KERNEL__ */
 #endif /* __ASSEMBLY__ */
 #endif /* _H8300_PTRACE_H */
index fd8b66e..c43c0a7 100644 (file)
@@ -154,8 +154,6 @@ typedef struct sigaltstack {
 #include <asm/sigcontext.h>
 #undef __HAVE_ARCH_SIG_BITOPS
 
-#define ptrace_signal_deliver(regs, cookie) do { } while (0)
-
 #endif /* __KERNEL__ */
 
 #endif /* _H8300_SIGNAL_H */
index 5cd8828..c2c2f5c 100644 (file)
 #define __ARCH_WANT_SYS_SIGPROCMASK
 #define __ARCH_WANT_SYS_RT_SIGACTION
 #define __ARCH_WANT_SYS_RT_SIGSUSPEND
+#define __ARCH_WANT_SYS_EXECVE
+#define __ARCH_WANT_SYS_FORK
+#define __ARCH_WANT_SYS_VFORK
+#define __ARCH_WANT_SYS_CLONE
 
 /*
  * "Conditional" syscalls
index ca74316..617a687 100644 (file)
@@ -158,6 +158,7 @@ INTERRUPTS = 128
 .globl SYMBOL_NAME(system_call)
 .globl SYMBOL_NAME(ret_from_exception)
 .globl SYMBOL_NAME(ret_from_fork)
+.globl SYMBOL_NAME(ret_from_kernel_thread)
 .globl SYMBOL_NAME(ret_from_interrupt)
 .globl SYMBOL_NAME(interrupt_redirect_table)
 .globl SYMBOL_NAME(sw_ksp),SYMBOL_NAME(sw_usp)
@@ -330,6 +331,14 @@ SYMBOL_NAME_LABEL(ret_from_fork)
        jsr     @SYMBOL_NAME(schedule_tail)
        jmp     @SYMBOL_NAME(ret_from_exception)
 
+SYMBOL_NAME_LABEL(ret_from_kernel_thread)
+       mov.l   er2,er0
+       jsr     @SYMBOL_NAME(schedule_tail)
+       mov.l   @(LER4:16,sp),er0
+       mov.l   @(LER5:16,sp),er1
+       jsr     @er1
+       jmp     @SYMBOL_NAME(ret_from_exception)
+
 SYMBOL_NAME_LABEL(resume)
        /*
         * Beware - when entering resume, offset of tss is in d1,
index 6866bd9..53d7c0e 100644 (file)
@@ -33,7 +33,6 @@ EXPORT_SYMBOL(strncmp);
 
 EXPORT_SYMBOL(ip_fast_csum);
 
-EXPORT_SYMBOL(kernel_thread);
 EXPORT_SYMBOL(enable_irq);
 EXPORT_SYMBOL(disable_irq);
 
index e8dc139..b609f63 100644 (file)
@@ -47,6 +47,7 @@ void (*pm_power_off)(void) = NULL;
 EXPORT_SYMBOL(pm_power_off);
 
 asmlinkage void ret_from_fork(void);
+asmlinkage void ret_from_kernel_thread(void);
 
 /*
  * The idle loop on an H8/300..
@@ -122,113 +123,34 @@ void show_regs(struct pt_regs * regs)
                printk("\n");
 }
 
-/*
- * Create a kernel thread
- */
-int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
-{
-       long retval;
-       long clone_arg;
-       mm_segment_t fs;
-
-       fs = get_fs();
-       set_fs (KERNEL_DS);
-       clone_arg = flags | CLONE_VM;
-       __asm__("mov.l sp,er3\n\t"
-               "sub.l er2,er2\n\t"
-               "mov.l %2,er1\n\t"
-               "mov.l %1,er0\n\t"
-               "trapa #0\n\t"
-               "cmp.l sp,er3\n\t"
-               "beq 1f\n\t"
-               "mov.l %4,er0\n\t"
-               "mov.l %3,er1\n\t"
-               "jsr @er1\n\t"
-               "mov.l %5,er0\n\t"
-               "trapa #0\n"
-               "1:\n\t"
-               "mov.l er0,%0"
-               :"=r"(retval)
-               :"i"(__NR_clone),"g"(clone_arg),"g"(fn),"g"(arg),"i"(__NR_exit)
-               :"er0","er1","er2","er3");
-       set_fs (fs);
-       return retval;
-}
-
 void flush_thread(void)
 {
 }
 
-/*
- * "h8300_fork()".. By the time we get here, the
- * non-volatile registers have also been saved on the
- * stack. We do some ugly pointer stuff here.. (see
- * also copy_thread)
- */
-
-asmlinkage int h8300_fork(struct pt_regs *regs)
-{
-       return -EINVAL;
-}
-
-asmlinkage int h8300_vfork(struct pt_regs *regs)
-{
-       return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), regs, 0, NULL, NULL);
-}
-
-asmlinkage int h8300_clone(struct pt_regs *regs)
-{
-       unsigned long clone_flags;
-       unsigned long newsp;
-
-       /* syscall2 puts clone_flags in er1 and usp in er2 */
-       clone_flags = regs->er1;
-       newsp = regs->er2;
-       if (!newsp)
-               newsp  = rdusp();
-       return do_fork(clone_flags, newsp, regs, 0, NULL, NULL);
-
-}
-
 int copy_thread(unsigned long clone_flags,
                 unsigned long usp, unsigned long topstk,
-                struct task_struct * p, struct pt_regs * regs)
+                struct task_struct * p)
 {
        struct pt_regs * childregs;
 
        childregs = (struct pt_regs *) (THREAD_SIZE + task_stack_page(p)) - 1;
 
-       *childregs = *regs;
+       if (unlikely(p->flags & PF_KTHREAD)) {
+               memset(childregs, 0, sizeof(struct pt_regs));
+               childregs->retpc = (unsigned long) ret_from_kernel_thread;
+               childregs->er4 = topstk; /* arg */
+               childregs->er5 = usp; /* fn */
+               p->thread.ksp = (unsigned long)childregs;
+       }
+       *childregs = *current_pt_regs();
        childregs->retpc = (unsigned long) ret_from_fork;
        childregs->er0 = 0;
-
-       p->thread.usp = usp;
+       p->thread.usp = usp ?: rdusp();
        p->thread.ksp = (unsigned long)childregs;
 
        return 0;
 }
 
-/*
- * sys_execve() executes a new program.
- */
-asmlinkage int sys_execve(const char *name,
-                         const char *const *argv,
-                         const char *const *envp,
-                         int dummy, ...)
-{
-       int error;
-       struct filename *filename;
-       struct pt_regs *regs = (struct pt_regs *) ((unsigned char *)&dummy-4);
-
-       filename = getname(name);
-       error = PTR_ERR(filename);
-       if (IS_ERR(filename))
-               return error;
-       error = do_execve(filename->name, argv, envp, regs);
-       putname(filename);
-       return error;
-}
-
 unsigned long thread_saved_pc(struct task_struct *tsk)
 {
        return ((struct pt_regs *)tsk->thread.esp0)->pc;
index 4bdc731..bf350cb 100644 (file)
@@ -46,29 +46,3 @@ asmlinkage void syscall_print(void *dummy,...)
                ((regs->pc)&0xffffff)-2,regs->orig_er0,regs->er1,regs->er2,regs->er3,regs->er0);
 }
 #endif
-
-/*
- * Do a system call from kernel instead of calling sys_execve so we
- * end up with proper pt_regs.
- */
-asmlinkage
-int kernel_execve(const char *filename,
-                 const char *const argv[],
-                 const char *const envp[])
-{
-       register long res __asm__("er0");
-       register const char *const *_c __asm__("er3") = envp;
-       register const char *const *_b __asm__("er2") = argv;
-       register const char * _a __asm__("er1") = filename;
-       __asm__ __volatile__ ("mov.l %1,er0\n\t"
-                       "trapa  #0\n\t"
-                       : "=r" (res)
-                       : "g" (__NR_execve),
-                         "g" (_a),
-                         "g" (_b),
-                         "g" (_c)
-                       : "cc", "memory");
-       return res;
-}
-
-
index 9d77e71..b74dd0a 100644 (file)
@@ -340,21 +340,12 @@ SYMBOL_NAME_LABEL(sys_call_table)
        bra     SYMBOL_NAME(syscall_trampoline):8
        .endm
 
-SYMBOL_NAME_LABEL(sys_clone)   
-       call_sp h8300_clone
-       
 SYMBOL_NAME_LABEL(sys_sigreturn)
        call_sp do_sigreturn
 
 SYMBOL_NAME_LABEL(sys_rt_sigreturn)
        call_sp do_rt_sigreturn
 
-SYMBOL_NAME_LABEL(sys_fork)
-       call_sp h8300_fork
-
-SYMBOL_NAME_LABEL(sys_vfork)
-       call_sp h8300_vfork
-
 SYMBOL_NAME_LABEL(syscall_trampoline)
        mov.l   sp,er0
        jmp     @er6
index 0744f7d..e418803 100644 (file)
@@ -31,6 +31,8 @@ config HEXAGON
        select GENERIC_CLOCKEVENTS
        select GENERIC_CLOCKEVENTS_BROADCAST
        select MODULES_USE_ELF_RELA
+       select GENERIC_KERNEL_THREAD
+       select GENERIC_KERNEL_EXECVE
        ---help---
          Qualcomm Hexagon is a processor architecture designed for high
          performance and low power across a wide variety of applications.
index a03323a..6dd5d37 100644 (file)
@@ -34,7 +34,6 @@
 struct task_struct;
 
 /*  this is defined in arch/process.c  */
-extern pid_t kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
 extern unsigned long thread_saved_pc(struct task_struct *tsk);
 
 extern void start_thread(struct pt_regs *, unsigned long, unsigned long);
index fb0e9d4..4af9c7b 100644 (file)
@@ -25,14 +25,6 @@ typedef long (*syscall_fn)(unsigned long, unsigned long,
        unsigned long, unsigned long,
        unsigned long, unsigned long);
 
-asmlinkage int sys_execve(char __user *ufilename, char __user * __user *argv,
-                         char __user * __user *envp);
-asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp,
-                        unsigned long parent_tidp, unsigned long child_tidp);
-
-#define sys_execve     sys_execve
-#define sys_clone      sys_clone
-
 #include <asm-generic/syscalls.h>
 
 extern void *sys_call_table[];
index 8ef7840..1ffce0c 100644 (file)
@@ -32,4 +32,8 @@
 extern int regs_query_register_offset(const char *name);
 extern const char *regs_query_register_name(unsigned int offset);
 
+#define current_pt_regs() \
+       ((struct pt_regs *) \
+        ((unsigned long)current_thread_info() + THREAD_SIZE) - 1)
+
 #endif
index 81312d6..2af8153 100644 (file)
@@ -27,5 +27,7 @@
  */
 
 #define sys_mmap2 sys_mmap_pgoff
+#define __ARCH_WANT_SYS_EXECVE
+#define __ARCH_WANT_SYS_CLONE
 
 #include <asm-generic/unistd.h>
index 536aec0..6c19501 100644 (file)
@@ -3,8 +3,7 @@ extra-y := head.o vmlinux.lds
 obj-$(CONFIG_SMP) += smp.o topology.o
 
 obj-y += setup.o irq_cpu.o traps.o syscalltab.o signal.o time.o
-obj-y += process.o syscall.o trampoline.o reset.o ptrace.o
-obj-y += vdso.o
+obj-y += process.o trampoline.o reset.o ptrace.o vdso.o
 
 obj-$(CONFIG_KGDB)    += kgdb.o
 obj-$(CONFIG_MODULES) += module.o hexagon_ksyms.o
index 9f6d741..06ae9ff 100644 (file)
 #include <linux/slab.h>
 
 /*
- * Kernel thread creation.  The desired kernel function is "wrapped"
- * in the kernel_thread_helper function, which does cleanup
- * afterwards.
- */
-static void __noreturn kernel_thread_helper(void *arg, int (*fn)(void *))
-{
-       do_exit(fn(arg));
-}
-
-int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
-{
-       struct pt_regs regs;
-
-       memset(&regs, 0, sizeof(regs));
-       /*
-        * Yes, we're exploting illicit knowledge of the ABI here.
-        */
-       regs.r00 = (unsigned long) arg;
-       regs.r01 = (unsigned long) fn;
-       pt_set_elr(&regs, (unsigned long)kernel_thread_helper);
-       pt_set_kmode(&regs);
-
-       return do_fork(flags|CLONE_VM|CLONE_UNTRACED, 0, &regs, 0, NULL, NULL);
-}
-EXPORT_SYMBOL(kernel_thread);
-
-/*
  * Program thread launch.  Often defined as a macro in processor.h,
  * but we're shooting for a small footprint and it's not an inner-loop
  * performance-critical operation.
@@ -114,8 +87,7 @@ unsigned long thread_saved_pc(struct task_struct *tsk)
  * Copy architecture-specific thread state
  */
 int copy_thread(unsigned long clone_flags, unsigned long usp,
-               unsigned long unused, struct task_struct *p,
-               struct pt_regs *regs)
+               unsigned long arg, struct task_struct *p)
 {
        struct thread_info *ti = task_thread_info(p);
        struct hexagon_switch_stack *ss;
@@ -125,61 +97,51 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,
        childregs = (struct pt_regs *) (((unsigned long) ti + THREAD_SIZE) -
                                        sizeof(*childregs));
 
-       memcpy(childregs, regs, sizeof(*childregs));
        ti->regs = childregs;
 
        /*
         * Establish kernel stack pointer and initial PC for new thread
+        * Note that unlike the usual situation, we do not copy the
+        * parent's callee-saved here; those are in pt_regs and whatever
+        * we leave here will be overridden on return to userland.
         */
        ss = (struct hexagon_switch_stack *) ((unsigned long) childregs -
                                                    sizeof(*ss));
        ss->lr = (unsigned long)ret_from_fork;
        p->thread.switch_sp = ss;
+       if (unlikely(p->flags & PF_KTHREAD)) {
+               memset(childregs, 0, sizeof(struct pt_regs));
+               /* r24 <- fn, r25 <- arg */
+               ss->r2524 = usp | ((u64)arg << 32);
+               pt_set_kmode(childregs);
+               return 0;
+       }
+       memcpy(childregs, current_pt_regs(), sizeof(*childregs));
+       ss->r2524 = 0;
 
-       /* If User mode thread, set pt_reg stack pointer as per parameter */
-       if (user_mode(childregs)) {
+       if (usp)
                pt_set_rte_sp(childregs, usp);
 
-               /* Child sees zero return value */
-               childregs->r00 = 0;
-
-               /*
-                * The clone syscall has the C signature:
-                * int [r0] clone(int flags [r0],
-                *           void *child_frame [r1],
-                *           void *parent_tid [r2],
-                *           void *child_tid [r3],
-                *           void *thread_control_block [r4]);
-                * ugp is used to provide TLS support.
-                */
-               if (clone_flags & CLONE_SETTLS)
-                       childregs->ugp = childregs->r04;
-
-               /*
-                * Parent sees new pid -- not necessary, not even possible at
-                * this point in the fork process
-                * Might also want to set things like ti->addr_limit
-                */
-       } else {
-               /*
-                * If kernel thread, resume stack is kernel stack base.
-                * Note that this is pointer arithmetic on pt_regs *
-                */
-               pt_set_rte_sp(childregs, (unsigned long)(childregs + 1));
-               /*
-                * We need the current thread_info fast path pointer
-                * set up in pt_regs.  The register to be used is
-                * parametric for assembler code, but the mechanism
-                * doesn't drop neatly into C.  Needs to be fixed.
-                */
-               childregs->THREADINFO_REG = (unsigned long) ti;
-       }
+       /* Child sees zero return value */
+       childregs->r00 = 0;
+
+       /*
+        * The clone syscall has the C signature:
+        * int [r0] clone(int flags [r0],
+        *           void *child_frame [r1],
+        *           void *parent_tid [r2],
+        *           void *child_tid [r3],
+        *           void *thread_control_block [r4]);
+        * ugp is used to provide TLS support.
+        */
+       if (clone_flags & CLONE_SETTLS)
+               childregs->ugp = childregs->r04;
 
        /*
-        * thread_info pointer is pulled out of task_struct "stack"
-        * field on switch_to.
+        * Parent sees new pid -- not necessary, not even possible at
+        * this point in the fork process
+        * Might also want to set things like ti->addr_limit
         */
-       p->stack = (void *)ti;
 
        return 0;
 }
index 5047b8b..fe0d137 100644 (file)
@@ -249,14 +249,14 @@ void do_notify_resume(struct pt_regs *regs, unsigned long thread_info_flags)
  */
 asmlinkage int sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss)
 {
-       struct pt_regs *regs = current_thread_info()->regs;
+       struct pt_regs *regs = current_pt_regs();
 
        return do_sigaltstack(uss, uoss, regs->r29);
 }
 
 asmlinkage int sys_rt_sigreturn(void)
 {
-       struct pt_regs *regs = current_thread_info()->regs;
+       struct pt_regs *regs = current_pt_regs();
        struct rt_sigframe __user *frame;
        sigset_t blocked;
 
diff --git a/arch/hexagon/kernel/syscall.c b/arch/hexagon/kernel/syscall.c
deleted file mode 100644 (file)
index 319fa64..0000000
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Hexagon system calls
- *
- * Copyright (c) 2010-2011, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
- */
-
-#include <linux/file.h>
-#include <linux/fs.h>
-#include <linux/linkage.h>
-#include <linux/mm.h>
-#include <linux/module.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/syscalls.h>
-#include <linux/unistd.h>
-#include <asm/mman.h>
-#include <asm/registers.h>
-
-/*
- * System calls with architecture-specific wrappers.
- * See signal.c for signal-related system call wrappers.
- */
-
-asmlinkage int sys_execve(char __user *ufilename,
-                         const char __user *const __user *argv,
-                         const char __user *const __user *envp)
-{
-       struct pt_regs *pregs = current_thread_info()->regs;
-       struct filename *filename;
-       int retval;
-
-       filename = getname(ufilename);
-       retval = PTR_ERR(filename);
-       if (IS_ERR(filename))
-               return retval;
-
-       retval = do_execve(filename->name, argv, envp, pregs);
-       putname(filename);
-
-       return retval;
-}
-
-asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp,
-                        unsigned long parent_tidp, unsigned long child_tidp)
-{
-       struct pt_regs *pregs = current_thread_info()->regs;
-
-       if (!newsp)
-               newsp = pregs->SP;
-       return do_fork(clone_flags, newsp, pregs, 0, (int __user *)parent_tidp,
-                      (int __user *)child_tidp);
-}
-
-/*
- * Do a system call from the kernel, so as to have a proper pt_regs
- * and recycle the sys_execvpe infrustructure.
- */
-int kernel_execve(const char *filename,
-                 const char *const argv[], const char *const envp[])
-{
-       register unsigned long __a0 asm("r0") = (unsigned long) filename;
-       register unsigned long __a1 asm("r1") = (unsigned long) argv;
-       register unsigned long __a2 asm("r2") = (unsigned long) envp;
-       int retval;
-
-       __asm__ volatile(
-               "       R6 = #%4;\n"
-               "       trap0(#1);\n"
-               "       %0 = R0;\n"
-               : "=r" (retval)
-               : "r" (__a0), "r" (__a1), "r" (__a2), "i" (__NR_execve)
-       );
-
-       return retval;
-}
index cd71673..425e50c 100644 (file)
@@ -266,4 +266,8 @@ _K_enter_machcheck:
        .globl ret_from_fork
 ret_from_fork:
        call schedule_tail
+       P0 = cmp.eq(R24, #0);
+       if P0 jump return_from_syscall
+       R0 = R25;
+       callr R24
        jump return_from_syscall
index 3279646..6706004 100644 (file)
@@ -42,6 +42,8 @@ config IA64
        select GENERIC_TIME_VSYSCALL_OLD
        select HAVE_MOD_ARCH_SPECIFIC
        select MODULES_USE_ELF_RELA
+       select GENERIC_KERNEL_THREAD
+       select GENERIC_KERNEL_EXECVE
        default y
        help
          The Itanium Processor Family is Intel's 64-bit successor to
index 944152a..e0a899a 100644 (file)
@@ -340,22 +340,6 @@ struct task_struct;
  */
 #define release_thread(dead_task)
 
-/*
- * This is the mechanism for creating a new kernel thread.
- *
- * NOTE 1: Only a kernel-only process (ie the swapper or direct
- * descendants who haven't done an "execve()") should use this: it
- * will work within a system call from a "real" process, but the
- * process memory space will not be free'd until both the parent and
- * the child have exited.
- *
- * NOTE 2: This MUST NOT be an inlined function.  Otherwise, we get
- * into trouble in init/main.c when the child thread returns to
- * do_basic_setup() and the timing is such that free_initmem() has
- * been called already.
- */
-extern pid_t kernel_thread (int (*fn)(void *), void *arg, unsigned long flags);
-
 /* Get wait channel for task P.  */
 extern unsigned long get_wchan (struct task_struct *p);
 
index aecda5b..3a1b20e 100644 (file)
@@ -38,7 +38,5 @@ struct k_sigaction {
 
 #  include <asm/sigcontext.h>
 
-#define ptrace_signal_deliver(regs, cookie) do { } while (0)
-
 # endif /* !__ASSEMBLY__ */
 #endif /* _ASM_IA64_SIGNAL_H */
index 8b3ff2f..1574bca 100644 (file)
@@ -29,6 +29,7 @@
 
 #define __ARCH_WANT_SYS_RT_SIGACTION
 #define __ARCH_WANT_SYS_RT_SIGSUSPEND
+#define __ARCH_WANT_SYS_EXECVE
 
 #if !defined(__ASSEMBLY__) && !defined(ASSEMBLER)
 
index 1ccbe12..e25b784 100644 (file)
@@ -61,14 +61,13 @@ ENTRY(ia64_execve)
         * Allocate 8 input registers since ptrace() may clobber them
         */
        .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8)
-       alloc loc1=ar.pfs,8,2,4,0
+       alloc loc1=ar.pfs,8,2,3,0
        mov loc0=rp
        .body
        mov out0=in0                    // filename
        ;;                              // stop bit between alloc and call
        mov out1=in1                    // argv
        mov out2=in2                    // envp
-       add out3=16,sp                  // regs
        br.call.sptk.many rp=sys_execve
 .ret0:
        cmp4.ge p6,p7=r8,r0
@@ -76,7 +75,6 @@ ENTRY(ia64_execve)
        sxt4 r8=r8                      // return 64-bit result
        ;;
        stf.spill [sp]=f0
-(p6)   cmp.ne pKStk,pUStk=r0,r0        // a successful execve() lands us in user-mode...
        mov rp=loc0
 (p6)   mov ar.pfs=r0                   // clear ar.pfs on success
 (p7)   br.ret.sptk.many rp
@@ -118,13 +116,12 @@ GLOBAL_ENTRY(sys_clone2)
        mov loc1=r16                            // save ar.pfs across do_fork
        .body
        mov out1=in1
-       mov out3=in2
+       mov out2=in2
        tbit.nz p6,p0=in0,CLONE_SETTLS_BIT
-       mov out4=in3    // parent_tidptr: valid only w/CLONE_PARENT_SETTID
+       mov out3=in3    // parent_tidptr: valid only w/CLONE_PARENT_SETTID
        ;;
 (p6)   st8 [r2]=in5                            // store TLS in r16 for copy_thread()
-       mov out5=in4    // child_tidptr:  valid only w/CLONE_CHILD_SETTID or CLONE_CHILD_CLEARTID
-       adds out2=IA64_SWITCH_STACK_SIZE+16,sp  // out2 = &regs
+       mov out4=in4    // child_tidptr:  valid only w/CLONE_CHILD_SETTID or CLONE_CHILD_CLEARTID
        mov out0=in0                            // out0 = clone_flags
        br.call.sptk.many rp=do_fork
 .ret1: .restore sp
@@ -150,13 +147,12 @@ GLOBAL_ENTRY(sys_clone)
        mov loc1=r16                            // save ar.pfs across do_fork
        .body
        mov out1=in1
-       mov out3=16                             // stacksize (compensates for 16-byte scratch area)
+       mov out2=16                             // stacksize (compensates for 16-byte scratch area)
        tbit.nz p6,p0=in0,CLONE_SETTLS_BIT
-       mov out4=in2    // parent_tidptr: valid only w/CLONE_PARENT_SETTID
+       mov out3=in2    // parent_tidptr: valid only w/CLONE_PARENT_SETTID
        ;;
 (p6)   st8 [r2]=in4                            // store TLS in r13 (tp)
-       mov out5=in3    // child_tidptr:  valid only w/CLONE_CHILD_SETTID or CLONE_CHILD_CLEARTID
-       adds out2=IA64_SWITCH_STACK_SIZE+16,sp  // out2 = &regs
+       mov out4=in3    // child_tidptr:  valid only w/CLONE_CHILD_SETTID or CLONE_CHILD_CLEARTID
        mov out0=in0                            // out0 = clone_flags
        br.call.sptk.many rp=do_fork
 .ret2: .restore sp
@@ -484,19 +480,6 @@ GLOBAL_ENTRY(prefetch_stack)
        br.ret.sptk.many rp
 END(prefetch_stack)
 
-GLOBAL_ENTRY(kernel_execve)
-       rum psr.ac
-       mov r15=__NR_execve                     // put syscall number in place
-       break __BREAK_SYSCALL
-       br.ret.sptk.many rp
-END(kernel_execve)
-
-GLOBAL_ENTRY(clone)
-       mov r15=__NR_clone                      // put syscall number in place
-       break __BREAK_SYSCALL
-       br.ret.sptk.many rp
-END(clone)
-
        /*
         * Invoke a system call, but do some tracing before and after the call.
         * We MUST preserve the current register frame throughout this routine
@@ -600,6 +583,27 @@ GLOBAL_ENTRY(ia64_strace_leave_kernel)
 .ret4: br.cond.sptk ia64_leave_kernel
 END(ia64_strace_leave_kernel)
 
+ENTRY(call_payload)
+       .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(0)
+       /* call the kernel_thread payload; fn is in r4, arg - in r5 */
+       alloc loc1=ar.pfs,0,3,1,0
+       mov loc0=rp
+       mov loc2=gp
+       mov out0=r5             // arg
+       ld8 r14 = [r4], 8       // fn.address
+       ;;
+       mov b6 = r14
+       ld8 gp = [r4]           // fn.gp
+       ;;
+       br.call.sptk.many rp=b6 // fn(arg)
+.ret12:        mov gp=loc2
+       mov rp=loc0
+       mov ar.pfs=loc1
+       /* ... and if it has returned, we are going to userland */
+       cmp.ne pKStk,pUStk=r0,r0
+       br.ret.sptk.many rp
+END(call_payload)
+
 GLOBAL_ENTRY(ia64_ret_from_clone)
        PT_REGS_UNWIND_INFO(0)
 {      /*
@@ -616,6 +620,7 @@ GLOBAL_ENTRY(ia64_ret_from_clone)
        br.call.sptk.many rp=ia64_invoke_schedule_tail
 }
 .ret8:
+(pKStk)        br.call.sptk.many rp=call_payload
        adds r2=TI_FLAGS+IA64_TASK_SIZE,r13
        ;;
        ld4 r2=[r2]
index 629a250..4738ff7 100644 (file)
@@ -1093,19 +1093,6 @@ GLOBAL_ENTRY(cycle_to_cputime)
 END(cycle_to_cputime)
 #endif /* CONFIG_VIRT_CPU_ACCOUNTING */
 
-GLOBAL_ENTRY(start_kernel_thread)
-       .prologue
-       .save rp, r0                            // this is the end of the call-chain
-       .body
-       alloc r2 = ar.pfs, 0, 0, 2, 0
-       mov out0 = r9
-       mov out1 = r11;;
-       br.call.sptk.many rp = kernel_thread_helper;;
-       mov out0 = r8
-       br.call.sptk.many rp = sys_exit;;
-1:     br.sptk.few 1b                          // not reached
-END(start_kernel_thread)
-
 #ifdef CONFIG_IA64_BRL_EMU
 
 /*
index 35e106f..31360cb 100644 (file)
@@ -393,72 +393,24 @@ ia64_load_extra (struct task_struct *task)
 int
 copy_thread(unsigned long clone_flags,
             unsigned long user_stack_base, unsigned long user_stack_size,
-            struct task_struct *p, struct pt_regs *regs)
+            struct task_struct *p)
 {
        extern char ia64_ret_from_clone;
        struct switch_stack *child_stack, *stack;
        unsigned long rbs, child_rbs, rbs_size;
        struct pt_regs *child_ptregs;
+       struct pt_regs *regs = current_pt_regs();
        int retval = 0;
 
-#ifdef CONFIG_SMP
-       /*
-        * For SMP idle threads, fork_by_hand() calls do_fork with
-        * NULL regs.
-        */
-       if (!regs)
-               return 0;
-#endif
-
-       stack = ((struct switch_stack *) regs) - 1;
-
        child_ptregs = (struct pt_regs *) ((unsigned long) p + IA64_STK_OFFSET) - 1;
        child_stack = (struct switch_stack *) child_ptregs - 1;
 
-       /* copy parent's switch_stack & pt_regs to child: */
-       memcpy(child_stack, stack, sizeof(*child_ptregs) + sizeof(*child_stack));
-
        rbs = (unsigned long) current + IA64_RBS_OFFSET;
        child_rbs = (unsigned long) p + IA64_RBS_OFFSET;
-       rbs_size = stack->ar_bspstore - rbs;
-
-       /* copy the parent's register backing store to the child: */
-       memcpy((void *) child_rbs, (void *) rbs, rbs_size);
-
-       if (likely(user_mode(child_ptregs))) {
-               if (clone_flags & CLONE_SETTLS)
-                       child_ptregs->r13 = regs->r16;  /* see sys_clone2() in entry.S */
-               if (user_stack_base) {
-                       child_ptregs->r12 = user_stack_base + user_stack_size - 16;
-                       child_ptregs->ar_bspstore = user_stack_base;
-                       child_ptregs->ar_rnat = 0;
-                       child_ptregs->loadrs = 0;
-               }
-       } else {
-               /*
-                * Note: we simply preserve the relative position of
-                * the stack pointer here.  There is no need to
-                * allocate a scratch area here, since that will have
-                * been taken care of by the caller of sys_clone()
-                * already.
-                */
-               child_ptregs->r12 = (unsigned long) child_ptregs - 16; /* kernel sp */
-               child_ptregs->r13 = (unsigned long) p;          /* set `current' pointer */
-       }
-       child_stack->ar_bspstore = child_rbs + rbs_size;
-       child_stack->b0 = (unsigned long) &ia64_ret_from_clone;
 
        /* copy parts of thread_struct: */
        p->thread.ksp = (unsigned long) child_stack - 16;
 
-       /* stop some PSR bits from being inherited.
-        * the psr.up/psr.pp bits must be cleared on fork but inherited on execve()
-        * therefore we must specify them explicitly here and not include them in
-        * IA64_PSR_BITS_TO_CLEAR.
-        */
-       child_ptregs->cr_ipsr = ((child_ptregs->cr_ipsr | IA64_PSR_BITS_TO_SET)
-                                & ~(IA64_PSR_BITS_TO_CLEAR | IA64_PSR_PP | IA64_PSR_UP));
-
        /*
         * NOTE: The calling convention considers all floating point
         * registers in the high partition (fph) to be scratch.  Since
@@ -480,8 +432,66 @@ copy_thread(unsigned long clone_flags,
 #      define THREAD_FLAGS_TO_SET      0
        p->thread.flags = ((current->thread.flags & ~THREAD_FLAGS_TO_CLEAR)
                           | THREAD_FLAGS_TO_SET);
+
        ia64_drop_fpu(p);       /* don't pick up stale state from a CPU's fph */
 
+       if (unlikely(p->flags & PF_KTHREAD)) {
+               if (unlikely(!user_stack_base)) {
+                       /* fork_idle() called us */
+                       return 0;
+               }
+               memset(child_stack, 0, sizeof(*child_ptregs) + sizeof(*child_stack));
+               child_stack->r4 = user_stack_base;      /* payload */
+               child_stack->r5 = user_stack_size;      /* argument */
+               /*
+                * Preserve PSR bits, except for bits 32-34 and 37-45,
+                * which we can't read.
+                */
+               child_ptregs->cr_ipsr = ia64_getreg(_IA64_REG_PSR) | IA64_PSR_BN;
+               /* mark as valid, empty frame */
+               child_ptregs->cr_ifs = 1UL << 63;
+               child_stack->ar_fpsr = child_ptregs->ar_fpsr
+                       = ia64_getreg(_IA64_REG_AR_FPSR);
+               child_stack->pr = (1 << PRED_KERNEL_STACK);
+               child_stack->ar_bspstore = child_rbs;
+               child_stack->b0 = (unsigned long) &ia64_ret_from_clone;
+
+               /* stop some PSR bits from being inherited.
+                * the psr.up/psr.pp bits must be cleared on fork but inherited on execve()
+                * therefore we must specify them explicitly here and not include them in
+                * IA64_PSR_BITS_TO_CLEAR.
+                */
+               child_ptregs->cr_ipsr = ((child_ptregs->cr_ipsr | IA64_PSR_BITS_TO_SET)
+                                & ~(IA64_PSR_BITS_TO_CLEAR | IA64_PSR_PP | IA64_PSR_UP));
+
+               return 0;
+       }
+       stack = ((struct switch_stack *) regs) - 1;
+       /* copy parent's switch_stack & pt_regs to child: */
+       memcpy(child_stack, stack, sizeof(*child_ptregs) + sizeof(*child_stack));
+
+       /* copy the parent's register backing store to the child: */
+       rbs_size = stack->ar_bspstore - rbs;
+       memcpy((void *) child_rbs, (void *) rbs, rbs_size);
+       if (clone_flags & CLONE_SETTLS)
+               child_ptregs->r13 = regs->r16;  /* see sys_clone2() in entry.S */
+       if (user_stack_base) {
+               child_ptregs->r12 = user_stack_base + user_stack_size - 16;
+               child_ptregs->ar_bspstore = user_stack_base;
+               child_ptregs->ar_rnat = 0;
+               child_ptregs->loadrs = 0;
+       }
+       child_stack->ar_bspstore = child_rbs + rbs_size;
+       child_stack->b0 = (unsigned long) &ia64_ret_from_clone;
+
+       /* stop some PSR bits from being inherited.
+        * the psr.up/psr.pp bits must be cleared on fork but inherited on execve()
+        * therefore we must specify them explicitly here and not include them in
+        * IA64_PSR_BITS_TO_CLEAR.
+        */
+       child_ptregs->cr_ipsr = ((child_ptregs->cr_ipsr | IA64_PSR_BITS_TO_SET)
+                                & ~(IA64_PSR_BITS_TO_CLEAR | IA64_PSR_PP | IA64_PSR_UP));
+
 #ifdef CONFIG_PERFMON
        if (current->thread.pfm_context)
                pfm_inherit(p, child_ptregs);
@@ -608,57 +618,6 @@ dump_fpu (struct pt_regs *pt, elf_fpregset_t dst)
        return 1;       /* f0-f31 are always valid so we always return 1 */
 }
 
-long
-sys_execve (const char __user *filename,
-           const char __user *const __user *argv,
-           const char __user *const __user *envp,
-           struct pt_regs *regs)
-{
-       struct filename *fname;
-       int error;
-
-       fname = getname(filename);
-       error = PTR_ERR(fname);
-       if (IS_ERR(fname))
-               goto out;
-       error = do_execve(fname->name, argv, envp, regs);
-       putname(fname);
-out:
-       return error;
-}
-
-pid_t
-kernel_thread (int (*fn)(void *), void *arg, unsigned long flags)
-{
-       extern void start_kernel_thread (void);
-       unsigned long *helper_fptr = (unsigned long *) &start_kernel_thread;
-       struct {
-               struct switch_stack sw;
-               struct pt_regs pt;
-       } regs;
-
-       memset(&regs, 0, sizeof(regs));
-       regs.pt.cr_iip = helper_fptr[0];        /* set entry point (IP) */
-       regs.pt.r1 = helper_fptr[1];            /* set GP */
-       regs.pt.r9 = (unsigned long) fn;        /* 1st argument */
-       regs.pt.r11 = (unsigned long) arg;      /* 2nd argument */
-       /* Preserve PSR bits, except for bits 32-34 and 37-45, which we can't read.  */
-       regs.pt.cr_ipsr = ia64_getreg(_IA64_REG_PSR) | IA64_PSR_BN;
-       regs.pt.cr_ifs = 1UL << 63;             /* mark as valid, empty frame */
-       regs.sw.ar_fpsr = regs.pt.ar_fpsr = ia64_getreg(_IA64_REG_AR_FPSR);
-       regs.sw.ar_bspstore = (unsigned long) current + IA64_RBS_OFFSET;
-       regs.sw.pr = (1 << PRED_KERNEL_STACK);
-       return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, &regs.pt, 0, NULL, NULL);
-}
-EXPORT_SYMBOL(kernel_thread);
-
-/* This gets called from kernel_thread() via ia64_invoke_thread_helper().  */
-int
-kernel_thread_helper (int (*fn)(void *), void *arg)
-{
-       return (*fn)(arg);
-}
-
 /*
  * Flush thread state.  This is called when a thread does an execve().
  */
index 963d2db..6a368cb 100644 (file)
@@ -460,11 +460,6 @@ start_secondary (void *unused)
        return 0;
 }
 
-struct pt_regs * __cpuinit idle_regs(struct pt_regs *regs)
-{
-       return NULL;
-}
-
 static int __cpuinit
 do_boot_cpu (int sapicid, int cpu, struct task_struct *idle)
 {
index f807721..5183f43 100644 (file)
@@ -15,6 +15,8 @@ config M32R
        select GENERIC_ATOMIC64
        select ARCH_USES_GETTIMEOFFSET
        select MODULES_USE_ELF_RELA
+       select GENERIC_KERNEL_THREAD
+       select GENERIC_KERNEL_EXECVE
 
 config SBUS
        bool
index da17253..5767367 100644 (file)
@@ -118,11 +118,6 @@ struct mm_struct;
 /* Free all resources held by a thread. */
 extern void release_thread(struct task_struct *);
 
-/*
- * create a kernel thread without removing it from tasklists
- */
-extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
-
 /* Copy and release all segment info associated with a VM */
 extern void copy_segments(struct task_struct *p, struct mm_struct * mm);
 extern void release_segments(struct mm_struct * mm);
index 4313aa6..c4432f1 100644 (file)
@@ -139,6 +139,8 @@ extern void withdraw_debug_trap(struct pt_regs *regs);
 
 #define task_pt_regs(task) \
         ((struct pt_regs *)(task_stack_page(task) + THREAD_SIZE) - 1)
+#define current_pt_regs() ((struct pt_regs *) \
+       ((unsigned long)current_thread_info() + THREAD_SIZE) - 1)
 
 #endif /* __KERNEL */
 
index ea5f95e..e4d2e2a 100644 (file)
@@ -149,10 +149,6 @@ typedef struct sigaltstack {
 
 #undef __HAVE_ARCH_SIG_BITOPS
 
-struct pt_regs;
-
-#define ptrace_signal_deliver(regs, cookie)    do { } while (0)
-
 #endif /* __KERNEL__ */
 
 #endif  /* _ASM_M32R_SIGNAL_H */
index d5e66a4..d9e7351 100644 (file)
 #define __ARCH_WANT_SYS_OLDUMOUNT
 #define __ARCH_WANT_SYS_RT_SIGACTION
 #define __ARCH_WANT_SYS_RT_SIGSUSPEND
+#define __ARCH_WANT_SYS_EXECVE
+#define __ARCH_WANT_SYS_CLONE
+#define __ARCH_WANT_SYS_FORK
+#define __ARCH_WANT_SYS_VFORK
 
 #define __IGNORE_lchown
 #define __IGNORE_setuid
index 225412b..0c01543 100644 (file)
        and     \reg, sp
        .endm
 
+ENTRY(ret_from_kernel_thread)
+       pop     r0
+       bl      schedule_tail
+       GET_THREAD_INFO(r8)
+       ld      r0, R0(r8)
+       ld      r1, R1(r8)
+       jl      r1
+       bra     syscall_exit
+
 ENTRY(ret_from_fork)
        pop     r0
        bl      schedule_tail
index 7005707..b727e69 100644 (file)
@@ -21,7 +21,6 @@ EXPORT_SYMBOL(boot_cpu_data);
 EXPORT_SYMBOL(dump_fpu);
 EXPORT_SYMBOL(__ioremap);
 EXPORT_SYMBOL(iounmap);
-EXPORT_SYMBOL(kernel_thread);
 
 EXPORT_SYMBOL(strncpy_from_user);
 EXPORT_SYMBOL(__strncpy_from_user);
index e736627..765d0f5 100644 (file)
@@ -165,41 +165,6 @@ void show_regs(struct pt_regs * regs)
 }
 
 /*
- * Create a kernel thread
- */
-
-/*
- * This is the mechanism for creating a new kernel thread.
- *
- * NOTE! Only a kernel-only process(ie the swapper or direct descendants
- * who haven't done an "execve()") should use this: it will work within
- * a system call from a "real" process, but the process memory space will
- * not be free'd until both the parent and the child have exited.
- */
-static void kernel_thread_helper(void *nouse, int (*fn)(void *), void *arg)
-{
-       fn(arg);
-       do_exit(-1);
-}
-
-int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
-{
-       struct pt_regs regs;
-
-       memset(&regs, 0, sizeof (regs));
-       regs.r1 = (unsigned long)fn;
-       regs.r2 = (unsigned long)arg;
-
-       regs.bpc = (unsigned long)kernel_thread_helper;
-
-       regs.psw = M32R_PSW_BIE;
-
-       /* Ok, create the new process. */
-       return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, &regs, 0, NULL,
-               NULL);
-}
-
-/*
  * Free current thread data structures etc..
  */
 void exit_thread(void)
@@ -227,88 +192,31 @@ int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu)
 }
 
 int copy_thread(unsigned long clone_flags, unsigned long spu,
-       unsigned long unused, struct task_struct *tsk, struct pt_regs *regs)
+       unsigned long arg, struct task_struct *tsk)
 {
        struct pt_regs *childregs = task_pt_regs(tsk);
        extern void ret_from_fork(void);
-
-       /* Copy registers */
-       *childregs = *regs;
-
-       childregs->spu = spu;
-       childregs->r0 = 0;      /* Child gets zero as return value */
-       regs->r0 = tsk->pid;
+       extern void ret_from_kernel_thread(void);
+
+       if (unlikely(tsk->flags & PF_KTHREAD)) {
+               memset(childregs, 0, sizeof(struct pt_regs));
+               childregs->psw = M32R_PSW_BIE;
+               childregs->r1 = spu;    /* fn */
+               childregs->r0 = arg;
+               tsk->thread.lr = (unsigned long)ret_from_kernel_thread;
+       } else {
+               /* Copy registers */
+               *childregs = *current_pt_regs();
+               if (spu)
+                       childregs->spu = spu;
+               childregs->r0 = 0;      /* Child gets zero as return value */
+               tsk->thread.lr = (unsigned long)ret_from_fork;
+       }
        tsk->thread.sp = (unsigned long)childregs;
-       tsk->thread.lr = (unsigned long)ret_from_fork;
 
        return 0;
 }
 
-asmlinkage int sys_fork(unsigned long r0, unsigned long r1, unsigned long r2,
-       unsigned long r3, unsigned long r4, unsigned long r5, unsigned long r6,
-       struct pt_regs regs)
-{
-#ifdef CONFIG_MMU
-       return do_fork(SIGCHLD, regs.spu, &regs, 0, NULL, NULL);
-#else
-       return -EINVAL;
-#endif /* CONFIG_MMU */
-}
-
-asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp,
-                        unsigned long parent_tidptr,
-                        unsigned long child_tidptr,
-                        unsigned long r4, unsigned long r5, unsigned long r6,
-                        struct pt_regs regs)
-{
-       if (!newsp)
-               newsp = regs.spu;
-
-       return do_fork(clone_flags, newsp, &regs, 0,
-                      (int __user *)parent_tidptr, (int __user *)child_tidptr);
-}
-
-/*
- * This is trivial, and on the face of it looks like it
- * could equally well be done in user mode.
- *
- * Not so, for quite unobvious reasons - register pressure.
- * In user mode vfork() cannot have a stack frame, and if
- * done by calling the "clone()" system call directly, you
- * do not have enough call-clobbered registers to hold all
- * the information you need.
- */
-asmlinkage int sys_vfork(unsigned long r0, unsigned long r1, unsigned long r2,
-       unsigned long r3, unsigned long r4, unsigned long r5, unsigned long r6,
-       struct pt_regs regs)
-{
-       return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs.spu, &regs, 0,
-                       NULL, NULL);
-}
-
-/*
- * sys_execve() executes a new program.
- */
-asmlinkage int sys_execve(const char __user *ufilename,
-                         const char __user *const __user *uargv,
-                         const char __user *const __user *uenvp,
-                         unsigned long r3, unsigned long r4, unsigned long r5,
-                         unsigned long r6, struct pt_regs regs)
-{
-       int error;
-       struct filename *filename;
-
-       filename = getname(ufilename);
-       error = PTR_ERR(filename);
-       if (IS_ERR(filename))
-               goto out;
-
-       error = do_execve(filename->name, uargv, uenvp, &regs);
-       putname(filename);
-out:
-       return error;
-}
-
 /*
  * These bracket the sleeping functions..
  */
index d841fb6..c3fdd63 100644 (file)
@@ -88,24 +88,3 @@ asmlinkage int sys_cachectl(char *addr, int nbytes, int op)
        /* Not implemented yet. */
        return -ENOSYS;
 }
-
-/*
- * Do a system call from kernel instead of calling sys_execve so we
- * end up with proper pt_regs.
- */
-int kernel_execve(const char *filename,
-                 const char *const argv[],
-                 const char *const envp[])
-{
-       register long __scno __asm__ ("r7") = __NR_execve;
-       register long __arg3 __asm__ ("r2") = (long)(envp);
-       register long __arg2 __asm__ ("r1") = (long)(argv);
-       register long __res __asm__ ("r0") = (long)(filename);
-       __asm__ __volatile__ (
-               "trap #" SYSCALL_VECTOR "|| nop"
-               : "=r" (__res)
-               : "r" (__scno), "0" (__res), "r" (__arg2),
-                       "r" (__arg3)
-               : "memory");
-       return __res;
-}
index e7c1614..953a7ba 100644 (file)
@@ -16,6 +16,7 @@ config M68K
        select ARCH_WANT_IPC_PARSE_VERSION
        select ARCH_USES_GETTIMEOFFSET if MMU && !COLDFIRE
        select GENERIC_KERNEL_THREAD
+       select GENERIC_KERNEL_EXECVE
        select HAVE_MOD_ARCH_SPECIFIC
        select MODULES_USE_ELF_REL
        select MODULES_USE_ELF_RELA
index 2df26b5..9c8c46b 100644 (file)
@@ -86,11 +86,9 @@ static inline int sigfindinword(unsigned long word)
 
 #endif /* !CONFIG_CPU_HAS_NO_BITFIELDS */
 
-#ifdef __uClinux__
-#define ptrace_signal_deliver(regs, cookie) do { } while (0)
-#else
-struct pt_regs;
-extern void ptrace_signal_deliver(struct pt_regs *regs, void *cookie);
+#ifndef __uClinux__
+extern void ptrace_signal_deliver(void);
+#define ptrace_signal_deliver ptrace_signal_deliver
 #endif /* __uClinux__ */
 
 #endif /* _M68K_SIGNAL_H */
index 5fc7f7b..a021d67 100644 (file)
@@ -32,7 +32,8 @@
 #define __ARCH_WANT_SYS_RT_SIGACTION
 #define __ARCH_WANT_SYS_RT_SIGSUSPEND
 #define __ARCH_WANT_SYS_EXECVE
-#define __ARCH_WANT_KERNEL_EXECVE
+#define __ARCH_WANT_SYS_FORK
+#define __ARCH_WANT_SYS_VFORK
 
 /*
  * "Conditional" syscalls
index 946cb01..a78f564 100644 (file)
 
 .globl system_call, buserr, trap, resume
 .globl sys_call_table
-.globl sys_fork, sys_clone, sys_vfork
+.globl __sys_fork, __sys_clone, __sys_vfork
 .globl ret_from_interrupt, bad_interrupt
 .globl auto_irqhandler_fixup
 .globl user_irqvec_fixup
 
 .text
-ENTRY(sys_fork)
+ENTRY(__sys_fork)
        SAVE_SWITCH_STACK
-       pea     %sp@(SWITCH_STACK_SIZE)
-       jbsr    m68k_fork
-       addql   #4,%sp
-       RESTORE_SWITCH_STACK
+       jbsr    sys_fork
+       lea     %sp@(24),%sp
        rts
 
-ENTRY(sys_clone)
+ENTRY(__sys_clone)
        SAVE_SWITCH_STACK
        pea     %sp@(SWITCH_STACK_SIZE)
        jbsr    m68k_clone
-       addql   #4,%sp
-       RESTORE_SWITCH_STACK
+       lea     %sp@(28),%sp
        rts
 
-ENTRY(sys_vfork)
+ENTRY(__sys_vfork)
        SAVE_SWITCH_STACK
-       pea     %sp@(SWITCH_STACK_SIZE)
-       jbsr    m68k_vfork
-       addql   #4,%sp
-       RESTORE_SWITCH_STACK
+       jbsr    sys_vfork
+       lea     %sp@(24),%sp
        rts
 
 ENTRY(sys_sigreturn)
@@ -115,16 +110,9 @@ ENTRY(ret_from_kernel_thread)
        | a3 contains the kernel thread payload, d7 - its argument
        movel   %d1,%sp@-
        jsr     schedule_tail
-       GET_CURRENT(%d0)
        movel   %d7,(%sp)
        jsr     %a3@
        addql   #4,%sp
-       movel   %d0,(%sp)
-       jra     sys_exit
-
-ENTRY(ret_from_kernel_execve)
-       movel   4(%sp), %sp
-       GET_CURRENT(%d0)
        jra     ret_from_exception
 
 #if defined(CONFIG_COLDFIRE) || !defined(CONFIG_MMU)
index c51bb17..d538694 100644 (file)
@@ -136,57 +136,35 @@ void flush_thread(void)
 }
 
 /*
- * "m68k_fork()".. By the time we get here, the
- * non-volatile registers have also been saved on the
- * stack. We do some ugly pointer stuff here.. (see
- * also copy_thread)
+ * Why not generic sys_clone, you ask?  m68k passes all arguments on stack.
+ * And we need all registers saved, which means a bunch of stuff pushed
+ * on top of pt_regs, which means that sys_clone() arguments would be
+ * buried.  We could, of course, copy them, but it's too costly for no
+ * good reason - generic clone() would have to copy them *again* for
+ * do_fork() anyway.  So in this case it's actually better to pass pt_regs *
+ * and extract arguments for do_fork() from there.  Eventually we might
+ * go for calling do_fork() directly from the wrapper, but only after we
+ * are finished with do_fork() prototype conversion.
  */
-
-asmlinkage int m68k_fork(struct pt_regs *regs)
-{
-#ifdef CONFIG_MMU
-       return do_fork(SIGCHLD, rdusp(), regs, 0, NULL, NULL);
-#else
-       return -EINVAL;
-#endif
-}
-
-asmlinkage int m68k_vfork(struct pt_regs *regs)
-{
-       return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), regs, 0,
-                      NULL, NULL);
-}
-
 asmlinkage int m68k_clone(struct pt_regs *regs)
 {
-       unsigned long clone_flags;
-       unsigned long newsp;
-       int __user *parent_tidptr, *child_tidptr;
-
-       /* syscall2 puts clone_flags in d1 and usp in d2 */
-       clone_flags = regs->d1;
-       newsp = regs->d2;
-       parent_tidptr = (int __user *)regs->d3;
-       child_tidptr = (int __user *)regs->d4;
-       if (!newsp)
-               newsp = rdusp();
-       return do_fork(clone_flags, newsp, regs, 0,
-                      parent_tidptr, child_tidptr);
+       /* regs will be equal to current_pt_regs() */
+       return do_fork(regs->d1, regs->d2, 0,
+                      (int __user *)regs->d3, (int __user *)regs->d4);
 }
 
 int copy_thread(unsigned long clone_flags, unsigned long usp,
-                unsigned long arg,
-                struct task_struct * p, struct pt_regs * regs)
+                unsigned long arg, struct task_struct *p)
 {
-       struct pt_regs * childregs;
-       struct switch_stack *childstack;
+       struct fork_frame {
+               struct switch_stack sw;
+               struct pt_regs regs;
+       } *frame;
 
-       childregs = (struct pt_regs *) (task_stack_page(p) + THREAD_SIZE) - 1;
-       childstack = ((struct switch_stack *) childregs) - 1;
+       frame = (struct fork_frame *) (task_stack_page(p) + THREAD_SIZE) - 1;
 
-       p->thread.usp = usp;
-       p->thread.ksp = (unsigned long)childstack;
-       p->thread.esp0 = (unsigned long)childregs;
+       p->thread.ksp = (unsigned long)frame;
+       p->thread.esp0 = (unsigned long)&frame->regs;
 
        /*
         * Must save the current SFC/DFC value, NOT the value when
@@ -194,25 +172,24 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,
         */
        p->thread.fs = get_fs().seg;
 
-       if (unlikely(!regs)) {
+       if (unlikely(p->flags & PF_KTHREAD)) {
                /* kernel thread */
-               memset(childstack, 0,
-                       sizeof(struct switch_stack) + sizeof(struct pt_regs));
-               childregs->sr = PS_S;
-               childstack->a3 = usp; /* function */
-               childstack->d7 = arg;
-               childstack->retpc = (unsigned long)ret_from_kernel_thread;
+               memset(frame, 0, sizeof(struct fork_frame));
+               frame->regs.sr = PS_S;
+               frame->sw.a3 = usp; /* function */
+               frame->sw.d7 = arg;
+               frame->sw.retpc = (unsigned long)ret_from_kernel_thread;
                p->thread.usp = 0;
                return 0;
        }
-       *childregs = *regs;
-       childregs->d0 = 0;
-
-       *childstack = ((struct switch_stack *) regs)[-1];
-       childstack->retpc = (unsigned long)ret_from_fork;
+       memcpy(frame, container_of(current_pt_regs(), struct fork_frame, regs),
+               sizeof(struct fork_frame));
+       frame->regs.d0 = 0;
+       frame->sw.retpc = (unsigned long)ret_from_fork;
+       p->thread.usp = usp ?: rdusp();
 
        if (clone_flags & CLONE_SETTLS)
-               task_thread_info(p)->tp_value = regs->d5;
+               task_thread_info(p)->tp_value = frame->regs.d5;
 
 #ifdef CONFIG_FPU
        if (!FPU_IS_EMU) {
index 710a528..9a396cd 100644 (file)
@@ -108,8 +108,9 @@ int handle_kernel_fault(struct pt_regs *regs)
        return 1;
 }
 
-void ptrace_signal_deliver(struct pt_regs *regs, void *cookie)
+void ptrace_signal_deliver(void)
 {
+       struct pt_regs *regs = signal_pt_regs();
        if (regs->orig_d0 < 0)
                return;
        switch (regs->d0) {
index 4fc2e29..c30da5b 100644 (file)
@@ -22,7 +22,7 @@ ALIGN
 ENTRY(sys_call_table)
        .long sys_restart_syscall       /* 0 - old "setup()" system call, used for restarting */
        .long sys_exit
-       .long sys_fork
+       .long __sys_fork
        .long sys_read
        .long sys_write
        .long sys_open                  /* 5 */
@@ -140,7 +140,7 @@ ENTRY(sys_call_table)
        .long sys_ipc
        .long sys_fsync
        .long sys_sigreturn
-       .long sys_clone                 /* 120 */
+       .long __sys_clone               /* 120 */
        .long sys_setdomainname
        .long sys_newuname
        .long sys_cacheflush            /* modify_ldt for i386 */
@@ -210,7 +210,7 @@ ENTRY(sys_call_table)
        .long sys_sendfile
        .long sys_ni_syscall            /* streams1 */
        .long sys_ni_syscall            /* streams2 */
-       .long sys_vfork                 /* 190 */
+       .long __sys_vfork               /* 190 */
        .long sys_getrlimit
        .long sys_mmap2
        .long sys_truncate64
index 4cba743..4bcf891 100644 (file)
@@ -26,6 +26,9 @@ config MICROBLAZE
        select GENERIC_ATOMIC64
        select GENERIC_CLOCKEVENTS
        select MODULES_USE_ELF_RELA
+       select GENERIC_KERNEL_THREAD
+       select GENERIC_KERNEL_EXECVE
+       select CLONE_BACKWARDS
 
 config SWAP
        def_bool n
index 2957fcc..eb3a46c 100644 (file)
@@ -4,3 +4,4 @@ header-y  += elf.h
 generic-y += clkdev.h
 generic-y += exec.h
 generic-y += trace_clock.h
+generic-y += syscalls.h
index af2bb96..0759153 100644 (file)
@@ -31,6 +31,7 @@ extern const struct seq_operations cpuinfo_op;
 void start_thread(struct pt_regs *regs, unsigned long pc, unsigned long usp);
 
 extern void ret_from_fork(void);
+extern void ret_from_kernel_thread(void);
 
 # endif /* __ASSEMBLY__ */
 
@@ -78,11 +79,6 @@ extern unsigned long thread_saved_pc(struct task_struct *t);
 
 extern unsigned long get_wchan(struct task_struct *p);
 
-/*
- * create a kernel thread without removing it from tasklists
- */
-extern int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags);
-
 # define KSTK_EIP(tsk) (0)
 # define KSTK_ESP(tsk) (0)
 
@@ -131,8 +127,6 @@ extern inline void release_thread(struct task_struct *dead_task)
 {
 }
 
-extern int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags);
-
 /* Free current thread data structures etc.  */
 static inline void exit_thread(void)
 {
diff --git a/arch/microblaze/include/asm/syscalls.h b/arch/microblaze/include/asm/syscalls.h
deleted file mode 100644 (file)
index 27f2f4c..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-#ifndef __ASM_MICROBLAZE_SYSCALLS_H
-
-asmlinkage long microblaze_vfork(struct pt_regs *regs);
-asmlinkage long microblaze_clone(int flags, unsigned long stack,
-                                                       struct pt_regs *regs);
-asmlinkage long microblaze_execve(const char __user *filenamei,
-                                 const char __user *const __user *argv,
-                                 const char __user *const __user *envp,
-                                 struct pt_regs *regs);
-
-asmlinkage long sys_clone(int flags, unsigned long stack, struct pt_regs *regs);
-#define sys_clone sys_clone
-
-#include <asm-generic/syscalls.h>
-
-#endif /* __ASM_MICROBLAZE_SYSCALLS_H */
index 6985e6e..94d9789 100644 (file)
 #define __ARCH_WANT_SYS_SIGPROCMASK
 #define __ARCH_WANT_SYS_RT_SIGACTION
 #define __ARCH_WANT_SYS_RT_SIGSUSPEND
+#define __ARCH_WANT_SYS_EXECVE
+#define __ARCH_WANT_SYS_CLONE
+#define __ARCH_WANT_SYS_VFORK
+#ifdef CONFIG_MMU
+#define __ARCH_WANT_SYS_FORK
+#endif
 
 /*
  * "Conditional" syscalls
index 75c3ea1..cb0327f 100644 (file)
@@ -474,6 +474,14 @@ ENTRY(ret_from_fork)
        brid    ret_to_user
        nop
 
+ENTRY(ret_from_kernel_thread)
+       brlid   r15, schedule_tail
+       addk    r5, r0, r3
+       brald   r15, r20
+       addk    r5, r0, r19
+       brid    ret_to_user
+       addk    r3, r0, r0
+
 work_pending:
        enable_irq
 
@@ -551,18 +559,6 @@ no_work_pending:
        rtid    r14, 0
        nop
 
-sys_vfork:
-       brid    microblaze_vfork
-       addk    r5, r1, r0
-
-sys_clone:
-       brid    microblaze_clone
-       addk    r7, r1, r0
-
-sys_execve:
-       brid    microblaze_execve
-       addk    r8, r1, r0
-
 sys_rt_sigreturn_wrapper:
        brid    sys_rt_sigreturn
        addk    r5, r1, r0
index 03f7b8c..c217367 100644 (file)
@@ -293,24 +293,6 @@ C_ENTRY(_user_exception):
        swi     r1, r0, TOPHYS(PER_CPU(ENTRY_SP)) /* save stack */
        addi    r14, r14, 4     /* return address is 4 byte after call */
 
-       mfs     r1, rmsr
-       nop
-       andi    r1, r1, MSR_UMS
-       bnei    r1, 1f
-
-/* Kernel-mode state save - kernel execve */
-       lwi     r1, r0, TOPHYS(PER_CPU(ENTRY_SP)); /* Reload kernel stack-ptr*/
-       tophys(r1,r1);
-
-       addik   r1, r1, -PT_SIZE; /* Make room on the stack. */
-       SAVE_REGS
-
-       swi     r1, r1, PT_MODE; /* pt_regs -> kernel mode */
-       brid    2f;
-       nop;                            /* Fill delay slot */
-
-/* User-mode state save.  */
-1:
        lwi     r1, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); /* get saved current */
        tophys(r1,r1);
        lwi     r1, r1, TS_THREAD_INFO; /* get stack from task_struct */
@@ -460,18 +442,6 @@ TRAP_return:               /* Make global symbol for debugging */
        nop;
 
 
-/* These syscalls need access to the struct pt_regs on the stack, so we
-   implement them in assembly (they're basically all wrappers anyway).  */
-
-C_ENTRY(sys_fork_wrapper):
-       addi    r5, r0, SIGCHLD                 /* Arg 0: flags */
-       lwi     r6, r1, PT_R1   /* Arg 1: child SP (use parent's) */
-       addik   r7, r1, 0                       /* Arg 2: parent context */
-       add     r8, r0, r0                      /* Arg 3: (unused) */
-       add     r9, r0, r0;                     /* Arg 4: (unused) */
-       brid    do_fork         /* Do real work (tail-call) */
-       add     r10, r0, r0;                    /* Arg 5: (unused) */
-
 /* This the initial entry point for a new child thread, with an appropriate
    stack in place that makes it look the the child is in the middle of an
    syscall.  This function is actually `returned to' from switch_thread
@@ -479,28 +449,19 @@ C_ENTRY(sys_fork_wrapper):
    saved context).  */
 C_ENTRY(ret_from_fork):
        bralid  r15, schedule_tail; /* ...which is schedule_tail's arg */
-       add     r3, r5, r0;     /* switch_thread returns the prev task */
+       add     r5, r3, r0;     /* switch_thread returns the prev task */
                                /* ( in the delay slot ) */
        brid    ret_from_trap;  /* Do normal trap return */
        add     r3, r0, r0;     /* Child's fork call should return 0. */
 
-C_ENTRY(sys_vfork):
-       brid    microblaze_vfork        /* Do real work (tail-call) */
-       addik   r5, r1, 0
-
-C_ENTRY(sys_clone):
-       bnei    r6, 1f;                 /* See if child SP arg (arg 1) is 0. */
-       lwi     r6, r1, PT_R1;  /* If so, use paret's stack ptr */
-1:     addik   r7, r1, 0;                      /* Arg 2: parent context */
-       lwi     r9, r1, PT_R8;          /* parent tid.  */
-       lwi     r10, r1, PT_R9;         /* child tid.  */
-       /* do_fork will pick up TLS from regs->r10.  */
-       brid    do_fork         /* Do real work (tail-call) */
-       add     r8, r0, r0;             /* Arg 3: (unused) */
-
-C_ENTRY(sys_execve):
-       brid    microblaze_execve;      /* Do real work (tail-call).*/
-       addik   r8, r1, 0;              /* add user context as 4th arg */
+C_ENTRY(ret_from_kernel_thread):
+       bralid  r15, schedule_tail; /* ...which is schedule_tail's arg */
+       add     r5, r3, r0;     /* switch_thread returns the prev task */
+                               /* ( in the delay slot ) */
+       brald   r15, r20        /* fn was left in r20 */
+       addk    r5, r0, r19     /* ... and argument - in r19 */
+       brid    ret_from_trap
+       add     r3, r0, r0
 
 C_ENTRY(sys_rt_sigreturn_wrapper):
        brid    sys_rt_sigreturn        /* Do real work */
index 1944e00..40823fd 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/pm.h>
 #include <linux/tick.h>
 #include <linux/bitops.h>
+#include <linux/ptrace.h>
 #include <asm/pgalloc.h>
 #include <asm/uaccess.h> /* for USER_DS macros */
 #include <asm/cacheflush.h>
@@ -119,46 +120,38 @@ void flush_thread(void)
 }
 
 int copy_thread(unsigned long clone_flags, unsigned long usp,
-               unsigned long unused,
-               struct task_struct *p, struct pt_regs *regs)
+               unsigned long arg, struct task_struct *p)
 {
        struct pt_regs *childregs = task_pt_regs(p);
        struct thread_info *ti = task_thread_info(p);
 
-       *childregs = *regs;
-       if (user_mode(regs))
+       if (unlikely(p->flags & PF_KTHREAD)) {
+               /* if we're creating a new kernel thread then just zeroing all
+                * the registers. That's OK for a brand new thread.*/
+               memset(childregs, 0, sizeof(struct pt_regs));
+               memset(&ti->cpu_context, 0, sizeof(struct cpu_context));
+               ti->cpu_context.r1  = (unsigned long)childregs;
+               ti->cpu_context.r20 = (unsigned long)usp; /* fn */
+               ti->cpu_context.r19 = (unsigned long)arg;
+               childregs->pt_mode = 1;
+               local_save_flags(childregs->msr);
+#ifdef CONFIG_MMU
+               ti->cpu_context.msr = childregs->msr & ~MSR_IE;
+#endif
+               ti->cpu_context.r15 = (unsigned long)ret_from_kernel_thread - 8;
+               return 0;
+       }
+       *childregs = *current_pt_regs();
+       if (usp)
                childregs->r1 = usp;
-       else
-               childregs->r1 = ((unsigned long) ti) + THREAD_SIZE;
 
-#ifndef CONFIG_MMU
        memset(&ti->cpu_context, 0, sizeof(struct cpu_context));
        ti->cpu_context.r1 = (unsigned long)childregs;
+#ifndef CONFIG_MMU
        ti->cpu_context.msr = (unsigned long)childregs->msr;
 #else
+       childregs->msr |= MSR_UMS;
 
-       /* if creating a kernel thread then update the current reg (we don't
-        * want to use the parent's value when restoring by POP_STATE) */
-       if (kernel_mode(regs))
-               /* save new current on stack to use POP_STATE */
-               childregs->CURRENT_TASK = (unsigned long)p;
-       /* if returning to user then use the parent's value of this register */
-
-       /* if we're creating a new kernel thread then just zeroing all
-        * the registers. That's OK for a brand new thread.*/
-       /* Pls. note that some of them will be restored in POP_STATE */
-       if (kernel_mode(regs))
-               memset(&ti->cpu_context, 0, sizeof(struct cpu_context));
-       /* if this thread is created for fork/vfork/clone, then we want to
-        * restore all the parent's context */
-       /* in addition to the registers which will be restored by POP_STATE */
-       else {
-               ti->cpu_context = *(struct cpu_context *)regs;
-               childregs->msr |= MSR_UMS;
-       }
-
-       /* FIXME STATE_SAVE_PT_OFFSET; */
-       ti->cpu_context.r1  = (unsigned long)childregs;
        /* we should consider the fact that childregs is a copy of the parent
         * regs which were saved immediately after entering the kernel state
         * before enabling VM. This MSR will be restored in switch_to and
@@ -209,29 +202,6 @@ unsigned long thread_saved_pc(struct task_struct *tsk)
 }
 #endif
 
-static void kernel_thread_helper(int (*fn)(void *), void *arg)
-{
-       fn(arg);
-       do_exit(-1);
-}
-
-int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
-{
-       struct pt_regs regs;
-
-       memset(&regs, 0, sizeof(regs));
-       /* store them in non-volatile registers */
-       regs.r5 = (unsigned long)fn;
-       regs.r6 = (unsigned long)arg;
-       local_save_flags(regs.msr);
-       regs.pc = (unsigned long)kernel_thread_helper;
-       regs.pt_mode = 1;
-
-       return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0,
-                       &regs, 0, NULL, NULL);
-}
-EXPORT_SYMBOL_GPL(kernel_thread);
-
 unsigned long get_wchan(struct task_struct *p)
 {
 /* TBD (used by procfs) */
@@ -246,6 +216,7 @@ void start_thread(struct pt_regs *regs, unsigned long pc, unsigned long usp)
        regs->pt_mode = 0;
 #ifdef CONFIG_MMU
        regs->msr |= MSR_UMS;
+       regs->msr &= ~MSR_VM;
 #endif
 }
 
index 404c0f2..63647c5 100644 (file)
 
 #include <asm/syscalls.h>
 
-asmlinkage long microblaze_vfork(struct pt_regs *regs)
-{
-       return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->r1,
-                                               regs, 0, NULL, NULL);
-}
-
-asmlinkage long microblaze_clone(int flags, unsigned long stack,
-                                                       struct pt_regs *regs)
-{
-       if (!stack)
-               stack = regs->r1;
-       return do_fork(flags, stack, regs, 0, NULL, NULL);
-}
-
-asmlinkage long microblaze_execve(const char __user *filenamei,
-                                 const char __user *const __user *argv,
-                                 const char __user *const __user *envp,
-                                 struct pt_regs *regs)
-{
-       int error;
-       struct filename *filename;
-
-       filename = getname(filenamei);
-       error = PTR_ERR(filename);
-       if (IS_ERR(filename))
-               goto out;
-       error = do_execve(filename->name, argv, envp, regs);
-       putname(filename);
-out:
-       return error;
-}
-
 asmlinkage long sys_mmap(unsigned long addr, unsigned long len,
                        unsigned long prot, unsigned long flags,
                        unsigned long fd, off_t pgoff)
@@ -75,24 +43,3 @@ asmlinkage long sys_mmap(unsigned long addr, unsigned long len,
 
        return sys_mmap_pgoff(addr, len, prot, flags, fd, pgoff >> PAGE_SHIFT);
 }
-
-/*
- * Do a system call from kernel instead of calling sys_execve so we
- * end up with proper pt_regs.
- */
-int kernel_execve(const char *filename,
-                 const char *const argv[],
-                 const char *const envp[])
-{
-       register const char *__a __asm__("r5") = filename;
-       register const void *__b __asm__("r6") = argv;
-       register const void *__c __asm__("r7") = envp;
-       register unsigned long __syscall __asm__("r12") = __NR_execve;
-       register unsigned long __ret __asm__("r3");
-       __asm__ __volatile__ ("brki r14, 0x8"
-                       : "=r" (__ret), "=r" (__syscall)
-                       : "1" (__syscall), "r" (__a), "r" (__b), "r" (__c)
-                       : "r4", "r8", "r9",
-                       "r10", "r11", "r14", "cc", "memory");
-       return __ret;
-}
index 6a2b294..ff6431e 100644 (file)
@@ -2,11 +2,7 @@ ENTRY(sys_call_table)
        .long sys_restart_syscall       /* 0 - old "setup()" system call,
                                         * used for restarting */
        .long sys_exit
-#ifdef CONFIG_MMU
-       .long sys_fork_wrapper
-#else
-       .long sys_ni_syscall
-#endif
+       .long sys_fork
        .long sys_read
        .long sys_write
        .long sys_open                  /* 5 */
index dba9390..4183e62 100644 (file)
@@ -40,6 +40,8 @@ config MIPS
        select HAVE_MOD_ARCH_SPECIFIC
        select MODULES_USE_ELF_REL
        select MODULES_USE_ELF_RELA if 64BIT
+       select GENERIC_KERNEL_THREAD
+       select GENERIC_KERNEL_EXECVE
 
 menu "Machine selection"
 
index 5e33fab..d28c41e 100644 (file)
@@ -310,8 +310,6 @@ struct task_struct;
 /* Free all resources held by a thread. */
 #define release_thread(thread) do { } while(0)
 
-extern long kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
-
 extern unsigned long thread_saved_pc(struct task_struct *tsk);
 
 /*
index 4f5da94..cec5e12 100644 (file)
@@ -61,4 +61,10 @@ static inline void die_if_kernel(const char *str, struct pt_regs *regs)
                die(str, regs);
 }
 
+#define current_pt_regs()                                              \
+({                                                                     \
+       unsigned long sp = (unsigned long)__builtin_frame_address(0);   \
+       (struct pt_regs *)((sp | (THREAD_SIZE - 1)) + 1 - 32) - 1;      \
+})
+
 #endif /* _ASM_PTRACE_H */
index 880240d..cf4a080 100644 (file)
@@ -21,6 +21,4 @@
 #include <asm/sigcontext.h>
 #include <asm/siginfo.h>
 
-#define ptrace_signal_deliver(regs, cookie) do { } while (0)
-
 #endif /* _ASM_SIGNAL_H */
index 9e47cc1..b306e20 100644 (file)
@@ -20,6 +20,7 @@
 #define __ARCH_OMIT_COMPAT_SYS_GETDENTS64
 #define __ARCH_WANT_OLD_READDIR
 #define __ARCH_WANT_SYS_ALARM
+#define __ARCH_WANT_SYS_EXECVE
 #define __ARCH_WANT_SYS_GETHOSTNAME
 #define __ARCH_WANT_SYS_IPC
 #define __ARCH_WANT_SYS_PAUSE
index 9b00362..e578685 100644 (file)
@@ -70,6 +70,12 @@ need_resched:
        b       need_resched
 #endif
 
+FEXPORT(ret_from_kernel_thread)
+       jal     schedule_tail           # a0 = struct task_struct *prev
+       move    a0, s1
+       jal     s0
+       j       syscall_exit
+
 FEXPORT(ret_from_fork)
        jal     schedule_tail           # a0 = struct task_struct *prev
 
index 3a21ace..7adab86 100644 (file)
@@ -3,7 +3,6 @@
  *
  * Copyright (C) 2000 Silicon Graphics, Inc.
  * Written by Ulf Carlsson (ulfc@engr.sgi.com)
- * sys32_execve from ia64/ia32 code, Feb 2000, Kanoj Sarcar (kanoj@sgi.com)
  */
 #include <linux/compiler.h>
 #include <linux/mm.h>
@@ -77,26 +76,6 @@ out:
        return error;
 }
 
-/*
- * sys_execve() executes a new program.
- */
-asmlinkage int sys32_execve(nabi_no_regargs struct pt_regs regs)
-{
-       int error;
-       struct filename *filename;
-
-       filename = getname(compat_ptr(regs.regs[4]));
-       error = PTR_ERR(filename);
-       if (IS_ERR(filename))
-               goto out;
-       error = compat_do_execve(filename->name, compat_ptr(regs.regs[5]),
-                                compat_ptr(regs.regs[6]), &regs);
-       putname(filename);
-
-out:
-       return error;
-}
-
 #define RLIM_INFINITY32        0x7fffffff
 #define RESOURCE32(x) ((x > RLIM_INFINITY32) ? RLIM_INFINITY32 : x)
 
@@ -333,7 +312,7 @@ _sys32_clone(nabi_no_regargs struct pt_regs regs)
        /* Use __dummy4 instead of getting it off the stack, so that
           syscall() works.  */
        child_tidptr = (int __user *) __dummy4;
-       return do_fork(clone_flags, newsp, &regs, 0,
+       return do_fork(clone_flags, newsp, 0,
                       parent_tidptr, child_tidptr);
 }
 
index 3fc1691..2d9304c 100644 (file)
@@ -32,8 +32,6 @@ EXPORT_SYMBOL(memset);
 EXPORT_SYMBOL(memcpy);
 EXPORT_SYMBOL(memmove);
 
-EXPORT_SYMBOL(kernel_thread);
-
 /*
  * Functions that operate on entire pages.  Mostly used by memory management.
  */
index e9a5fd7..3809765 100644 (file)
@@ -84,6 +84,7 @@ void __noreturn cpu_idle(void)
 }
 
 asmlinkage void ret_from_fork(void);
+asmlinkage void ret_from_kernel_thread(void);
 
 void start_thread(struct pt_regs * regs, unsigned long pc, unsigned long sp)
 {
@@ -113,10 +114,10 @@ void flush_thread(void)
 }
 
 int copy_thread(unsigned long clone_flags, unsigned long usp,
-       unsigned long unused, struct task_struct *p, struct pt_regs *regs)
+       unsigned long arg, struct task_struct *p)
 {
        struct thread_info *ti = task_thread_info(p);
-       struct pt_regs *childregs;
+       struct pt_regs *childregs, *regs = current_pt_regs();
        unsigned long childksp;
        p->set_child_tid = p->clear_child_tid = NULL;
 
@@ -136,19 +137,30 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,
        childregs = (struct pt_regs *) childksp - 1;
        /*  Put the stack after the struct pt_regs.  */
        childksp = (unsigned long) childregs;
+       p->thread.cp0_status = read_c0_status() & ~(ST0_CU2|ST0_CU1);
+       if (unlikely(p->flags & PF_KTHREAD)) {
+               unsigned long status = p->thread.cp0_status;
+               memset(childregs, 0, sizeof(struct pt_regs));
+               ti->addr_limit = KERNEL_DS;
+               p->thread.reg16 = usp; /* fn */
+               p->thread.reg17 = arg;
+               p->thread.reg29 = childksp;
+               p->thread.reg31 = (unsigned long) ret_from_kernel_thread;
+#if defined(CONFIG_CPU_R3000) || defined(CONFIG_CPU_TX39XX)
+               status = (status & ~(ST0_KUP | ST0_IEP | ST0_IEC)) |
+                        ((status & (ST0_KUC | ST0_IEC)) << 2);
+#else
+               status |= ST0_EXL;
+#endif
+               childregs->cp0_status = status;
+               return 0;
+       }
        *childregs = *regs;
        childregs->regs[7] = 0; /* Clear error flag */
-
        childregs->regs[2] = 0; /* Child gets zero as return value */
+       childregs->regs[29] = usp;
+       ti->addr_limit = USER_DS;
 
-       if (childregs->cp0_status & ST0_CU0) {
-               childregs->regs[28] = (unsigned long) ti;
-               childregs->regs[29] = childksp;
-               ti->addr_limit = KERNEL_DS;
-       } else {
-               childregs->regs[29] = usp;
-               ti->addr_limit = USER_DS;
-       }
        p->thread.reg29 = (unsigned long) childregs;
        p->thread.reg31 = (unsigned long) ret_from_fork;
 
@@ -156,7 +168,6 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,
         * New tasks lose permission to use the fpu. This accelerates context
         * switching for most programs since they don't use the fpu.
         */
-       p->thread.cp0_status = read_c0_status() & ~(ST0_CU2|ST0_CU1);
        childregs->cp0_status &= ~(ST0_CU2|ST0_CU1);
 
 #ifdef CONFIG_MIPS_MT_SMTC
@@ -222,35 +233,6 @@ int dump_task_fpu(struct task_struct *t, elf_fpregset_t *fpr)
 }
 
 /*
- * Create a kernel thread
- */
-static void __noreturn kernel_thread_helper(void *arg, int (*fn)(void *))
-{
-       do_exit(fn(arg));
-}
-
-long kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
-{
-       struct pt_regs regs;
-
-       memset(&regs, 0, sizeof(regs));
-
-       regs.regs[4] = (unsigned long) arg;
-       regs.regs[5] = (unsigned long) fn;
-       regs.cp0_epc = (unsigned long) kernel_thread_helper;
-       regs.cp0_status = read_c0_status();
-#if defined(CONFIG_CPU_R3000) || defined(CONFIG_CPU_TX39XX)
-       regs.cp0_status = (regs.cp0_status & ~(ST0_KUP | ST0_IEP | ST0_IEC)) |
-                         ((regs.cp0_status & (ST0_KUC | ST0_IEC)) << 2);
-#else
-       regs.cp0_status |= ST0_EXL;
-#endif
-
-       /* Ok, create the new process.. */
-       return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, &regs, 0, NULL, NULL);
-}
-
-/*
  *
  */
 struct mips_frame_info {
index 86ec03f..6297191 100644 (file)
@@ -167,7 +167,7 @@ EXPORT(sysn32_call_table)
        PTR     sys_getsockopt
        PTR     sys_clone                       /* 6055 */
        PTR     sys_fork
-       PTR     sys32_execve
+       PTR     compat_sys_execve
        PTR     sys_exit
        PTR     compat_sys_wait4
        PTR     sys_kill                        /* 6060 */
index 53c2d72..9601be6 100644 (file)
@@ -203,7 +203,7 @@ sys_call_table:
        PTR     sys_creat
        PTR     sys_link
        PTR     sys_unlink                      /* 4010 */
-       PTR     sys32_execve
+       PTR     compat_sys_execve
        PTR     sys_chdir
        PTR     compat_sys_time
        PTR     sys_mknod
index 2bd561b..201cb76 100644 (file)
@@ -92,7 +92,7 @@ save_static_function(sys_fork);
 static int __used noinline
 _sys_fork(nabi_no_regargs struct pt_regs regs)
 {
-       return do_fork(SIGCHLD, regs.regs[29], &regs, 0, NULL, NULL);
+       return do_fork(SIGCHLD, regs.regs[29], 0, NULL, NULL);
 }
 
 save_static_function(sys_clone);
@@ -123,32 +123,10 @@ _sys_clone(nabi_no_regargs struct pt_regs regs)
 #else
        child_tidptr = (int __user *) regs.regs[8];
 #endif
-       return do_fork(clone_flags, newsp, &regs, 0,
+       return do_fork(clone_flags, newsp, 0,
                       parent_tidptr, child_tidptr);
 }
 
-/*
- * sys_execve() executes a new program.
- */
-asmlinkage int sys_execve(nabi_no_regargs struct pt_regs regs)
-{
-       int error;
-       struct filename *filename;
-
-       filename = getname((const char __user *) (long)regs.regs[4]);
-       error = PTR_ERR(filename);
-       if (IS_ERR(filename))
-               goto out;
-       error = do_execve(filename->name,
-                         (const char __user *const __user *) (long)regs.regs[5],
-                         (const char __user *const __user *) (long)regs.regs[6],
-                         &regs);
-       putname(filename);
-
-out:
-       return error;
-}
-
 SYSCALL_DEFINE1(set_thread_area, unsigned long, addr)
 {
        struct thread_info *ti = task_thread_info(current);
@@ -313,34 +291,3 @@ asmlinkage void bad_stack(void)
 {
        do_exit(SIGSEGV);
 }
-
-/*
- * Do a system call from kernel instead of calling sys_execve so we
- * end up with proper pt_regs.
- */
-int kernel_execve(const char *filename,
-                 const char *const argv[],
-                 const char *const envp[])
-{
-       register unsigned long __a0 asm("$4") = (unsigned long) filename;
-       register unsigned long __a1 asm("$5") = (unsigned long) argv;
-       register unsigned long __a2 asm("$6") = (unsigned long) envp;
-       register unsigned long __a3 asm("$7");
-       unsigned long __v0;
-
-       __asm__ volatile ("                                     \n"
-       "       .set    noreorder                               \n"
-       "       li      $2, %5          # __NR_execve           \n"
-       "       syscall                                         \n"
-       "       move    %0, $2                                  \n"
-       "       .set    reorder                                 \n"
-       : "=&r" (__v0), "=r" (__a3)
-       : "r" (__a0), "r" (__a1), "r" (__a2), "i" (__NR_execve)
-       : "$2", "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15", "$24",
-         "memory");
-
-       if (__a3 == 0)
-               return __v0;
-
-       return -__v0;
-}
index 04669fa..7247174 100644 (file)
@@ -9,6 +9,7 @@ config MN10300
        select HAVE_NMI_WATCHDOG if MN10300_WD_TIMER
        select GENERIC_CLOCKEVENTS
        select GENERIC_KERNEL_THREAD
+       select GENERIC_KERNEL_EXECVE
        select MODULES_USE_ELF_RELA
 
 config AM33_2
index f9668ec..d280e97 100644 (file)
@@ -45,8 +45,4 @@ struct k_sigaction {
 };
 #include <asm/sigcontext.h>
 
-
-struct pt_regs;
-#define ptrace_signal_deliver(regs, cookie) do { } while (0)
-
 #endif /* _ASM_SIGNAL_H */
index 55bbec1..cabf8ba 100644 (file)
@@ -44,7 +44,9 @@
 #define __ARCH_WANT_SYS_RT_SIGACTION
 #define __ARCH_WANT_SYS_RT_SIGSUSPEND
 #define __ARCH_WANT_SYS_EXECVE
-#define __ARCH_WANT_KERNEL_EXECVE
+#define __ARCH_WANT_SYS_FORK
+#define __ARCH_WANT_SYS_VFORK
+#define __ARCH_WANT_SYS_CLONE
 
 /*
  * "Conditional" syscalls
index 0c631d3..68fcab8 100644 (file)
@@ -60,13 +60,8 @@ ENTRY(ret_from_kernel_thread)
        mov     (REG_D0,fp),d0
        mov     (REG_A0,fp),a0
        calls   (a0)
-       jmp     sys_exit
-
-ENTRY(ret_from_kernel_execve)
-       add     -12,d0  /* pt_regs -> frame */
-       mov     d0,sp
-       GET_THREAD_INFO a2
        clr     d0
+       mov     d0,(REG_D0,fp)
        jmp     syscall_exit
 
 ###############################################################################
index d0c671b..eb09f5a 100644 (file)
@@ -206,7 +206,7 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
  */
 int copy_thread(unsigned long clone_flags,
                unsigned long c_usp, unsigned long ustk_size,
-               struct task_struct *p, struct pt_regs *kregs)
+               struct task_struct *p)
 {
        struct thread_info *ti = task_thread_info(p);
        struct pt_regs *c_regs;
@@ -227,7 +227,7 @@ int copy_thread(unsigned long clone_flags,
        p->thread.wchan = p->thread.pc;
        p->thread.usp   = c_usp;
 
-       if (unlikely(!kregs)) {
+       if (unlikely(p->flags & PF_KTHREAD)) {
                memset(c_regs, 0, sizeof(struct pt_regs));
                c_regs->a0 = c_usp; /* function */
                c_regs->d0 = ustk_size; /* argument */
@@ -236,8 +236,9 @@ int copy_thread(unsigned long clone_flags,
                p->thread.pc    = (unsigned long) ret_from_kernel_thread;
                return 0;
        }
-       *c_regs = *kregs;
-       c_regs->sp = c_usp;
+       *c_regs = *current_pt_regs();
+       if (c_usp)
+               c_regs->sp = c_usp;
        c_regs->epsw &= ~EPSW_FE; /* my FPU */
 
        /* the new TLS pointer is passed in as arg #5 to sys_clone() */
@@ -249,30 +250,6 @@ int copy_thread(unsigned long clone_flags,
        return 0;
 }
 
-/*
- * clone a process
- * - tlsptr is retrieved by copy_thread() from current_frame()->d3
- */
-asmlinkage long sys_clone(unsigned long clone_flags, unsigned long newsp,
-                         int __user *parent_tidptr, int __user *child_tidptr,
-                         int __user *tlsptr)
-{
-       return do_fork(clone_flags, newsp ?: current_frame()->sp,
-                      current_frame(), 0, parent_tidptr, child_tidptr);
-}
-
-asmlinkage long sys_fork(void)
-{
-       return do_fork(SIGCHLD, current_frame()->sp,
-                      current_frame(), 0, NULL, NULL);
-}
-
-asmlinkage long sys_vfork(void)
-{
-       return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, current_frame()->sp,
-                      current_frame(), 0, NULL, NULL);
-}
-
 unsigned long get_wchan(struct task_struct *p)
 {
        return p->thread.wchan;
index 05f2ba4..e7f1a29 100644 (file)
@@ -22,6 +22,8 @@ config OPENRISC
        select GENERIC_STRNCPY_FROM_USER
        select GENERIC_STRNLEN_USER
        select MODULES_USE_ELF_RELA
+       select GENERIC_KERNEL_THREAD
+       select GENERIC_KERNEL_EXECVE
 
 config MMU
        def_bool y
index 43decdb..3369138 100644 (file)
@@ -81,8 +81,6 @@ struct thread_struct {
 #define KSTK_ESP(tsk)   (task_pt_regs(tsk)->sp)
 
 
-extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
-
 void start_thread(struct pt_regs *regs, unsigned long nip, unsigned long sp);
 void release_thread(struct task_struct *);
 unsigned long get_wchan(struct task_struct *p);
index 84a978a..8ee8168 100644 (file)
@@ -24,4 +24,11 @@ asmlinkage long sys_or1k_atomic(unsigned long type, unsigned long *v1,
 
 #include <asm-generic/syscalls.h>
 
+asmlinkage long __sys_clone(unsigned long clone_flags, unsigned long newsp,
+                       void __user *parent_tid, void __user *child_tid, int tls);
+asmlinkage long __sys_fork(void);
+
+#define sys_clone __sys_clone
+#define sys_fork __sys_fork
+
 #endif /* __ASM_OPENRISC_SYSCALLS_H */
index 437bdbb..5082b80 100644 (file)
 
 #define sys_mmap2 sys_mmap_pgoff
 
+#define __ARCH_WANT_SYS_EXECVE
+#define __ARCH_WANT_SYS_FORK
+#define __ARCH_WANT_SYS_CLONE
+
 #include <asm-generic/unistd.h>
 
 #define __NR_or1k_atomic __NR_arch_specific_syscall
index e1ee0fa..35f92ce 100644 (file)
@@ -5,7 +5,7 @@
 extra-y        := head.o vmlinux.lds
 
 obj-y  := setup.o idle.o or32_ksyms.o process.o dma.o \
-          traps.o time.o irq.o entry.o ptrace.o signal.o sys_or32.o \
+          traps.o time.o irq.o entry.o ptrace.o signal.o \
           sys_call_table.o
 
 obj-$(CONFIG_MODULES)          += module.o
index ddfcaa8..5e5b306 100644 (file)
@@ -894,6 +894,16 @@ ENTRY(ret_from_fork)
        l.jal   schedule_tail
         l.nop
 
+       /* Check if we are a kernel thread */
+       l.sfeqi r20,0
+       l.bf    1f
+        l.nop
+
+       /* ...we are a kernel thread so invoke the requested callback */
+       l.jalr  r20
+        l.or   r3,r22,r0
+
+1:
        /* _syscall_returns expect r11 to contain return value */
        l.lwz   r11,PT_GPR11(r1)
 
@@ -915,26 +925,6 @@ ENTRY(ret_from_fork)
        l.j     _syscall_return
         l.nop
 
-/* Since syscalls don't save call-clobbered registers, the args to
- * kernel_thread_helper will need to be passed through callee-saved
- * registers and copied to the parameter registers when the thread
- * begins running.
- *
- * See arch/openrisc/kernel/process.c:
- * The args are passed as follows:
- *   arg1 (r3) : passed in r20
- *   arg2 (r4) : passed in r22
- */
-
-ENTRY(_kernel_thread_helper)
-       l.or    r3,r20,r0
-       l.or    r4,r22,r0
-       l.movhi r31,hi(kernel_thread_helper)
-       l.ori   r31,r31,lo(kernel_thread_helper)
-       l.jr    r31
-        l.nop
-
-
 /* ========================================================[ switch ] === */
 
 /*
@@ -1044,8 +1034,13 @@ ENTRY(_switch)
        /* Unwind stack to pre-switch state */
        l.addi  r1,r1,(INT_FRAME_SIZE)
 
-       /* Return via the link-register back to where we 'came from', where that can be
-        * either schedule() or return_from_fork()... */
+       /* Return via the link-register back to where we 'came from', where
+        * that may be either schedule(), ret_from_fork(), or
+        * ret_from_kernel_thread().  If we are returning to a new thread,
+        * we are expected to have set up the arg to schedule_tail already,
+        * hence we do so here unconditionally:
+        */
+       l.lwz   r3,TI_STACK(r3)         /* Load 'prev' as schedule_tail arg */
        l.jr    r9
         l.nop
 
@@ -1076,22 +1071,18 @@ _fork_save_extra_regs_and_call:
        l.jr    r29
         l.sw    PT_GPR28(r1),r28
 
-ENTRY(sys_clone)
-       l.movhi r29,hi(_sys_clone)
-       l.ori   r29,r29,lo(_sys_clone)
+ENTRY(__sys_clone)
+       l.movhi r29,hi(sys_clone)
+       l.ori   r29,r29,lo(sys_clone)
        l.j     _fork_save_extra_regs_and_call
         l.addi r7,r1,0
 
-ENTRY(sys_fork)
-       l.movhi r29,hi(_sys_fork)
-       l.ori   r29,r29,lo(_sys_fork)
+ENTRY(__sys_fork)
+       l.movhi r29,hi(sys_fork)
+       l.ori   r29,r29,lo(sys_fork)
        l.j     _fork_save_extra_regs_and_call
         l.addi r3,r1,0
 
-ENTRY(sys_execve)
-       l.j     _sys_execve
-        l.addi r6,r1,0
-
 ENTRY(sys_sigaltstack)
        l.j     _sys_sigaltstack
         l.addi r5,r1,0
index c35f3ab..00c233b 100644 (file)
@@ -109,66 +109,83 @@ void release_thread(struct task_struct *dead_task)
  */
 extern asmlinkage void ret_from_fork(void);
 
+/*
+ * copy_thread
+ * @clone_flags: flags
+ * @usp: user stack pointer or fn for kernel thread
+ * @arg: arg to fn for kernel thread; always NULL for userspace thread
+ * @p: the newly created task
+ * @regs: CPU context to copy for userspace thread; always NULL for kthread
+ *
+ * At the top of a newly initialized kernel stack are two stacked pt_reg
+ * structures.  The first (topmost) is the userspace context of the thread.
+ * The second is the kernelspace context of the thread.
+ *
+ * A kernel thread will not be returning to userspace, so the topmost pt_regs
+ * struct can be uninitialized; it _does_ need to exist, though, because
+ * a kernel thread can become a userspace thread by doing a kernel_execve, in
+ * which case the topmost context will be initialized and used for 'returning'
+ * to userspace.
+ *
+ * The second pt_reg struct needs to be initialized to 'return' to
+ * ret_from_fork.  A kernel thread will need to set r20 to the address of
+ * a function to call into (with arg in r22); userspace threads need to set
+ * r20 to NULL in which case ret_from_fork will just continue a return to
+ * userspace.
+ *
+ * A kernel thread 'fn' may return; this is effectively what happens when
+ * kernel_execve is called.  In that case, the userspace pt_regs must have
+ * been initialized (which kernel_execve takes care of, see start_thread
+ * below); ret_from_fork will then continue its execution causing the
+ * 'kernel thread' to return to userspace as a userspace thread.
+ */
+
 int
 copy_thread(unsigned long clone_flags, unsigned long usp,
-           unsigned long unused, struct task_struct *p, struct pt_regs *regs)
+           unsigned long arg, struct task_struct *p)
 {
-       struct pt_regs *childregs;
+       struct pt_regs *userregs;
        struct pt_regs *kregs;
        unsigned long sp = (unsigned long)task_stack_page(p) + THREAD_SIZE;
-       struct thread_info *ti;
        unsigned long top_of_kernel_stack;
 
        top_of_kernel_stack = sp;
 
        p->set_child_tid = p->clear_child_tid = NULL;
 
-       /* Copy registers */
-       /* redzone */
-       sp -= STACK_FRAME_OVERHEAD;
+       /* Locate userspace context on stack... */
+       sp -= STACK_FRAME_OVERHEAD;     /* redzone */
        sp -= sizeof(struct pt_regs);
-       childregs = (struct pt_regs *)sp;
+       userregs = (struct pt_regs *) sp;
 
-       /* Copy parent registers */
-       *childregs = *regs;
+       /* ...and kernel context */
+       sp -= STACK_FRAME_OVERHEAD;     /* redzone */
+       sp -= sizeof(struct pt_regs);
+       kregs = (struct pt_regs *)sp;
 
-       if ((childregs->sr & SPR_SR_SM) == 1) {
-               /* for kernel thread, set `current_thread_info'
-                * and stackptr in new task
-                */
-               childregs->sp = (unsigned long)task_stack_page(p) + THREAD_SIZE;
-               childregs->gpr[10] = (unsigned long)task_thread_info(p);
+       if (unlikely(p->flags & PF_KTHREAD)) {
+               memset(kregs, 0, sizeof(struct pt_regs));
+               kregs->gpr[20] = usp; /* fn, kernel thread */
+               kregs->gpr[22] = arg;
        } else {
-               childregs->sp = usp;
-       }
-
-       childregs->gpr[11] = 0; /* Result from fork() */
+               *userregs = *current_pt_regs();
 
-       /*
-        * The way this works is that at some point in the future
-        * some task will call _switch to switch to the new task.
-        * That will pop off the stack frame created below and start
-        * the new task running at ret_from_fork.  The new task will
-        * do some house keeping and then return from the fork or clone
-        * system call, using the stack frame created above.
-        */
-       /* redzone */
-       sp -= STACK_FRAME_OVERHEAD;
-       sp -= sizeof(struct pt_regs);
-       kregs = (struct pt_regs *)sp;
+               if (usp)
+                       userregs->sp = usp;
+               userregs->gpr[11] = 0;  /* Result from fork() */
 
-       ti = task_thread_info(p);
-       ti->ksp = sp;
+               kregs->gpr[20] = 0;     /* Userspace thread */
+       }
 
-       /* kregs->sp must store the location of the 'pre-switch' kernel stack
-        * pointer... for a newly forked process, this is simply the top of
-        * the kernel stack.
+       /*
+        * _switch wants the kernel stack page in pt_regs->sp so that it
+        * can restore it to thread_info->ksp... see _switch for details.
         */
        kregs->sp = top_of_kernel_stack;
-       kregs->gpr[3] = (unsigned long)current; /* arg to schedule_tail */
-       kregs->gpr[10] = (unsigned long)task_thread_info(p);
        kregs->gpr[9] = (unsigned long)ret_from_fork;
 
+       task_thread_info(p)->ksp = (unsigned long)kregs;
+
        return 0;
 }
 
@@ -177,16 +194,14 @@ copy_thread(unsigned long clone_flags, unsigned long usp,
  */
 void start_thread(struct pt_regs *regs, unsigned long pc, unsigned long sp)
 {
-       unsigned long sr = regs->sr & ~SPR_SR_SM;
+       unsigned long sr = mfspr(SPR_SR) & ~SPR_SR_SM;
 
        set_fs(USER_DS);
-       memset(regs->gpr, 0, sizeof(regs->gpr));
+       memset(regs, 0, sizeof(struct pt_regs));
 
        regs->pc = pc;
        regs->sr = sr;
        regs->sp = sp;
-
-/*     printk("start thread, ksp = %lx\n", current_thread_info()->ksp);*/
 }
 
 /* Fill in the fpu structure for a core dump.  */
@@ -237,74 +252,9 @@ void dump_elf_thread(elf_greg_t *dest, struct pt_regs* regs)
        dest[35] = 0;
 }
 
-extern void _kernel_thread_helper(void);
-
-void __noreturn kernel_thread_helper(int (*fn) (void *), void *arg)
-{
-       do_exit(fn(arg));
-}
-
-/*
- * Create a kernel thread.
- */
-int kernel_thread(int (*fn) (void *), void *arg, unsigned long flags)
-{
-       struct pt_regs regs;
-
-       memset(&regs, 0, sizeof(regs));
-
-       regs.gpr[20] = (unsigned long)fn;
-       regs.gpr[22] = (unsigned long)arg;
-       regs.sr = mfspr(SPR_SR);
-       regs.pc = (unsigned long)_kernel_thread_helper;
-
-       return do_fork(flags | CLONE_VM | CLONE_UNTRACED,
-                      0, &regs, 0, NULL, NULL);
-}
-
-/*
- * sys_execve() executes a new program.
- */
-asmlinkage long _sys_execve(const char __user *name,
-                           const char __user * const __user *argv,
-                           const char __user * const __user *envp,
-                           struct pt_regs *regs)
-{
-       int error;
-       struct filename *filename;
-
-       filename = getname(name);
-       error = PTR_ERR(filename);
-
-       if (IS_ERR(filename))
-               goto out;
-
-       error = do_execve(filename->name, argv, envp, regs);
-       putname(filename);
-
-out:
-       return error;
-}
-
 unsigned long get_wchan(struct task_struct *p)
 {
        /* TODO */
 
        return 0;
 }
-
-int kernel_execve(const char *filename, char *const argv[], char *const envp[])
-{
-       register long __res asm("r11") = __NR_execve;
-       register long __a asm("r3") = (long)(filename);
-       register long __b asm("r4") = (long)(argv);
-       register long __c asm("r5") = (long)(envp);
-       __asm__ volatile ("l.sys 1"
-                         : "=r" (__res), "=r"(__a), "=r"(__b), "=r"(__c)
-                         : "0"(__res), "1"(__a), "2"(__b), "3"(__c)
-                         : "r6", "r7", "r8", "r12", "r13", "r15",
-                           "r17", "r19", "r21", "r23", "r25", "r27",
-                           "r29", "r31");
-       __asm__ volatile ("l.nop");
-       return __res;
-}
diff --git a/arch/openrisc/kernel/sys_or32.c b/arch/openrisc/kernel/sys_or32.c
deleted file mode 100644 (file)
index 5706008..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * OpenRISC sys_or32.c
- *
- * Linux architectural port borrowing liberally from similar works of
- * others.  All original copyrights apply as per the original source
- * declaration.
- *
- * Modifications for the OpenRISC architecture:
- * Copyright (C) 2003 Matjaz Breskvar <phoenix@bsemi.com>
- * Copyright (C) 2010-2011 Jonas Bonn <jonas@southpole.se>
- *
- *      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.
- *
- * This file contains various random system calls that
- * have a non-standard calling sequence on some platforms.
- * Since we don't have to do any backwards compatibility, our
- * versions are done in the most "normal" way possible.
- */
-
-#include <linux/errno.h>
-#include <linux/syscalls.h>
-#include <linux/mm.h>
-
-#include <asm/syscalls.h>
-
-/* These are secondary entry points as the primary entry points are defined in
- * entry.S where we add the 'regs' parameter value
- */
-
-asmlinkage long _sys_clone(unsigned long clone_flags, unsigned long newsp,
-                          int __user *parent_tid, int __user *child_tid,
-                          struct pt_regs *regs)
-{
-       long ret;
-
-       /* FIXME: Is alignment necessary? */
-       /* newsp = ALIGN(newsp, 4); */
-
-       if (!newsp)
-               newsp = regs->sp;
-
-       ret = do_fork(clone_flags, newsp, regs, 0, parent_tid, child_tid);
-
-       return ret;
-}
-
-asmlinkage int _sys_fork(struct pt_regs *regs)
-{
-#ifdef CONFIG_MMU
-       return do_fork(SIGCHLD, regs->sp, regs, 0, NULL, NULL);
-#else
-       return -EINVAL;
-#endif
-}
index 11def45..e688a2b 100644 (file)
@@ -22,6 +22,9 @@ config PARISC
        select GENERIC_STRNCPY_FROM_USER
        select HAVE_MOD_ARCH_SPECIFIC
        select MODULES_USE_ELF_RELA
+       select GENERIC_KERNEL_THREAD
+       select GENERIC_KERNEL_EXECVE
+       select CLONE_BACKWARDS
 
        help
          The PA-RISC microprocessor is designed by Hewlett-Packard and used
index 0e8b7b8..09b54a5 100644 (file)
@@ -326,7 +326,6 @@ struct mm_struct;
 
 /* Free all resources held by a thread. */
 extern void release_thread(struct task_struct *);
-extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
 
 extern void map_hpux_gateway_page(struct task_struct *tsk, struct mm_struct *mm);
 
index 21abf4f..0fdb3c8 100644 (file)
@@ -34,8 +34,6 @@ struct k_sigaction {
        struct sigaction sa;
 };
 
-#define ptrace_signal_deliver(regs, cookie) do { } while (0)
-
 #include <asm/sigcontext.h>
 
 #endif /* !__ASSEMBLY */
index 541639c..1efef41 100644 (file)
@@ -163,6 +163,10 @@ type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5)      \
 #define __ARCH_WANT_SYS_RT_SIGACTION
 #define __ARCH_WANT_SYS_RT_SIGSUSPEND
 #define __ARCH_WANT_COMPAT_SYS_RT_SIGSUSPEND
+#define __ARCH_WANT_SYS_EXECVE
+#define __ARCH_WANT_SYS_FORK
+#define __ARCH_WANT_SYS_VFORK
+#define __ARCH_WANT_SYS_CLONE
 
 #endif /* __ASSEMBLY__ */
 
index 18670a0..bfb4424 100644 (file)
@@ -708,59 +708,9 @@ ENTRY(end_fault_vector)
        .import         do_cpu_irq_mask,code
 
        /*
-        * r26 = function to be called
-        * r25 = argument to pass in
-        * r24 = flags for do_fork()
-        *
-        * Kernel threads don't ever return, so they don't need
-        * a true register context. We just save away the arguments
-        * for copy_thread/ret_ to properly set up the child.
-        */
-
-#define CLONE_VM 0x100 /* Must agree with <linux/sched.h> */
-#define CLONE_UNTRACED 0x00800000
-
-       .import do_fork
-ENTRY(__kernel_thread)
-       STREG   %r2, -RP_OFFSET(%r30)
-
-       copy    %r30, %r1
-       ldo     PT_SZ_ALGN(%r30),%r30
-#ifdef CONFIG_64BIT
-       /* Yo, function pointers in wide mode are little structs... -PB */
-       ldd     24(%r26), %r2
-       STREG   %r2, PT_GR27(%r1)       /* Store childs %dp */
-       ldd     16(%r26), %r26
-
-       STREG   %r22, PT_GR22(%r1)      /* save r22 (arg5) */
-       copy    %r0, %r22               /* user_tid */
-#endif
-       STREG   %r26, PT_GR26(%r1)  /* Store function & argument for child */
-       STREG   %r25, PT_GR25(%r1)
-       ldil    L%CLONE_UNTRACED, %r26
-       ldo     CLONE_VM(%r26), %r26   /* Force CLONE_VM since only init_mm */
-       or      %r26, %r24, %r26      /* will have kernel mappings.      */
-       ldi     1, %r25                 /* stack_start, signals kernel thread */
-       stw     %r0, -52(%r30)          /* user_tid */
-#ifdef CONFIG_64BIT
-       ldo     -16(%r30),%r29          /* Reference param save area */
-#endif
-       BL      do_fork, %r2
-       copy    %r1, %r24               /* pt_regs */
-
-       /* Parent Returns here */
-
-       LDREG   -PT_SZ_ALGN-RP_OFFSET(%r30), %r2
-       ldo     -PT_SZ_ALGN(%r30), %r30
-       bv      %r0(%r2)
-       nop
-ENDPROC(__kernel_thread)
-
-       /*
         * Child Returns here
         *
-        * copy_thread moved args from temp save area set up above
-        * into task save area.
+        * copy_thread moved args into task save area.
         */
 
 ENTRY(ret_from_kernel_thread)
@@ -769,51 +719,17 @@ ENTRY(ret_from_kernel_thread)
        BL      schedule_tail, %r2
        nop
 
-       LDREG   TI_TASK-THREAD_SZ_ALGN(%r30), %r1
+       LDREG   TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30), %r1
        LDREG   TASK_PT_GR25(%r1), %r26
 #ifdef CONFIG_64BIT
        LDREG   TASK_PT_GR27(%r1), %r27
-       LDREG   TASK_PT_GR22(%r1), %r22
 #endif
        LDREG   TASK_PT_GR26(%r1), %r1
        ble     0(%sr7, %r1)
        copy    %r31, %r2
-
-#ifdef CONFIG_64BIT
-       ldo     -16(%r30),%r29          /* Reference param save area */
-       loadgp                          /* Thread could have been in a module */
-#endif
-#ifndef CONFIG_64BIT
-       b       sys_exit
-#else
-       load32  sys_exit, %r1
-       bv      %r0(%r1)
-#endif
-       ldi     0, %r26
-ENDPROC(ret_from_kernel_thread)
-
-       .import sys_execve, code
-ENTRY(__execve)
-       copy    %r2, %r15
-       copy    %r30, %r16
-       ldo     PT_SZ_ALGN(%r30), %r30
-       STREG   %r26, PT_GR26(%r16)
-       STREG   %r25, PT_GR25(%r16)
-       STREG   %r24, PT_GR24(%r16)
-#ifdef CONFIG_64BIT
-       ldo     -16(%r30),%r29          /* Reference param save area */
-#endif
-       BL      sys_execve, %r2
-       copy    %r16, %r26
-
-       cmpib,=,n 0,%r28,intr_return    /* forward */
-
-       /* yes, this will trap and die. */
-       copy    %r15, %r2
-       copy    %r16, %r30
-       bv      %r0(%r2)
+       b       finish_child_return
        nop
-ENDPROC(__execve)
+ENDPROC(ret_from_kernel_thread)
 
 
        /*
@@ -1772,151 +1688,36 @@ dtlb_fault:
        LDREG   PT_GR18(\regs),%r18
        .endm
 
-ENTRY(sys_fork_wrapper)
+       .macro  fork_like name
+ENTRY(sys_\name\()_wrapper)
        LDREG   TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30), %r1
        ldo     TASK_REGS(%r1),%r1
        reg_save %r1
-       mfctl   %cr27, %r3
-       STREG   %r3, PT_CR27(%r1)
-
-       STREG   %r2,-RP_OFFSET(%r30)
-       ldo     FRAME_SIZE(%r30),%r30
-#ifdef CONFIG_64BIT
-       ldo     -16(%r30),%r29          /* Reference param save area */
-#endif
-
-       /* These are call-clobbered registers and therefore
-          also syscall-clobbered (we hope). */
-       STREG   %r2,PT_GR19(%r1)        /* save for child */
-       STREG   %r30,PT_GR21(%r1)
-
-       LDREG   PT_GR30(%r1),%r25
-       copy    %r1,%r24
-       BL      sys_clone,%r2
-       ldi     SIGCHLD,%r26
-
-       LDREG   -RP_OFFSET-FRAME_SIZE(%r30),%r2
-wrapper_exit:
-       ldo     -FRAME_SIZE(%r30),%r30          /* get the stackframe */
-       LDREG   TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r1
-       ldo     TASK_REGS(%r1),%r1       /* get pt regs */
-
-       LDREG   PT_CR27(%r1), %r3
-       mtctl   %r3, %cr27
-       reg_restore %r1
+       mfctl   %cr27, %r28
+       b       sys_\name
+       STREG   %r28, PT_CR27(%r1)
+ENDPROC(sys_\name\()_wrapper)
+       .endm
 
-       /* strace expects syscall # to be preserved in r20 */
-       ldi     __NR_fork,%r20
-       bv %r0(%r2)
-       STREG   %r20,PT_GR20(%r1)
-ENDPROC(sys_fork_wrapper)
+fork_like clone
+fork_like fork
+fork_like vfork
 
        /* Set the return value for the child */
 ENTRY(child_return)
        BL      schedule_tail, %r2
        nop
+finish_child_return:
+       LDREG   TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30), %r1
+       ldo     TASK_REGS(%r1),%r1       /* get pt regs */
 
-       LDREG   TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE-FRAME_SIZE(%r30), %r1
-       LDREG   TASK_PT_GR19(%r1),%r2
-       b       wrapper_exit
+       LDREG   PT_CR27(%r1), %r3
+       mtctl   %r3, %cr27
+       reg_restore %r1
+       b       syscall_exit
        copy    %r0,%r28
 ENDPROC(child_return)
 
-
-ENTRY(sys_clone_wrapper)
-       LDREG   TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r1
-       ldo     TASK_REGS(%r1),%r1      /* get pt regs */
-       reg_save %r1
-       mfctl   %cr27, %r3
-       STREG   %r3, PT_CR27(%r1)
-
-       STREG   %r2,-RP_OFFSET(%r30)
-       ldo     FRAME_SIZE(%r30),%r30
-#ifdef CONFIG_64BIT
-       ldo     -16(%r30),%r29          /* Reference param save area */
-#endif
-
-       /* WARNING - Clobbers r19 and r21, userspace must save these! */
-       STREG   %r2,PT_GR19(%r1)        /* save for child */
-       STREG   %r30,PT_GR21(%r1)
-       BL      sys_clone,%r2
-       copy    %r1,%r24
-
-       b       wrapper_exit
-       LDREG   -RP_OFFSET-FRAME_SIZE(%r30),%r2
-ENDPROC(sys_clone_wrapper)
-
-
-ENTRY(sys_vfork_wrapper)
-       LDREG   TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r1
-       ldo     TASK_REGS(%r1),%r1      /* get pt regs */
-       reg_save %r1
-       mfctl   %cr27, %r3
-       STREG   %r3, PT_CR27(%r1)
-
-       STREG   %r2,-RP_OFFSET(%r30)
-       ldo     FRAME_SIZE(%r30),%r30
-#ifdef CONFIG_64BIT
-       ldo     -16(%r30),%r29          /* Reference param save area */
-#endif
-
-       STREG   %r2,PT_GR19(%r1)        /* save for child */
-       STREG   %r30,PT_GR21(%r1)
-
-       BL      sys_vfork,%r2
-       copy    %r1,%r26
-
-       b       wrapper_exit
-       LDREG   -RP_OFFSET-FRAME_SIZE(%r30),%r2
-ENDPROC(sys_vfork_wrapper)
-
-       
-       .macro  execve_wrapper execve
-       LDREG   TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r1
-       ldo     TASK_REGS(%r1),%r1      /* get pt regs */
-
-       /*
-        * Do we need to save/restore r3-r18 here?
-        * I don't think so. why would new thread need old
-        * threads registers?
-        */
-
-       /* %arg0 - %arg3 are already saved for us. */
-
-       STREG %r2,-RP_OFFSET(%r30)
-       ldo FRAME_SIZE(%r30),%r30
-#ifdef CONFIG_64BIT
-       ldo     -16(%r30),%r29          /* Reference param save area */
-#endif
-       BL \execve,%r2
-       copy %r1,%arg0
-
-       ldo -FRAME_SIZE(%r30),%r30
-       LDREG -RP_OFFSET(%r30),%r2
-
-       /* If exec succeeded we need to load the args */
-
-       ldo -1024(%r0),%r1
-       cmpb,>>= %r28,%r1,error_\execve
-       copy %r2,%r19
-
-error_\execve:
-       bv %r0(%r19)
-       nop
-       .endm
-
-       .import sys_execve
-ENTRY(sys_execve_wrapper)
-       execve_wrapper sys_execve
-ENDPROC(sys_execve_wrapper)
-
-#ifdef CONFIG_64BIT
-       .import sys32_execve
-ENTRY(sys32_execve_wrapper)
-       execve_wrapper sys32_execve
-ENDPROC(sys32_execve_wrapper)
-#endif
-
 ENTRY(sys_rt_sigreturn_wrapper)
        LDREG   TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r26
        ldo     TASK_REGS(%r26),%r26    /* get pt regs */
index cbc3721..d135072 100644 (file)
@@ -52,6 +52,7 @@
 
 #include <asm/io.h>
 #include <asm/asm-offsets.h>
+#include <asm/assembly.h>
 #include <asm/pdc.h>
 #include <asm/pdc_chassis.h>
 #include <asm/pgalloc.h>
@@ -165,23 +166,6 @@ void (*pm_power_off)(void) = machine_power_off;
 EXPORT_SYMBOL(pm_power_off);
 
 /*
- * Create a kernel thread
- */
-
-extern pid_t __kernel_thread(int (*fn)(void *), void *arg, unsigned long flags);
-pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
-{
-
-       /*
-        * FIXME: Once we are sure we don't need any debug here,
-        *        kernel_thread can become a #define.
-        */
-
-       return __kernel_thread(fn, arg, flags);
-}
-EXPORT_SYMBOL(kernel_thread);
-
-/*
  * Free current thread data structures etc..
  */
 void exit_thread(void)
@@ -218,48 +202,11 @@ int dump_task_fpu (struct task_struct *tsk, elf_fpregset_t *r)
        return 1;
 }
 
-/* Note that "fork()" is implemented in terms of clone, with
-   parameters (SIGCHLD, regs->gr[30], regs). */
-int
-sys_clone(unsigned long clone_flags, unsigned long usp,
-         struct pt_regs *regs)
-{
-       /* Arugments from userspace are:
-          r26 = Clone flags.
-          r25 = Child stack.
-          r24 = parent_tidptr.
-          r23 = Is the TLS storage descriptor 
-          r22 = child_tidptr 
-          
-          However, these last 3 args are only examined
-          if the proper flags are set. */
-       int __user *parent_tidptr = (int __user *)regs->gr[24];
-       int __user *child_tidptr  = (int __user *)regs->gr[22];
-
-       /* usp must be word aligned.  This also prevents users from
-        * passing in the value 1 (which is the signal for a special
-        * return for a kernel thread) */
-       usp = ALIGN(usp, 4);
-
-       /* A zero value for usp means use the current stack */
-       if (usp == 0)
-         usp = regs->gr[30];
-
-       return do_fork(clone_flags, usp, regs, 0, parent_tidptr, child_tidptr);
-}
-
-int
-sys_vfork(struct pt_regs *regs)
-{
-       return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->gr[30], regs, 0, NULL, NULL);
-}
-
 int
 copy_thread(unsigned long clone_flags, unsigned long usp,
-           unsigned long unused,       /* in ia64 this is "user_stack_size" */
-           struct task_struct * p, struct pt_regs * pregs)
+           unsigned long arg, struct task_struct *p)
 {
-       struct pt_regs * cregs = &(p->thread.regs);
+       struct pt_regs *cregs = &(p->thread.regs);
        void *stack = task_stack_page(p);
        
        /* We have to use void * instead of a function pointer, because
@@ -270,48 +217,39 @@ copy_thread(unsigned long clone_flags, unsigned long usp,
 #ifdef CONFIG_HPUX
        extern void * const hpux_child_return;
 #endif
+       if (unlikely(p->flags & PF_KTHREAD)) {
+               memset(cregs, 0, sizeof(struct pt_regs));
+               if (!usp) /* idle thread */
+                       return 0;
 
-       *cregs = *pregs;
-
-       /* Set the return value for the child.  Note that this is not
-           actually restored by the syscall exit path, but we put it
-           here for consistency in case of signals. */
-       cregs->gr[28] = 0; /* child */
-
-       /*
-        * We need to differentiate between a user fork and a
-        * kernel fork. We can't use user_mode, because the
-        * the syscall path doesn't save iaoq. Right now
-        * We rely on the fact that kernel_thread passes
-        * in zero for usp.
-        */
-       if (usp == 1) {
                /* kernel thread */
-               cregs->ksp = (unsigned long)stack + THREAD_SZ_ALGN;
                /* Must exit via ret_from_kernel_thread in order
                 * to call schedule_tail()
                 */
+               cregs->ksp = (unsigned long)stack + THREAD_SZ_ALGN + FRAME_SIZE;
                cregs->kpc = (unsigned long) &ret_from_kernel_thread;
                /*
                 * Copy function and argument to be called from
                 * ret_from_kernel_thread.
                 */
 #ifdef CONFIG_64BIT
-               cregs->gr[27] = pregs->gr[27];
+               cregs->gr[27] = ((unsigned long *)usp)[3];
+               cregs->gr[26] = ((unsigned long *)usp)[2];
+#else
+               cregs->gr[26] = usp;
 #endif
-               cregs->gr[26] = pregs->gr[26];
-               cregs->gr[25] = pregs->gr[25];
+               cregs->gr[25] = arg;
        } else {
                /* user thread */
-               /*
-                * Note that the fork wrappers are responsible
-                * for setting gr[21].
-                */
-
-               /* Use same stack depth as parent */
-               cregs->ksp = (unsigned long)stack
-                       + (pregs->gr[21] & (THREAD_SIZE - 1));
-               cregs->gr[30] = usp;
+               /* usp must be word aligned.  This also prevents users from
+                * passing in the value 1 (which is the signal for a special
+                * return for a kernel thread) */
+               if (usp) {
+                       usp = ALIGN(usp, 4);
+                       if (likely(usp))
+                               cregs->gr[30] = usp;
+               }
+               cregs->ksp = (unsigned long)stack + THREAD_SZ_ALGN + FRAME_SIZE;
                if (personality(p->personality) == PER_HPUX) {
 #ifdef CONFIG_HPUX
                        cregs->kpc = (unsigned long) &hpux_child_return;
@@ -323,8 +261,7 @@ copy_thread(unsigned long clone_flags, unsigned long usp,
                }
                /* Setup thread TLS area from the 4th parameter in clone */
                if (clone_flags & CLONE_SETTLS)
-                 cregs->cr27 = pregs->gr[23];
-       
+                       cregs->cr27 = cregs->gr[23];
        }
 
        return 0;
@@ -335,39 +272,6 @@ unsigned long thread_saved_pc(struct task_struct *t)
        return t->thread.regs.kpc;
 }
 
-/*
- * sys_execve() executes a new program.
- */
-
-asmlinkage int sys_execve(struct pt_regs *regs)
-{
-       int error;
-       struct filename *filename;
-
-       filename = getname((const char __user *) regs->gr[26]);
-       error = PTR_ERR(filename);
-       if (IS_ERR(filename))
-               goto out;
-       error = do_execve(filename->name,
-                         (const char __user *const __user *) regs->gr[25],
-                         (const char __user *const __user *) regs->gr[24],
-                         regs);
-       putname(filename);
-out:
-
-       return error;
-}
-
-extern int __execve(const char *filename,
-                   const char *const argv[],
-                   const char *const envp[], struct task_struct *task);
-int kernel_execve(const char *filename,
-                 const char *const argv[],
-                 const char *const envp[])
-{
-       return __execve(filename, argv, envp, current);
-}
-
 unsigned long
 get_wchan(struct task_struct *p)
 {
index bf5b93a..9cfdaa1 100644 (file)
 #define DBG(x)
 #endif
 
-/*
- * sys32_execve() executes a new program.
- */
-
-asmlinkage int sys32_execve(struct pt_regs *regs)
-{
-       int error;
-       struct filename *filename;
-
-       DBG(("sys32_execve(%p) r26 = 0x%lx\n", regs, regs->gr[26]));
-       filename = getname((const char __user *) regs->gr[26]);
-       error = PTR_ERR(filename);
-       if (IS_ERR(filename))
-               goto out;
-       error = compat_do_execve(filename->name, compat_ptr(regs->gr[25]),
-                                compat_ptr(regs->gr[24]), regs);
-       putname(filename);
-out:
-
-       return error;
-}
-
 asmlinkage long sys32_unimplemented(int r26, int r25, int r24, int r23,
        int r22, int r21, int r20)
 {
index cbf5d59..54d950b 100644 (file)
@@ -66,7 +66,7 @@
        ENTRY_SAME(creat)
        ENTRY_SAME(link)
        ENTRY_SAME(unlink)              /* 10 */
-       ENTRY_DIFF(execve_wrapper)
+       ENTRY_COMP(execve)
        ENTRY_SAME(chdir)
        /* See comments in kernel/time.c!!! Maybe we don't need this? */
        ENTRY_COMP(time)
index a902a5c..951a517 100644 (file)
@@ -144,6 +144,8 @@ config PPC
        select GENERIC_KERNEL_THREAD
        select HAVE_MOD_ARCH_SPECIFIC
        select MODULES_USE_ELF_RELA
+       select GENERIC_KERNEL_EXECVE
+       select CLONE_BACKWARDS
 
 config EARLY_PRINTK
        bool
index 189998b..a101637 100644 (file)
@@ -3,6 +3,4 @@
 
 #include <uapi/asm/signal.h>
 
-struct pt_regs;
-#define ptrace_signal_deliver(regs, cookie) do { } while (0)
 #endif /* _ASM_POWERPC_SIGNAL_H */
index 329db4e..b5308d3 100644 (file)
@@ -17,15 +17,6 @@ asmlinkage unsigned long sys_mmap(unsigned long addr, size_t len,
 asmlinkage unsigned long sys_mmap2(unsigned long addr, size_t len,
                unsigned long prot, unsigned long flags,
                unsigned long fd, unsigned long pgoff);
-asmlinkage int sys_clone(unsigned long clone_flags, unsigned long usp,
-               int __user *parent_tidp, void __user *child_threadptr,
-               int __user *child_tidp, int p6, struct pt_regs *regs);
-asmlinkage int sys_fork(unsigned long p1, unsigned long p2,
-               unsigned long p3, unsigned long p4, unsigned long p5,
-               unsigned long p6, struct pt_regs *regs);
-asmlinkage int sys_vfork(unsigned long p1, unsigned long p2,
-               unsigned long p3, unsigned long p4, unsigned long p5,
-               unsigned long p6, struct pt_regs *regs);
 asmlinkage long sys_pipe(int __user *fildes);
 asmlinkage long sys_pipe2(int __user *fildes, int flags);
 asmlinkage long sys_rt_sigaction(int sig,
index 921dce6..76fe846 100644 (file)
@@ -56,7 +56,9 @@
 #define __ARCH_WANT_COMPAT_SYS_SENDFILE
 #endif
 #define __ARCH_WANT_SYS_EXECVE
-#define __ARCH_WANT_KERNEL_EXECVE
+#define __ARCH_WANT_SYS_FORK
+#define __ARCH_WANT_SYS_VFORK
+#define __ARCH_WANT_SYS_CLONE
 
 /*
  * "Conditional" syscalls
index 9499385..d22e73e 100644 (file)
@@ -444,11 +444,6 @@ ret_from_kernel_thread:
        PPC440EP_ERR42
        blrl
        li      r3,0
-       b       do_exit         # no return
-
-       .globl  __ret_from_kernel_execve
-__ret_from_kernel_execve:
-       addi    r1,r3,-STACK_FRAME_OVERHEAD
        b       ret_from_syscall
 
 /* Traced system call support */
index 56e0ff0..e9a906c 100644 (file)
@@ -373,17 +373,11 @@ _GLOBAL(ret_from_fork)
 _GLOBAL(ret_from_kernel_thread)
        bl      .schedule_tail
        REST_NVGPRS(r1)
-       REST_GPR(2,r1)
+       ld      r14, 0(r14)
        mtlr    r14
        mr      r3,r15
        blrl
        li      r3,0
-       b       .do_exit        # no return
-
-_GLOBAL(__ret_from_kernel_execve)
-       addi    r1,r3,-STACK_FRAME_OVERHEAD
-       li      r10,1
-       std     r10,SOFTE(r1)
        b       syscall_exit
 
        .section        ".toc","aw"
index ba48233..8143067 100644 (file)
@@ -733,8 +733,7 @@ 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 arg, struct task_struct *p,
-               struct pt_regs *regs)
+               unsigned long arg, struct task_struct *p)
 {
        struct pt_regs *childregs, *kregs;
        extern void ret_from_fork(void);
@@ -745,25 +744,25 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,
        /* Copy registers */
        sp -= sizeof(struct pt_regs);
        childregs = (struct pt_regs *) sp;
-       if (!regs) {
-               /* for kernel thread, set `current' and stackptr in new task */
+       if (unlikely(p->flags & PF_KTHREAD)) {
+               struct thread_info *ti = (void *)task_stack_page(p);
                memset(childregs, 0, sizeof(struct pt_regs));
                childregs->gpr[1] = sp + sizeof(struct pt_regs);
+               childregs->gpr[14] = usp;       /* function */
 #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;
+               childregs->softe = 1;
 #endif
                childregs->gpr[15] = arg;
                p->thread.regs = NULL;  /* no user register state */
+               ti->flags |= _TIF_RESTOREALL;
                f = ret_from_kernel_thread;
        } else {
+               struct pt_regs *regs = current_pt_regs();
                CHECK_FULL_REGS(regs);
                *childregs = *regs;
-               childregs->gpr[1] = usp;
+               if (usp)
+                       childregs->gpr[1] = usp;
                p->thread.regs = childregs;
                childregs->gpr[3] = 0;  /* Result from fork() */
                if (clone_flags & CLONE_SETTLS) {
@@ -1027,51 +1026,6 @@ int get_unalign_ctl(struct task_struct *tsk, unsigned long adr)
        return put_user(tsk->thread.align_ctl, (unsigned int __user *)adr);
 }
 
-#define TRUNC_PTR(x)   ((typeof(x))(((unsigned long)(x)) & 0xffffffff))
-
-int sys_clone(unsigned long clone_flags, unsigned long usp,
-             int __user *parent_tidp, void __user *child_threadptr,
-             int __user *child_tidp, int p6,
-             struct pt_regs *regs)
-{
-       CHECK_FULL_REGS(regs);
-       if (usp == 0)
-               usp = regs->gpr[1];     /* stack pointer for child */
-#ifdef CONFIG_PPC64
-       if (is_32bit_task()) {
-               parent_tidp = TRUNC_PTR(parent_tidp);
-               child_tidp = TRUNC_PTR(child_tidp);
-       }
-#endif
-       return do_fork(clone_flags, usp, regs, 0, parent_tidp, child_tidp);
-}
-
-int sys_fork(unsigned long p1, unsigned long p2, unsigned long p3,
-            unsigned long p4, unsigned long p5, unsigned long p6,
-            struct pt_regs *regs)
-{
-       CHECK_FULL_REGS(regs);
-       return do_fork(SIGCHLD, regs->gpr[1], regs, 0, NULL, NULL);
-}
-
-int sys_vfork(unsigned long p1, unsigned long p2, unsigned long p3,
-             unsigned long p4, unsigned long p5, unsigned long p6,
-             struct pt_regs *regs)
-{
-       CHECK_FULL_REGS(regs);
-       return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->gpr[1],
-                       regs, 0, NULL, NULL);
-}
-
-void __ret_from_kernel_execve(struct pt_regs *normal)
-__noreturn;
-
-void ret_from_kernel_execve(struct pt_regs *normal)
-{
-       set_thread_flag(TIF_RESTOREALL);
-       __ret_from_kernel_execve(normal);
-}
-
 static inline int valid_irq_stack(unsigned long sp, struct task_struct *p,
                                  unsigned long nbytes)
 {
index d385f39..3cbb875 100644 (file)
@@ -138,8 +138,10 @@ config S390
        select KTIME_SCALAR if 32BIT
        select HAVE_ARCH_SECCOMP_FILTER
        select GENERIC_KERNEL_THREAD
+       select GENERIC_KERNEL_EXE