David Miller writes: > From: Mikael Pettersson <mikpe@xxxxxxxx> > Date: Wed, 4 Apr 2007 09:23:07 +0200 (MEST) > > > The 2.6.21-rc5 kernel compiled with gcc-4.2.0 20070316 boots ok > > but is thrown into an infinite loop by `hdparm -Tt /dev/hda'. > > Sysrq-P tells me that the call chain in the loop is: > > > > __up_read or __handle_mm_fault [varies] > > do_sparc64_fault > > sparc64_realfault_common > > compat_sys_shmat > > > > The kernel works when built with gcc-3.4.6, 4.0.4, or 4.1.2. > > > > I'll do some more debugging next week, if I have time. > > Any updates? Yes, but I can't yet reproduce the problem in a user-mode test case, or pinpoint the exact object code that broke. In ipc/compat.c:compat_sys_shmat(): long compat_sys_shmat(int first, int second, compat_uptr_t third, int version, void __user *uptr) { int err; unsigned long raddr; compat_ulong_t __user *uaddr; if (version == 1) return -EINVAL; err = do_shmat(first, uptr, second, &raddr); if (err < 0) return err; uaddr = compat_ptr(third); return put_user(raddr, uaddr); } The syscall originated from a 32-bit process, and `third' is a high user-space pointer 0xffxxxxxx. If I insert a printk("uaddr %#lx third %#x\n", (long)uaddr, third) just before the final put_user(), I find that with gcc-4.2.0 uaddr will be 0xffffffffffxxxxxx, i.e. sign-extended from third, and this causes sparc64_realfault_common() to loop. With gcc-4.1.2 uaddr is 0x00000000ffxxxxxx and put_user() works. Both gcc-4.2.0 and gcc-4.1.2 compile compat_ptr(u32) as a nop, so it seems that something earlier in the call chain must have left a sign-extended value in the argument register for `third'. And true enough, in arch/sparc64/kernel/sys32.S we find that the entry for sys32_ipc() explicitly sign-extends %o1/%o2/%o3. %o3 is passed on as-is to `u32 third' in compat_sys_ipc() and `compat_uptr_t third' in compat_sys_shmat(). I don't know the sparc64 ABI rules for how the high 32 bits of a 64-bit register containing a 32-bit value are supposed to be (sign-extended, zero-extended, or undefined), but it seems that u32 values should be zero-extended, which would make the sign-extension in sys32.S broken. At this point I'm lost. I don't even understand how this could have worked with gcc < 4.2.0, much less where exactly gcc-4.2.0 broke things. /Mikael - To unsubscribe from this list: send the line "unsubscribe sparclinux" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html