vserver 2.0 rc7
[linux-2.6.git] / arch / ppc / kernel / ptrace.c
index f912078..70ee816 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/ptrace.h>
 #include <linux/user.h>
 #include <linux/security.h>
+#include <linux/signal.h>
 
 #include <asm/uaccess.h>
 #include <asm/page.h>
@@ -35,7 +36,7 @@
 /*
  * Set of msr bits that gdb can change on behalf of a process.
  */
-#ifdef CONFIG_4xx
+#if defined(CONFIG_40x) || defined(CONFIG_BOOKE)
 #define MSR_DEBUGCHANGE        0
 #else
 #define MSR_DEBUGCHANGE        (MSR_SE | MSR_BE)
@@ -77,7 +78,7 @@ static inline int put_reg(struct task_struct *task, int regno,
 /*
  * Get contents of AltiVec register state in task TASK
  */
-static inline int get_vrregs(unsigned long *data, struct task_struct *task)
+static inline int get_vrregs(unsigned long __user *data, struct task_struct *task)
 {
        int i, j;
 
@@ -105,7 +106,7 @@ static inline int get_vrregs(unsigned long *data, struct task_struct *task)
 /*
  * Write contents of AltiVec register state into task TASK.
  */
-static inline int set_vrregs(struct task_struct *task, unsigned long *data)
+static inline int set_vrregs(struct task_struct *task, unsigned long __user *data)
 {
        int i, j;
 
@@ -131,15 +132,79 @@ static inline int set_vrregs(struct task_struct *task, unsigned long *data)
 }
 #endif
 
+#ifdef CONFIG_SPE
+
+/*
+ * For get_evrregs/set_evrregs functions 'data' has the following layout:
+ *
+ * struct {
+ *   u32 evr[32];
+ *   u64 acc;
+ *   u32 spefscr;
+ * }
+ */
+
+/*
+ * Get contents of SPE register state in task TASK.
+ */
+static inline int get_evrregs(unsigned long *data, struct task_struct *task)
+{
+       int i;
+
+       if (!access_ok(VERIFY_WRITE, data, 35 * sizeof(unsigned long)))
+               return -EFAULT;
+
+       /* copy SPEFSCR */
+       if (__put_user(task->thread.spefscr, &data[34]))
+               return -EFAULT;
+
+       /* copy SPE registers EVR[0] .. EVR[31] */
+       for (i = 0; i < 32; i++, data++)
+               if (__put_user(task->thread.evr[i], data))
+                       return -EFAULT;
+
+       /* copy ACC */
+       if (__put_user64(task->thread.acc, (unsigned long long *)data))
+               return -EFAULT;
+
+       return 0;
+}
+
+/*
+ * Write contents of SPE register state into task TASK.
+ */
+static inline int set_evrregs(struct task_struct *task, unsigned long *data)
+{
+       int i;
+
+       if (!access_ok(VERIFY_READ, data, 35 * sizeof(unsigned long)))
+               return -EFAULT;
+
+       /* copy SPEFSCR */
+       if (__get_user(task->thread.spefscr, &data[34]))
+               return -EFAULT;
+
+       /* copy SPE registers EVR[0] .. EVR[31] */
+       for (i = 0; i < 32; i++, data++)
+               if (__get_user(task->thread.evr[i], data))
+                       return -EFAULT;
+       /* copy ACC */
+       if (__get_user64(task->thread.acc, (unsigned long long*)data))
+               return -EFAULT;
+
+       return 0;
+}
+#endif /* CONFIG_SPE */
+
 static inline void
 set_single_step(struct task_struct *task)
 {
        struct pt_regs *regs = task->thread.regs;
 
        if (regs != NULL) {
-#ifdef CONFIG_4xx
+#if defined(CONFIG_40x) || defined(CONFIG_BOOKE)
                task->thread.dbcr0 = DBCR0_IDM | DBCR0_IC;
-               /* MSR.DE should already be set */
+               regs->msr |= MSR_DE;
 #else
                regs->msr |= MSR_SE;
 #endif
@@ -152,8 +217,9 @@ clear_single_step(struct task_struct *task)
        struct pt_regs *regs = task->thread.regs;
 
        if (regs != NULL) {
-#ifdef CONFIG_4xx
+#if defined(CONFIG_40x) || defined(CONFIG_BOOKE)
                task->thread.dbcr0 = 0;
+               regs->msr &= ~MSR_DE;
 #else
                regs->msr &= ~MSR_SE;
 #endif
@@ -224,7 +290,7 @@ int sys_ptrace(long request, long pid, long addr, long data)
                ret = -EIO;
                if (copied != sizeof(tmp))
                        break;
-               ret = put_user(tmp,(unsigned long *) data);
+               ret = put_user(tmp,(unsigned long __user *) data);
                break;
        }
 
@@ -250,7 +316,7 @@ int sys_ptrace(long request, long pid, long addr, long data)
                        preempt_enable();
                        tmp = ((unsigned long *)child->thread.fpr)[index - PT_FPR0];
                }
-               ret = put_user(tmp,(unsigned long *) data);
+               ret = put_user(tmp,(unsigned long __user *) data);
                break;
        }
 
@@ -293,7 +359,7 @@ int sys_ptrace(long request, long pid, long addr, long data)
        case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
        case PTRACE_CONT: { /* restart after signal. */
                ret = -EIO;
-               if ((unsigned long) data > _NSIG)
+               if (!valid_signal(data))
                        break;
                if (request == PTRACE_SYSCALL) {
                        set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
@@ -315,7 +381,7 @@ int sys_ptrace(long request, long pid, long addr, long data)
  */
        case PTRACE_KILL: {
                ret = 0;
-               if (child->state == TASK_ZOMBIE)        /* already dead */
+               if (child->exit_state == EXIT_ZOMBIE)   /* already dead */
                        break;
                child->exit_code = SIGKILL;
                /* make sure the single step bit is not set. */
@@ -326,7 +392,7 @@ int sys_ptrace(long request, long pid, long addr, long data)
 
        case PTRACE_SINGLESTEP: {  /* set the trap flag. */
                ret = -EIO;
-               if ((unsigned long) data > _NSIG)
+               if (!valid_signal(data))
                        break;
                clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
                set_single_step(child);
@@ -348,7 +414,7 @@ int sys_ptrace(long request, long pid, long addr, long data)
                if (child->thread.regs->msr & MSR_VEC)
                        giveup_altivec(child);
                preempt_enable();
-               ret = get_vrregs((unsigned long *)data, child);
+               ret = get_vrregs((unsigned long __user *)data, child);
                break;
 
        case PTRACE_SETVRREGS:
@@ -359,7 +425,24 @@ int sys_ptrace(long request, long pid, long addr, long data)
                if (child->thread.regs->msr & MSR_VEC)
                        giveup_altivec(child);
                preempt_enable();
-               ret = set_vrregs(child, (unsigned long *)data);
+               ret = set_vrregs(child, (unsigned long __user *)data);
+               break;
+#endif
+#ifdef CONFIG_SPE
+       case PTRACE_GETEVRREGS:
+               /* Get the child spe register state. */
+               if (child->thread.regs->msr & MSR_SPE)
+                       giveup_spe(child);
+               ret = get_evrregs((unsigned long __user *)data, child);
+               break;
+
+       case PTRACE_SETEVRREGS:
+               /* Set the child spe register state. */
+               /* this is to clear the MSR_SPE bit to force a reload
+                * of register state from memory */
+               if (child->thread.regs->msr & MSR_SPE)
+                       giveup_spe(child);
+               ret = set_evrregs(child, (unsigned long __user *)data);
                break;
 #endif