aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kernel/ptrace.c
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2007-06-04 01:15:44 -0400
committerPaul Mackerras <paulus@samba.org>2007-06-14 08:29:57 -0400
commit865418d8e78b9c11c964157740b2596d6ffe9dfa (patch)
tree2ef4b1652fe38c7b9e172ca7a8aef906602d3692 /arch/powerpc/kernel/ptrace.c
parente17666ba48f78ff10162d7448e7c92d668d8faf6 (diff)
[POWERPC] Uninline common ptrace bits
This folds back the ptrace-common.h bits back into ptrace.c and removes that file. The FSL SPE bits from ptrace-ppc32.h are folded back in as well. Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> Signed-off-by: Paul Mackerras <paulus@samba.org>
Diffstat (limited to 'arch/powerpc/kernel/ptrace.c')
-rw-r--r--arch/powerpc/kernel/ptrace.c233
1 files changed, 227 insertions, 6 deletions
diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c
index 230d5f5bfab6..875bfda90b21 100644
--- a/arch/powerpc/kernel/ptrace.c
+++ b/arch/powerpc/kernel/ptrace.c
@@ -41,14 +41,235 @@
41#include "ptrace-ppc32.h" 41#include "ptrace-ppc32.h"
42#endif 42#endif
43 43
44#include "ptrace-common.h"
45
46/* 44/*
47 * does not yet catch signals sent when the child dies. 45 * does not yet catch signals sent when the child dies.
48 * in exit.c or in signal.c. 46 * in exit.c or in signal.c.
49 */ 47 */
50 48
51/* 49/*
50 * Get contents of register REGNO in task TASK.
51 */
52unsigned long ptrace_get_reg(struct task_struct *task, int regno)
53{
54 unsigned long tmp = 0;
55
56 if (task->thread.regs == NULL)
57 return -EIO;
58
59 if (regno == PT_MSR) {
60 tmp = ((unsigned long *)task->thread.regs)[PT_MSR];
61 return PT_MUNGE_MSR(tmp, task);
62 }
63
64 if (regno < (sizeof(struct pt_regs) / sizeof(unsigned long)))
65 return ((unsigned long *)task->thread.regs)[regno];
66
67 return -EIO;
68}
69
70/*
71 * Write contents of register REGNO in task TASK.
72 */
73int ptrace_put_reg(struct task_struct *task, int regno, unsigned long data)
74{
75 if (task->thread.regs == NULL)
76 return -EIO;
77
78 if (regno <= PT_MAX_PUT_REG) {
79 if (regno == PT_MSR)
80 data = (data & MSR_DEBUGCHANGE)
81 | (task->thread.regs->msr & ~MSR_DEBUGCHANGE);
82 ((unsigned long *)task->thread.regs)[regno] = data;
83 return 0;
84 }
85 return -EIO;
86}
87
88
89static int get_fpregs(void __user *data, struct task_struct *task,
90 int has_fpscr)
91{
92 unsigned int count = has_fpscr ? 33 : 32;
93
94 if (copy_to_user(data, task->thread.fpr, count * sizeof(double)))
95 return -EFAULT;
96 return 0;
97}
98
99static int set_fpregs(void __user *data, struct task_struct *task,
100 int has_fpscr)
101{
102 unsigned int count = has_fpscr ? 33 : 32;
103
104 if (copy_from_user(task->thread.fpr, data, count * sizeof(double)))
105 return -EFAULT;
106 return 0;
107}
108
109
110#ifdef CONFIG_ALTIVEC
111/*
112 * Get/set all the altivec registers vr0..vr31, vscr, vrsave, in one go.
113 * The transfer totals 34 quadword. Quadwords 0-31 contain the
114 * corresponding vector registers. Quadword 32 contains the vscr as the
115 * last word (offset 12) within that quadword. Quadword 33 contains the
116 * vrsave as the first word (offset 0) within the quadword.
117 *
118 * This definition of the VMX state is compatible with the current PPC32
119 * ptrace interface. This allows signal handling and ptrace to use the
120 * same structures. This also simplifies the implementation of a bi-arch
121 * (combined (32- and 64-bit) gdb.
122 */
123
124/*
125 * Get contents of AltiVec register state in task TASK
126 */
127static int get_vrregs(unsigned long __user *data, struct task_struct *task)
128{
129 unsigned long regsize;
130
131 /* copy AltiVec registers VR[0] .. VR[31] */
132 regsize = 32 * sizeof(vector128);
133 if (copy_to_user(data, task->thread.vr, regsize))
134 return -EFAULT;
135 data += (regsize / sizeof(unsigned long));
136
137 /* copy VSCR */
138 regsize = 1 * sizeof(vector128);
139 if (copy_to_user(data, &task->thread.vscr, regsize))
140 return -EFAULT;
141 data += (regsize / sizeof(unsigned long));
142
143 /* copy VRSAVE */
144 if (put_user(task->thread.vrsave, (u32 __user *)data))
145 return -EFAULT;
146
147 return 0;
148}
149
150/*
151 * Write contents of AltiVec register state into task TASK.
152 */
153static int set_vrregs(struct task_struct *task, unsigned long __user *data)
154{
155 unsigned long regsize;
156
157 /* copy AltiVec registers VR[0] .. VR[31] */
158 regsize = 32 * sizeof(vector128);
159 if (copy_from_user(task->thread.vr, data, regsize))
160 return -EFAULT;
161 data += (regsize / sizeof(unsigned long));
162
163 /* copy VSCR */
164 regsize = 1 * sizeof(vector128);
165 if (copy_from_user(&task->thread.vscr, data, regsize))
166 return -EFAULT;
167 data += (regsize / sizeof(unsigned long));
168
169 /* copy VRSAVE */
170 if (get_user(task->thread.vrsave, (u32 __user *)data))
171 return -EFAULT;
172
173 return 0;
174}
175#endif /* CONFIG_ALTIVEC */
176
177#ifdef CONFIG_SPE
178
179/*
180 * For get_evrregs/set_evrregs functions 'data' has the following layout:
181 *
182 * struct {
183 * u32 evr[32];
184 * u64 acc;
185 * u32 spefscr;
186 * }
187 */
188
189/*
190 * Get contents of SPE register state in task TASK.
191 */
192static int get_evrregs(unsigned long *data, struct task_struct *task)
193{
194 int i;
195
196 if (!access_ok(VERIFY_WRITE, data, 35 * sizeof(unsigned long)))
197 return -EFAULT;
198
199 /* copy SPEFSCR */
200 if (__put_user(task->thread.spefscr, &data[34]))
201 return -EFAULT;
202
203 /* copy SPE registers EVR[0] .. EVR[31] */
204 for (i = 0; i < 32; i++, data++)
205 if (__put_user(task->thread.evr[i], data))
206 return -EFAULT;
207
208 /* copy ACC */
209 if (__put_user64(task->thread.acc, (unsigned long long *)data))
210 return -EFAULT;
211
212 return 0;
213}
214
215/*
216 * Write contents of SPE register state into task TASK.
217 */
218static int set_evrregs(struct task_struct *task, unsigned long *data)
219{
220 int i;
221
222 if (!access_ok(VERIFY_READ, data, 35 * sizeof(unsigned long)))
223 return -EFAULT;
224
225 /* copy SPEFSCR */
226 if (__get_user(task->thread.spefscr, &data[34]))
227 return -EFAULT;
228
229 /* copy SPE registers EVR[0] .. EVR[31] */
230 for (i = 0; i < 32; i++, data++)
231 if (__get_user(task->thread.evr[i], data))
232 return -EFAULT;
233 /* copy ACC */
234 if (__get_user64(task->thread.acc, (unsigned long long*)data))
235 return -EFAULT;
236
237 return 0;
238}
239#endif /* CONFIG_SPE */
240
241
242static void set_single_step(struct task_struct *task)
243{
244 struct pt_regs *regs = task->thread.regs;
245
246 if (regs != NULL) {
247#if defined(CONFIG_40x) || defined(CONFIG_BOOKE)
248 task->thread.dbcr0 = DBCR0_IDM | DBCR0_IC;
249 regs->msr |= MSR_DE;
250#else
251 regs->msr |= MSR_SE;
252#endif
253 }
254 set_tsk_thread_flag(task, TIF_SINGLESTEP);
255}
256
257static void clear_single_step(struct task_struct *task)
258{
259 struct pt_regs *regs = task->thread.regs;
260
261 if (regs != NULL) {
262#if defined(CONFIG_40x) || defined(CONFIG_BOOKE)
263 task->thread.dbcr0 = 0;
264 regs->msr &= ~MSR_DE;
265#else
266 regs->msr &= ~MSR_SE;
267#endif
268 }
269 clear_tsk_thread_flag(task, TIF_SINGLESTEP);
270}
271
272/*
52 * Called by kernel/ptrace.c when detaching.. 273 * Called by kernel/ptrace.c when detaching..
53 * 274 *
54 * Make sure single step bits etc are not set. 275 * Make sure single step bits etc are not set.
@@ -154,7 +375,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
154 CHECK_FULL_REGS(child->thread.regs); 375 CHECK_FULL_REGS(child->thread.regs);
155#endif 376#endif
156 if (index < PT_FPR0) { 377 if (index < PT_FPR0) {
157 tmp = get_reg(child, (int) index); 378 tmp = ptrace_get_reg(child, (int) index);
158 } else { 379 } else {
159 flush_fp_to_thread(child); 380 flush_fp_to_thread(child);
160 tmp = ((unsigned long *)child->thread.fpr)[index - PT_FPR0]; 381 tmp = ((unsigned long *)child->thread.fpr)[index - PT_FPR0];
@@ -195,7 +416,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
195 if (index == PT_ORIG_R3) 416 if (index == PT_ORIG_R3)
196 break; 417 break;
197 if (index < PT_FPR0) { 418 if (index < PT_FPR0) {
198 ret = put_reg(child, index, data); 419 ret = ptrace_put_reg(child, index, data);
199 } else { 420 } else {
200 flush_fp_to_thread(child); 421 flush_fp_to_thread(child);
201 ((unsigned long *)child->thread.fpr)[index - PT_FPR0] = data; 422 ((unsigned long *)child->thread.fpr)[index - PT_FPR0] = data;
@@ -282,7 +503,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
282 } 503 }
283 ret = 0; 504 ret = 0;
284 for (ui = 0; ui < PT_REGS_COUNT; ui ++) { 505 for (ui = 0; ui < PT_REGS_COUNT; ui ++) {
285 ret |= __put_user(get_reg(child, ui), 506 ret |= __put_user(ptrace_get_reg(child, ui),
286 (unsigned long __user *) data); 507 (unsigned long __user *) data);
287 data += sizeof(long); 508 data += sizeof(long);
288 } 509 }
@@ -305,7 +526,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
305 ret = __get_user(tmp, (unsigned long __user *) data); 526 ret = __get_user(tmp, (unsigned long __user *) data);
306 if (ret) 527 if (ret)
307 break; 528 break;
308 put_reg(child, ui, tmp); 529 ptrace_put_reg(child, ui, tmp);
309 data += sizeof(long); 530 data += sizeof(long);
310 } 531 }
311 break; 532 break;