diff --git a/[refs] b/[refs] index bee5b5dc4b0e..f42964df6fb1 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 5fd0b580a9fda554eae27fff4953e6622bd792d7 +refs/heads/master: ee1e17c69eb3c843d283eb3fbed1616ed9a122eb diff --git a/trunk/arch/avr32/Kconfig b/trunk/arch/avr32/Kconfig index 649aeb9acecb..06e73bf665e9 100644 --- a/trunk/arch/avr32/Kconfig +++ b/trunk/arch/avr32/Kconfig @@ -17,8 +17,6 @@ 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 diff --git a/trunk/arch/avr32/include/asm/processor.h b/trunk/arch/avr32/include/asm/processor.h index 48d71c5c898a..87d8baccc60e 100644 --- a/trunk/arch/avr32/include/asm/processor.h +++ b/trunk/arch/avr32/include/asm/processor.h @@ -142,6 +142,9 @@ 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) diff --git a/trunk/arch/avr32/include/asm/unistd.h b/trunk/arch/avr32/include/asm/unistd.h index 641023d1bcb5..157b4bd3d5e5 100644 --- a/trunk/arch/avr32/include/asm/unistd.h +++ b/trunk/arch/avr32/include/asm/unistd.h @@ -39,7 +39,6 @@ #define __ARCH_WANT_SYS_GETPGRP #define __ARCH_WANT_SYS_RT_SIGACTION #define __ARCH_WANT_SYS_RT_SIGSUSPEND -#define __ARCH_WANT_SYS_EXECVE /* * "Conditional" syscalls diff --git a/trunk/arch/avr32/kernel/Makefile b/trunk/arch/avr32/kernel/Makefile index 119a2e41defe..9e2c465ef3a6 100644 --- a/trunk/arch/avr32/kernel/Makefile +++ b/trunk/arch/avr32/kernel/Makefile @@ -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 process.o time.o +obj-y += signal.o sys_avr32.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 diff --git a/trunk/arch/avr32/kernel/entry-avr32b.S b/trunk/arch/avr32/kernel/entry-avr32b.S index 9899d3cc6f03..df2884181313 100644 --- a/trunk/arch/avr32/kernel/entry-avr32b.S +++ b/trunk/arch/avr32/kernel/entry-avr32b.S @@ -251,15 +251,13 @@ syscall_badsys: .global ret_from_fork ret_from_fork: call schedule_tail - mov r12, 0 - rjmp syscall_return - .global ret_from_kernel_thread -ret_from_kernel_thread: - call schedule_tail - mov r12, r0 - mov lr, r2 /* syscall_return */ - mov pc, r1 + /* 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 syscall_trace_enter: pushm r8-r12 diff --git a/trunk/arch/avr32/kernel/process.c b/trunk/arch/avr32/kernel/process.c index 09b894d96d6e..1bb0a8abd79b 100644 --- a/trunk/arch/avr32/kernel/process.c +++ b/trunk/arch/avr32/kernel/process.c @@ -68,6 +68,44 @@ 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(®s, 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, ®s, 0, NULL, NULL); +} +EXPORT_SYMBOL(kernel_thread); + /* * Free current thread data structures etc */ @@ -294,31 +332,26 @@ 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 arg, + unsigned long unused, struct task_struct *p, struct pt_regs *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; + struct pt_regs *childregs; + + childregs = ((struct pt_regs *)(THREAD_SIZE + (unsigned long)task_stack_page(p))) - 1; + *childregs = *regs; + + if (user_mode(regs)) childregs->sp = usp; - childregs->r12 = 0; /* Set return value for child */ - p->thread.cpu_context.pc = (unsigned long)ret_from_fork; - } + else + childregs->sp = (unsigned long)task_stack_page(p) + THREAD_SIZE; + + childregs->r12 = 0; /* Set return value for child */ 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)) @@ -349,6 +382,27 @@ 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/trunk/arch/avr32/kernel/sys_avr32.c b/trunk/arch/avr32/kernel/sys_avr32.c new file mode 100644 index 000000000000..62635a09ae3e --- /dev/null +++ b/trunk/arch/avr32/kernel/sys_avr32.c @@ -0,0 +1,24 @@ +/* + * 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 + +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; +} diff --git a/trunk/arch/avr32/kernel/syscall-stubs.S b/trunk/arch/avr32/kernel/syscall-stubs.S index 285a61b9194e..0447a3e2ba64 100644 --- a/trunk/arch/avr32/kernel/syscall-stubs.S +++ b/trunk/arch/avr32/kernel/syscall-stubs.S @@ -50,6 +50,12 @@ __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: diff --git a/trunk/arch/avr32/kernel/syscall_table.S b/trunk/arch/avr32/kernel/syscall_table.S index fc6497706819..6eba53530d1c 100644 --- a/trunk/arch/avr32/kernel/syscall_table.S +++ b/trunk/arch/avr32/kernel/syscall_table.S @@ -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 diff --git a/trunk/arch/blackfin/Kconfig b/trunk/arch/blackfin/Kconfig index b6f3ad5441c5..ab9ff4075f4d 100644 --- a/trunk/arch/blackfin/Kconfig +++ b/trunk/arch/blackfin/Kconfig @@ -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 diff --git a/trunk/arch/blackfin/include/asm/processor.h b/trunk/arch/blackfin/include/asm/processor.h index 4ef7cfe43ceb..d0e72e9475a6 100644 --- a/trunk/arch/blackfin/include/asm/processor.h +++ b/trunk/arch/blackfin/include/asm/processor.h @@ -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.. */ diff --git a/trunk/arch/blackfin/kernel/entry.S b/trunk/arch/blackfin/kernel/entry.S index f33792cc1a0d..78f4f637e155 100644 --- a/trunk/arch/blackfin/kernel/entry.S +++ b/trunk/arch/blackfin/kernel/entry.S @@ -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) diff --git a/trunk/arch/blackfin/kernel/process.c b/trunk/arch/blackfin/kernel/process.c index bb1cc721fcf7..9945b94c63d4 100644 --- a/trunk/arch/blackfin/kernel/process.c +++ b/trunk/arch/blackfin/kernel/process.c @@ -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(®s, 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, ®s, 0, NULL, - NULL); -} -EXPORT_SYMBOL(kernel_thread); - /* * Do necessary setup to start up a newly executed thread. * @@ -193,13 +159,26 @@ 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; diff --git a/trunk/arch/blackfin/mach-common/entry.S b/trunk/arch/blackfin/mach-common/entry.S index 1c3d2c5bb0bb..4a38c68e2dde 100644 --- a/trunk/arch/blackfin/mach-common/entry.S +++ b/trunk/arch/blackfin/mach-common/entry.S @@ -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);