Merge branches 'no-rebases', 'arch-avr32', 'arch-blackfin', 'arch-cris', 'arch-h8300...
authorAl Viro <viro@zeniv.linux.org.uk>
Thu, 29 Nov 2012 02:52:07 +0000 (21:52 -0500)
committerAl Viro <viro@zeniv.linux.org.uk>
Thu, 29 Nov 2012 02:52:07 +0000 (21:52 -0500)
165 files changed:
arch/arm64/Kconfig
arch/arm64/include/asm/processor.h
arch/arm64/include/asm/syscalls.h
arch/arm64/include/asm/unistd.h
arch/arm64/include/asm/unistd32.h
arch/arm64/kernel/entry.S
arch/arm64/kernel/process.c
arch/arm64/kernel/sys.c
arch/arm64/kernel/sys32.S
arch/arm64/kernel/sys_compat.c
arch/avr32/Kconfig
arch/avr32/include/asm/processor.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/mach-common/entry.S
arch/c6x/Kconfig
arch/c6x/include/uapi/asm/unistd.h
arch/c6x/kernel/entry.S
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/unistd.h
arch/cris/kernel/crisksyms.c
arch/h8300/Kconfig
arch/h8300/include/asm/processor.h
arch/h8300/include/asm/ptrace.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/hexagon/Kconfig
arch/hexagon/include/asm/processor.h
arch/hexagon/include/uapi/asm/ptrace.h
arch/hexagon/include/uapi/asm/unistd.h
arch/hexagon/kernel/process.c
arch/hexagon/kernel/signal.c
arch/hexagon/kernel/syscall.c
arch/hexagon/kernel/vm_entry.S
arch/ia64/Kconfig
arch/ia64/include/asm/processor.h
arch/ia64/include/asm/unistd.h
arch/ia64/kernel/entry.S
arch/ia64/kernel/head.S
arch/ia64/kernel/process.c
arch/m32r/Kconfig
arch/m32r/include/asm/processor.h
arch/m32r/include/asm/ptrace.h
arch/m32r/include/asm/unistd.h
arch/m32r/kernel/entry.S
arch/m32r/kernel/process.c
arch/m32r/kernel/sys_m32r.c
arch/m68k/Kconfig
arch/m68k/include/asm/unistd.h
arch/m68k/kernel/entry.S
arch/microblaze/Kconfig
arch/microblaze/include/asm/processor.h
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/mips/Kconfig
arch/mips/include/asm/processor.h
arch/mips/include/asm/ptrace.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/unistd.h
arch/mn10300/kernel/entry.S
arch/openrisc/Kconfig
arch/openrisc/include/uapi/asm/unistd.h
arch/openrisc/kernel/entry.S
arch/openrisc/kernel/process.c
arch/parisc/Kconfig
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/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/unistd.h
arch/s390/kernel/entry.S
arch/s390/kernel/entry64.S
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/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
include/linux/compat.h

index 15ac18a..20b688c 100644 (file)
@@ -7,6 +7,8 @@ config ARM64
        select GENERIC_IOMAP
        select GENERIC_IRQ_PROBE
        select GENERIC_IRQ_SHOW
+       select GENERIC_KERNEL_EXECVE
+       select GENERIC_KERNEL_THREAD
        select GENERIC_SMP_IDLE_THREAD
        select GENERIC_TIME_VSYSCALL
        select HARDIRQS_SW_RESEND
index 77f696c..ab239b2 100644 (file)
@@ -128,11 +128,6 @@ unsigned long get_wchan(struct task_struct *p);
 extern struct task_struct *cpu_switch_to(struct task_struct *prev,
                                         struct task_struct *next);
 
-/*
- * Create a new kernel thread
- */
-extern int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags);
-
 #define task_pt_regs(p) \
        ((struct pt_regs *)(THREAD_START_SP + task_stack_page(p)) - 1)
 
index 09ff335..a1b00cd 100644 (file)
 /*
  * System call wrappers implemented in kernel/entry.S.
  */
-asmlinkage long sys_execve_wrapper(const char __user *filename,
-                                  const char __user *const __user *argv,
-                                  const char __user *const __user *envp);
-asmlinkage long sys_clone_wrapper(unsigned long clone_flags,
-                                 unsigned long newsp,
-                                 void __user *parent_tid,
-                                 unsigned long tls_val,
-                                 void __user *child_tid);
 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 68aff28..43064a8 100644 (file)
@@ -25,4 +25,5 @@
 #define __ARCH_WANT_COMPAT_SYS_RT_SIGSUSPEND
 #define __ARCH_WANT_COMPAT_SYS_SENDFILE
 #endif
+#define __ARCH_WANT_SYS_EXECVE
 #include <uapi/asm/unistd.h>
index 6d909fa..d9850cf 100644 (file)
@@ -23,7 +23,7 @@
 
 __SYSCALL(0,   sys_restart_syscall)
 __SYSCALL(1,   sys_exit)
-__SYSCALL(2,   compat_sys_fork_wrapper)
+__SYSCALL(2,   compat_sys_fork)
 __SYSCALL(3,   sys_read)
 __SYSCALL(4,   sys_write)
 __SYSCALL(5,   compat_sys_open)
@@ -32,7 +32,7 @@ __SYSCALL(7,   sys_ni_syscall)                        /* 7 was sys_waitpid */
 __SYSCALL(8,   sys_creat)
 __SYSCALL(9,   sys_link)
 __SYSCALL(10,  sys_unlink)
-__SYSCALL(11,  compat_sys_execve_wrapper)
+__SYSCALL(11,  compat_sys_execve)
 __SYSCALL(12,  sys_chdir)
 __SYSCALL(13,  sys_ni_syscall)                 /* 13 was sys_time */
 __SYSCALL(14,  sys_mknod)
@@ -141,7 +141,7 @@ __SYSCALL(116, compat_sys_sysinfo)
 __SYSCALL(117, sys_ni_syscall)                 /* 117 was sys_ipc */
 __SYSCALL(118, sys_fsync)
 __SYSCALL(119, compat_sys_sigreturn_wrapper)
-__SYSCALL(120, compat_sys_clone_wrapper)
+__SYSCALL(120, sys_clone)
 __SYSCALL(121, sys_setdomainname)
 __SYSCALL(122, sys_newuname)
 __SYSCALL(123, sys_ni_syscall)                 /* 123 was sys_modify_ldt */
@@ -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_wrapper)
+__SYSCALL(190, compat_sys_vfork)
 __SYSCALL(191, compat_sys_getrlimit)           /* SuS compliant getrlimit */
 __SYSCALL(192, sys_mmap_pgoff)
 __SYSCALL(193, compat_sys_truncate64_wrapper)
index a6f3f7d..cbfa4d2 100644 (file)
@@ -594,7 +594,7 @@ work_resched:
 /*
  * "slow" syscall return path.
  */
-ENTRY(ret_to_user)
+ret_to_user:
        disable_irq                             // disable interrupts
        ldr     x1, [tsk, #TI_FLAGS]
        and     x2, x1, #_TIF_WORK_MASK
@@ -611,7 +611,10 @@ ENDPROC(ret_to_user)
  */
 ENTRY(ret_from_fork)
        bl      schedule_tail
-       get_thread_info tsk
+       cbz     x19, 1f                         // not a kernel thread
+       mov     x0, x20
+       blr     x19
+1:     get_thread_info tsk
        b       ret_to_user
 ENDPROC(ret_from_fork)
 
@@ -673,16 +676,6 @@ __sys_trace_return:
 /*
  * Special system call wrappers.
  */
-ENTRY(sys_execve_wrapper)
-       mov     x3, sp
-       b       sys_execve
-ENDPROC(sys_execve_wrapper)
-
-ENTRY(sys_clone_wrapper)
-       mov     x5, sp
-       b       sys_clone
-ENDPROC(sys_clone_wrapper)
-
 ENTRY(sys_rt_sigreturn_wrapper)
        mov     x0, sp
        b       sys_rt_sigreturn
index e04cebd..8a5f334 100644 (file)
@@ -240,27 +240,41 @@ int copy_thread(unsigned long clone_flags, unsigned long stack_start,
        struct pt_regs *childregs = task_pt_regs(p);
        unsigned long tls = p->thread.tp_value;
 
-       *childregs = *regs;
-       childregs->regs[0] = 0;
+       memset(&p->thread.cpu_context, 0, sizeof(struct cpu_context));
 
-       if (is_compat_thread(task_thread_info(p)))
-               childregs->compat_sp = stack_start;
-       else {
+       if (likely(regs)) {
+               *childregs = *regs;
+               childregs->regs[0] = 0;
+               if (is_compat_thread(task_thread_info(p))) {
+                       if (stack_start)
+                               childregs->compat_sp = stack_start;
+               } else {
+                       /*
+                        * Read the current TLS pointer from tpidr_el0 as it may be
+                        * out-of-sync with the saved value.
+                        */
+                       asm("mrs %0, tpidr_el0" : "=r" (tls));
+                       if (stack_start) {
+                               /* 16-byte aligned stack mandatory on AArch64 */
+                               if (stack_start & 15)
+                                       return -EINVAL;
+                               childregs->sp = stack_start;
+                       }
+               }
                /*
-                * Read the current TLS pointer from tpidr_el0 as it may be
-                * out-of-sync with the saved value.
+                * If a TLS pointer was passed to clone (4th argument), use it
+                * for the new thread.
                 */
-               asm("mrs %0, tpidr_el0" : "=r" (tls));
-               childregs->sp = stack_start;
+               if (clone_flags & CLONE_SETTLS)
+                       tls = regs->regs[3];
+       } else {
+               memset(childregs, 0, sizeof(struct pt_regs));
+               childregs->pstate = PSR_MODE_EL1h;
+               p->thread.cpu_context.x19 = stack_start;
+               p->thread.cpu_context.x20 = stk_sz;
        }
-
-       memset(&p->thread.cpu_context, 0, sizeof(struct cpu_context));
-       p->thread.cpu_context.sp = (unsigned long)childregs;
        p->thread.cpu_context.pc = (unsigned long)ret_from_fork;
-
-       /* If a TLS pointer was passed to clone, use that for the new thread. */
-       if (clone_flags & CLONE_SETTLS)
-               tls = regs->regs[3];
+       p->thread.cpu_context.sp = (unsigned long)childregs;
        p->thread.tp_value = tls;
 
        ptrace_hw_copy_thread(p);
@@ -309,43 +323,6 @@ struct task_struct *__switch_to(struct task_struct *prev,
        return last;
 }
 
-/*
- * Shuffle the argument into the correct register before calling the
- * thread function.  x1 is the thread argument, x2 is the pointer to
- * the thread function, and x3 points to the exit function.
- */
-extern void kernel_thread_helper(void);
-asm(   ".section .text\n"
-"      .align\n"
-"      .type   kernel_thread_helper, #function\n"
-"kernel_thread_helper:\n"
-"      mov     x0, x1\n"
-"      mov     x30, x3\n"
-"      br      x2\n"
-"      .size   kernel_thread_helper, . - kernel_thread_helper\n"
-"      .previous");
-
-#define kernel_thread_exit     do_exit
-
-/*
- * 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.regs[1] = (unsigned long)arg;
-       regs.regs[2] = (unsigned long)fn;
-       regs.regs[3] = (unsigned long)kernel_thread_exit;
-       regs.pc = (unsigned long)kernel_thread_helper;
-       regs.pstate = PSR_MODE_EL1h;
-
-       return do_fork(flags|CLONE_VM|CLONE_UNTRACED, 0, &regs, 0, NULL, NULL);
-}
-EXPORT_SYMBOL(kernel_thread);
-
 unsigned long get_wchan(struct task_struct *p)
 {
        struct stackframe frame;
index b120df3..4364df8 100644 (file)
  */
 asmlinkage long sys_clone(unsigned long clone_flags, unsigned long newsp,
                          int __user *parent_tidptr, unsigned long tls_val,
-                         int __user *child_tidptr, struct pt_regs *regs)
+                         int __user *child_tidptr)
 {
-       if (!newsp)
-               newsp = regs->sp;
-       /* 16-byte aligned stack mandatory on AArch64 */
-       if (newsp & 15)
-               return -EINVAL;
-       return do_fork(clone_flags, newsp, regs, 0, parent_tidptr, child_tidptr);
-}
-
-/*
- * sys_execve() executes a new program.
- */
-asmlinkage long sys_execve(const char __user *filenamei,
-                          const char __user *const __user *argv,
-                          const char __user *const __user *envp,
-                          struct pt_regs *regs)
-{
-       long 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;
-}
-
-int kernel_execve(const char *filename,
-                 const char *const argv[],
-                 const char *const envp[])
-{
-       struct pt_regs regs;
-       int ret;
-
-       memset(&regs, 0, sizeof(struct pt_regs));
-       ret = do_execve(filename,
-                       (const char __user *const __user *)argv,
-                       (const char __user *const __user *)envp, &regs);
-       if (ret < 0)
-               goto out;
-
-       /*
-        * Save argc to the register structure for userspace.
-        */
-       regs.regs[0] = ret;
-
-       /*
-        * We were successful.  We won't be returning to our caller, but
-        * instead to user space by manipulating the kernel stack.
-        */
-       asm(    "add    x0, %0, %1\n\t"
-               "mov    x1, %2\n\t"
-               "mov    x2, %3\n\t"
-               "bl     memmove\n\t"    /* copy regs to top of stack */
-               "mov    x27, #0\n\t"    /* not a syscall */
-               "mov    x28, %0\n\t"    /* thread structure */
-               "mov    sp, x0\n\t"     /* reposition stack pointer */
-               "b      ret_to_user"
-               :
-               : "r" (current_thread_info()),
-                 "Ir" (THREAD_START_SP - sizeof(regs)),
-                 "r" (&regs),
-                 "Ir" (sizeof(regs))
-               : "x0", "x1", "x2", "x27", "x28", "x30", "memory");
-
- out:
-       return ret;
+       return do_fork(clone_flags, newsp, current_pt_regs(), 0,
+                       parent_tidptr, child_tidptr);
 }
-EXPORT_SYMBOL(kernel_execve);
 
 asmlinkage long sys_mmap(unsigned long addr, unsigned long len,
                         unsigned long prot, unsigned long flags,
@@ -118,8 +50,6 @@ asmlinkage long sys_mmap(unsigned long addr, unsigned long len,
 /*
  * Wrappers to pass the pt_regs argument.
  */
-#define sys_execve             sys_execve_wrapper
-#define sys_clone              sys_clone_wrapper
 #define sys_rt_sigreturn       sys_rt_sigreturn_wrapper
 #define sys_sigaltstack                sys_sigaltstack_wrapper
 
index 54c4aec..7ef59e9 100644 (file)
 /*
  * System call wrappers for the AArch32 compatibility layer.
  */
-compat_sys_fork_wrapper:
-       mov     x0, sp
-       b       compat_sys_fork
-ENDPROC(compat_sys_fork_wrapper)
-
-compat_sys_vfork_wrapper:
-       mov     x0, sp
-       b       compat_sys_vfork
-ENDPROC(compat_sys_vfork_wrapper)
-
-compat_sys_execve_wrapper:
-       mov     x3, sp
-       b       compat_sys_execve
-ENDPROC(compat_sys_execve_wrapper)
-
-compat_sys_clone_wrapper:
-       mov     x5, sp
-       b       compat_sys_clone
-ENDPROC(compat_sys_clone_wrapper)
 
 compat_sys_sigreturn_wrapper:
        mov     x0, sp
index 906e3bd..6fabc19 100644 (file)
 #include <asm/cacheflush.h>
 #include <asm/unistd32.h>
 
-asmlinkage int compat_sys_fork(struct pt_regs *regs)
+asmlinkage int compat_sys_fork(void)
 {
-       return do_fork(SIGCHLD, regs->compat_sp, regs, 0, NULL, NULL);
+       return do_fork(SIGCHLD, 0, current_pt_regs(), 0, NULL, NULL);
 }
 
-asmlinkage int compat_sys_clone(unsigned long clone_flags, unsigned long newsp,
-                         int __user *parent_tidptr, int tls_val,
-                         int __user *child_tidptr, struct pt_regs *regs)
+asmlinkage int compat_sys_vfork(void)
 {
-       if (!newsp)
-               newsp = regs->compat_sp;
-
-       return do_fork(clone_flags, newsp, regs, 0, parent_tidptr, child_tidptr);
-}
-
-asmlinkage int compat_sys_vfork(struct pt_regs *regs)
-{
-       return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->compat_sp,
-                      regs, 0, NULL, NULL);
-}
-
-asmlinkage int compat_sys_execve(const char __user *filenamei,
-                                compat_uptr_t argv, compat_uptr_t envp,
-                                struct pt_regs *regs)
-{
-       int error;
-       struct filename *filename;
-
-       filename = getname(filenamei);
-       error = PTR_ERR(filename);
-       if (IS_ERR(filename))
-               goto out;
-       error = compat_do_execve(filename->name, compat_ptr(argv),
-                                       compat_ptr(envp), regs);
-       putname(filename);
-out:
-       return error;
+       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,
index 06e73bf..649aeb9 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 157b4bd..641023d 100644 (file)
@@ -39,6 +39,7 @@
 #define __ARCH_WANT_SYS_GETPGRP
 #define __ARCH_WANT_SYS_RT_SIGACTION
 #define __ARCH_WANT_SYS_RT_SIGSUSPEND
+#define __ARCH_WANT_SYS_EXECVE
 
 /*
  * "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..09b894d 100644 (file)
@@ -68,44 +68,6 @@ void machine_restart(char *cmd)
        while (1) ;
 }
 
-/*
- * 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
  */
@@ -332,26 +294,31 @@ 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,
+               unsigned long arg,
                struct task_struct *p, struct pt_regs *regs)
 {
-       struct pt_regs *childregs;
-
-       childregs = ((struct pt_regs *)(THREAD_SIZE + (unsigned long)task_stack_page(p))) - 1;
-       *childregs = *regs;
-
-       if (user_mode(regs))
+       struct pt_regs *childregs = task_pt_regs(p);
+
+       if (unlikely(!regs)) {
+               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 = *regs;
                childregs->sp = usp;
-       else
-               childregs->sp = (unsigned long)task_stack_page(p) + THREAD_SIZE;
-
-       childregs->r12 = 0; /* Set return value for child */
+               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))
@@ -382,27 +349,6 @@ asmlinkage int sys_vfork(struct pt_regs *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..285a61b 100644 (file)
@@ -50,12 +50,6 @@ __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..fc64977 100644 (file)
@@ -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
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..b4ec1bb 100644 (file)
 #define __ARCH_WANT_SYS_NICE
 #define __ARCH_WANT_SYS_RT_SIGACTION
 #define __ARCH_WANT_SYS_RT_SIGSUSPEND
+#define __ARCH_WANT_SYS_EXECVE
 
 /*
  * "Conditional" syscalls
index f33792c..78f4f63 100644 (file)
@@ -46,22 +46,16 @@ 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)
index bb1cc72..da8df0e 100644 (file)
@@ -101,40 +101,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.
  *
@@ -193,38 +159,31 @@ copy_thread(unsigned long clone_flags,
            struct task_struct *p, struct pt_regs *regs)
 {
        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(!regs)) {
+               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 = *regs;
+               childregs->r0 = 0;
+               p->thread.usp = usp;
+               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 1c3d2c5..4a38c68 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);
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 4ff747d..625beaf 100644 (file)
@@ -14,7 +14,6 @@
  *   more details.
  */
 
-#define __ARCH_WANT_KERNEL_EXECVE
 #define __ARCH_WANT_SYS_EXECVE
 
 /* Use the standard ABI for syscalls. */
index 5449c36..75f6f36 100644 (file)
@@ -413,19 +413,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 __do_IRQ()
        ;; int6 is used for syscalls (see _system_call entry)
index a672444..81b59d1 100644 (file)
@@ -49,6 +49,8 @@ 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
 
 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..1d64582 100644 (file)
@@ -17,6 +17,7 @@
 #include <arch/svinto.h>
 #include <linux/init.h>
 #include <arch/system.h>
+#include <asm/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,35 @@ 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,
+               unsigned long arg,
                struct task_struct *p, struct pt_regs *regs)
 {
-       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);
-        
+       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 = *regs;  /* struct copy of pt_regs */
-        
-        p->set_child_tid = p->clear_child_tid = NULL;
 
         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 +129,7 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,
        
        /* fix the user-mode stackpointer */
 
-       p->thread.usp = usp;    
+       p->thread.usp = usp;
 
        /* and the kernel-mode one */
 
@@ -161,68 +143,28 @@ 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)
+asmlinkage int sys_fork(void)
 {
-       return do_fork(SIGCHLD, rdusp(), regs, 0, NULL, NULL);
+       return do_fork(SIGCHLD, rdusp(), current_pt_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)
+                        int* parent_tid, int* child_tid)
 {
        if (!newusp)
                newusp = rdusp();
-       return do_fork(flags, newusp, regs, 0, parent_tid, child_tid);
+       return do_fork(flags, newusp, current_pt_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)
+asmlinkage int sys_vfork(void)
 {
-       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;
+        return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), current_pt_regs(), 0, NULL, NULL);
 }
 
 unsigned long get_wchan(struct task_struct *p)
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..fe46540 100644 (file)
@@ -16,6 +16,7 @@
 #include <hwregs/reg_map.h>
 #include <hwregs/timer_defs.h>
 #include <hwregs/intr_vect_defs.h>
+#include <asm/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,23 +105,33 @@ 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,
+       unsigned long arg,
        struct task_struct *p, struct pt_regs *regs)
 {
-       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);
+       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 = *regs;     /* Struct copy of pt_regs. */
-        p->set_child_tid = p->clear_child_tid = NULL;
         childregs->r10 = 0;    /* Child returns 0 after a fork/clone. */
 
        /* Set a new TLS ?
@@ -156,7 +142,6 @@ copy_thread(unsigned long clone_flags, unsigned long usp,
        }
 
        /* 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;
@@ -174,35 +159,21 @@ 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)
+sys_fork(void)
 {
-       return do_fork(SIGCHLD, rdusp(), regs, 0, NULL, NULL);
+       return do_fork(SIGCHLD, rdusp(), current_pt_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)
+       unsigned long tls)
 {
        if (!newusp)
                newusp = rdusp();
 
-       return do_fork(flags, newusp, regs, 0, parent_tid, child_tid);
+       return do_fork(flags, newusp, current_pt_regs(), 0, parent_tid, child_tid);
 }
 
 /*
@@ -210,32 +181,9 @@ sys_clone(unsigned long newusp, unsigned long flags, int *parent_tid, int *child
  * 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)
+sys_vfork(void)
 {
-       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;
+       return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), current_pt_regs(), 0, NULL, NULL);
 }
 
 unsigned long
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 51873a4..f181d1f 100644 (file)
 #define __ARCH_WANT_SYS_SIGPROCMASK
 #define __ARCH_WANT_SYS_RT_SIGACTION
 #define __ARCH_WANT_SYS_RT_SIGSUSPEND
+#define __ARCH_WANT_SYS_EXECVE
 
 /*
  * "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 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..00502a6 100644 (file)
@@ -60,6 +60,8 @@ 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)
 #endif /* __KERNEL__ */
 #endif /* __ASSEMBLY__ */
 #endif /* _H8300_PTRACE_H */
index 5cd8828..07afcfa 100644 (file)
 #define __ARCH_WANT_SYS_SIGPROCMASK
 #define __ARCH_WANT_SYS_RT_SIGACTION
 #define __ARCH_WANT_SYS_RT_SIGSUSPEND
+#define __ARCH_WANT_SYS_EXECVE
 
 /*
  * "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..2a45718 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,39 +123,6 @@ 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)
 {
 }
@@ -198,6 +166,13 @@ int copy_thread(unsigned long clone_flags,
 
        childregs = (struct pt_regs *) (THREAD_SIZE + task_stack_page(p)) - 1;
 
+       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 = *regs;
        childregs->retpc = (unsigned long) ret_from_fork;
        childregs->er0 = 0;
@@ -208,27 +183,6 @@ int copy_thread(unsigned long clone_flags,
        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 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 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..26b2e0f 100644 (file)
@@ -27,5 +27,6 @@
  */
 
 #define sys_mmap2 sys_mmap_pgoff
+#define __ARCH_WANT_SYS_EXECVE
 
 #include <asm-generic/unistd.h>
index 9f6d741..cfbc52b 100644 (file)
 #include <linux/uaccess.h>
 #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
@@ -114,7 +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,
+               unsigned long arg, struct task_struct *p,
                struct pt_regs *regs)
 {
        struct thread_info *ti = task_thread_info(p);
@@ -125,61 +98,50 @@ 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 User mode thread, set pt_reg stack pointer as per parameter */
-       if (user_mode(childregs)) {
-               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;
+       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, regs, sizeof(*childregs));
+       ss->r2524 = 0;
+
+       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;
 
        /*
-        * 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;
 
index 319fa64..d2cc327 100644 (file)
  * 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;
+       struct pt_regs *pregs = current_pt_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 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..940a672 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
@@ -484,19 +482,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 +585,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 +622,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..25543a2 100644 (file)
@@ -401,64 +401,15 @@ copy_thread(unsigned long clone_flags,
        struct pt_regs *child_ptregs;
        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 +431,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 +617,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 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 d5e66a4..b27bdcb 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 __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 e736627..62c713f 100644 (file)
@@ -164,41 +164,6 @@ void show_regs(struct pt_regs * regs)
 #endif
 }
 
-/*
- * 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..
  */
@@ -227,29 +192,35 @@ 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 *regs)
 {
        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 = *regs;
+               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)
+asmlinkage int sys_fork(void)
 {
 #ifdef CONFIG_MMU
-       return do_fork(SIGCHLD, regs.spu, &regs, 0, NULL, NULL);
+       struct pt_regs *regs = current_pt_regs();
+       return do_fork(SIGCHLD, regs->spu, regs, 0, NULL, NULL);
 #else
        return -EINVAL;
 #endif /* CONFIG_MMU */
@@ -257,14 +228,13 @@ asmlinkage int sys_fork(unsigned long r0, unsigned long r1, unsigned long r2,
 
 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)
+                        unsigned long child_tidptr)
 {
+       struct pt_regs *regs = current_pt_regs();
        if (!newsp)
-               newsp = regs.spu;
+               newsp = regs->spu;
 
-       return do_fork(clone_flags, newsp, &regs, 0,
+       return do_fork(clone_flags, newsp, regs, 0,
                       (int __user *)parent_tidptr, (int __user *)child_tidptr);
 }
 
@@ -278,37 +248,13 @@ asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp,
  * 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)
+asmlinkage int sys_vfork(void)
 {
-       return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs.spu, &regs, 0,
+       struct pt_regs *regs = current_pt_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 5fc7f7b..0aa1654 100644 (file)
@@ -32,7 +32,6 @@
 #define __ARCH_WANT_SYS_RT_SIGACTION
 #define __ARCH_WANT_SYS_RT_SIGSUSPEND
 #define __ARCH_WANT_SYS_EXECVE
-#define __ARCH_WANT_KERNEL_EXECVE
 
 /*
  * "Conditional" syscalls
index 946cb01..45b2f29 100644 (file)
@@ -115,16 +115,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 4cba743..198abf6 100644 (file)
@@ -26,6 +26,8 @@ config MICROBLAZE
        select GENERIC_ATOMIC64
        select GENERIC_CLOCKEVENTS
        select MODULES_USE_ELF_RELA
+       select GENERIC_KERNEL_THREAD
+       select GENERIC_KERNEL_EXECVE
 
 config SWAP
        def_bool n
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)
 {
index 6985e6e..ea74428 100644 (file)
 #define __ARCH_WANT_SYS_SIGPROCMASK
 #define __ARCH_WANT_SYS_RT_SIGACTION
 #define __ARCH_WANT_SYS_RT_SIGSUSPEND
+#define __ARCH_WANT_SYS_EXECVE
 
 /*
  * "Conditional" syscalls
index 75c3ea1..673a49c 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
 
@@ -559,10 +567,6 @@ 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..10f360e 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 */
@@ -479,11 +461,20 @@ 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(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_vfork):
        brid    microblaze_vfork        /* Do real work (tail-call) */
        addik   r5, r1, 0
@@ -498,10 +489,6 @@ C_ENTRY(sys_clone):
        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(sys_rt_sigreturn_wrapper):
        brid    sys_rt_sigreturn        /* Do real work */
        addik   r5, r1, 0;              /* add user context as 1st arg */
index 1944e00..29768c3 100644 (file)
@@ -119,46 +119,38 @@ void flush_thread(void)
 }
 
 int copy_thread(unsigned long clone_flags, unsigned long usp,
-               unsigned long unused,
+               unsigned long arg,
                struct task_struct *p, struct pt_regs *regs)
 {
        struct pt_regs *childregs = task_pt_regs(p);
        struct thread_info *ti = task_thread_info(p);
 
+       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 = *regs;
-       if (user_mode(regs))
-               childregs->r1 = usp;
-       else
-               childregs->r1 = ((unsigned long) ti) + THREAD_SIZE;
+       childregs->r1 = usp;
 
-#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 +201,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 +215,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..a6a7bae 100644 (file)
@@ -48,24 +48,6 @@ asmlinkage long microblaze_clone(int flags, unsigned long stack,
        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 +57,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 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 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 a6c1332..3320cb4 100644 (file)
@@ -65,6 +65,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..8796dbc 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)
 
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..d13720a 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,7 +114,7 @@ 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 *regs)
 {
        struct thread_info *ti = task_thread_info(p);
        struct pt_regs *childregs;
@@ -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
@@ -221,35 +232,6 @@ int dump_task_fpu(struct task_struct *t, elf_fpregset_t *fpr)
        return 1;
 }
 
-/*
- * 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);
-}
-
 /*
  *
  */
index f6ba838..d27ca34 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..c611e2d 100644 (file)
@@ -127,28 +127,6 @@ _sys_clone(nabi_no_regargs struct pt_regs regs)
                       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 55bbec1..9711d51 100644 (file)
@@ -44,7 +44,6 @@
 #define __ARCH_WANT_SYS_RT_SIGACTION
 #define __ARCH_WANT_SYS_RT_SIGSUSPEND
 #define __ARCH_WANT_SYS_EXECVE
-#define __ARCH_WANT_KERNEL_EXECVE
 
 /*
  * "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 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 437bdbb..5db7bc0 100644 (file)
@@ -20,6 +20,8 @@
 
 #define sys_mmap2 sys_mmap_pgoff
 
+#define __ARCH_WANT_SYS_EXECVE
+
 #include <asm-generic/unistd.h>
 
 #define __NR_or1k_atomic __NR_arch_specific_syscall
index ddfcaa8..c60a09d 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
 
@@ -1088,10 +1083,6 @@ ENTRY(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..e0874b8 100644 (file)
@@ -109,66 +109,82 @@ 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 *regs)
 {
-       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 = *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;
+               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 +193,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 +251,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;
-}
index 11def45..0aec70c 100644 (file)
@@ -22,6 +22,8 @@ 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
 
        help
          The PA-RISC microprocessor is designed by Hewlett-Packard and used
index 541639c..55512e2 100644 (file)
@@ -163,6 +163,7 @@ 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
 
 #endif /* __ASSEMBLY__ */
 
index 18670a0..c9a9abd 100644 (file)
@@ -707,60 +707,10 @@ ENTRY(end_fault_vector)
        .import         handle_interruption,code
        .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)
 
 
        /*
@@ -1776,49 +1692,27 @@ ENTRY(sys_fork_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)
+       mfctl   %cr27, %r28
+       STREG   %r28, PT_CR27(%r1)
 
        LDREG   PT_GR30(%r1),%r25
        copy    %r1,%r24
-       BL      sys_clone,%r2
+       b       sys_clone
        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
-
-       /* strace expects syscall # to be preserved in r20 */
-       ldi     __NR_fork,%r20
-       bv %r0(%r2)
-       STREG   %r20,PT_GR20(%r1)
 ENDPROC(sys_fork_wrapper)
 
        /* 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)
 
@@ -1827,23 +1721,10 @@ 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
+       mfctl   %cr27, %r28
+       STREG   %r28, PT_CR27(%r1)
+       b       sys_clone
        copy    %r1,%r24
-
-       b       wrapper_exit
-       LDREG   -RP_OFFSET-FRAME_SIZE(%r30),%r2
 ENDPROC(sys_clone_wrapper)
 
 
@@ -1851,72 +1732,14 @@ 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)
+       mfctl   %cr27, %r28
+       STREG   %r28, 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
+       b       sys_vfork
        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..38db36f 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>
@@ -164,23 +165,6 @@ void machine_power_off(void)
 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..
  */
@@ -256,8 +240,8 @@ sys_vfork(struct pt_regs *regs)
 
 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 *pregs)
 {
        struct pt_regs * cregs = &(p->thread.regs);
        void *stack = task_stack_page(p);
@@ -270,48 +254,32 @@ 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;
+               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 +291,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 = pregs->gr[23];
        }
 
        return 0;
@@ -335,39 +302,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 3735abd..cb2da96 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..5af5aa7 100644 (file)
@@ -144,6 +144,7 @@ config PPC
        select GENERIC_KERNEL_THREAD
        select HAVE_MOD_ARCH_SPECIFIC
        select MODULES_USE_ELF_RELA
+       select GENERIC_KERNEL_EXECVE
 
 config EARLY_PRINTK
        bool
index 921dce6..280068c 100644 (file)
@@ -56,7 +56,6 @@
 #define __ARCH_WANT_COMPAT_SYS_SENDFILE
 #endif
 #define __ARCH_WANT_SYS_EXECVE
-#define __ARCH_WANT_KERNEL_EXECVE
 
 /*
  * "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..f6d244d 100644 (file)
@@ -745,25 +745,24 @@ 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 {
                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,22 +1026,11 @@ 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);
 }
 
@@ -1050,28 +1038,17 @@ 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);
+       return do_fork(SIGCHLD, 0, 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],
+       return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, 0,
                        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..a163784 100644 (file)
@@ -138,6 +138,7 @@ config S390
        select KTIME_SCALAR if 32BIT
        select HAVE_ARCH_SECCOMP_FILTER
        select GENERIC_KERNEL_THREAD
+       select GENERIC_KERNEL_EXECVE
        select HAVE_MOD_ARCH_SPECIFIC
        select MODULES_USE_ELF_RELA
 
index bbbae41..ccbcab7 100644 (file)
@@ -54,7 +54,6 @@
 #   define __ARCH_WANT_COMPAT_SYS_RT_SIGSUSPEND
 # endif
 #define __ARCH_WANT_SYS_EXECVE
-#define __ARCH_WANT_KERNEL_EXECVE
 
 /*
  * "Conditional" syscalls
index ef46f66..aa8f2ba 100644 (file)
@@ -330,40 +330,18 @@ ENTRY(ret_from_fork)
        la      %r11,STACK_FRAME_OVERHEAD(%r15)
        l       %r12,__LC_THREAD_INFO
        l       %r13,__LC_SVC_NEW_PSW+4
-       tm      __PT_PSW+1(%r11),0x01   # forking a kernel thread ?
-       je      1f
        l       %r1,BASED(.Lschedule_tail)
        basr    %r14,%r1                # call schedule_tail
        TRACE_IRQS_ON
        ssm     __LC_SVC_NEW_PSW        # reenable interrupts
-       j       sysc_tracenogo
-
-1:     # it's a kernel thread
-       st      %r15,__PT_R15(%r11)     # store stack pointer for new kthread
-       l       %r1,BASED(.Lschedule_tail)
-       basr    %r14,%r1                # call schedule_tail
-       TRACE_IRQS_ON
-       ssm     __LC_SVC_NEW_PSW        # reenable interrupts
-       lm      %r9,%r11,__PT_R9(%r11)  # load gprs
+       tm      __PT_PSW+1(%r11),0x01   # forking a kernel thread ?
+       jne     sysc_tracenogo
+       # it's a kernel thread
+       lm      %r9,%r10,__PT_R9(%r11)  # load gprs
 ENTRY(kernel_thread_starter)
        la      %r2,0(%r10)
        basr    %r14,%r9
-       la      %r2,0
-       br      %r11                    # do_exit
-
-#
-# kernel_execve function needs to deal with pt_regs that is not
-# at the usual place
-#
-ENTRY(ret_from_kernel_execve)
-       ssm     __LC_PGM_NEW_PSW        # disable I/O and ext. interrupts
-       lr      %r15,%r2
-       lr      %r11,%r2
-       ahi     %r15,-STACK_FRAME_OVERHEAD
-       xc      __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15)
-       l       %r12,__LC_THREAD_INFO
-       ssm     __LC_SVC_NEW_PSW        # reenable interrupts
-       j       sysc_return
+       j       sysc_tracenogo
 
 /*
  * Program check handler routine
index 07d8de3..499e95e 100644 (file)
@@ -352,33 +352,17 @@ sysc_tracenogo:
 ENTRY(ret_from_fork)
        la      %r11,STACK_FRAME_OVERHEAD(%r15)
        lg      %r12,__LC_THREAD_INFO
-       tm      __PT_PSW+1(%r11),0x01   # forking a kernel thread ?
-       je      1f
        brasl   %r14,schedule_tail
        TRACE_IRQS_ON
        ssm     __LC_SVC_NEW_PSW        # reenable interrupts
-       j       sysc_tracenogo
-1:     # it's a kernel thread
-       stg     %r15,__PT_R15(%r11)     # store stack pointer for new kthread
-       brasl   %r14,schedule_tail
-       TRACE_IRQS_ON
-       ssm     __LC_SVC_NEW_PSW        # reenable interrupts
-       lmg     %r9,%r11,__PT_R9(%r11)  # load gprs
+       tm      __PT_PSW+1(%r11),0x01   # forking a kernel thread ?
+       jne     sysc_tracenogo
+       # it's a kernel thread
+       lmg     %r9,%r10,__PT_R9(%r11)  # load gprs
 ENTRY(kernel_thread_starter)
        la      %r2,0(%r10)
        basr    %r14,%r9
-       la      %r2,0
-       br      %r11                    # do_exit
-
-ENTRY(ret_from_kernel_execve)
-       ssm     __LC_PGM_NEW_PSW        # disable I/O and ext. interrupts
-       lgr     %r15,%r2
-       lgr     %r11,%r2
-       aghi    %r15,-STACK_FRAME_OVERHEAD
-       xc      __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15)
-       lg      %r12,__LC_THREAD_INFO
-       ssm     __LC_SVC_NEW_PSW        # reenable interrupts
-       j       sysc_return
+       j       sysc_tracenogo
 
 /*
  * Program check handler routine
index 4f93a43..a285e78 100644 (file)
@@ -13,6 +13,8 @@ config SCORE
        select GENERIC_CLOCKEVENTS
        select HAVE_MOD_ARCH_SPECIFIC
        select MODULES_USE_ELF_REL
+       select GENERIC_KERNEL_THREAD
+       select GENERIC_KERNEL_EXECVE
 
 choice
        prompt "System type"
index ab3aceb..d9a922d 100644 (file)
@@ -13,7 +13,6 @@ struct task_struct;
  */
 extern void (*cpu_wait)(void);
 
-extern long 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 *regs,
                        unsigned long pc, unsigned long sp);
index 1dd5e0d..8d33253 100644 (file)
@@ -2,7 +2,6 @@
 #define _ASM_SCORE_SYSCALLS_H
 
 asmlinkage long score_clone(struct pt_regs *regs);
-asmlinkage long score_execve(struct pt_regs *regs);
 asmlinkage long score_sigaltstack(struct pt_regs *regs);
 asmlinkage long score_rt_sigreturn(struct pt_regs *regs);
 
index a862384..b006ca4 100644 (file)
@@ -4,5 +4,6 @@
 #define __ARCH_WANT_SYSCALL_NO_FLAGS
 #define __ARCH_WANT_SYSCALL_OFF_T
 #define __ARCH_WANT_SYSCALL_DEPRECATED
+#define __ARCH_WANT_SYS_EXECVE
 
 #include <asm-generic/unistd.h>
index 83bb960..da99010 100644 (file)
@@ -278,6 +278,13 @@ need_resched:
        nop
 #endif
 
+ENTRY(ret_from_kernel_thread)
+       bl      schedule_tail                   # r4=struct task_struct *prev
+       nop
+       mv      r4, r13
+       brl     r12
+       j       syscall_exit
+
 ENTRY(ret_from_fork)
        bl      schedule_tail                   # r4=struct task_struct *prev
 
@@ -480,11 +487,6 @@ illegal_syscall:
        sw      r9, [r0, PT_R7]
        j       syscall_return
 
-ENTRY(sys_execve)
-       mv      r4, r0
-       la      r8, score_execve
-       br      r8
-
 ENTRY(sys_clone)
        mv      r4, r0
        la      r8, score_clone
index 637970c..6f311cf 100644 (file)
@@ -60,6 +60,7 @@ void __noreturn cpu_idle(void)
 }
 
 void ret_from_fork(void);
+void ret_from_kernel_thread(void);
 
 void start_thread(struct pt_regs *regs, unsigned long pc, unsigned long sp)
 {
@@ -86,29 +87,27 @@ void flush_thread(void) {}
  * set up the kernel stack and exception frames for a new process
  */
 int copy_thread(unsigned long clone_flags, unsigned long usp,
-               unsigned long unused,
+               unsigned long arg,
                struct task_struct *p, struct pt_regs *regs)
 {
        struct thread_info *ti = task_thread_info(p);
        struct pt_regs *childregs = task_pt_regs(p);
 
-       p->set_child_tid = NULL;
-       p->clear_child_tid = NULL;
-
-       *childregs = *regs;
-       childregs->regs[7] = 0;         /* Clear error flag */
-       childregs->regs[4] = 0;         /* Child gets zero as return value */
-       regs->regs[4] = p->pid;
-
-       if (childregs->cp0_psr & 0x8) { /* test kernel fork or user fork */
-               childregs->regs[0] = usp;               /* user fork */
+       p->thread.reg0 = (unsigned long) childregs;
+       if (unlikely(!regs)) {
+               memset(childregs, 0, sizeof(struct pt_regs));
+               p->thread->reg12 = usp;
+               p->thread->reg13 = arg;
+               p->thread.reg3 = (unsigned long) ret_from_kernel_thread;
        } else {
-               childregs->regs[28] = (unsigned long) ti; /* kernel fork */
-               childregs->regs[0] = (unsigned long) childregs;
+               *childregs = *regs;
+               childregs->regs[7] = 0;         /* Clear error flag */
+               childregs->regs[4] = 0;         /* Child gets zero as return value */
+               childregs->regs[0] = usp;       /* user fork */
+               regs->regs[4] = p->pid;         /* WTF? */
+               p->thread.reg3 = (unsigned long) ret_from_fork;
        }
 
-       p->thread.reg0 = (unsigned long) childregs;
-       p->thread.reg3 = (unsigned long) ret_from_fork;
        p->thread.cp0_psr = 0;
 
        return 0;
@@ -120,32 +119,6 @@ int dump_fpu(struct pt_regs *regs, elf_fpregset_t *r)
        return 1;
 }
 
-static void __noreturn
-kernel_thread_helper(void *unused0, int (*fn)(void *),
-                void *arg, void *unused1)
-{
-       do_exit(fn(arg));
-}
-
-/*
- * Create a kernel thread.
- */
-long kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
-{
-       struct pt_regs regs;
-
-       memset(&regs, 0, sizeof(regs));
-
-       regs.regs[6] = (unsigned long) arg;
-       regs.regs[5] = (unsigned long) fn;
-       regs.cp0_epc = (unsigned long) kernel_thread_helper;
-       regs.cp0_psr = (regs.cp0_psr & ~(0x1|0x4|0x8)) | \
-                       ((regs.cp0_psr & 0x3) << 2);
-
-       return do_fork(flags | CLONE_VM | CLONE_UNTRACED, \
-                       0, &regs, 0, NULL, NULL);
-}
-
 unsigned long thread_saved_pc(struct task_struct *tsk)
 {
        return task_pt_regs(tsk)->cp0_epc;
index d45cf00..c54434c 100644 (file)
@@ -83,57 +83,3 @@ score_vfork(struct pt_regs *regs)
        return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD,
                        regs->regs[0], regs, 0, NULL, NULL);
 }
-
-/*
- * sys_execve() executes a new program.
- * This is called indirectly via a small wrapper
- */
-asmlinkage long
-score_execve(struct pt_regs *regs)
-{
-       int error;
-       struct filename *filename;
-
-       filename = getname((char __user*)regs->regs[4]);
-       error = PTR_ERR(filename);
-       if (IS_ERR(filename))
-               return error;
-
-       error = do_execve(filename->name,
-                         (const char __user *const __user *)regs->regs[5],
-                         (const char __user *const __user *)regs->regs[6],
-                         regs);
-
-       putname(filename);
-       return error;
-}
-
-/*
- * 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 unsigned long __r4 asm("r4") = (unsigned long) filename;
-       register unsigned long __r5 asm("r5") = (unsigned long) argv;
-       register unsigned long __r6 asm("r6") = (unsigned long) envp;
-       register unsigned long __r7 asm("r7");
-
-       __asm__ __volatile__ (" \n"
-               "ldi    r27, %5         \n"
-               "syscall                \n"
-               "mv     %0, r4          \n"
-               "mv     %1, r7          \n"
-               : "=&r" (__r4), "=r" (__r7)
-               : "r" (__r4), "r" (__r5), "r" (__r6), "i" (__NR_execve)
-               : "r8", "r9", "r10", "r11", "r22", "r23", "r24", "r25",
-                 "r26", "r27", "memory");
-
-       if (__r7 == 0)
-               return __r4;
-
-       return -__r4;
-}
index babc2b8..8451317 100644 (file)
@@ -40,6 +40,8 @@ config SUPERH
        select GENERIC_STRNLEN_USER
        select HAVE_MOD_ARCH_SPECIFIC if DWARF_UNWINDER
        select MODULES_USE_ELF_RELA
+       select GENERIC_KERNEL_THREAD
+       select GENERIC_KERNEL_EXECVE
        help
          The SuperH is a RISC processor targeted for use in embedded systems
          and consumer electronics; it was also used in the Sega Dreamcast
index b6311fd..b1320d5 100644 (file)
@@ -126,11 +126,6 @@ extern void start_thread(struct pt_regs *regs, unsigned long new_pc, unsigned lo
 /* 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 */
 #define copy_segments(p, mm)   do { } while(0)
 #define release_segments(mm)   do { } while(0)
index cd6029f..1ee8946 100644 (file)
@@ -159,11 +159,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 */
 #define copy_segments(p, mm)   do { } while (0)
index 6c1fa55..d2f89f1 100644 (file)
@@ -19,10 +19,6 @@ asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp,
 asmlinkage int sys_vfork(unsigned long r4, unsigned long r5,
                         unsigned long r6, unsigned long r7,
                         struct pt_regs __regs);
-asmlinkage int sys_execve(const char __user *ufilename,
-                         const char __user *const __user *uargv,
-                         const char __user *const __user *uenvp,
-                         unsigned long r7, struct pt_regs __regs);
 asmlinkage int sys_sigsuspend(old_sigset_t mask);
 asmlinkage int sys_sigaction(int sig, const struct old_sigaction __user *act,
                             struct old_sigaction __user *oact);
index ee519f4..3fedd9f 100644 (file)
@@ -21,10 +21,6 @@ asmlinkage int sys_vfork(unsigned long r2, unsigned long r3,
                         unsigned long r4, unsigned long r5,
                         unsigned long r6, unsigned long r7,
                         struct pt_regs *pregs);
-asmlinkage int sys_execve(const char *ufilename, char **uargv,
-                         char **uenvp, unsigned long r5,
-                         unsigned long r6, unsigned long r7,
-                         struct pt_regs *pregs);
 
 /* Misc syscall related bits */
 asmlinkage long long do_syscall_trace_enter(struct pt_regs *regs);
index 38956df..f1f4775 100644 (file)
@@ -28,6 +28,7 @@
 # define __ARCH_WANT_SYS_SIGPENDING
 # define __ARCH_WANT_SYS_SIGPROCMASK
 # define __ARCH_WANT_SYS_RT_SIGACTION
+# define __ARCH_WANT_SYS_EXECVE
 
 /*
  * "Conditional" syscalls
index 88571ff..f259b37 100644 (file)
@@ -16,7 +16,7 @@ obj-y := debugtraps.o dma-nommu.o dumpstack.o                 \
           machvec.o nmi_debug.o process.o                              \
           process_$(BITS).o ptrace.o ptrace_$(BITS).o                  \
           reboot.o return_address.o                                    \
-          setup.o signal_$(BITS).o sys_sh.o sys_sh$(BITS).o            \
+          setup.o signal_$(BITS).o sys_sh.o                            \
           syscalls_$(BITS).o time.o topology.o traps.o                 \
           traps_$(BITS).o unwinder.o
 
@@ -25,6 +25,7 @@ obj-y                         += iomap.o
 obj-$(CONFIG_HAS_IOPORT)       += ioport.o
 endif
 
+obj-$(CONFIG_SUPERH32)         += sys_sh32.o
 obj-y                          += cpu/
 obj-$(CONFIG_VSYSCALL)         += vsyscall/
 obj-$(CONFIG_SMP)              += smp.o
index 7e605b9..0c8d037 100644 (file)
@@ -1228,6 +1228,25 @@ ret_from_fork:
        pta     ret_from_syscall, tr0
        blink   tr0, ZERO
 
+.global        ret_from_kernel_thread
+ret_from_kernel_thread:
+
+       movi    schedule_tail,r5
+       ori     r5, 1, r5
+       ptabs   r5, tr0
+       blink   tr0, LINK
+
+       ld.q    SP, FRAME_R(2), r2
+       ld.q    SP, FRAME_R(3), r3
+       ptabs   r3, tr0
+       blink   tr0, LINK
+
+       ld.q    SP, FRAME_S(FSPC), r2
+       addi    r2, 4, r2               /* Move PC, being pre-execution event */
+       st.q    SP, FRAME_S(FSPC), r2
+       pta     ret_from_syscall, tr0
+       blink   tr0, ZERO
+
 syscall_allowed:
        /* Use LINK to deflect the exit point, default is syscall_ret */
        pta     syscall_ret, tr0
index b96489d..9b6e4be 100644 (file)
@@ -297,6 +297,19 @@ ret_from_fork:
         mov    r0, r4
        bra     syscall_exit
         nop
+
+       .align  2
+       .globl  ret_from_kernel_thread
+ret_from_kernel_thread:
+       mov.l   1f, r8
+       jsr     @r8
+        mov    r0, r4
+       mov.l   @(OFF_R5,r15), r5   ! fn
+       jsr     @r5
+        mov.l  @(OFF_R4,r15), r4   ! arg
+       bra     syscall_exit
+        nop
+
        .align  2
 1:     .long   schedule_tail
 
index ba7345f..fce8029 100644 (file)
@@ -68,38 +68,6 @@ void show_regs(struct pt_regs * regs)
        show_code(regs);
 }
 
-/*
- * Create a kernel thread
- */
-__noreturn void kernel_thread_helper(void *arg, int (*fn)(void *))
-{
-       do_exit(fn(arg));
-}
-
-/* Don't use this in BL=1(cli).  Or else, CPU resets! */
-int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
-{
-       struct pt_regs regs;
-       int pid;
-
-       memset(&regs, 0, sizeof(regs));
-       regs.regs[4] = (unsigned long)arg;
-       regs.regs[5] = (unsigned long)fn;
-
-       regs.pc = (unsigned long)kernel_thread_helper;
-       regs.sr = SR_MD;
-#if defined(CONFIG_SH_FPU)
-       regs.sr |= SR_FD;
-#endif
-
-       /* Ok, create the new process.. */
-       pid = do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0,
-                     &regs, 0, NULL, NULL);
-
-       return pid;
-}
-EXPORT_SYMBOL(kernel_thread);
-
 void start_thread(struct pt_regs *regs, unsigned long new_pc,
                  unsigned long new_sp)
 {
@@ -157,9 +125,10 @@ int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu)
 EXPORT_SYMBOL(dump_fpu);
 
 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,
+               unsigned long arg,
                struct task_struct *p, struct pt_regs *regs)
 {
        struct thread_info *ti = task_thread_info(p);
@@ -177,29 +146,34 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,
        }
 #endif
 
-       childregs = task_pt_regs(p);
-       *childregs = *regs;
+       memset(p->thread.ptrace_bps, 0, sizeof(p->thread.ptrace_bps));
 
-       if (user_mode(regs)) {
-               childregs->regs[15] = usp;
-               ti->addr_limit = USER_DS;
-       } else {
-               childregs->regs[15] = (unsigned long)childregs;
+       childregs = task_pt_regs(p);
+       p->thread.sp = (unsigned long) childregs;
+       if (unlikely(p->flags & PF_KTHREAD)) {
+               memset(childregs, 0, sizeof(struct pt_regs));
+               p->thread.pc = (unsigned long) ret_from_kernel_thread;
+               childregs->regs[4] = arg;
+               childregs->regs[5] = usp;
+               childregs->sr = SR_MD;
+#if defined(CONFIG_SH_FPU)
+               childregs->sr |= SR_FD;
+#endif
                ti->addr_limit = KERNEL_DS;
                ti->status &= ~TS_USEDFPU;
                p->fpu_counter = 0;
+               return 0;
        }
+       *childregs = *regs;
+
+       childregs->regs[15] = usp;
+       ti->addr_limit = USER_DS;
 
        if (clone_flags & CLONE_SETTLS)
                childregs->gbr = childregs->regs[0];
 
        childregs->regs[0] = 0; /* Set return value for child */
-
-       p->thread.sp = (unsigned long) childregs;
        p->thread.pc = (unsigned long) ret_from_fork;
-
-       memset(p->thread.ptrace_bps, 0, sizeof(p->thread.ptrace_bps));
-
        return 0;
 }
 
@@ -288,29 +262,6 @@ asmlinkage int sys_vfork(unsigned long r4, unsigned long r5,
                       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 r7, struct pt_regs __regs)
-{
-       struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
-       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;
-}
-
 unsigned long get_wchan(struct task_struct *p)
 {
        unsigned long pc;
index 98a709f..3a0f3fd 100644 (file)
@@ -284,39 +284,6 @@ void show_regs(struct pt_regs *regs)
        }
 }
 
-/*
- * Create a kernel thread
- */
-__noreturn void kernel_thread_helper(void *arg, int (*fn)(void *))
-{
-       do_exit(fn(arg));
-}
-
-/*
- * 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 freed until both the parent and the child have exited.
- */
-int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
-{
-       struct pt_regs regs;
-
-       memset(&regs, 0, sizeof(regs));
-       regs.regs[2] = (unsigned long)arg;
-       regs.regs[3] = (unsigned long)fn;
-
-       regs.pc = (unsigned long)kernel_thread_helper;
-       regs.sr = (1 << 30);
-
-       /* Ok, create the new process.. */
-       return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0,
-                     &regs, 0, NULL, NULL);
-}
-EXPORT_SYMBOL(kernel_thread);
-
 /*
  * Free current thread data structures etc..
  */
@@ -401,15 +368,17 @@ int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu)
 EXPORT_SYMBOL(dump_fpu);
 
 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,
+               unsigned long arg,
                struct task_struct *p, struct pt_regs *regs)
 {
        struct pt_regs *childregs;
 
 #ifdef CONFIG_SH_FPU
-       if(last_task_used_math == current) {
+       /* can't happen for a kernel thread */
+       if (last_task_used_math == current) {
                enable_fpu();
                save_fpu(current);
                disable_fpu();
@@ -419,7 +388,17 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,
 #endif
        /* Copy from sh version */
        childregs = (struct pt_regs *)(THREAD_SIZE + task_stack_page(p)) - 1;
+       p->thread.sp = (unsigned long) childregs;
 
+       if (unlikely(p->flags & PF_KTHREAD)) {
+               memset(childregs, 0, sizeof(struct pt_regs));
+               childregs->regs[2] = (unsigned long)arg;
+               childregs->regs[3] = (unsigned long)fn;
+               childregs->sr = (1 << 30); /* not user_mode */
+               childregs->sr |= SR_FD; /* Invalidate FPU flag */
+               p->thread.pc = (unsigned long) ret_from_kernel_thread;
+               return 0;
+       }
        *childregs = *regs;
 
        /*
@@ -428,19 +407,12 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,
         * 32-bit wide and context switch must take care
         * of NEFF sign extension.
         */
-       if (user_mode(regs)) {
-               childregs->regs[15] = neff_sign_extend(usp);
-               p->thread.uregs = childregs;
-       } else {
-               childregs->regs[15] =
-                       neff_sign_extend((unsigned long)task_stack_page(p) +
-                                        THREAD_SIZE);
-       }
+       childregs->regs[15] = neff_sign_extend(usp);
+       p->thread.uregs = childregs;
 
        childregs->regs[9] = 0; /* Set return value for child */
        childregs->sr |= SR_FD; /* Invalidate FPU flag */
 
-       p->thread.sp = (unsigned long) childregs;
        p->thread.pc = (unsigned long) ret_from_fork;
 
        return 0;
@@ -482,31 +454,6 @@ asmlinkage int sys_vfork(unsigned long r2, unsigned long r3,
        return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, pregs->regs[15], pregs, 0, 0, 0);
 }
 
-/*
- * sys_execve() executes a new program.
- */
-asmlinkage int sys_execve(const char *ufilename, char **uargv,
-                         char **uenvp, unsigned long r5,
-                         unsigned long r6, unsigned long r7,
-                         struct pt_regs *pregs)
-{
-       int error;
-       struct filename *filename;
-
-       filename = getname((char __user *)ufilename);
-       error = PTR_ERR(filename);
-       if (IS_ERR(filename))
-               goto out;
-
-       error = do_execve(filename->name,
-                         (const char __user *const __user *)uargv,
-                         (const char __user *const __user *)uenvp,
-                         pregs);
-       putname(filename);
-out:
-       return error;
-}
-
 #ifdef CONFIG_FRAME_POINTER
 static int in_sh64_switch_to(unsigned long pc)
 {
index f56b6fe..497bab3 100644 (file)
@@ -60,27 +60,3 @@ asmlinkage int sys_fadvise64_64_wrapper(int fd, u32 offset0, u32 offset1,
                                (u64)len0 << 32 | len1, advice);
 #endif
 }
-
-#if defined(CONFIG_CPU_SH2) || defined(CONFIG_CPU_SH2A)
-#define SYSCALL_ARG3   "trapa #0x23"
-#else
-#define SYSCALL_ARG3   "trapa #0x13"
-#endif
-
-/*
- * 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 __sc0 __asm__ ("r3") = __NR_execve;
-       register long __sc4 __asm__ ("r4") = (long) filename;
-       register long __sc5 __asm__ ("r5") = (long) argv;
-       register long __sc6 __asm__ ("r6") = (long) envp;
-       __asm__ __volatile__ (SYSCALL_ARG3 : "=z" (__sc0)
-                       : "0" (__sc0), "r" (__sc4), "r" (__sc5), "r" (__sc6)
-                       : "memory");
-       return __sc0;
-}
diff --git a/arch/sh/kernel/sys_sh64.c b/arch/sh/kernel/sys_sh64.c
deleted file mode 100644 (file)
index c5a38c4..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * arch/sh/kernel/sys_sh64.c
- *
- * Copyright (C) 2000, 2001  Paolo Alberelli
- *
- * This file contains various random system calls that
- * have a non-standard calling sequence on the Linux/SH5
- * platform.
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- */
-#include <linux/errno.h>
-#include <linux/rwsem.h>
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <linux/fs.h>
-#include <linux/smp.h>
-#include <linux/sem.h>
-#include <linux/msg.h>
-#include <linux/shm.h>
-#include <linux/stat.h>
-#include <linux/mman.h>
-#include <linux/file.h>
-#include <linux/syscalls.h>
-#include <linux/ipc.h>
-#include <asm/uaccess.h>
-#include <asm/ptrace.h>
-#include <asm/unistd.h>
-
-/*
- * 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 __sc0 __asm__ ("r9") = ((0x13 << 16) | __NR_execve);
-       register unsigned long __sc2 __asm__ ("r2") = (unsigned long) filename;
-       register unsigned long __sc3 __asm__ ("r3") = (unsigned long) argv;
-       register unsigned long __sc4 __asm__ ("r4") = (unsigned long) envp;
-       __asm__ __volatile__ ("trapa    %1 !\t\t\t execve(%2,%3,%4)"
-       : "=r" (__sc0)
-       : "r" (__sc0), "r" (__sc2), "r" (__sc3), "r" (__sc4) );
-       __asm__ __volatile__ ("!dummy   %0 %1 %2 %3"
-       : : "r" (__sc0), "r" (__sc2), "r" (__sc3), "r" (__sc4) : "memory");
-       return __sc0;
-}
index 9f2edb5..0c7d365 100644 (file)
@@ -41,6 +41,8 @@ config SPARC
        select GENERIC_STRNCPY_FROM_USER
        select GENERIC_STRNLEN_USER
        select MODULES_USE_ELF_RELA
+       select GENERIC_KERNEL_THREAD
+       select GENERIC_KERNEL_EXECVE
 
 config SPARC32
        def_bool !64BIT
index f74ac9e..c1e0191 100644 (file)
@@ -106,7 +106,6 @@ static inline void start_thread(struct pt_regs * regs, unsigned long pc,
 
 /* Free all resources held by a thread. */
 #define release_thread(tsk)            do { } while(0)
-extern pid_t kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
 
 extern unsigned long get_wchan(struct task_struct *);
 
index 721e25f..cce72ce 100644 (file)
@@ -94,6 +94,7 @@ struct thread_struct {
 #ifndef __ASSEMBLY__
 
 #include <linux/types.h>
+#include <asm/fpumacro.h>
 
 /* Return saved PC of a blocked thread. */
 struct task_struct;
@@ -143,6 +144,10 @@ do { \
        : \
        : "r" (regs), "r" (sp - sizeof(struct reg_window) - STACK_BIAS), \
          "i" ((const unsigned long)(&((struct pt_regs *)0)->u_regs[0]))); \
+       fprs_write(0);  \
+       current_thread_info()->xfsr[0] = 0;     \
+       current_thread_info()->fpsaved[0] = 0;  \
+       regs->tstate &= ~TSTATE_PEF;    \
 } while (0)
 
 #define start_thread32(regs, pc, sp) \
@@ -183,13 +188,15 @@ do { \
        : \
        : "r" (regs), "r" (sp - sizeof(struct reg_window32)), \
          "i" ((const unsigned long)(&((struct pt_regs *)0)->u_regs[0]))); \
+       fprs_write(0);  \
+       current_thread_info()->xfsr[0] = 0;     \
+       current_thread_info()->fpsaved[0] = 0;  \
+       regs->tstate &= ~TSTATE_PEF;    \
 } while (0)
 
 /* Free all resources held by a thread. */
 #define release_thread(tsk)            do { } while (0)
 
-extern pid_t kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
-
 extern unsigned long get_wchan(struct task_struct *task);
 
 #define task_pt_regs(tsk) (task_thread_info(tsk)->kregs)
index da43bdc..bdfafd7 100644 (file)
@@ -32,6 +32,9 @@ static inline bool pt_regs_clear_syscall(struct pt_regs *regs)
 #define arch_ptrace_stop(exit_code, info) \
        synchronize_user_stack()
 
+#define current_pt_regs() \
+       ((struct pt_regs *)((unsigned long)current_thread_info() + THREAD_SIZE) - 1)
+
 struct global_reg_snapshot {
        unsigned long           tstate;
        unsigned long           tpc;
@@ -55,9 +58,7 @@ union global_cpu_snapshot {
 
 extern union global_cpu_snapshot global_cpu_snapshot[NR_CPUS];
 
-#define force_successful_syscall_return()          \
-do {   current_thread_info()->syscall_noerror = 1; \
-} while (0)
+#define force_successful_syscall_return() set_thread_noerror(1)
 #define user_mode(regs) (!((regs)->tstate & TSTATE_PRIV))
 #define instruction_pointer(regs) ((regs)->tpc)
 #define instruction_pointer_set(regs, val) ((regs)->tpc = (val))
@@ -100,6 +101,9 @@ static inline bool pt_regs_clear_syscall(struct pt_regs *regs)
 #define arch_ptrace_stop(exit_code, info) \
        synchronize_user_stack()
 
+#define current_pt_regs() \
+       ((struct pt_regs *)((unsigned long)current_thread_info() + THREAD_SIZE) - 1)
+
 #define user_mode(regs) (!((regs)->psr & PSR_PS))
 #define instruction_pointer(regs) ((regs)->pc)
 #define user_stack_pointer(regs) ((regs)->u_regs[UREG_FP])
index 7923c4a..cad36f5 100644 (file)
@@ -23,7 +23,7 @@ do {  flush_tlb_pending();                                            \
        /* If you are tempted to conditionalize the following */        \
        /* so that ASI is only written if it changes, think again. */   \
        __asm__ __volatile__("wr %%g0, %0, %%asi"                       \
-       : : "r" (__thread_flag_byte_ptr(task_thread_info(next))[TI_FLAG_BYTE_CURRENT_DS]));\
+       : : "r" (task_thread_info(next)->current_ds));\
        trap_block[current_thread_info()->cpu].thread =                 \
                task_thread_info(next);                                 \
        __asm__ __volatile__(                                           \
index 45a43f6..bf8972a 100644 (file)
@@ -8,6 +8,4 @@ extern asmlinkage long sparc_do_fork(unsigned long clone_flags,
                                     struct pt_regs *regs,
                                     unsigned long stack_size);
 
-extern asmlinkage int sparc_execve(struct pt_regs *regs);
-
 #endif /* _SPARC64_SYSCALLS_H */
index a3fe4dc..269bd92 100644 (file)
 #define TI_FLAG_FAULT_CODE_SHIFT       56
 #define TI_FLAG_BYTE_WSTATE            1
 #define TI_FLAG_WSTATE_SHIFT           48
-#define TI_FLAG_BYTE_CWP               2
-#define TI_FLAG_CWP_SHIFT              40
-#define TI_FLAG_BYTE_CURRENT_DS                3
-#define TI_FLAG_CURRENT_DS_SHIFT       32
-#define TI_FLAG_BYTE_FPDEPTH           4
-#define TI_FLAG_FPDEPTH_SHIFT          24
+#define TI_FLAG_BYTE_NOERROR           2
+#define TI_FLAG_BYTE_NOERROR_SHIFT     40
+#define TI_FLAG_BYTE_FPDEPTH           3
+#define TI_FLAG_FPDEPTH_SHIFT          32
+#define TI_FLAG_BYTE_CWP               4
+#define TI_FLAG_CWP_SHIFT              24
 #define TI_FLAG_BYTE_WSAVED            5
 #define TI_FLAG_WSAVED_SHIFT           16
 
@@ -47,7 +47,7 @@ struct thread_info {
        struct exec_domain      *exec_domain;
        int                     preempt_count;  /* 0 => preemptable, <0 => BUG */
        __u8                    new_child;
-       __u8                    syscall_noerror;
+       __u8                    current_ds;
        __u16                   cpu;
 
        unsigned long           *utraps;
@@ -74,9 +74,9 @@ struct thread_info {
 #define TI_FAULT_CODE  (TI_FLAGS + TI_FLAG_BYTE_FAULT_CODE)
 #define TI_WSTATE      (TI_FLAGS + TI_FLAG_BYTE_WSTATE)
 #define TI_CWP         (TI_FLAGS + TI_FLAG_BYTE_CWP)
-#define TI_CURRENT_DS  (TI_FLAGS + TI_FLAG_BYTE_CURRENT_DS)
 #define TI_FPDEPTH     (TI_FLAGS + TI_FLAG_BYTE_FPDEPTH)
 #define TI_WSAVED      (TI_FLAGS + TI_FLAG_BYTE_WSAVED)
+#define TI_SYS_NOERROR (TI_FLAGS + TI_FLAG_BYTE_NOERROR)
 #define TI_FPSAVED     0x00000010
 #define TI_KSP         0x00000018
 #define TI_FAULT_ADDR  0x00000020
@@ -84,7 +84,7 @@ struct thread_info {
 #define TI_EXEC_DOMAIN 0x00000030
 #define TI_PRE_COUNT   0x00000038
 #define TI_NEW_CHILD   0x0000003c
-#define TI_SYS_NOERROR 0x0000003d
+#define TI_CURRENT_DS  0x0000003d
 #define TI_CPU         0x0000003e
 #define TI_UTRAPS      0x00000040
 #define TI_REG_WINDOW  0x00000048
@@ -121,7 +121,7 @@ struct thread_info {
 #define INIT_THREAD_INFO(tsk)                          \
 {                                                      \
        .task           =       &tsk,                   \
-       .flags          = ((unsigned long)ASI_P) << TI_FLAG_CURRENT_DS_SHIFT,   \
+       .current_ds     =       ASI_P,                  \
        .exec_domain    =       &default_exec_domain,   \
        .preempt_count  =       INIT_PREEMPT_COUNT,     \
        .restart_block  = {                             \
@@ -153,13 +153,12 @@ register struct thread_info *current_thread_info_reg asm("g6");
 #define set_thread_wstate(val)         (__cur_thread_flag_byte_ptr[TI_FLAG_BYTE_WSTATE] = (val))
 #define get_thread_cwp()               (__cur_thread_flag_byte_ptr[TI_FLAG_BYTE_CWP])
 #define set_thread_cwp(val)            (__cur_thread_flag_byte_ptr[TI_FLAG_BYTE_CWP] = (val))
-#define get_thread_current_ds()                (__cur_thread_flag_byte_ptr[TI_FLAG_BYTE_CURRENT_DS])
-#define set_thread_current_ds(val)     (__cur_thread_flag_byte_ptr[TI_FLAG_BYTE_CURRENT_DS] = (val))
+#define get_thread_noerror()           (__cur_thread_flag_byte_ptr[TI_FLAG_BYTE_NOERROR])
+#define set_thread_noerror(val)                (__cur_thread_flag_byte_ptr[TI_FLAG_BYTE_NOERROR] = (val))
 #define get_thread_fpdepth()           (__cur_thread_flag_byte_ptr[TI_FLAG_BYTE_FPDEPTH])
 #define set_thread_fpdepth(val)                (__cur_thread_flag_byte_ptr[TI_FLAG_BYTE_FPDEPTH] = (val))
 #define get_thread_wsaved()            (__cur_thread_flag_byte_ptr[TI_FLAG_BYTE_WSAVED])
 #define set_thread_wsaved(val)         (__cur_thread_flag_byte_ptr[TI_FLAG_BYTE_WSAVED] = (val))
-
 #endif /* !(__ASSEMBLY__) */
 
 /*
index 73083e1..e562d3c 100644 (file)
 #define VERIFY_READ    0
 #define VERIFY_WRITE   1
 
-#define get_fs() ((mm_segment_t) { get_thread_current_ds() })
+#define get_fs() ((mm_segment_t){(current_thread_info()->current_ds)})
 #define get_ds() (KERNEL_DS)
 
 #define segment_eq(a,b)  ((a).seg == (b).seg)
 
 #define set_fs(val)                                                            \
 do {                                                                           \
-       set_thread_current_ds((val).seg);                                       \
+       current_thread_info()->current_ds =(val).seg;                           \
        __asm__ __volatile__ ("wr %%g0, %0, %%asi" : : "r" ((val).seg));        \
 } while(0)
 
index 0ecea6e..c3e5d8b 100644 (file)
@@ -46,6 +46,7 @@
 #define __ARCH_WANT_COMPAT_SYS_RT_SIGSUSPEND
 #define __ARCH_WANT_COMPAT_SYS_SENDFILE
 #endif
+#define __ARCH_WANT_SYS_EXECVE
 
 /*
  * "Conditional" syscalls
index dcaa1cf..21fd1a8 100644 (file)
@@ -806,23 +806,10 @@ sys_nis_syscall:
        call    c_sys_nis_syscall
         mov    %l5, %o7
 
-       .align  4
-       .globl  sys_execve
-sys_execve:
-       mov     %o7, %l5
-       add     %sp, STACKFRAME_SZ, %o0         ! pt_regs *regs arg
-       call    sparc_execve
-        mov    %l5, %o7
-
-       .globl  sunos_execv
 sunos_execv:
-       st      %g0, [%sp + STACKFRAME_SZ + PT_I2]
-
-       call    sparc_execve
-        add    %sp, STACKFRAME_SZ, %o0
-
-       b       ret_sys_call
-        ld     [%sp + STACKFRAME_SZ + PT_I0], %o0
+       .globl  sunos_execv
+       b       sys_execve
+        clr    %i2
 
        .align  4
        .globl  sys_sparc_pipe
@@ -959,17 +946,9 @@ flush_patch_four:
         .align  4
 linux_sparc_ni_syscall:
        sethi   %hi(sys_ni_syscall), %l7
-       b       syscall_is_too_hard
+       b       do_syscall
         or     %l7, %lo(sys_ni_syscall), %l7
 
-linux_fast_syscall:
-       andn    %l7, 3, %l7
-       mov     %i0, %o0
-       mov     %i1, %o1
-       mov     %i2, %o2
-       jmpl    %l7 + %g0, %g0
-        mov    %i3, %o3
-
 linux_syscall_trace:
        add     %sp, STACKFRAME_SZ, %o0
        call    syscall_trace
@@ -991,6 +970,23 @@ ret_from_fork:
        b       ret_sys_call
         ld     [%sp + STACKFRAME_SZ + PT_I0], %o0
 
+       .globl  ret_from_kernel_thread
+ret_from_kernel_thread:
+       call    schedule_tail
+        ld     [%g3 + TI_TASK], %o0
+       ld      [%sp + STACKFRAME_SZ + PT_G1], %l0
+       call    %l0
+        ld     [%sp + STACKFRAME_SZ + PT_G2], %o0
+       rd      %psr, %l1
+       ld      [%sp + STACKFRAME_SZ + PT_PSR], %l0
+       andn    %l0, PSR_CWP, %l0
+       nop
+       and     %l1, PSR_CWP, %l1
+       or      %l0, %l1, %l0
+       st      %l0, [%sp + STACKFRAME_SZ + PT_PSR]
+       b       ret_sys_call
+        mov    0, %o0
+
        /* Linux native system calls enter here... */
        .align  4
        .globl  linux_sparc_syscall
@@ -1002,11 +998,8 @@ linux_sparc_syscall:
        bgeu    linux_sparc_ni_syscall
         sll    %g1, 2, %l4
        ld      [%l7 + %l4], %l7
-       andcc   %l7, 1, %g0
-       bne     linux_fast_syscall
-        /* Just do first insn from SAVE_ALL in the delay slot */
 
-syscall_is_too_hard:
+do_syscall:
        SAVE_ALL_HEAD
         rd     %wim, %l3
 
index 786b185..1276ca2 100644 (file)
@@ -92,8 +92,10 @@ etrap_save:  save    %g2, -STACK_BIAS, %sp
                rdpr    %wstate, %g2
                wrpr    %g0, 0, %canrestore
                sll     %g2, 3, %g2
+
+               /* Set TI_SYS_FPDEPTH to 1 and clear TI_SYS_NOERROR.  */
                mov     1, %l5
-               stb     %l5, [%l6 + TI_FPDEPTH]
+               sth     %l5, [%l6 + TI_SYS_NOERROR]
 
                wrpr    %g3, 0, %otherwin
                wrpr    %g2, 0, %wstate
@@ -152,7 +154,9 @@ etrap_save: save    %g2, -STACK_BIAS, %sp
                add     %l6, TI_FPSAVED + 1, %l4
                srl     %l5, 1, %l3
                add     %l5, 2, %l5
-               stb     %l5, [%l6 + TI_FPDEPTH]
+
+               /* Set TI_SYS_FPDEPTH to %l5 and clear TI_SYS_NOERROR.  */
+               sth     %l5, [%l6 + TI_SYS_NOERROR]
                ba,pt   %xcc, 2b
                 stb    %g0, [%l4 + %l3]
                nop
index 487bffb..bf4c6ad 100644 (file)
@@ -316,9 +316,10 @@ asmlinkage int sparc_do_fork(unsigned long clone_flags,
  * XXX See comment above sys_vfork in sparc64. todo.
  */
 extern void ret_from_fork(void);
+extern void ret_from_kernel_thread(void);
 
 int copy_thread(unsigned long clone_flags, unsigned long sp,
-               unsigned long unused,
+               unsigned long arg,
                struct task_struct *p, struct pt_regs *regs)
 {
        struct thread_info *ti = task_thread_info(p);
@@ -336,16 +337,13 @@ int copy_thread(unsigned long clone_flags, unsigned long sp,
        }
 
        /*
-        *  p->thread_info         new_stack   childregs
-        *  !                      !           !             {if(PSR_PS) }
-        *  V                      V (stk.fr.) V  (pt_regs)  { (stk.fr.) }
-        *  +----- - - - - - ------+===========+============={+==========}+
+        *  p->thread_info         new_stack   childregs stack bottom
+        *  !                      !           !             !
+        *  V                      V (stk.fr.) V  (pt_regs)  V
+        *  +----- - - - - - ------+===========+=============+
         */
        new_stack = task_stack_page(p) + THREAD_SIZE;
-       if (regs->psr & PSR_PS)
-               new_stack -= STACKFRAME_SZ;
        new_stack -= STACKFRAME_SZ + TRACEREG_SZ;
-       memcpy(new_stack, (char *)regs - STACKFRAME_SZ, STACKFRAME_SZ + TRACEREG_SZ);
        childregs = (struct pt_regs *) (new_stack + STACKFRAME_SZ);
 
        /*
@@ -356,55 +354,58 @@ int copy_thread(unsigned long clone_flags, unsigned long sp,
         * Thus, kpsr|=PSR_PIL.
         */
        ti->ksp = (unsigned long) new_stack;
+       p->thread.kregs = childregs;
+
+       if (unlikely(p->flags & PF_KTHREAD)) {
+               extern int nwindows;
+               unsigned long psr;
+               memset(new_stack, 0, STACKFRAME_SZ + TRACEREG_SZ);
+               p->thread.flags |= SPARC_FLAG_KTHREAD;
+               p->thread.current_ds = KERNEL_DS;
+               ti->kpc = (((unsigned long) ret_from_kernel_thread) - 0x8);
+               childregs->u_regs[UREG_G1] = sp; /* function */
+               childregs->u_regs[UREG_G2] = arg;
+               psr = childregs->psr = get_psr();
+               ti->kpsr = psr | PSR_PIL;
+               ti->kwim = 1 << (((psr & PSR_CWP) + 1) % nwindows);
+               return 0;
+       }
+       memcpy(new_stack, (char *)regs - STACKFRAME_SZ, STACKFRAME_SZ + TRACEREG_SZ);
+       childregs->u_regs[UREG_FP] = sp;
+       p->thread.flags &= ~SPARC_FLAG_KTHREAD;
+       p->thread.current_ds = USER_DS;
        ti->kpc = (((unsigned long) ret_from_fork) - 0x8);
        ti->kpsr = current->thread.fork_kpsr | PSR_PIL;
        ti->kwim = current->thread.fork_kwim;
 
-       if(regs->psr & PSR_PS) {
-               extern struct pt_regs fake_swapper_regs;
+       if (sp != regs->u_regs[UREG_FP]) {
+               struct sparc_stackf __user *childstack;
+               struct sparc_stackf __user *parentstack;
 
-               p->thread.kregs = &fake_swapper_regs;
-               new_stack += STACKFRAME_SZ + TRACEREG_SZ;
-               childregs->u_regs[UREG_FP] = (unsigned long) new_stack;
-               p->thread.flags |= SPARC_FLAG_KTHREAD;
-               p->thread.current_ds = KERNEL_DS;
-               memcpy(new_stack, (void *)regs->u_regs[UREG_FP], STACKFRAME_SZ);
-               childregs->u_regs[UREG_G6] = (unsigned long) ti;
-       } else {
-               p->thread.kregs = childregs;
-               childregs->u_regs[UREG_FP] = sp;
-               p->thread.flags &= ~SPARC_FLAG_KTHREAD;
-               p->thread.current_ds = USER_DS;
-
-               if (sp != regs->u_regs[UREG_FP]) {
-                       struct sparc_stackf __user *childstack;
-                       struct sparc_stackf __user *parentstack;
-
-                       /*
-                        * This is a clone() call with supplied user stack.
-                        * Set some valid stack frames to give to the child.
-                        */
-                       childstack = (struct sparc_stackf __user *)
-                               (sp & ~0xfUL);
-                       parentstack = (struct sparc_stackf __user *)
-                               regs->u_regs[UREG_FP];
+               /*
+                * This is a clone() call with supplied user stack.
+                * Set some valid stack frames to give to the child.
+                */
+               childstack = (struct sparc_stackf __user *)
+                       (sp & ~0xfUL);
+               parentstack = (struct sparc_stackf __user *)
+                       regs->u_regs[UREG_FP];
 
 #if 0
-                       printk("clone: parent stack:\n");
-                       show_stackframe(parentstack);
+               printk("clone: parent stack:\n");
+               show_stackframe(parentstack);
 #endif
 
-                       childstack = clone_stackframe(childstack, parentstack);
-                       if (!childstack)
-                               return -EFAULT;
+               childstack = clone_stackframe(childstack, parentstack);
+               if (!childstack)
+                       return -EFAULT;
 
 #if 0
-                       printk("clone: child stack:\n");
-                       show_stackframe(childstack);
+               printk("clone: child stack:\n");
+               show_stackframe(childstack);
 #endif
 
-                       childregs->u_regs[UREG_FP] = (unsigned long)childstack;
-               }
+               childregs->u_regs[UREG_FP] = (unsigned long)childstack;
        }
 
 #ifdef CONFIG_SMP
@@ -475,69 +476,6 @@ int dump_fpu (struct pt_regs * regs, elf_fpregset_t * fpregs)
        return 1;
 }
 
-/*
- * sparc_execve() executes a new program after the asm stub has set
- * things up for us.  This should basically do what I want it to.
- */
-asmlinkage int sparc_execve(struct pt_regs *regs)
-{
-       int error, base = 0;
-       struct filename *filename;
-
-       /* Check for indirect call. */
-       if(regs->u_regs[UREG_G1] == 0)
-               base = 1;
-
-       filename = getname((char __user *)regs->u_regs[base + UREG_I0]);
-       error = PTR_ERR(filename);
-       if(IS_ERR(filename))
-               goto out;
-       error = do_execve(filename->name,
-                         (const char __user *const  __user *)
-                         regs->u_regs[base + UREG_I1],
-                         (const char __user *const  __user *)
-                         regs->u_regs[base + UREG_I2],
-                         regs);
-       putname(filename);
-out:
-       return error;
-}
-
-/*
- * 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 freed until both the parent and the child have exited.
- */
-pid_t kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
-{
-       long retval;
-
-       __asm__ __volatile__("mov %4, %%g2\n\t"    /* Set aside fn ptr... */
-                            "mov %5, %%g3\n\t"    /* and arg. */
-                            "mov %1, %%g1\n\t"
-                            "mov %2, %%o0\n\t"    /* Clone flags. */
-                            "mov 0, %%o1\n\t"     /* usp arg == 0 */
-                            "t 0x10\n\t"          /* Linux/Sparc clone(). */
-                            "cmp %%o1, 0\n\t"
-                            "be 1f\n\t"           /* The parent, just return. */
-                            " nop\n\t"            /* Delay slot. */
-                            "jmpl %%g2, %%o7\n\t" /* Call the function. */
-                            " mov %%g3, %%o0\n\t" /* Get back the arg in delay. */
-                            "mov %3, %%g1\n\t"
-                            "t 0x10\n\t"          /* Linux/Sparc exit(). */
-                            /* Notreached by child. */
-                            "1: mov %%o0, %0\n\t" :
-                            "=r" (retval) :
-                            "i" (__NR_clone), "r" (flags | CLONE_VM | CLONE_UNTRACED),
-                            "i" (__NR_exit),  "r" (fn), "r" (arg) :
-                            "g1", "g2", "g3", "o0", "o1", "memory", "cc");
-       return retval;
-}
-EXPORT_SYMBOL(kernel_thread);
-
 unsigned long get_wchan(struct task_struct *task)
 {
        unsigned long pc, fp, bias = 0;
index c6e0c29..dff54f4 100644 (file)
@@ -622,64 +622,55 @@ asmlinkage long sparc_do_fork(unsigned long clone_flags,
  * Child  -->  %o0 == parents pid, %o1 == 1
  */
 int copy_thread(unsigned long clone_flags, unsigned long sp,
-               unsigned long unused,
+               unsigned long arg,
                struct task_struct *p, struct pt_regs *regs)
 {
        struct thread_info *t = task_thread_info(p);
        struct sparc_stackf *parent_sf;
        unsigned long child_stack_sz;
        char *child_trap_frame;
-       int kernel_thread;
-
-       kernel_thread = (regs->tstate & TSTATE_PRIV) ? 1 : 0;
-       parent_sf = ((struct sparc_stackf *) regs) - 1;
 
        /* Calculate offset to stack_frame & pt_regs */
-       child_stack_sz = ((STACKFRAME_SZ + TRACEREG_SZ) +
-                         (kernel_thread ? STACKFRAME_SZ : 0));
+       child_stack_sz = (STACKFRAME_SZ + TRACEREG_SZ);
        child_trap_frame = (task_stack_page(p) +
                            (THREAD_SIZE - child_stack_sz));
-       memcpy(child_trap_frame, parent_sf, child_stack_sz);
 
-       t->flags = (t->flags & ~((0xffUL << TI_FLAG_CWP_SHIFT) |
-                                (0xffUL << TI_FLAG_CURRENT_DS_SHIFT))) |
-               (((regs->tstate + 1) & TSTATE_CWP) << TI_FLAG_CWP_SHIFT);
        t->new_child = 1;
        t->ksp = ((unsigned long) child_trap_frame) - STACK_BIAS;
        t->kregs = (struct pt_regs *) (child_trap_frame +
                                       sizeof(struct sparc_stackf));
        t->fpsaved[0] = 0;
 
-       if (kernel_thread) {
-               struct sparc_stackf *child_sf = (struct sparc_stackf *)
-                       (child_trap_frame + (STACKFRAME_SZ + TRACEREG_SZ));
-
-               /* Zero terminate the stack backtrace.  */
-               child_sf->fp = NULL;
-               t->kregs->u_regs[UREG_FP] =
-                 ((unsigned long) child_sf) - STACK_BIAS;
+       if (unlikely(p->flags & PF_KTHREAD)) {
+               memset(child_trap_frame, 0, child_stack_sz);
+               __thread_flag_byte_ptr(t)[TI_FLAG_BYTE_CWP] = 
+                       (current_pt_regs()->tstate + 1) & TSTATE_CWP;
+               t->current_ds = ASI_P;
+               t->kregs->u_regs[UREG_G1] = sp; /* function */
+               t->kregs->u_regs[UREG_G2] = arg;
+               return 0;
+       }
 
-               t->flags |= ((long)ASI_P << TI_FLAG_CURRENT_DS_SHIFT);
-               t->kregs->u_regs[UREG_G6] = (unsigned long) t;
-               t->kregs->u_regs[UREG_G4] = (unsigned long) t->task;
-       } else {
-               if (t->flags & _TIF_32BIT) {
-                       sp &= 0x00000000ffffffffUL;
-                       regs->u_regs[UREG_FP] &= 0x00000000ffffffffUL;
-               }
-               t->kregs->u_regs[UREG_FP] = sp;
-               t->flags |= ((long)ASI_AIUS << TI_FLAG_CURRENT_DS_SHIFT);
-               if (sp != regs->u_regs[UREG_FP]) {
-                       unsigned long csp;
-
-                       csp = clone_stackframe(sp, regs->u_regs[UREG_FP]);
-                       if (!csp)
-                               return -EFAULT;
-                       t->kregs->u_regs[UREG_FP] = csp;
-               }
-               if (t->utraps)
-                       t->utraps[0]++;
+       parent_sf = ((struct sparc_stackf *) regs) - 1;
+       memcpy(child_trap_frame, parent_sf, child_stack_sz);
+       if (t->flags & _TIF_32BIT) {
+               sp &= 0x00000000ffffffffUL;
+               regs->u_regs[UREG_FP] &= 0x00000000ffffffffUL;
        }
+       t->kregs->u_regs[UREG_FP] = sp;
+       __thread_flag_byte_ptr(t)[TI_FLAG_BYTE_CWP] = 
+               (regs->tstate + 1) & TSTATE_CWP;
+       t->current_ds = ASI_AIUS;
+       if (sp != regs->u_regs[UREG_FP]) {
+               unsigned long csp;
+
+               csp = clone_stackframe(sp, regs->u_regs[UREG_FP]);
+               if (!csp)
+                       return -EFAULT;
+               t->kregs->u_regs[UREG_FP] = csp;
+       }
+       if (t->utraps)
+               t->utraps[0]++;
 
        /* Set the return value for the child. */
        t->kregs->u_regs[UREG_I0] = current->pid;
@@ -694,45 +685,6 @@ int copy_thread(unsigned long clone_flags, unsigned long sp,
        return 0;
 }
 
-/*
- * 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 freed until both the parent and the child have exited.
- */
-pid_t kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
-{
-       long retval;
-
-       /* If the parent runs before fn(arg) is called by the child,
-        * the input registers of this function can be clobbered.
-        * So we stash 'fn' and 'arg' into global registers which
-        * will not be modified by the parent.
-        */
-       __asm__ __volatile__("mov %4, %%g2\n\t"    /* Save FN into global */
-                            "mov %5, %%g3\n\t"    /* Save ARG into global */
-                            "mov %1, %%g1\n\t"    /* Clone syscall nr. */
-                            "mov %2, %%o0\n\t"    /* Clone flags. */
-                            "mov 0, %%o1\n\t"     /* usp arg == 0 */
-                            "t 0x6d\n\t"          /* Linux/Sparc clone(). */
-                            "brz,a,pn %%o1, 1f\n\t" /* Parent, just return. */
-                            " mov %%o0, %0\n\t"
-                            "jmpl %%g2, %%o7\n\t"   /* Call the function. */
-                            " mov %%g3, %%o0\n\t"   /* Set arg in delay. */
-                            "mov %3, %%g1\n\t"
-                            "t 0x6d\n\t"          /* Linux/Sparc exit(). */
-                            /* Notreached by child. */
-                            "1:" :
-                            "=r" (retval) :
-                            "i" (__NR_clone), "r" (flags | CLONE_VM | CLONE_UNTRACED),
-                            "i" (__NR_exit),  "r" (fn), "r" (arg) :
-                            "g1", "g2", "g3", "o0", "o1", "memory", "cc");
-       return retval;
-}
-EXPORT_SYMBOL(kernel_thread);
-
 typedef struct {
        union {
                unsigned int    pr_regs[32];
@@ -799,41 +751,6 @@ int dump_fpu (struct pt_regs * regs, elf_fpregset_t * fpregs)
 }
 EXPORT_SYMBOL(dump_fpu);
 
-/*
- * sparc_execve() executes a new program after the asm stub has set
- * things up for us.  This should basically do what I want it to.
- */
-asmlinkage int sparc_execve(struct pt_regs *regs)
-{
-       int error, base = 0;
-       struct filename *filename;
-
-       /* User register window flush is done by entry.S */
-
-       /* Check for indirect call. */
-       if (regs->u_regs[UREG_G1] == 0)
-               base = 1;
-
-       filename = getname((char __user *)regs->u_regs[base + UREG_I0]);
-       error = PTR_ERR(filename);
-       if (IS_ERR(filename))
-               goto out;
-       error = do_execve(filename->name,
-                         (const char __user *const __user *)
-                         regs->u_regs[base + UREG_I1],
-                         (const char __user *const __user *)
-                         regs->u_regs[base + UREG_I2], regs);
-       putname(filename);
-       if (!error) {
-               fprs_write(0);
-               current_thread_info()->xfsr[0] = 0;
-               current_thread_info()->fpsaved[0] = 0;
-               regs->tstate &= ~TSTATE_PEF;
-       }
-out:
-       return error;
-}
-
 unsigned long get_wchan(struct task_struct *task)
 {
        unsigned long pc, fp, bias = 0;
index c323981..03c7e92 100644 (file)
@@ -396,42 +396,6 @@ asmlinkage long compat_sys_rt_sigaction(int sig,
         return ret;
 }
 
-/*
- * sparc32_execve() executes a new program after the asm stub has set
- * things up for us.  This should basically do what I want it to.
- */
-asmlinkage long sparc32_execve(struct pt_regs *regs)
-{
-       int error, base = 0;
-       struct filename *filename;
-
-       /* User register window flush is done by entry.S */
-
-       /* Check for indirect call. */
-       if ((u32)regs->u_regs[UREG_G1] == 0)
-               base = 1;
-
-       filename = getname(compat_ptr(regs->u_regs[base + UREG_I0]));
-       error = PTR_ERR(filename);
-       if (IS_ERR(filename))
-               goto out;
-
-       error = compat_do_execve(filename->name,
-                                compat_ptr(regs->u_regs[base + UREG_I1]),
-                                compat_ptr(regs->u_regs[base + UREG_I2]), regs);
-
-       putname(filename);
-
-       if (!error) {
-               fprs_write(0);
-               current_thread_info()->xfsr[0] = 0;
-               current_thread_info()->fpsaved[0] = 0;
-               regs->tstate &= ~TSTATE_PEF;
-       }
-out:
-       return error;
-}
-
 #ifdef CONFIG_MODULES
 
 asmlinkage long sys32_init_module(void __user *umod, u32 len,
index 0c9b31b..a8e6eb0 100644 (file)
@@ -258,27 +258,3 @@ out:
        up_read(&uts_sem);
        return err;
 }
-
-/*
- * 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[])
-{
-       long __res;
-       register long __g1 __asm__ ("g1") = __NR_execve;
-       register long __o0 __asm__ ("o0") = (long)(filename);
-       register long __o1 __asm__ ("o1") = (long)(argv);
-       register long __o2 __asm__ ("o2") = (long)(envp);
-       asm volatile ("t 0x10\n\t"
-                     "bcc 1f\n\t"
-                     "mov %%o0, %0\n\t"
-                     "sub %%g0, %%o0, %0\n\t"
-                     "1:\n\t"
-                     : "=r" (__res), "=&r" (__o0)
-                     : "1" (__o0), "r" (__o1), "r" (__o2), "r" (__g1)
-                     : "cc");
-       return __res;
-}
index 878ef3d..51b85fe 100644 (file)
@@ -730,28 +730,6 @@ SYSCALL_DEFINE5(rt_sigaction, int, sig, const struct sigaction __user *, act,
        return ret;
 }
 
-/*
- * 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[])
-{
-       long __res;
-       register long __g1 __asm__ ("g1") = __NR_execve;
-       register long __o0 __asm__ ("o0") = (long)(filename);
-       register long __o1 __asm__ ("o1") = (long)(argv);
-       register long __o2 __asm__ ("o2") = (long)(envp);
-       asm volatile ("t 0x6d\n\t"
-                     "sub %%g0, %%o0, %0\n\t"
-                     "movcc %%xcc, %%o0, %0\n\t"
-                     : "=r" (__res), "=&r" (__o0)
-                     : "1" (__o0), "r" (__o1), "r" (__o2), "r" (__g1)
-                     : "cc");
-       return __res;
-}
-
 asmlinkage long sys_kern_features(void)
 {
        return KERN_FEATURE_MIXED_MODE_STACK;
index 7f5f65d..2ef41e6 100644 (file)
@@ -1,23 +1,19 @@
        /* SunOS's execv() call only specifies the argv argument, the
         * environment settings are the same as the calling processes.
         */
-sys_execve:
-       sethi   %hi(sparc_execve), %g1
-       ba,pt   %xcc, execve_merge
-        or     %g1, %lo(sparc_execve), %g1
+sys64_execve:
+       set     sys_execve, %g1
+       jmpl    %g1, %g0
+        flushw
 
 #ifdef CONFIG_COMPAT
 sunos_execv:
-       stx     %g0, [%sp + PTREGS_OFF + PT_V9_I2]
+       mov     %g0, %o2
 sys32_execve:
-       sethi   %hi(sparc32_execve), %g1
-       or      %g1, %lo(sparc32_execve), %g1
-#endif
-
-execve_merge:
-       flushw
+       set     compat_sys_execve, %g1
        jmpl    %g1, %g0
-        add    %sp, PTREGS_OFF, %o0
+        flushw
+#endif
 
        .align  32
 sys_sparc_pipe:
@@ -112,11 +108,16 @@ sys_clone:
 ret_from_syscall:
        /* Clear current_thread_info()->new_child. */
        stb     %g0, [%g6 + TI_NEW_CHILD]
-       ldx     [%g6 + TI_FLAGS], %l0
        call    schedule_tail
         mov    %g7, %o0
+       ldx     [%sp + PTREGS_OFF + PT_V9_I0], %o0
+       brnz,pt %o0, ret_sys_call
+        ldx    [%g6 + TI_FLAGS], %l0
+       ldx     [%sp + PTREGS_OFF + PT_V9_G1], %l1
+       call    %l1
+        ldx    [%sp + PTREGS_OFF + PT_V9_G2], %o0
        ba,pt   %xcc, ret_sys_call
-        ldx    [%sp + PTREGS_OFF + PT_V9_I0], %o0
+        mov    0, %o0
 
        .globl  sparc_exit
        .type   sparc_exit,#function
@@ -222,7 +223,6 @@ ret_sys_call:
        ldx     [%sp + PTREGS_OFF + PT_V9_TNPC], %l1 ! pc = npc
 
 2:
-       stb     %g0, [%g6 + TI_SYS_NOERROR]
        /* System call success, clear Carry condition code. */
        andn    %g3, %g2, %g3
 3:
index 1c9af9f..ebb7f5f 100644 (file)
@@ -107,7 +107,7 @@ sys_call_table:
 /*40*/ .word sys_newlstat, sys_dup, sys_sparc_pipe, sys_times, sys_nis_syscall
        .word sys_umount, sys_setgid, sys_getgid, sys_signal, sys_geteuid
 /*50*/ .word sys_getegid, sys_acct, sys_memory_ordering, sys_nis_syscall, sys_ioctl
-       .word sys_reboot, sys_nis_syscall, sys_symlink, sys_readlink, sys_execve
+       .word sys_reboot, sys_nis_syscall, sys_symlink, sys_readlink, sys64_execve
 /*60*/ .word sys_umask, sys_chroot, sys_newfstat, sys_fstat64, sys_getpagesize
        .word sys_msync, sys_vfork, sys_pread64, sys_pwrite64, sys_nis_syscall
 /*70*/ .word sys_nis_syscall, sys_mmap, sys_nis_syscall, sys_64_munmap, sys_mprotect
index b66a779..e7ecf15 100644 (file)
@@ -2688,8 +2688,8 @@ void __init trap_init(void)
                     TI_PRE_COUNT != offsetof(struct thread_info,
                                              preempt_count) ||
                     TI_NEW_CHILD != offsetof(struct thread_info, new_child) ||
-                    TI_SYS_NOERROR != offsetof(struct thread_info,
-                                               syscall_noerror) ||
+                    TI_CURRENT_DS != offsetof(struct thread_info,
+                                               current_ds) ||
                     TI_RESTART_BLOCK != offsetof(struct thread_info,
                                                  restart_block) ||
                     TI_KUNA_REGS != offsetof(struct thread_info,
index 9e28a11..85be1ca 100644 (file)
@@ -624,7 +624,7 @@ static void __init inherit_prom_mappings(void)
 void prom_world(int enter)
 {
        if (!enter)
-               set_fs((mm_segment_t) { get_thread_current_ds() });
+               set_fs(get_fs());
 
        __asm__ __volatile__("flushw");
 }
index 875d008..ea7f61e 100644 (file)
@@ -21,6 +21,8 @@ config TILE
        select ARCH_HAVE_NMI_SAFE_CMPXCHG
        select GENERIC_CLOCKEVENTS
        select MODULES_USE_ELF_RELA
+       select GENERIC_KERNEL_THREAD
+       select GENERIC_KERNEL_EXECVE
 
 # FIXME: investigate whether we need/want these options.
 #      select HAVE_IOREMAP_PROT
index 3063e6f..ca61fb4 100644 (file)
@@ -275,18 +275,14 @@ extern int compat_setup_rt_frame(int sig, struct k_sigaction *ka,
 struct compat_sigaction;
 struct compat_siginfo;
 struct compat_sigaltstack;
-long compat_sys_execve(const char __user *path,
-                      compat_uptr_t __user *argv,
-                      compat_uptr_t __user *envp, struct pt_regs *);
 long compat_sys_rt_sigaction(int sig, struct compat_sigaction __user *act,
                             struct compat_sigaction __user *oact,
                             size_t sigsetsize);
 long compat_sys_rt_sigqueueinfo(int pid, int sig,
                                struct compat_siginfo __user *uinfo);
-long compat_sys_rt_sigreturn(struct pt_regs *);
+long compat_sys_rt_sigreturn(void);
 long compat_sys_sigaltstack(const struct compat_sigaltstack __user *uss_ptr,
-                           struct compat_sigaltstack __user *uoss_ptr,
-                           struct pt_regs *);
+                           struct compat_sigaltstack __user *uoss_ptr);
 long compat_sys_truncate64(char __user *filename, u32 dummy, u32 low, u32 high);
 long compat_sys_ftruncate64(unsigned int fd, u32 dummy, u32 low, u32 high);
 long compat_sys_pread64(unsigned int fd, char __user *ubuf, size_t count,
@@ -303,12 +299,7 @@ long compat_sys_fallocate(int fd, int mode,
 long compat_sys_sched_rr_get_interval(compat_pid_t pid,
                                      struct compat_timespec __user *interval);
 
-/* These are the intvec_64.S trampolines. */
-long _compat_sys_execve(const char __user *path,
-                       const compat_uptr_t __user *argv,
-                       const compat_uptr_t __user *envp);
-long _compat_sys_sigaltstack(const struct compat_sigaltstack __user *uss_ptr,
-                           struct compat_sigaltstack __user *uoss_ptr);
+/* Assembly trampoline to avoid clobbering r0. */
 long _compat_sys_rt_sigreturn(void);
 
 #endif /* _ASM_TILE_COMPAT_H */
index f8ccf08..b73e103 100644 (file)
@@ -148,6 +148,7 @@ extern int arch_setup_additional_pages(struct linux_binprm *bprm,
 #define compat_start_thread(regs, ip, usp) do { \
                regs->pc = ptr_to_compat_reg((void *)(ip)); \
                regs->sp = ptr_to_compat_reg((void *)(usp)); \
+               single_step_execve();   \
        } while (0)
 
 /*
index 8c4dd9f..879073e 100644 (file)
@@ -211,6 +211,7 @@ static inline void start_thread(struct pt_regs *regs,
 {
        regs->pc = pc;
        regs->sp = usp;
+       single_step_execve();
 }
 
 /* Free all resources held by a thread. */
@@ -239,6 +240,9 @@ unsigned long get_wchan(struct task_struct *p);
 #define KSTK_TOP(task) (task_ksp0(task) - STACK_TOP_DELTA)
 #define task_pt_regs(task) \
   ((struct pt_regs *)(task_ksp0(task) - KSTK_PTREGS_GAP) - 1)
+#define current_pt_regs()                                   \
+  ((struct pt_regs *)((stack_pointer | (THREAD_SIZE - 1)) - \
+                      (KSTK_PTREGS_GAP - 1)) - 1)
 #define task_sp(task)  (task_pt_regs(task)->sp)
 #define task_pc(task)  (task_pt_regs(task)->pc)
 /* Aliases for pc and sp (used in fs/proc/array.c) */
index 1d48c5f..b8f888c 100644 (file)
@@ -68,7 +68,10 @@ extern unsigned long get_switch_to_pc(void);
 /* Support function for forking a new task. */
 void ret_from_fork(void);
 
-/* Called from ret_from_fork() when a new process starts up. */
+/* Support function for forking a new kernel thread. */
+void ret_from_kernel_thread(void *fn, void *arg);
+
+/* Called from ret_from_xxx() when a new process starts up. */
 struct task_struct *sim_notify_fork(struct task_struct *prev);
 
 #endif /* !__ASSEMBLY__ */
index 06f0464..369696d 100644 (file)
@@ -51,8 +51,7 @@ long sys_cacheflush(unsigned long addr, unsigned long len,
 
 #ifndef __tilegx__
 /* mm/fault.c */
-long sys_cmpxchg_badaddr(unsigned long address, struct pt_regs *);
-long _sys_cmpxchg_badaddr(unsigned long address);
+long sys_cmpxchg_badaddr(unsigned long address);
 #endif
 
 #ifdef CONFIG_COMPAT
@@ -63,14 +62,23 @@ long sys_truncate64(const char __user *path, loff_t length);
 long sys_ftruncate64(unsigned int fd, loff_t length);
 #endif
 
+/* Provide versions of standard syscalls that use current_pt_regs(). */
+long sys_clone(unsigned long clone_flags, unsigned long newsp,
+               void __user *parent_tid, void __user *child_tid);
+long sys_execve(const char __user *filename,
+                const char __user *const __user *argv,
+                const char __user *const __user *envp);
+long sys_rt_sigreturn(void);
+long sys_sigaltstack(const stack_t __user *, stack_t __user *);
+#define sys_clone sys_clone
+#define sys_execve sys_execve
+#define sys_rt_sigreturn sys_rt_sigreturn
+#define sys_sigaltstack sys_sigaltstack
+
 /* These are the intvec*.S trampolines. */
-long _sys_sigaltstack(const stack_t __user *, stack_t __user *);
 long _sys_rt_sigreturn(void);
 long _sys_clone(unsigned long clone_flags, unsigned long newsp,
                void __user *parent_tid, void __user *child_tid);
-long _sys_execve(const char __user *filename,
-                const char __user *const __user *argv,
-                const char __user *const __user *envp);
 
 #include <asm-generic/syscalls.h>
 
index 6e032a0..dab827d 100644 (file)
@@ -16,4 +16,5 @@
 #define __ARCH_WANT_SYS_LLSEEK
 #endif
 #define __ARCH_WANT_SYS_NEWFSTATAT
+#define __ARCH_WANT_SYS_EXECVE
 #include <uapi/asm/unistd.h>
index d67459b..a2e8055 100644 (file)
@@ -102,10 +102,9 @@ long compat_sys_sched_rr_get_interval(compat_pid_t pid,
 #define compat_sys_fadvise64_64 sys32_fadvise64_64
 #define compat_sys_readahead sys32_readahead
 
-/* Call the trampolines to manage pt_regs where necessary. */
-#define compat_sys_execve _compat_sys_execve
-#define compat_sys_sigaltstack _compat_sys_sigaltstack
+/* Call the assembly trampolines where necessary. */
 #define compat_sys_rt_sigreturn _compat_sys_rt_sigreturn
+#undef sys_clone
 #define sys_clone _sys_clone
 
 /*
index 08b4fe1..2e4cc69 100644 (file)
@@ -197,8 +197,7 @@ int copy_siginfo_from_user32(siginfo_t *to, struct compat_siginfo __user *from)
 }
 
 long compat_sys_sigaltstack(const struct compat_sigaltstack __user *uss_ptr,
-                           struct compat_sigaltstack __user *uoss_ptr,
-                           struct pt_regs *regs)
+                           struct compat_sigaltstack __user *uoss_ptr)
 {
        stack_t uss, uoss;
        int ret;
@@ -219,7 +218,7 @@ long compat_sys_sigaltstack(const struct compat_sigaltstack __user *uss_ptr,
        set_fs(KERNEL_DS);
        ret = do_sigaltstack(uss_ptr ? (stack_t __user __force *)&uss : NULL,
                             (stack_t __user __force *)&uoss,
-                            (unsigned long)compat_ptr(regs->sp));
+                            (unsigned long)compat_ptr(current_pt_regs()->sp));
        set_fs(seg);
        if (ret >= 0 && uoss_ptr)  {
                if (!access_ok(VERIFY_WRITE, uoss_ptr, sizeof(*uoss_ptr)) ||
@@ -232,8 +231,9 @@ long compat_sys_sigaltstack(const struct compat_sigaltstack __user *uss_ptr,
 }
 
 /* The assembly shim for this function arranges to ignore the return value. */
-long compat_sys_rt_sigreturn(struct pt_regs *regs)
+long compat_sys_rt_sigreturn(void)
 {
+       struct pt_regs *regs = current_pt_regs();
        struct compat_rt_sigframe __user *frame =
                (struct compat_rt_sigframe __user *) compat_ptr(regs->sp);
        sigset_t set;
@@ -248,7 +248,7 @@ long compat_sys_rt_sigreturn(struct pt_regs *regs)
        if (restore_sigcontext(regs, &frame->uc.uc_mcontext))
                goto badframe;
 
-       if (compat_sys_sigaltstack(&frame->uc.uc_stack, NULL, regs) != 0)
+       if (compat_sys_sigaltstack(&frame->uc.uc_stack, NULL) == -EFAULT)
                goto badframe;
 
        return 0;
index c31637b..f116cb0 100644 (file)
@@ -27,17 +27,6 @@ STD_ENTRY(current_text_addr)
        { move r0, lr; jrp lr }
        STD_ENDPROC(current_text_addr)
 
-/*
- * Implement execve().  The i386 code has a note that forking from kernel
- * space results in no copy on write until the execve, so we should be
- * careful not to write to the stack here.
- */
-STD_ENTRY(kernel_execve)
-       moveli TREG_SYSCALL_NR_NAME, __NR_execve
-       swint1
-       jrp lr
-       STD_ENDPROC(kernel_execve)
-
 /*
  * We don't run this function directly, but instead copy it to a page
  * we map into every user process.  See vdso_setup().
index 6943515..f212bf7 100644 (file)
@@ -1291,6 +1291,21 @@ STD_ENTRY(ret_from_fork)
        }
        STD_ENDPROC(ret_from_fork)
 
+STD_ENTRY(ret_from_kernel_thread)
+       jal     sim_notify_fork
+       jal     schedule_tail
+       FEEDBACK_REENTER(ret_from_fork)
+       {
+        move   r0, r31
+        jalr   r30
+       }
+       FEEDBACK_REENTER(ret_from_kernel_thread)
+       {
+        movei  r30, 0               /* not an NMI */
+        j      .Lresume_userspace   /* jump into middle of interrupt_return */
+       }
+       STD_ENDPROC(ret_from_kernel_thread)
+
        /*
         * Code for ill interrupt.
         */
@@ -1437,15 +1452,6 @@ STD_ENTRY_LOCAL(bad_intr)
        panic   "Unhandled interrupt %#x: PC %#lx"
        STD_ENDPROC(bad_intr)
 
-/* Put address of pt_regs in reg and jump. */
-#define PTREGS_SYSCALL(x, reg)                          \
-       STD_ENTRY(_##x);                                \
-       {                                               \
-        PTREGS_PTR(reg, PTREGS_OFFSET_BASE);           \
-        j      x                                       \
-       };                                              \
-       STD_ENDPROC(_##x)
-
 /*
  * Special-case sigreturn to not write r0 to the stack on return.
  * This is technically more efficient, but it also avoids difficulties
@@ -1461,12 +1467,9 @@ STD_ENTRY_LOCAL(bad_intr)
        };                                              \
        STD_ENDPROC(_##x)
 
-PTREGS_SYSCALL(sys_execve, r3)
-PTREGS_SYSCALL(sys_sigaltstack, r2)
 PTREGS_SYSCALL_SIGRETURN(sys_rt_sigreturn, r0)
-PTREGS_SYSCALL(sys_cmpxchg_badaddr, r1)
 
-/* Save additional callee-saves to pt_regs, put address in r4 and jump. */
+/* Save additional callee-saves to pt_regs and jump to standard function. */
 STD_ENTRY(_sys_clone)
        push_extra_callee_saves r4
        j       sys_clone
index 7c06d59..54bc9a6 100644 (file)
@@ -1150,6 +1150,21 @@ STD_ENTRY(ret_from_fork)
        }
        STD_ENDPROC(ret_from_fork)
 
+STD_ENTRY(ret_from_kernel_thread)
+       jal     sim_notify_fork
+       jal     schedule_tail
+       FEEDBACK_REENTER(ret_from_fork)
+       {
+        move   r0, r31
+        jalr   r30
+       }
+       FEEDBACK_REENTER(ret_from_kernel_thread)
+       {
+        movei  r30, 0               /* not an NMI */
+        j      .Lresume_userspace   /* jump into middle of interrupt_return */
+       }
+       STD_ENDPROC(ret_from_kernel_thread)
+
 /* Various stub interrupt handlers and syscall handlers */
 
 STD_ENTRY_LOCAL(_kernel_double_fault)
@@ -1166,15 +1181,6 @@ STD_ENTRY_LOCAL(bad_intr)
        panic   "Unhandled interrupt %#x: PC %#lx"
        STD_ENDPROC(bad_intr)
 
-/* Put address of pt_regs in reg and jump. */
-#define PTREGS_SYSCALL(x, reg)                          \
-       STD_ENTRY(_##x);                                \
-       {                                               \
-        PTREGS_PTR(reg, PTREGS_OFFSET_BASE);           \
-        j      x                                       \
-       };                                              \
-       STD_ENDPROC(_##x)
-
 /*
  * Special-case sigreturn to not write r0 to the stack on return.
  * This is technically more efficient, but it also avoids difficulties
@@ -1190,16 +1196,12 @@ STD_ENTRY_LOCAL(bad_intr)
        };                                              \
        STD_ENDPROC(_##x)
 
-PTREGS_SYSCALL(sys_execve, r3)
-PTREGS_SYSCALL(sys_sigaltstack, r2)
 PTREGS_SYSCALL_SIGRETURN(sys_rt_sigreturn, r0)
 #ifdef CONFIG_COMPAT
-PTREGS_SYSCALL(compat_sys_execve, r3)
-PTREGS_SYSCALL(compat_sys_sigaltstack, r2)
 PTREGS_SYSCALL_SIGRETURN(compat_sys_rt_sigreturn, r0)
 #endif
 
-/* Save additional callee-saves to pt_regs, put address in r4 and jump. */
+/* Save additional callee-saves to pt_regs and jump to standard function. */
 STD_ENTRY(_sys_clone)
        push_extra_callee_saves r4
        j       sys_clone
index 307d010..1c20029 100644 (file)
@@ -157,24 +157,44 @@ void arch_release_thread_info(struct thread_info *info)
 static void save_arch_state(struct thread_struct *t);
 
 int copy_thread(unsigned long clone_flags, unsigned long sp,
-               unsigned long stack_size,
-               struct task_struct *p, struct pt_regs *regs)
+               unsigned long arg,
+               struct task_struct *p, struct pt_regs *unused)
 {
-       struct pt_regs *childregs;
+       struct pt_regs *childregs = task_pt_regs(p);
        unsigned long ksp;
+       unsigned long *callee_regs;
 
        /*
-        * When creating a new kernel thread we pass sp as zero.
-        * Assign it to a reasonable value now that we have the stack.
+        * Set up the stack and stack pointer appropriately for the
+        * new child to find itself woken up in __switch_to().
+        * The callee-saved registers must be on the stack to be read;
+        * the new task will then jump to assembly support to handle
+        * calling schedule_tail(), etc., and (for userspace tasks)
+        * returning to the context set up in the pt_regs.
         */
-       if (sp == 0 && regs->ex1 == PL_ICS_EX1(KERNEL_PL, 0))
-               sp = KSTK_TOP(p);
+       ksp = (unsigned long) childregs;
+       ksp -= C_ABI_SAVE_AREA_SIZE;   /* interrupt-entry save area */
+       ((long *)ksp)[0] = ((long *)ksp)[1] = 0;
+       ksp -= CALLEE_SAVED_REGS_COUNT * sizeof(unsigned long);
+       callee_regs = (unsigned long *)ksp;
+       ksp -= C_ABI_SAVE_AREA_SIZE;   /* __switch_to() save area */
+       ((long *)ksp)[0] = ((long *)ksp)[1] = 0;
+       p->thread.ksp = ksp;
 
-       /*
-        * Do not clone step state from the parent; each thread
-        * must make its own lazily.
-        */
-       task_thread_info(p)->step_state = NULL;
+       /* Record the pid of the task that created this one. */
+       p->thread.creator_pid = current->pid;
+
+       if (unlikely(p->flags & PF_KTHREAD)) {
+               /* kernel thread */
+               memset(childregs, 0, sizeof(struct pt_regs));
+               memset(&callee_regs[2], 0,
+                      (CALLEE_SAVED_REGS_COUNT - 2) * sizeof(unsigned long));
+               callee_regs[0] = sp;   /* r30 = function */
+               callee_regs[1] = arg;  /* r31 = arg */
+               childregs->ex1 = PL_ICS_EX1(KERNEL_PL, 0);
+               p->thread.pc = (unsigned long) ret_from_kernel_thread;
+               return 0;
+       }
 
        /*
         * Start new thread in ret_from_fork so it schedules properly
@@ -182,46 +202,33 @@ int copy_thread(unsigned long clone_flags, unsigned long sp,
         */
        p->thread.pc = (unsigned long) ret_from_fork;
 
-       /* Save user stack top pointer so we can ID the stack vm area later. */
-       p->thread.usp0 = sp;
-
-       /* Record the pid of the process that created this one. */
-       p->thread.creator_pid = current->pid;
+       /*
+        * Do not clone step state from the parent; each thread
+        * must make its own lazily.
+        */
+       task_thread_info(p)->step_state = NULL;
 
        /*
         * Copy the registers onto the kernel stack so the
         * return-from-interrupt code will reload it into registers.
         */
-       childregs = task_pt_regs(p);
-       *childregs = *regs;
+       *childregs = *current_pt_regs();
        childregs->regs[0] = 0;         /* return value is zero */
-       childregs->sp = sp;  /* override with new user stack pointer */
+       if (sp)
+               childregs->sp = sp;  /* override with new user stack pointer */
+       memcpy(callee_regs, &childregs->regs[CALLEE_SAVED_FIRST_REG],
+              CALLEE_SAVED_REGS_COUNT * sizeof(unsigned long));
+
+       /* Save user stack top pointer so we can ID the stack vm area later. */
+       p->thread.usp0 = childregs->sp;
 
        /*
         * If CLONE_SETTLS is set, set "tp" in the new task to "r4",
         * which is passed in as arg #5 to sys_clone().
         */
        if (clone_flags & CLONE_SETTLS)
-               childregs->tp = regs->regs[4];
+               childregs->tp = childregs->regs[4];
 
-       /*
-        * Copy the callee-saved registers from the passed pt_regs struct
-        * into the context-switch callee-saved registers area.
-        * This way when we start the interrupt-return sequence, the
-        * callee-save registers will be correctly in registers, which
-        * is how we assume the compiler leaves them as we start doing
-        * the normal return-from-interrupt path after calling C code.
-        * Zero out the C ABI save area to mark the top of the stack.
-        */
-       ksp = (unsigned long) childregs;
-       ksp -= C_ABI_SAVE_AREA_SIZE;   /* interrupt-entry save area */
-       ((long *)ksp)[0] = ((long *)ksp)[1] = 0;
-       ksp -= CALLEE_SAVED_REGS_COUNT * sizeof(unsigned long);
-       memcpy((void *)ksp, &regs->regs[CALLEE_SAVED_FIRST_REG],
-              CALLEE_SAVED_REGS_COUNT * sizeof(unsigned long));
-       ksp -= C_ABI_SAVE_AREA_SIZE;   /* __switch_to() save area */
-       ((long *)ksp)[0] = ((long *)ksp)[1] = 0;
-       p->thread.ksp = ksp;
 
 #if CHIP_HAS_TILE_DMA()
        /*
@@ -578,61 +585,13 @@ int do_work_pending(struct pt_regs *regs, u32 thread_info_flags)
 }
 
 /* Note there is an implicit fifth argument if (clone_flags & CLONE_SETTLS). */
-SYSCALL_DEFINE5(clone, unsigned long, clone_flags, unsigned long, newsp,
-               void __user *, parent_tidptr, void __user *, child_tidptr,
-               struct pt_regs *, regs)
+SYSCALL_DEFINE4(clone, unsigned long, clone_flags, unsigned long, newsp,
+               void __user *, parent_tidptr, void __user *, child_tidptr)
 {
-       if (!newsp)
-               newsp = regs->sp;
-       return do_fork(clone_flags, newsp, regs, 0,
+       return do_fork(clone_flags, newsp, current_pt_regs(), 0,
                       parent_tidptr, child_tidptr);
 }
 
-/*
- * sys_execve() executes a new program.
- */
-SYSCALL_DEFINE4(execve, const char __user *, path,
-               const char __user *const __user *, argv,
-               const char __user *const __user *, envp,
-               struct pt_regs *, regs)
-{
-       long error;
-       struct filename *filename;
-
-       filename = getname(path);
-       error = PTR_ERR(filename);
-       if (IS_ERR(filename))
-               goto out;
-       error = do_execve(filename->name, argv, envp, regs);
-       putname(filename);
-       if (error == 0)
-               single_step_execve();
-out:
-       return error;
-}
-
-#ifdef CONFIG_COMPAT
-long compat_sys_execve(const char __user *path,
-                      compat_uptr_t __user *argv,
-                      compat_uptr_t __user *envp,
-                      struct pt_regs *regs)
-{
-       long error;
-       struct filename *filename;
-
-       filename = getname(path);
-       error = PTR_ERR(filename);
-       if (IS_ERR(filename))
-               goto out;
-       error = compat_do_execve(filename->name, argv, envp, regs);
-       putname(filename);
-       if (error == 0)
-               single_step_execve();
-out:
-       return error;
-}
-#endif
-
 unsigned long get_wchan(struct task_struct *p)
 {
        struct KBacktraceIterator kbt;
@@ -650,37 +609,6 @@ unsigned long get_wchan(struct task_struct *p)
        return 0;
 }
 
-/*
- * We pass in lr as zero (cleared in kernel_thread) and the caller
- * part of the backtrace ABI on the stack also zeroed (in copy_thread)
- * so that backtraces will stop with this function.
- * Note that we don't use r0, since copy_thread() clears it.
- */
-static void start_kernel_thread(int dummy, int (*fn)(int), int 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.ex1 = PL_ICS_EX1(KERNEL_PL, 0);  /* run at kernel PL, no ICS */
-       regs.pc = (long) start_kernel_thread;
-       regs.flags = PT_FLAGS_CALLER_SAVES;   /* need to restore r1 and r2 */
-       regs.regs[1] = (long) fn;             /* function pointer */
-       regs.regs[2] = (long) arg;            /* parameter register */
-
-       /* Ok, create the new process.. */
-       return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, &regs,
-                      0, NULL, NULL);
-}
-EXPORT_SYMBOL(kernel_thread);
-
 /* Flush thread state. */
 void flush_thread(void)
 {
index 67efb65..657a7ac 100644 (file)
 
 #define DEBUG_SIG 0
 
-SYSCALL_DEFINE3(sigaltstack, const stack_t __user *, uss,
-               stack_t __user *, uoss, struct pt_regs *, regs)
+SYSCALL_DEFINE2(sigaltstack, const stack_t __user *, uss,
+               stack_t __user *, uoss)
 {
-       return do_sigaltstack(uss, uoss, regs->sp);
+       return do_sigaltstack(uss, uoss, current_pt_regs()->sp);
 }
 
 
@@ -83,8 +83,9 @@ void signal_fault(const char *type, struct pt_regs *regs,
 }
 
 /* The assembly shim for this function arranges to ignore the return value. */
-SYSCALL_DEFINE1(rt_sigreturn, struct pt_regs *, regs)
+SYSCALL_DEFINE0(rt_sigreturn)
 {
+       struct pt_regs *regs = current_pt_regs();
        struct rt_sigframe __user *frame =
                (struct rt_sigframe __user *)(regs->sp);
        sigset_t set;
index b08095b..02ff5c0 100644 (file)
@@ -106,14 +106,11 @@ SYSCALL_DEFINE6(mmap, unsigned long, addr, unsigned long, len,
 #define sys_readahead sys32_readahead
 #endif
 
-/* Call the trampolines to manage pt_regs where necessary. */
-#define sys_execve _sys_execve
-#define sys_sigaltstack _sys_sigaltstack
+/* Call the assembly trampolines where necessary. */
+#undef sys_rt_sigreturn
 #define sys_rt_sigreturn _sys_rt_sigreturn
+#undef sys_clone
 #define sys_clone _sys_clone
-#ifndef __tilegx__
-#define sys_cmpxchg_badaddr _sys_cmpxchg_badaddr
-#endif
 
 /*
  * Note that we can't include <linux/unistd.h> here since the header
index fe811fa..3d2b81c 100644 (file)
@@ -70,9 +70,10 @@ static noinline void force_sig_info_fault(const char *type, int si_signo,
  * Synthesize the fault a PL0 process would get by doing a word-load of
  * an unaligned address or a high kernel address.
  */
-SYSCALL_DEFINE2(cmpxchg_badaddr, unsigned long, address,
-               struct pt_regs *, regs)
+SYSCALL_DEFINE1(cmpxchg_badaddr, unsigned long, address)
 {
+       struct pt_regs *regs = current_pt_regs();
+
        if (address >= PAGE_OFFSET)
                force_sig_info_fault("atomic segfault", SIGSEGV, SEGV_MAPERR,
                                     address, INT_DTLB_MISS, current, regs);
index d0ced10..d2db710 100644 (file)
@@ -286,10 +286,8 @@ asmlinkage ssize_t compat_sys_pwritev(unsigned long fd,
 
 int compat_do_execve(const char *filename, const compat_uptr_t __user *argv,
                     const compat_uptr_t __user *envp, struct pt_regs *regs);
-#ifdef __ARCH_WANT_SYS_EXECVE
 asmlinkage long compat_sys_execve(const char __user *filename, const compat_uptr_t __user *argv,
                     const compat_uptr_t __user *envp);
-#endif
 
 asmlinkage long compat_sys_select(int n, compat_ulong_t __user *inp,
                compat_ulong_t __user *outp, compat_ulong_t __user *exp,