]> Pileus Git - ~andy/linux/blobdiff - arch/mips/kernel/ptrace32.c
MIPS: Support for 64-bit FP with O32 binaries
[~andy/linux] / arch / mips / kernel / ptrace32.c
index 9486055ba660319c415b7ec7affdd07b9eff887e..b8aa2dd5b00bc13af9f2b88225718773d7b5732d 100644 (file)
@@ -80,6 +80,7 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
        /* Read the word at location addr in the USER area. */
        case PTRACE_PEEKUSR: {
                struct pt_regs *regs;
+               fpureg_t *fregs;
                unsigned int tmp;
 
                regs = task_pt_regs(child);
@@ -90,21 +91,25 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
                        tmp = regs->regs[addr];
                        break;
                case FPR_BASE ... FPR_BASE + 31:
-                       if (tsk_used_math(child)) {
-                               fpureg_t *fregs = get_fpu_regs(child);
-
+                       if (!tsk_used_math(child)) {
+                               /* FP not yet used */
+                               tmp = -1;
+                               break;
+                       }
+                       fregs = get_fpu_regs(child);
+                       if (test_thread_flag(TIF_32BIT_FPREGS)) {
                                /*
                                 * The odd registers are actually the high
                                 * order bits of the values stored in the even
                                 * registers - unless we're using r2k_switch.S.
                                 */
                                if (addr & 1)
-                                       tmp = (unsigned long) (fregs[((addr & ~1) - 32)] >> 32);
+                                       tmp = fregs[(addr & ~1) - 32] >> 32;
                                else
-                                       tmp = (unsigned long) (fregs[(addr - 32)] & 0xffffffff);
-                       } else {
-                               tmp = -1;       /* FP not yet used  */
+                                       tmp = fregs[addr - 32];
+                               break;
                        }
+                       tmp = fregs[addr - FPR_BASE];
                        break;
                case PC:
                        tmp = regs->cp0_epc;
@@ -147,13 +152,13 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
                        if (cpu_has_mipsmt) {
                                unsigned int vpflags = dvpe();
                                flags = read_c0_status();
-                               __enable_fpu();
+                               __enable_fpu(FPU_AS_IS);
                                __asm__ __volatile__("cfc1\t%0,$0": "=r" (tmp));
                                write_c0_status(flags);
                                evpe(vpflags);
                        } else {
                                flags = read_c0_status();
-                               __enable_fpu();
+                               __enable_fpu(FPU_AS_IS);
                                __asm__ __volatile__("cfc1\t%0,$0": "=r" (tmp));
                                write_c0_status(flags);
                        }
@@ -236,20 +241,24 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
                                       sizeof(child->thread.fpu));
                                child->thread.fpu.fcr31 = 0;
                        }
-                       /*
-                        * The odd registers are actually the high order bits
-                        * of the values stored in the even registers - unless
-                        * we're using r2k_switch.S.
-                        */
-                       if (addr & 1) {
-                               fregs[(addr & ~1) - FPR_BASE] &= 0xffffffff;
-                               fregs[(addr & ~1) - FPR_BASE] |= ((unsigned long long) data) << 32;
-                       } else {
-                               fregs[addr - FPR_BASE] &= ~0xffffffffLL;
-                               /* Must cast, lest sign extension fill upper
-                                  bits!  */
-                               fregs[addr - FPR_BASE] |= (unsigned int)data;
+                       if (test_thread_flag(TIF_32BIT_FPREGS)) {
+                               /*
+                                * The odd registers are actually the high
+                                * order bits of the values stored in the even
+                                * registers - unless we're using r2k_switch.S.
+                                */
+                               if (addr & 1) {
+                                       fregs[(addr & ~1) - FPR_BASE] &=
+                                               0xffffffff;
+                                       fregs[(addr & ~1) - FPR_BASE] |=
+                                               ((u64)data) << 32;
+                               } else {
+                                       fregs[addr - FPR_BASE] &= ~0xffffffffLL;
+                                       fregs[addr - FPR_BASE] |= data;
+                               }
+                               break;
                        }
+                       fregs[addr - FPR_BASE] = data;
                        break;
                }
                case PC: