Merge git://git.infradead.org/users/eparis/audit
[cascardo/linux.git] / arch / mips / kernel / ptrace.c
index 65ba622..71f85f4 100644 (file)
@@ -114,51 +114,30 @@ int ptrace_setregs(struct task_struct *child, __s64 __user *data)
 int ptrace_getfpregs(struct task_struct *child, __u32 __user *data)
 {
        int i;
-       unsigned int tmp;
 
        if (!access_ok(VERIFY_WRITE, data, 33 * 8))
                return -EIO;
 
        if (tsk_used_math(child)) {
-               fpureg_t *fregs = get_fpu_regs(child);
+               union fpureg *fregs = get_fpu_regs(child);
                for (i = 0; i < 32; i++)
-                       __put_user(fregs[i], i + (__u64 __user *) data);
+                       __put_user(get_fpr64(&fregs[i], 0),
+                                  i + (__u64 __user *)data);
        } else {
                for (i = 0; i < 32; i++)
                        __put_user((__u64) -1, i + (__u64 __user *) data);
        }
 
        __put_user(child->thread.fpu.fcr31, data + 64);
-
-       preempt_disable();
-       if (cpu_has_fpu) {
-               unsigned int flags;
-
-               if (cpu_has_mipsmt) {
-                       unsigned int vpflags = dvpe();
-                       flags = read_c0_status();
-                       __enable_fpu();
-                       __asm__ __volatile__("cfc1\t%0,$0" : "=r" (tmp));
-                       write_c0_status(flags);
-                       evpe(vpflags);
-               } else {
-                       flags = read_c0_status();
-                       __enable_fpu();
-                       __asm__ __volatile__("cfc1\t%0,$0" : "=r" (tmp));
-                       write_c0_status(flags);
-               }
-       } else {
-               tmp = 0;
-       }
-       preempt_enable();
-       __put_user(tmp, data + 65);
+       __put_user(current_cpu_data.fpu_id, data + 65);
 
        return 0;
 }
 
 int ptrace_setfpregs(struct task_struct *child, __u32 __user *data)
 {
-       fpureg_t *fregs;
+       union fpureg *fregs;
+       u64 fpr_val;
        int i;
 
        if (!access_ok(VERIFY_READ, data, 33 * 8))
@@ -166,8 +145,10 @@ int ptrace_setfpregs(struct task_struct *child, __u32 __user *data)
 
        fregs = get_fpu_regs(child);
 
-       for (i = 0; i < 32; i++)
-               __get_user(fregs[i], i + (__u64 __user *) data);
+       for (i = 0; i < 32; i++) {
+               __get_user(fpr_val, i + (__u64 __user *)data);
+               set_fpr64(&fregs[i], 0, fpr_val);
+       }
 
        __get_user(child->thread.fpu.fcr31, data + 64);
 
@@ -300,10 +281,27 @@ static int fpr_get(struct task_struct *target,
                   unsigned int pos, unsigned int count,
                   void *kbuf, void __user *ubuf)
 {
-       return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
-                                  &target->thread.fpu,
-                                  0, sizeof(elf_fpregset_t));
+       unsigned i;
+       int err;
+       u64 fpr_val;
+
        /* XXX fcr31  */
+
+       if (sizeof(target->thread.fpu.fpr[i]) == sizeof(elf_fpreg_t))
+               return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+                                          &target->thread.fpu,
+                                          0, sizeof(elf_fpregset_t));
+
+       for (i = 0; i < NUM_FPU_REGS; i++) {
+               fpr_val = get_fpr64(&target->thread.fpu.fpr[i], 0);
+               err = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+                                         &fpr_val, i * sizeof(elf_fpreg_t),
+                                         (i + 1) * sizeof(elf_fpreg_t));
+               if (err)
+                       return err;
+       }
+
+       return 0;
 }
 
 static int fpr_set(struct task_struct *target,
@@ -311,10 +309,27 @@ static int fpr_set(struct task_struct *target,
                   unsigned int pos, unsigned int count,
                   const void *kbuf, const void __user *ubuf)
 {
-       return user_regset_copyin(&pos, &count, &kbuf, &ubuf,
-                                 &target->thread.fpu,
-                                 0, sizeof(elf_fpregset_t));
+       unsigned i;
+       int err;
+       u64 fpr_val;
+
        /* XXX fcr31  */
+
+       if (sizeof(target->thread.fpu.fpr[i]) == sizeof(elf_fpreg_t))
+               return user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+                                         &target->thread.fpu,
+                                         0, sizeof(elf_fpregset_t));
+
+       for (i = 0; i < NUM_FPU_REGS; i++) {
+               err = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+                                        &fpr_val, i * sizeof(elf_fpreg_t),
+                                        (i + 1) * sizeof(elf_fpreg_t));
+               if (err)
+                       return err;
+               set_fpr64(&target->thread.fpu.fpr[i], 0, fpr_val);
+       }
+
+       return 0;
 }
 
 enum mips_regset {
@@ -408,6 +423,7 @@ long arch_ptrace(struct task_struct *child, long request,
        /* Read the word at location addr in the USER area. */
        case PTRACE_PEEKUSR: {
                struct pt_regs *regs;
+               union fpureg *fregs;
                unsigned long tmp = 0;
 
                regs = task_pt_regs(child);
@@ -418,26 +434,26 @@ long arch_ptrace(struct task_struct *child, long 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);
 
 #ifdef CONFIG_32BIT
+                       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);
-                               else
-                                       tmp = (unsigned long) (fregs[(addr - 32)] & 0xffffffff);
-#endif
-#ifdef CONFIG_64BIT
-                               tmp = fregs[addr - FPR_BASE];
-#endif
-                       } else {
-                               tmp = -1;       /* FP not yet used  */
+                               tmp = get_fpr32(&fregs[(addr & ~1) - FPR_BASE],
+                                               addr & 1);
+                               break;
                        }
+#endif
+                       tmp = get_fpr32(&fregs[addr - FPR_BASE], 0);
                        break;
                case PC:
                        tmp = regs->cp0_epc;
@@ -462,44 +478,10 @@ long arch_ptrace(struct task_struct *child, long request,
                case FPC_CSR:
                        tmp = child->thread.fpu.fcr31;
                        break;
-               case FPC_EIR: { /* implementation / version register */
-                       unsigned int flags;
-#ifdef CONFIG_MIPS_MT_SMTC
-                       unsigned long irqflags;
-                       unsigned int mtflags;
-#endif /* CONFIG_MIPS_MT_SMTC */
-
-                       preempt_disable();
-                       if (!cpu_has_fpu) {
-                               preempt_enable();
-                               break;
-                       }
-
-#ifdef CONFIG_MIPS_MT_SMTC
-                       /* Read-modify-write of Status must be atomic */
-                       local_irq_save(irqflags);
-                       mtflags = dmt();
-#endif /* CONFIG_MIPS_MT_SMTC */
-                       if (cpu_has_mipsmt) {
-                               unsigned int vpflags = dvpe();
-                               flags = read_c0_status();
-                               __enable_fpu();
-                               __asm__ __volatile__("cfc1\t%0,$0": "=r" (tmp));
-                               write_c0_status(flags);
-                               evpe(vpflags);
-                       } else {
-                               flags = read_c0_status();
-                               __enable_fpu();
-                               __asm__ __volatile__("cfc1\t%0,$0": "=r" (tmp));
-                               write_c0_status(flags);
-                       }
-#ifdef CONFIG_MIPS_MT_SMTC
-                       emt(mtflags);
-                       local_irq_restore(irqflags);
-#endif /* CONFIG_MIPS_MT_SMTC */
-                       preempt_enable();
+               case FPC_EIR:
+                       /* implementation / version register */
+                       tmp = current_cpu_data.fpu_id;
                        break;
-               }
                case DSP_BASE ... DSP_BASE + 5: {
                        dspreg_t *dregs;
 
@@ -545,7 +527,7 @@ long arch_ptrace(struct task_struct *child, long request,
                        regs->regs[addr] = data;
                        break;
                case FPR_BASE ... FPR_BASE + 31: {
-                       fpureg_t *fregs = get_fpu_regs(child);
+                       union fpureg *fregs = get_fpu_regs(child);
 
                        if (!tsk_used_math(child)) {
                                /* FP not yet used  */
@@ -554,22 +536,18 @@ long arch_ptrace(struct task_struct *child, long request,
                                child->thread.fpu.fcr31 = 0;
                        }
 #ifdef CONFIG_32BIT
-                       /*
-                        * 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;
-                               fregs[addr - FPR_BASE] |= 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.
+                                */
+                               set_fpr32(&fregs[(addr & ~1) - FPR_BASE],
+                                         addr & 1, data);
+                               break;
                        }
 #endif
-#ifdef CONFIG_64BIT
-                       fregs[addr - FPR_BASE] = data;
-#endif
+                       set_fpr64(&fregs[addr - FPR_BASE], 0, data);
                        break;
                }
                case PC:
@@ -656,13 +634,13 @@ long arch_ptrace(struct task_struct *child, long request,
  * Notification of system call entry/exit
  * - triggered by current->work.syscall_trace
  */
-asmlinkage void syscall_trace_enter(struct pt_regs *regs)
+asmlinkage long syscall_trace_enter(struct pt_regs *regs, long syscall)
 {
        long ret = 0;
        user_exit();
 
-       /* do the secure computing check first */
-       secure_computing_strict(regs->regs[2]);
+       if (secure_computing(syscall) == -1)
+               return -1;
 
        if (test_thread_flag(TIF_SYSCALL_TRACE) &&
            tracehook_report_syscall_entry(regs))
@@ -672,9 +650,10 @@ asmlinkage void syscall_trace_enter(struct pt_regs *regs)
                trace_sys_enter(regs, regs->regs[2]);
 
        audit_syscall_entry(syscall_get_arch(),
-                           regs->regs[2],
+                           syscall,
                            regs->regs[4], regs->regs[5],
                            regs->regs[6], regs->regs[7]);
+       return syscall;
 }
 
 /*