From 0973c687e05a802a757664722678d2b5016f1c1c Mon Sep 17 00:00:00 2001 From: Greg Ungerer Date: Wed, 12 Sep 2012 05:13:19 -0400 Subject: m68k: always set stack frame format for ColdFire on thread start The stack frame "format" field needs to be explicitly set on thread creation on ColdFire. For a normal long word aligned user stack pointer the frame format is 0x4. We were doing this for non-MMU ColdFire, but not for the case with MMU enabled. So fix it so we always do it if targeting ColdFire. The old code happend to rely on the stack frame format being inhereted from the process calling exec. Furture changes means that may not always work, so we really do want to set it explicitly. Signed-off-by: Greg Ungerer Signed-off-by: Al Viro --- arch/m68k/include/asm/processor.h | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) (limited to 'arch/m68k') diff --git a/arch/m68k/include/asm/processor.h b/arch/m68k/include/asm/processor.h index f17c42aff7ff..9b4c82c1ef47 100644 --- a/arch/m68k/include/asm/processor.h +++ b/arch/m68k/include/asm/processor.h @@ -100,6 +100,16 @@ struct thread_struct { .fs = __KERNEL_DS, \ } +/* + * ColdFire stack format sbould be 0x4 for an aligned usp (will always be + * true on thread creation). We need to set this explicitly. + */ +#ifdef CONFIG_COLDFIRE +#define setframeformat(_regs) do { (_regs)->format = 0x4; } while(0) +#else +#define setframeformat(_regs) do { } while (0) +#endif + #ifdef CONFIG_MMU /* * Do necessary setup to start up a newly executed thread. @@ -109,6 +119,7 @@ static inline void start_thread(struct pt_regs * regs, unsigned long pc, { regs->pc = pc; regs->sr &= ~0x2000; + setframeformat(regs); wrusp(usp); } @@ -116,21 +127,11 @@ extern int handle_kernel_fault(struct pt_regs *regs); #else -/* - * Coldfire stacks need to be re-aligned on trap exit, conventional - * 68k can handle this case cleanly. - */ -#ifdef CONFIG_COLDFIRE -#define reformat(_regs) do { (_regs)->format = 0x4; } while(0) -#else -#define reformat(_regs) do { } while (0) -#endif - #define start_thread(_regs, _pc, _usp) \ do { \ (_regs)->pc = (_pc); \ ((struct switch_stack *)(_regs))[-1].a6 = 0; \ - reformat(_regs); \ + setframeformat(_regs); \ if (current->mm) \ (_regs)->d5 = current->mm->start_data; \ (_regs)->sr &= ~0x2000; \ -- cgit v1.2.3 From 533e6903bea0440816a0f517b0845ccea4cc7917 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 16 Sep 2012 12:05:09 -0400 Subject: m68k: split ret_from_fork(), simplify kernel_thread() Signed-off-by: Al Viro --- arch/m68k/Kconfig | 1 + arch/m68k/include/asm/processor.h | 2 - arch/m68k/kernel/entry.S | 11 +++++ arch/m68k/kernel/process.c | 84 +++++++++++---------------------------- 4 files changed, 36 insertions(+), 62 deletions(-) (limited to 'arch/m68k') diff --git a/arch/m68k/Kconfig b/arch/m68k/Kconfig index b22df9410dce..ccda007ba40f 100644 --- a/arch/m68k/Kconfig +++ b/arch/m68k/Kconfig @@ -13,6 +13,7 @@ config M68K select FPU if MMU select ARCH_WANT_IPC_PARSE_VERSION select ARCH_USES_GETTIMEOFFSET if MMU && !COLDFIRE + select GENERIC_KERNEL_THREAD config RWSEM_GENERIC_SPINLOCK bool diff --git a/arch/m68k/include/asm/processor.h b/arch/m68k/include/asm/processor.h index 9b4c82c1ef47..ae700f49e51d 100644 --- a/arch/m68k/include/asm/processor.h +++ b/arch/m68k/include/asm/processor.h @@ -154,8 +154,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/arch/m68k/kernel/entry.S b/arch/m68k/kernel/entry.S index 165ee9f9d5c9..8a01f580a024 100644 --- a/arch/m68k/kernel/entry.S +++ b/arch/m68k/kernel/entry.S @@ -111,6 +111,17 @@ ENTRY(ret_from_fork) addql #4,%sp jra ret_from_exception +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 + #if defined(CONFIG_COLDFIRE) || !defined(CONFIG_MMU) #ifdef TRAP_DBG_INTERRUPT diff --git a/arch/m68k/kernel/process.c b/arch/m68k/kernel/process.c index c488e3cfab53..b3d4760c9750 100644 --- a/arch/m68k/kernel/process.c +++ b/arch/m68k/kernel/process.c @@ -34,6 +34,7 @@ asmlinkage void ret_from_fork(void); +asmlinkage void ret_from_kernel_thread(void); /* @@ -120,51 +121,6 @@ void show_regs(struct pt_regs * regs) printk("USP: %08lx\n", rdusp()); } -/* - * Create a kernel thread - */ -int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) -{ - int pid; - mm_segment_t fs; - - fs = get_fs(); - set_fs (KERNEL_DS); - - { - register long retval __asm__ ("d0"); - register long clone_arg __asm__ ("d1") = flags | CLONE_VM | CLONE_UNTRACED; - - retval = __NR_clone; - __asm__ __volatile__ - ("clrl %%d2\n\t" - "trap #0\n\t" /* Linux/m68k system call */ - "tstl %0\n\t" /* child or parent */ - "jne 1f\n\t" /* parent - jump */ -#ifdef CONFIG_MMU - "lea %%sp@(%c7),%6\n\t" /* reload current */ - "movel %6@,%6\n\t" -#endif - "movel %3,%%sp@-\n\t" /* push argument */ - "jsr %4@\n\t" /* call fn */ - "movel %0,%%d1\n\t" /* pass exit value */ - "movel %2,%%d0\n\t" /* exit */ - "trap #0\n" - "1:" - : "+d" (retval) - : "i" (__NR_clone), "i" (__NR_exit), - "r" (arg), "a" (fn), "d" (clone_arg), "r" (current), - "i" (-THREAD_SIZE) - : "d2"); - - pid = retval; - } - - set_fs (fs); - return pid; -} -EXPORT_SYMBOL(kernel_thread); - void flush_thread(void) { current->thread.fs = __USER_DS; @@ -216,30 +172,18 @@ asmlinkage int m68k_clone(struct pt_regs *regs) } 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 * childstack, *stack; - unsigned long *retp; + struct switch_stack *childstack; childregs = (struct pt_regs *) (task_stack_page(p) + THREAD_SIZE) - 1; - - *childregs = *regs; - childregs->d0 = 0; - - retp = ((unsigned long *) regs); - stack = ((struct switch_stack *) retp) - 1; - childstack = ((struct switch_stack *) childregs) - 1; - *childstack = *stack; - childstack->retpc = (unsigned long)ret_from_fork; p->thread.usp = usp; p->thread.ksp = (unsigned long)childstack; - - if (clone_flags & CLONE_SETTLS) - task_thread_info(p)->tp_value = regs->d5; + p->thread.esp0 = (unsigned long)childregs; /* * Must save the current SFC/DFC value, NOT the value when @@ -247,6 +191,26 @@ int copy_thread(unsigned long clone_flags, unsigned long usp, */ p->thread.fs = get_fs().seg; + if (unlikely(!regs)) { + /* kernel thread */ + memset(childstack, 0, + sizeof(struct switch_stack) + sizeof(struct pt_regs)); + childregs->sr = PS_S; + childstack->a3 = usp; /* function */ + childstack->d7 = arg; + childstack->retpc = (unsigned long)ret_from_kernel_thread; + p->thread.usp = 0; + return 0; + } + *childregs = *regs; + childregs->d0 = 0; + + *childstack = ((struct switch_stack *) regs)[-1]; + childstack->retpc = (unsigned long)ret_from_fork; + + if (clone_flags & CLONE_SETTLS) + task_thread_info(p)->tp_value = regs->d5; + #ifdef CONFIG_FPU if (!FPU_IS_EMU) { /* Copy the current fpu state */ -- cgit v1.2.3 From d878d6dacee2c862f02da20f7fa3e2c0e8820e71 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 16 Sep 2012 12:06:34 -0400 Subject: m68k: switch to generic sys_execve()/kernel_execve() The tricky part here is that task_pt_regs() on m68k works *only* for process inside do_signal(). However, we need something much simpler - pt_regs of a process inside do_signal() may be at different offsets from the stack bottom, depending on the way we'd entered the kernel, but for a task inside sys_execve() it *is* at constant offset. Moreover, for a kernel thread about to become a userland process the same location is also fine - setting sp to that will leave the kernel stack pointer at the very bottom of the kernel stack when we finally switch to userland. Signed-off-by: Al Viro --- arch/m68k/include/asm/ptrace.h | 2 ++ arch/m68k/include/asm/unistd.h | 2 ++ arch/m68k/kernel/entry.S | 5 +++++ arch/m68k/kernel/process.c | 20 -------------------- arch/m68k/kernel/sys_m68k.c | 17 ----------------- 5 files changed, 9 insertions(+), 37 deletions(-) (limited to 'arch/m68k') diff --git a/arch/m68k/include/asm/ptrace.h b/arch/m68k/include/asm/ptrace.h index 65322b17b6cf..5e08b597f012 100644 --- a/arch/m68k/include/asm/ptrace.h +++ b/arch/m68k/include/asm/ptrace.h @@ -85,6 +85,8 @@ struct switch_stack { #define user_mode(regs) (!((regs)->sr & PS_S)) #define instruction_pointer(regs) ((regs)->pc) #define profile_pc(regs) instruction_pointer(regs) +#define current_pt_regs() \ + (struct pt_regs *)((char *)current_thread_info() + THREAD_SIZE) - 1 #define arch_has_single_step() (1) diff --git a/arch/m68k/include/asm/unistd.h b/arch/m68k/include/asm/unistd.h index 045cfd6a9e31..c702ad716791 100644 --- a/arch/m68k/include/asm/unistd.h +++ b/arch/m68k/include/asm/unistd.h @@ -382,6 +382,8 @@ #define __ARCH_WANT_SYS_SIGPROCMASK #define __ARCH_WANT_SYS_RT_SIGACTION #define __ARCH_WANT_SYS_RT_SIGSUSPEND +#define __ARCH_WANT_SYS_EXECVE +#define __ARCH_WANT_KERNEL_EXECVE /* * "Conditional" syscalls diff --git a/arch/m68k/kernel/entry.S b/arch/m68k/kernel/entry.S index 8a01f580a024..946cb0187751 100644 --- a/arch/m68k/kernel/entry.S +++ b/arch/m68k/kernel/entry.S @@ -122,6 +122,11 @@ ENTRY(ret_from_kernel_thread) 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) #ifdef TRAP_DBG_INTERRUPT diff --git a/arch/m68k/kernel/process.c b/arch/m68k/kernel/process.c index b3d4760c9750..4e54b4c03081 100644 --- a/arch/m68k/kernel/process.c +++ b/arch/m68k/kernel/process.c @@ -298,26 +298,6 @@ int dump_fpu (struct pt_regs *regs, struct user_m68kfp_struct *fpu) EXPORT_SYMBOL(dump_fpu); #endif /* CONFIG_FPU */ -/* - * 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; - char * filename; - struct pt_regs *regs = (struct pt_regs *) &name; - - filename = getname(name); - error = PTR_ERR(filename); - if (IS_ERR(filename)) - return error; - error = do_execve(filename, argv, envp, regs); - putname(filename); - return error; -} - unsigned long get_wchan(struct task_struct *p) { unsigned long fp, pc; diff --git a/arch/m68k/kernel/sys_m68k.c b/arch/m68k/kernel/sys_m68k.c index 9a5932ec3689..3a480b3df0d6 100644 --- a/arch/m68k/kernel/sys_m68k.c +++ b/arch/m68k/kernel/sys_m68k.c @@ -549,23 +549,6 @@ asmlinkage int sys_getpagesize(void) return PAGE_SIZE; } -/* - * 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 __res asm ("%d0") = __NR_execve; - register long __a asm ("%d1") = (long)(filename); - register long __b asm ("%d2") = (long)(argv); - register long __c asm ("%d3") = (long)(envp); - asm volatile ("trap #0" : "+d" (__res) - : "d" (__a), "d" (__b), "d" (__c)); - return __res; -} - asmlinkage unsigned long sys_get_thread_area(void) { return current_thread_info()->tp_value; -- cgit v1.2.3