|
From: Kenn H. <ke...@us...> - 2005-05-29 12:11:07
|
Update of /cvsroot/linux-vax/kernel-2.5/arch/vax/kernel In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv6348 Modified Files: process.c Log Message: Fix kernel_thread(). I'm surprised it ever worked! Firstly, GCC 4.1 doesn't seem to notice the "clobbers AP" in the asm() block, and tries to use the modified AP to get fn and arg in the call to kernel_thread_exit(). Secondly, there is no guarantee that the location AP points to will still contain the argument list (CLONE_VM turns off copy-on-write, so if the parent runs first and overwrites that portion of memory, AP will point to garbage). For some reason, this never occurred with the old toolchain, but happens with our GGC4.1 toolchain. So, we pull fn and arg into R2 and R3, and do all the work within the asm() block. Index: process.c =================================================================== RCS file: /cvsroot/linux-vax/kernel-2.5/arch/vax/kernel/process.c,v retrieving revision 1.29 retrieving revision 1.30 diff -u -d -r1.29 -r1.30 --- process.c 9 May 2005 20:34:28 -0000 1.29 +++ process.c 29 May 2005 12:10:54 -0000 1.30 @@ -174,19 +174,14 @@ */ } -static ATTRIB_NORET void kernel_thread_exit(int exitcode) -{ - __chmk(__NR_exit); - while (1) - /* Keep GCC happy */; -} - /* * Create a kernel thread */ pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags) { asm( + " movl %2,%%r2 \n" + " movl %3,%%r3 \n" " clrl -(%%sp) \n" " movl %0, -(%%sp) \n" " pushl $0x2 \n" @@ -196,20 +191,20 @@ " beql child \n" " ret \n" "child: \n" + " pushl %%r3 \n" + " calls $1, *%%r2 \n" + " pushl %%r0 \n" + " movl %%sp, %%ap \n" + " chmk %4 \n" : /* no outputs */ - : "g"(flags | CLONE_VM), "g"(__NR_clone) - : "r0", "ap"); + : "g"(flags | CLONE_VM), "g"(__NR_clone), "g"(fn), "g"(arg), "g"(__NR_exit) + : "r0", "r2", "r3"); /* - * In child. At this point SP points to the very top of - * our kernel stack, so we cannot pop anything off. That - * means that we can never return from here. + * We never actually get here - there is a RET embedded above which + * returns in the parent, and the child exits with the CHMK __NR_exit */ -#ifdef VAX_PROCESS_DEBUG - printk("kernel_thread: task %p, pid %d, calling thread function at %08lx\n", - current, current->pid, (unsigned long) fn); -#endif - kernel_thread_exit(fn(arg)); + return 0; } int sys_clone(unsigned long clone_flags, unsigned long newsp, struct pt_regs *regs) |