diff --git a/[refs] b/[refs] index d7503c16ed71..352a33dec693 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 1703a219f7f5ab2c39514f9f0763001cdc907d25 +refs/heads/master: 557e1995a92d318206910d8b5c62075fe02b37e0 diff --git a/trunk/arch/cris/Kconfig b/trunk/arch/cris/Kconfig index 81b59d18867e..a67244473a39 100644 --- a/trunk/arch/cris/Kconfig +++ b/trunk/arch/cris/Kconfig @@ -49,8 +49,6 @@ 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 diff --git a/trunk/arch/cris/arch-v10/kernel/entry.S b/trunk/arch/cris/arch-v10/kernel/entry.S index 897bba67bf7a..592fbe9dfb62 100644 --- a/trunk/arch/cris/arch-v10/kernel/entry.S +++ b/trunk/arch/cris/arch-v10/kernel/entry.S @@ -35,7 +35,6 @@ .globl system_call .globl ret_from_intr .globl ret_from_fork - .globl ret_from_kernel_thread .globl resume .globl multiple_interrupt .globl hwbreakpoint @@ -82,14 +81,7 @@ 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 @@ -594,6 +586,13 @@ _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: diff --git a/trunk/arch/cris/arch-v10/kernel/process.c b/trunk/arch/cris/arch-v10/kernel/process.c index 1d6458287f38..15ac7150371f 100644 --- a/trunk/arch/cris/arch-v10/kernel/process.c +++ b/trunk/arch/cris/arch-v10/kernel/process.c @@ -17,7 +17,6 @@ #include #include #include -#include #ifdef CONFIG_ETRAX_GPIO void etrax_gpio_wake_up_check(void); /* drivers/gpio.c */ @@ -82,6 +81,31 @@ 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(®s, 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, ®s, 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. @@ -91,36 +115,30 @@ unsigned long thread_saved_pc(struct task_struct *t) * */ 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 arg, + unsigned long unused, struct task_struct *p, struct pt_regs *regs) { - struct pt_regs *childregs = task_pt_regs(p); - struct switch_stack *swstack = ((struct switch_stack *)childregs) - 1; + struct pt_regs * childregs; + struct switch_stack *swstack; /* 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 */ - 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 = task_pt_regs(p); + *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; + swstack->r9 = 0; /* parameter to ret_from_sys_call, 0 == dont restart the syscall */ /* we want to return into ret_from_sys_call after the _resume */ @@ -129,7 +147,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 */ @@ -143,28 +161,68 @@ int copy_thread(unsigned long clone_flags, unsigned long usp, return 0; } -asmlinkage int sys_fork(void) +/* + * Be aware of the "magic" 7th argument in the four system-calls below. + * They need the latest stackframe, which is put as the 7th argument by + * entry.S. The previous arguments are dummies or actually used, but need + * to be defined to reach the 7th argument. + * + * N.B.: Another method to get the stackframe is to use current_regs(). But + * it returns the latest stack-frame stacked when going from _user mode_ and + * some of these (at least sys_clone) are called from kernel-mode sometimes + * (for example during kernel_thread, above) and thus cannot use it. Thus, + * to be sure not to get any surprises, we use the method for the other calls + * as well. + */ + +asmlinkage int sys_fork(long r10, long r11, long r12, long r13, long mof, long srp, + struct pt_regs *regs) { - return do_fork(SIGCHLD, rdusp(), current_pt_regs(), 0, NULL, NULL); + return do_fork(SIGCHLD, rdusp(), regs, 0, NULL, NULL); } /* if newusp is 0, we just grab the old usp */ /* FIXME: Is parent_tid/child_tid really third/fourth argument? Update lib? */ asmlinkage int sys_clone(unsigned long newusp, unsigned long flags, - int* parent_tid, int* child_tid) + int* parent_tid, int* child_tid, long mof, long srp, + struct pt_regs *regs) { if (!newusp) newusp = rdusp(); - return do_fork(flags, newusp, current_pt_regs(), 0, parent_tid, child_tid); + return do_fork(flags, newusp, regs, 0, parent_tid, child_tid); } /* vfork is a system call in i386 because of register-pressure - maybe * we can remove it and handle it in libc but we put it here until then. */ -asmlinkage int sys_vfork(void) +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) { - return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), current_pt_regs(), 0, NULL, NULL); + int error; + struct filename *filename; + + filename = getname(fname); + error = PTR_ERR(filename); + + if (IS_ERR(filename)) + goto out; + error = do_execve(filename->name, argv, envp, regs); + putname(filename); + out: + return error; } unsigned long get_wchan(struct task_struct *p) diff --git a/trunk/arch/cris/arch-v32/kernel/entry.S b/trunk/arch/cris/arch-v32/kernel/entry.S index faa644111feb..c3ea4694fbaf 100644 --- a/trunk/arch/cris/arch-v32/kernel/entry.S +++ b/trunk/arch/cris/arch-v32/kernel/entry.S @@ -31,7 +31,6 @@ .globl system_call .globl ret_from_intr .globl ret_from_fork - .globl ret_from_kernel_thread .globl resume .globl multiple_interrupt .globl nmi_interrupt @@ -85,18 +84,6 @@ 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 @@ -544,6 +531,15 @@ _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" diff --git a/trunk/arch/cris/arch-v32/kernel/process.c b/trunk/arch/cris/arch-v32/kernel/process.c index fe465401b6ec..4e9992246359 100644 --- a/trunk/arch/cris/arch-v32/kernel/process.c +++ b/trunk/arch/cris/arch-v32/kernel/process.c @@ -16,7 +16,6 @@ #include #include #include -#include extern void stop_watchdog(void); @@ -95,6 +94,31 @@ 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(®s, 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, ®s, 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 @@ -105,33 +129,23 @@ unsigned long thread_saved_pc(struct task_struct *t) */ 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 arg, + unsigned long unused, struct task_struct *p, struct pt_regs *regs) { - struct pt_regs *childregs = task_pt_regs(p); - struct switch_stack *swstack = ((struct switch_stack *) childregs) - 1; + struct pt_regs *childregs; + struct switch_stack *swstack; /* * 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. */ - 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 = task_pt_regs(p); *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 ? @@ -142,6 +156,7 @@ 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; @@ -159,21 +174,35 @@ 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(void) +sys_fork(long r10, long r11, long r12, long r13, long mof, long srp, + struct pt_regs *regs) { - return do_fork(SIGCHLD, rdusp(), current_pt_regs(), 0, NULL, NULL); + return do_fork(SIGCHLD, rdusp(), regs, 0, NULL, NULL); } /* FIXME: Is parent_tid/child_tid really third/fourth argument? Update lib? */ asmlinkage int sys_clone(unsigned long newusp, unsigned long flags, int *parent_tid, int *child_tid, - unsigned long tls) + unsigned long tls, long srp, struct pt_regs *regs) { if (!newusp) newusp = rdusp(); - return do_fork(flags, newusp, current_pt_regs(), 0, parent_tid, child_tid); + return do_fork(flags, newusp, regs, 0, parent_tid, child_tid); } /* @@ -181,9 +210,32 @@ 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(void) +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) { - return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), current_pt_regs(), 0, NULL, NULL); + int error; + struct filename *filename; + + filename = getname(fname); + error = PTR_ERR(filename); + + if (IS_ERR(filename)) + goto out; + + error = do_execve(filename->name, argv, envp, regs); + putname(filename); + out: + return error; } unsigned long diff --git a/trunk/arch/cris/include/asm/processor.h b/trunk/arch/cris/include/asm/processor.h index 675823f70c0f..ef4e1bc3efc8 100644 --- a/trunk/arch/cris/include/asm/processor.h +++ b/trunk/arch/cris/include/asm/processor.h @@ -49,6 +49,8 @@ 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) diff --git a/trunk/arch/cris/include/asm/unistd.h b/trunk/arch/cris/include/asm/unistd.h index f181d1fc7632..51873a446f87 100644 --- a/trunk/arch/cris/include/asm/unistd.h +++ b/trunk/arch/cris/include/asm/unistd.h @@ -371,7 +371,6 @@ #define __ARCH_WANT_SYS_SIGPROCMASK #define __ARCH_WANT_SYS_RT_SIGACTION #define __ARCH_WANT_SYS_RT_SIGSUSPEND -#define __ARCH_WANT_SYS_EXECVE /* * "Conditional" syscalls diff --git a/trunk/arch/cris/kernel/crisksyms.c b/trunk/arch/cris/kernel/crisksyms.c index 5868cee20ebd..7ac000f6a888 100644 --- a/trunk/arch/cris/kernel/crisksyms.c +++ b/trunk/arch/cris/kernel/crisksyms.c @@ -30,6 +30,7 @@ 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); diff --git a/trunk/arch/h8300/Kconfig b/trunk/arch/h8300/Kconfig index 98fabd10e95f..4cef8a91c2a0 100644 --- a/trunk/arch/h8300/Kconfig +++ b/trunk/arch/h8300/Kconfig @@ -8,6 +8,7 @@ config H8300 select GENERIC_IRQ_SHOW select GENERIC_CPU_DEVICES select MODULES_USE_ELF_RELA + select GENERIC_KERNEL_THREAD config SYMBOL_PREFIX string diff --git a/trunk/arch/h8300/include/asm/processor.h b/trunk/arch/h8300/include/asm/processor.h index 4c9f6f87b617..4b0ca49bb463 100644 --- a/trunk/arch/h8300/include/asm/processor.h +++ b/trunk/arch/h8300/include/asm/processor.h @@ -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.. */ diff --git a/trunk/arch/h8300/include/asm/ptrace.h b/trunk/arch/h8300/include/asm/ptrace.h index d09c440bdba7..00502a61bf0a 100644 --- a/trunk/arch/h8300/include/asm/ptrace.h +++ b/trunk/arch/h8300/include/asm/ptrace.h @@ -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 */ diff --git a/trunk/arch/h8300/kernel/entry.S b/trunk/arch/h8300/kernel/entry.S index ca7431690300..2cdb49a56099 100644 --- a/trunk/arch/h8300/kernel/entry.S +++ b/trunk/arch/h8300/kernel/entry.S @@ -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,15 @@ 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 + sub.l @er0,@er0 + jsr @SYMBOL_NAME(sys_exit) + SYMBOL_NAME_LABEL(resume) /* * Beware - when entering resume, offset of tss is in d1, diff --git a/trunk/arch/h8300/kernel/h8300_ksyms.c b/trunk/arch/h8300/kernel/h8300_ksyms.c index 6866bd9c7fb4..53d7c0e4bd83 100644 --- a/trunk/arch/h8300/kernel/h8300_ksyms.c +++ b/trunk/arch/h8300/kernel/h8300_ksyms.c @@ -33,7 +33,6 @@ EXPORT_SYMBOL(strncmp); EXPORT_SYMBOL(ip_fast_csum); -EXPORT_SYMBOL(kernel_thread); EXPORT_SYMBOL(enable_irq); EXPORT_SYMBOL(disable_irq); diff --git a/trunk/arch/h8300/kernel/process.c b/trunk/arch/h8300/kernel/process.c index e8dc1393a13a..e3dfea71c15f 100644 --- a/trunk/arch/h8300/kernel/process.c +++ b/trunk/arch/h8300/kernel/process.c @@ -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;