Merge branch 'misc' of master.kernel.org:/pub/scm/linux/kernel/git/galak/powerpc...
[pandora-kernel.git] / arch / mips / kernel / ptrace.c
index 122433f..f3106d0 100644 (file)
@@ -33,6 +33,7 @@
 #include <asm/dsp.h>
 #include <asm/fpu.h>
 #include <asm/mipsregs.h>
+#include <asm/mipsmtregs.h>
 #include <asm/pgtable.h>
 #include <asm/page.h>
 #include <asm/system.h>
@@ -63,8 +64,7 @@ int ptrace_getregs (struct task_struct *child, __s64 __user *data)
        if (!access_ok(VERIFY_WRITE, data, 38 * 8))
                return -EIO;
 
-       regs = (struct pt_regs *) ((unsigned long) child->thread_info +
-              THREAD_SIZE - 32 - sizeof(struct pt_regs));
+       regs = task_pt_regs(child);
 
        for (i = 0; i < 32; i++)
                __put_user (regs->regs[i], data + i);
@@ -91,8 +91,7 @@ int ptrace_setregs (struct task_struct *child, __s64 __user *data)
        if (!access_ok(VERIFY_READ, data, 38 * 8))
                return -EIO;
 
-       regs = (struct pt_regs *) ((unsigned long) child->thread_info +
-              THREAD_SIZE - 32 - sizeof(struct pt_regs));
+       regs = task_pt_regs(child);
 
        for (i = 0; i < 32; i++)
                __get_user (regs->regs[i], data + i);
@@ -126,10 +125,21 @@ int ptrace_getfpregs (struct task_struct *child, __u32 __user *data)
 
                __put_user (child->thread.fpu.hard.fcr31, data + 64);
 
-               flags = read_c0_status();
-               __enable_fpu();
-               __asm__ __volatile__("cfc1\t%0,$0" : "=r" (tmp));
-               write_c0_status(flags);
+               preempt_disable();
+               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);
+               }
+               preempt_enable();
                __put_user (tmp, data + 65);
        } else {
                __put_user (child->thread.fpu.soft.fcr31, data + 64);
@@ -162,51 +172,10 @@ int ptrace_setfpregs (struct task_struct *child, __u32 __user *data)
        return 0;
 }
 
-asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
+long arch_ptrace(struct task_struct *child, long request, long addr, long data)
 {
-       struct task_struct *child;
        int ret;
 
-#if 0
-       printk("ptrace(r=%d,pid=%d,addr=%08lx,data=%08lx)\n",
-              (int) request, (int) pid, (unsigned long) addr,
-              (unsigned long) data);
-#endif
-       lock_kernel();
-       ret = -EPERM;
-       if (request == PTRACE_TRACEME) {
-               /* are we already being traced? */
-               if (current->ptrace & PT_PTRACED)
-                       goto out;
-               if ((ret = security_ptrace(current->parent, current)))
-                       goto out;
-               /* set the ptrace bit in the process flags. */
-               current->ptrace |= PT_PTRACED;
-               ret = 0;
-               goto out;
-       }
-       ret = -ESRCH;
-       read_lock(&tasklist_lock);
-       child = find_task_by_pid(pid);
-       if (child)
-               get_task_struct(child);
-       read_unlock(&tasklist_lock);
-       if (!child)
-               goto out;
-
-       ret = -EPERM;
-       if (pid == 1)           /* you may not mess with init */
-               goto out_tsk;
-
-       if (request == PTRACE_ATTACH) {
-               ret = ptrace_attach(child);
-               goto out_tsk;
-       }
-
-       ret = ptrace_check_attach(child, request == PTRACE_KILL);
-       if (ret < 0)
-               goto out_tsk;
-
        switch (request) {
        /* when I and D space are separate, these will need to be fixed. */
        case PTRACE_PEEKTEXT: /* read word at location addr. */
@@ -227,8 +196,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
                struct pt_regs *regs;
                unsigned long tmp = 0;
 
-               regs = (struct pt_regs *) ((unsigned long) child->thread_info +
-                      THREAD_SIZE - 32 - sizeof(struct pt_regs));
+               regs = task_pt_regs(child);
                ret = 0;  /* Default return value. */
 
                switch (addr) {
@@ -280,14 +248,39 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
                        break;
                case FPC_EIR: { /* implementation / version register */
                        unsigned int flags;
+#ifdef CONFIG_MIPS_MT_SMTC
+                       unsigned int irqflags;
+                       unsigned int mtflags;
+#endif /* CONFIG_MIPS_MT_SMTC */
 
                        if (!cpu_has_fpu)
                                break;
 
-                       flags = read_c0_status();
-                       __enable_fpu();
-                       __asm__ __volatile__("cfc1\t%0,$0": "=r" (tmp));
-                       write_c0_status(flags);
+#ifdef CONFIG_MIPS_MT_SMTC
+                       /* Read-modify-write of Status must be atomic */
+                       local_irq_save(irqflags);
+                       mtflags = dmt();
+#endif /* CONFIG_MIPS_MT_SMTC */
+
+                       preempt_disable();
+                       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();
                        break;
                }
                case DSP_BASE ... DSP_BASE + 5: {
@@ -296,28 +289,24 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
                        if (!cpu_has_dsp) {
                                tmp = 0;
                                ret = -EIO;
-                               goto out_tsk;
-                       }
-                       if (child->thread.dsp.used_dsp) {
-                               dregs = __get_dsp_regs(child);
-                               tmp = (unsigned long) (dregs[addr - DSP_BASE]);
-                       } else {
-                               tmp = -1;       /* DSP registers yet used  */
+                               goto out;
                        }
+                       dregs = __get_dsp_regs(child);
+                       tmp = (unsigned long) (dregs[addr - DSP_BASE]);
                        break;
                }
                case DSP_CONTROL:
                        if (!cpu_has_dsp) {
                                tmp = 0;
                                ret = -EIO;
-                               goto out_tsk;
+                               goto out;
                        }
                        tmp = child->thread.dsp.dspcontrol;
                        break;
                default:
                        tmp = 0;
                        ret = -EIO;
-                       goto out_tsk;
+                       goto out;
                }
                ret = put_user(tmp, (unsigned long __user *) data);
                break;
@@ -336,8 +325,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
        case PTRACE_POKEUSR: {
                struct pt_regs *regs;
                ret = 0;
-               regs = (struct pt_regs *) ((unsigned long) child->thread_info +
-                      THREAD_SIZE - 32 - sizeof(struct pt_regs));
+               regs = task_pt_regs(child);
 
                switch (addr) {
                case 0 ... 31:
@@ -464,7 +452,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
                break;
 
        case PTRACE_GET_THREAD_AREA:
-               ret = put_user(child->thread_info->tp_value,
+               ret = put_user(task_thread_info(child)->tp_value,
                                (unsigned long __user *) data);
                break;
 
@@ -472,11 +460,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
                ret = ptrace_request(child, request, addr, data);
                break;
        }
-
-out_tsk:
-       put_task_struct(child);
-out:
-       unlock_kernel();
+ out:
        return ret;
 }