Fedora kernel-2.6.17-1.2142_FC4 patched with stable patch-2.6.17.4-vs2.0.2-rc26.diff
[linux-2.6.git] / arch / sparc64 / math-emu / math.c
index 48dfa37..6ee496c 100644 (file)
@@ -185,7 +185,7 @@ int do_mathemu(struct pt_regs *regs, struct fpustate *f)
                die_if_kernel("unfinished/unimplemented FPop from kernel", regs);
        if (test_thread_flag(TIF_32BIT))
                pc = (u32)pc;
-       if (get_user(insn, (u32 *)pc) != -EFAULT) {
+       if (get_user(insn, (u32 __user *) pc) != -EFAULT) {
                if ((insn & 0xc1f80000) == 0x81a00000) /* FPOP1 */ {
                        switch ((insn >> 5) & 0x1ff) {
                        /* QUAD - ftt == 3 */
@@ -206,9 +206,29 @@ int do_mathemu(struct pt_regs *regs, struct fpustate *f)
                        case FSTOQ: TYPE(3,3,1,1,1,0,0); break;
                        case FDTOQ: TYPE(3,3,1,2,1,0,0); break;
                        case FQTOI: TYPE(3,1,0,3,1,0,0); break;
+
+                       /* We can get either unimplemented or unfinished
+                        * for these cases.  Pre-Niagara systems generate
+                        * unfinished fpop for SUBNORMAL cases, and Niagara
+                        * always gives unimplemented fpop for fsqrt{s,d}.
+                        */
+                       case FSQRTS: {
+                               unsigned long x = current_thread_info()->xfsr[0];
+
+                               x = (x >> 14) & 0xf;
+                               TYPE(x,1,1,1,1,0,0);
+                               break;
+                       }
+
+                       case FSQRTD: {
+                               unsigned long x = current_thread_info()->xfsr[0];
+
+                               x = (x >> 14) & 0xf;
+                               TYPE(x,2,1,2,1,0,0);
+                               break;
+                       }
+
                        /* SUBNORMAL - ftt == 2 */
-                       case FSQRTS: TYPE(2,1,1,1,1,0,0); break;
-                       case FSQRTD: TYPE(2,2,1,2,1,0,0); break;
                        case FADDD:
                        case FSUBD:
                        case FMULD:
@@ -298,14 +318,14 @@ int do_mathemu(struct pt_regs *regs, struct fpustate *f)
                                else if (freg < 16)
                                        XR = regs->u_regs[freg];
                                else if (test_thread_flag(TIF_32BIT)) {
-                                       struct reg_window32 *win32;
+                                       struct reg_window32 __user *win32;
                                        flushw_user ();
-                                       win32 = (struct reg_window32 *)((unsigned long)((u32)regs->u_regs[UREG_FP]));
+                                       win32 = (struct reg_window32 __user *)((unsigned long)((u32)regs->u_regs[UREG_FP]));
                                        get_user(XR, &win32->locals[freg - 16]);
                                } else {
-                                       struct reg_window *win;
+                                       struct reg_window __user *win;
                                        flushw_user ();
-                                       win = (struct reg_window *)(regs->u_regs[UREG_FP] + STACK_BIAS);
+                                       win = (struct reg_window __user *)(regs->u_regs[UREG_FP] + STACK_BIAS);
                                        get_user(XR, &win->locals[freg - 16]);
                                }
                                IR = 0;