#include <linux/ptrace.h>
#include <linux/user.h>
#include <linux/security.h>
+#include <linux/signal.h>
#include <asm/uaccess.h>
#include <asm/page.h>
/*
* 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)
/*
* 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;
/*
* 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;
}
#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
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
ret = -EIO;
if (copied != sizeof(tmp))
break;
- ret = put_user(tmp,(unsigned long *) data);
+ ret = put_user(tmp,(unsigned long __user *) data);
break;
}
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;
}
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);
*/
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. */
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);
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:
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