Commit 962bca7f authored by Robert Jennings's avatar Robert Jennings Committed by Paul Mackerras

[PATCH] ppc64: Add PTRACE_{GET|SET}VRREGS

The ptrace get and set methods for VMX/Altivec registers present in the
ppc tree were missing for ppc64.  This patch adds the 32-bit and
64-bit methods.  Updated with the suggestions from Anton following the lines
of his code snippet.

Added:
 - flush_altivec_to_thread calls as suggested by Anton
 - piecewise copy of structure to preserve 32-bit vrsave data as per
   Anton

(I consolidated the 32 and 64bit versions with 2 helper macros - Anton)
Signed-off-by: default avatarRobert C Jennings <rcjenn@austin.ibm.com>
Signed-off-by: default avatarAnton Blanchard <anton@samba.org>
Signed-off-by: default avatarPaul Mackerras <paulus@samba.org>
parent 4267292b
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
* this archive for more details. * this archive for more details.
*/ */
#include <linux/config.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/mm.h> #include <linux/mm.h>
...@@ -274,6 +275,20 @@ int sys_ptrace(long request, long pid, long addr, long data) ...@@ -274,6 +275,20 @@ int sys_ptrace(long request, long pid, long addr, long data)
break; break;
} }
#ifdef CONFIG_ALTIVEC
case PTRACE_GETVRREGS:
/* Get the child altivec register state. */
flush_altivec_to_thread(child);
ret = get_vrregs((unsigned long __user *)data, child);
break;
case PTRACE_SETVRREGS:
/* Set the child altivec register state. */
flush_altivec_to_thread(child);
ret = set_vrregs(child, (unsigned long __user *)data);
break;
#endif
default: default:
ret = ptrace_request(child, request, addr, data); ret = ptrace_request(child, request, addr, data);
break; break;
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
* this archive for more details. * this archive for more details.
*/ */
#include <linux/config.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/mm.h> #include <linux/mm.h>
...@@ -409,6 +410,20 @@ int sys32_ptrace(long request, long pid, unsigned long addr, unsigned long data) ...@@ -409,6 +410,20 @@ int sys32_ptrace(long request, long pid, unsigned long addr, unsigned long data)
ret = put_user(child->ptrace_message, (unsigned int __user *) data); ret = put_user(child->ptrace_message, (unsigned int __user *) data);
break; break;
#ifdef CONFIG_ALTIVEC
case PTRACE_GETVRREGS:
/* Get the child altivec register state. */
flush_altivec_to_thread(child);
ret = get_vrregs((unsigned long __user *)data, child);
break;
case PTRACE_SETVRREGS:
/* Set the child altivec register state. */
flush_altivec_to_thread(child);
ret = set_vrregs(child, (unsigned long __user *)data);
break;
#endif
default: default:
ret = ptrace_request(child, request, addr, data); ret = ptrace_request(child, request, addr, data);
break; break;
......
...@@ -11,6 +11,9 @@ ...@@ -11,6 +11,9 @@
#ifndef _PPC64_PTRACE_COMMON_H #ifndef _PPC64_PTRACE_COMMON_H
#define _PPC64_PTRACE_COMMON_H #define _PPC64_PTRACE_COMMON_H
#include <linux/config.h>
/* /*
* Set of msr bits that gdb can change on behalf of a process. * Set of msr bits that gdb can change on behalf of a process.
*/ */
...@@ -69,4 +72,73 @@ static inline void clear_single_step(struct task_struct *task) ...@@ -69,4 +72,73 @@ static inline void clear_single_step(struct task_struct *task)
clear_ti_thread_flag(task->thread_info, TIF_SINGLESTEP); clear_ti_thread_flag(task->thread_info, TIF_SINGLESTEP);
} }
#ifdef CONFIG_ALTIVEC
/*
* Get/set all the altivec registers vr0..vr31, vscr, vrsave, in one go.
* The transfer totals 34 quadword. Quadwords 0-31 contain the
* corresponding vector registers. Quadword 32 contains the vscr as the
* last word (offset 12) within that quadword. Quadword 33 contains the
* vrsave as the first word (offset 0) within the quadword.
*
* This definition of the VMX state is compatible with the current PPC32
* ptrace interface. This allows signal handling and ptrace to use the
* same structures. This also simplifies the implementation of a bi-arch
* (combined (32- and 64-bit) gdb.
*/
/*
* Get contents of AltiVec register state in task TASK
*/
static inline int get_vrregs(unsigned long __user *data,
struct task_struct *task)
{
unsigned long regsize;
/* copy AltiVec registers VR[0] .. VR[31] */
regsize = 32 * sizeof(vector128);
if (copy_to_user(data, task->thread.vr, regsize))
return -EFAULT;
data += (regsize / sizeof(unsigned long));
/* copy VSCR */
regsize = 1 * sizeof(vector128);
if (copy_to_user(data, &task->thread.vscr, regsize))
return -EFAULT;
data += (regsize / sizeof(unsigned long));
/* copy VRSAVE */
if (put_user(task->thread.vrsave, (u32 __user *)data))
return -EFAULT;
return 0;
}
/*
* Write contents of AltiVec register state into task TASK.
*/
static inline int set_vrregs(struct task_struct *task,
unsigned long __user *data)
{
unsigned long regsize;
/* copy AltiVec registers VR[0] .. VR[31] */
regsize = 32 * sizeof(vector128);
if (copy_from_user(task->thread.vr, data, regsize))
return -EFAULT;
data += (regsize / sizeof(unsigned long));
/* copy VSCR */
regsize = 1 * sizeof(vector128);
if (copy_from_user(&task->thread.vscr, data, regsize))
return -EFAULT;
data += (regsize / sizeof(unsigned long));
/* copy VRSAVE */
if (get_user(task->thread.vrsave, (u32 __user *)data))
return -EFAULT;
return 0;
}
#endif
#endif /* _PPC64_PTRACE_COMMON_H */ #endif /* _PPC64_PTRACE_COMMON_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment