diff options
| author | Robert Jennings <rcjenn@austin.ibm.com> | 2005-09-10 02:01:07 -0400 |
|---|---|---|
| committer | Paul Mackerras <paulus@samba.org> | 2005-09-12 03:19:11 -0400 |
| commit | 962bca7f389229a30ced441d7b37f55f203006a2 (patch) | |
| tree | 9824ae5b923a477fb4a671eda60822f80610861e | |
| parent | 4267292b0f368c1633ff3316a53b5f7fbada95f8 (diff) | |
[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: Robert C Jennings <rcjenn@austin.ibm.com>
Signed-off-by: Anton Blanchard <anton@samba.org>
Signed-off-by: Paul Mackerras <paulus@samba.org>
| -rw-r--r-- | arch/ppc64/kernel/ptrace.c | 15 | ||||
| -rw-r--r-- | arch/ppc64/kernel/ptrace32.c | 15 | ||||
| -rw-r--r-- | include/asm-ppc64/ptrace-common.h | 72 |
3 files changed, 102 insertions, 0 deletions
diff --git a/arch/ppc64/kernel/ptrace.c b/arch/ppc64/kernel/ptrace.c index 2993f108d96d..bf7116d4c4c2 100644 --- a/arch/ppc64/kernel/ptrace.c +++ b/arch/ppc64/kernel/ptrace.c | |||
| @@ -17,6 +17,7 @@ | |||
| 17 | * this archive for more details. | 17 | * this archive for more details. |
| 18 | */ | 18 | */ |
| 19 | 19 | ||
| 20 | #include <linux/config.h> | ||
| 20 | #include <linux/kernel.h> | 21 | #include <linux/kernel.h> |
| 21 | #include <linux/sched.h> | 22 | #include <linux/sched.h> |
| 22 | #include <linux/mm.h> | 23 | #include <linux/mm.h> |
| @@ -274,6 +275,20 @@ int sys_ptrace(long request, long pid, long addr, long data) | |||
| 274 | break; | 275 | break; |
| 275 | } | 276 | } |
| 276 | 277 | ||
| 278 | #ifdef CONFIG_ALTIVEC | ||
| 279 | case PTRACE_GETVRREGS: | ||
| 280 | /* Get the child altivec register state. */ | ||
| 281 | flush_altivec_to_thread(child); | ||
| 282 | ret = get_vrregs((unsigned long __user *)data, child); | ||
| 283 | break; | ||
| 284 | |||
| 285 | case PTRACE_SETVRREGS: | ||
| 286 | /* Set the child altivec register state. */ | ||
| 287 | flush_altivec_to_thread(child); | ||
| 288 | ret = set_vrregs(child, (unsigned long __user *)data); | ||
| 289 | break; | ||
| 290 | #endif | ||
| 291 | |||
| 277 | default: | 292 | default: |
| 278 | ret = ptrace_request(child, request, addr, data); | 293 | ret = ptrace_request(child, request, addr, data); |
| 279 | break; | 294 | break; |
diff --git a/arch/ppc64/kernel/ptrace32.c b/arch/ppc64/kernel/ptrace32.c index 16436426c7e2..4d1568c946cc 100644 --- a/arch/ppc64/kernel/ptrace32.c +++ b/arch/ppc64/kernel/ptrace32.c | |||
| @@ -17,6 +17,7 @@ | |||
| 17 | * this archive for more details. | 17 | * this archive for more details. |
| 18 | */ | 18 | */ |
| 19 | 19 | ||
| 20 | #include <linux/config.h> | ||
| 20 | #include <linux/kernel.h> | 21 | #include <linux/kernel.h> |
| 21 | #include <linux/sched.h> | 22 | #include <linux/sched.h> |
| 22 | #include <linux/mm.h> | 23 | #include <linux/mm.h> |
| @@ -409,6 +410,20 @@ int sys32_ptrace(long request, long pid, unsigned long addr, unsigned long data) | |||
| 409 | ret = put_user(child->ptrace_message, (unsigned int __user *) data); | 410 | ret = put_user(child->ptrace_message, (unsigned int __user *) data); |
| 410 | break; | 411 | break; |
| 411 | 412 | ||
| 413 | #ifdef CONFIG_ALTIVEC | ||
| 414 | case PTRACE_GETVRREGS: | ||
| 415 | /* Get the child altivec register state. */ | ||
| 416 | flush_altivec_to_thread(child); | ||
| 417 | ret = get_vrregs((unsigned long __user *)data, child); | ||
| 418 | break; | ||
| 419 | |||
| 420 | case PTRACE_SETVRREGS: | ||
| 421 | /* Set the child altivec register state. */ | ||
| 422 | flush_altivec_to_thread(child); | ||
| 423 | ret = set_vrregs(child, (unsigned long __user *)data); | ||
| 424 | break; | ||
| 425 | #endif | ||
| 426 | |||
| 412 | default: | 427 | default: |
| 413 | ret = ptrace_request(child, request, addr, data); | 428 | ret = ptrace_request(child, request, addr, data); |
| 414 | break; | 429 | break; |
diff --git a/include/asm-ppc64/ptrace-common.h b/include/asm-ppc64/ptrace-common.h index af03547f9c7e..bd0f84c27bd0 100644 --- a/include/asm-ppc64/ptrace-common.h +++ b/include/asm-ppc64/ptrace-common.h | |||
| @@ -11,6 +11,9 @@ | |||
| 11 | 11 | ||
| 12 | #ifndef _PPC64_PTRACE_COMMON_H | 12 | #ifndef _PPC64_PTRACE_COMMON_H |
| 13 | #define _PPC64_PTRACE_COMMON_H | 13 | #define _PPC64_PTRACE_COMMON_H |
| 14 | |||
| 15 | #include <linux/config.h> | ||
| 16 | |||
| 14 | /* | 17 | /* |
| 15 | * Set of msr bits that gdb can change on behalf of a process. | 18 | * Set of msr bits that gdb can change on behalf of a process. |
| 16 | */ | 19 | */ |
| @@ -69,4 +72,73 @@ static inline void clear_single_step(struct task_struct *task) | |||
| 69 | clear_ti_thread_flag(task->thread_info, TIF_SINGLESTEP); | 72 | clear_ti_thread_flag(task->thread_info, TIF_SINGLESTEP); |
| 70 | } | 73 | } |
| 71 | 74 | ||
| 75 | #ifdef CONFIG_ALTIVEC | ||
| 76 | /* | ||
| 77 | * Get/set all the altivec registers vr0..vr31, vscr, vrsave, in one go. | ||
| 78 | * The transfer totals 34 quadword. Quadwords 0-31 contain the | ||
| 79 | * corresponding vector registers. Quadword 32 contains the vscr as the | ||
| 80 | * last word (offset 12) within that quadword. Quadword 33 contains the | ||
| 81 | * vrsave as the first word (offset 0) within the quadword. | ||
| 82 | * | ||
| 83 | * This definition of the VMX state is compatible with the current PPC32 | ||
| 84 | * ptrace interface. This allows signal handling and ptrace to use the | ||
| 85 | * same structures. This also simplifies the implementation of a bi-arch | ||
| 86 | * (combined (32- and 64-bit) gdb. | ||
| 87 | */ | ||
| 88 | |||
| 89 | /* | ||
| 90 | * Get contents of AltiVec register state in task TASK | ||
| 91 | */ | ||
| 92 | static inline int get_vrregs(unsigned long __user *data, | ||
| 93 | struct task_struct *task) | ||
| 94 | { | ||
| 95 | unsigned long regsize; | ||
| 96 | |||
| 97 | /* copy AltiVec registers VR[0] .. VR[31] */ | ||
| 98 | regsize = 32 * sizeof(vector128); | ||
| 99 | if (copy_to_user(data, task->thread.vr, regsize)) | ||
| 100 | return -EFAULT; | ||
| 101 | data += (regsize / sizeof(unsigned long)); | ||
| 102 | |||
| 103 | /* copy VSCR */ | ||
| 104 | regsize = 1 * sizeof(vector128); | ||
| 105 | if (copy_to_user(data, &task->thread.vscr, regsize)) | ||
| 106 | return -EFAULT; | ||
| 107 | data += (regsize / sizeof(unsigned long)); | ||
| 108 | |||
| 109 | /* copy VRSAVE */ | ||
| 110 | if (put_user(task->thread.vrsave, (u32 __user *)data)) | ||
| 111 | return -EFAULT; | ||
| 112 | |||
| 113 | return 0; | ||
| 114 | } | ||
| 115 | |||
| 116 | /* | ||
| 117 | * Write contents of AltiVec register state into task TASK. | ||
| 118 | */ | ||
| 119 | static inline int set_vrregs(struct task_struct *task, | ||
| 120 | unsigned long __user *data) | ||
| 121 | { | ||
| 122 | unsigned long regsize; | ||
| 123 | |||
| 124 | /* copy AltiVec registers VR[0] .. VR[31] */ | ||
| 125 | regsize = 32 * sizeof(vector128); | ||
| 126 | if (copy_from_user(task->thread.vr, data, regsize)) | ||
| 127 | return -EFAULT; | ||
| 128 | data += (regsize / sizeof(unsigned long)); | ||
| 129 | |||
| 130 | /* copy VSCR */ | ||
| 131 | regsize = 1 * sizeof(vector128); | ||
| 132 | if (copy_from_user(&task->thread.vscr, data, regsize)) | ||
| 133 | return -EFAULT; | ||
| 134 | data += (regsize / sizeof(unsigned long)); | ||
| 135 | |||
| 136 | /* copy VRSAVE */ | ||
| 137 | if (get_user(task->thread.vrsave, (u32 __user *)data)) | ||
| 138 | return -EFAULT; | ||
| 139 | |||
| 140 | return 0; | ||
| 141 | } | ||
| 142 | #endif | ||
| 143 | |||
| 72 | #endif /* _PPC64_PTRACE_COMMON_H */ | 144 | #endif /* _PPC64_PTRACE_COMMON_H */ |
