aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/kernel/ptrace.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/mips/kernel/ptrace.c')
-rw-r--r--arch/mips/kernel/ptrace.c223
1 files changed, 177 insertions, 46 deletions
diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c
index f639ccd5060c..645b3c4fcfba 100644
--- a/arch/mips/kernel/ptrace.c
+++ b/arch/mips/kernel/ptrace.c
@@ -24,7 +24,6 @@
24#include <linux/ptrace.h> 24#include <linux/ptrace.h>
25#include <linux/regset.h> 25#include <linux/regset.h>
26#include <linux/smp.h> 26#include <linux/smp.h>
27#include <linux/user.h>
28#include <linux/security.h> 27#include <linux/security.h>
29#include <linux/tracehook.h> 28#include <linux/tracehook.h>
30#include <linux/audit.h> 29#include <linux/audit.h>
@@ -63,7 +62,7 @@ void ptrace_disable(struct task_struct *child)
63 * for 32-bit kernels and for 32-bit processes on a 64-bit kernel. 62 * for 32-bit kernels and for 32-bit processes on a 64-bit kernel.
64 * Registers are sign extended to fill the available space. 63 * Registers are sign extended to fill the available space.
65 */ 64 */
66int ptrace_getregs(struct task_struct *child, __s64 __user *data) 65int ptrace_getregs(struct task_struct *child, struct user_pt_regs __user *data)
67{ 66{
68 struct pt_regs *regs; 67 struct pt_regs *regs;
69 int i; 68 int i;
@@ -74,13 +73,13 @@ int ptrace_getregs(struct task_struct *child, __s64 __user *data)
74 regs = task_pt_regs(child); 73 regs = task_pt_regs(child);
75 74
76 for (i = 0; i < 32; i++) 75 for (i = 0; i < 32; i++)
77 __put_user((long)regs->regs[i], data + i); 76 __put_user((long)regs->regs[i], (__s64 __user *)&data->regs[i]);
78 __put_user((long)regs->lo, data + EF_LO - EF_R0); 77 __put_user((long)regs->lo, (__s64 __user *)&data->lo);
79 __put_user((long)regs->hi, data + EF_HI - EF_R0); 78 __put_user((long)regs->hi, (__s64 __user *)&data->hi);
80 __put_user((long)regs->cp0_epc, data + EF_CP0_EPC - EF_R0); 79 __put_user((long)regs->cp0_epc, (__s64 __user *)&data->cp0_epc);
81 __put_user((long)regs->cp0_badvaddr, data + EF_CP0_BADVADDR - EF_R0); 80 __put_user((long)regs->cp0_badvaddr, (__s64 __user *)&data->cp0_badvaddr);
82 __put_user((long)regs->cp0_status, data + EF_CP0_STATUS - EF_R0); 81 __put_user((long)regs->cp0_status, (__s64 __user *)&data->cp0_status);
83 __put_user((long)regs->cp0_cause, data + EF_CP0_CAUSE - EF_R0); 82 __put_user((long)regs->cp0_cause, (__s64 __user *)&data->cp0_cause);
84 83
85 return 0; 84 return 0;
86} 85}
@@ -90,7 +89,7 @@ int ptrace_getregs(struct task_struct *child, __s64 __user *data)
90 * the 64-bit format. On a 32-bit kernel only the lower order half 89 * the 64-bit format. On a 32-bit kernel only the lower order half
91 * (according to endianness) will be used. 90 * (according to endianness) will be used.
92 */ 91 */
93int ptrace_setregs(struct task_struct *child, __s64 __user *data) 92int ptrace_setregs(struct task_struct *child, struct user_pt_regs __user *data)
94{ 93{
95 struct pt_regs *regs; 94 struct pt_regs *regs;
96 int i; 95 int i;
@@ -101,10 +100,10 @@ int ptrace_setregs(struct task_struct *child, __s64 __user *data)
101 regs = task_pt_regs(child); 100 regs = task_pt_regs(child);
102 101
103 for (i = 0; i < 32; i++) 102 for (i = 0; i < 32; i++)
104 __get_user(regs->regs[i], data + i); 103 __get_user(regs->regs[i], (__s64 __user *)&data->regs[i]);
105 __get_user(regs->lo, data + EF_LO - EF_R0); 104 __get_user(regs->lo, (__s64 __user *)&data->lo);
106 __get_user(regs->hi, data + EF_HI - EF_R0); 105 __get_user(regs->hi, (__s64 __user *)&data->hi);
107 __get_user(regs->cp0_epc, data + EF_CP0_EPC - EF_R0); 106 __get_user(regs->cp0_epc, (__s64 __user *)&data->cp0_epc);
108 107
109 /* badvaddr, status, and cause may not be written. */ 108 /* badvaddr, status, and cause may not be written. */
110 109
@@ -129,7 +128,7 @@ int ptrace_getfpregs(struct task_struct *child, __u32 __user *data)
129 } 128 }
130 129
131 __put_user(child->thread.fpu.fcr31, data + 64); 130 __put_user(child->thread.fpu.fcr31, data + 64);
132 __put_user(current_cpu_data.fpu_id, data + 65); 131 __put_user(boot_cpu_data.fpu_id, data + 65);
133 132
134 return 0; 133 return 0;
135} 134}
@@ -151,6 +150,7 @@ int ptrace_setfpregs(struct task_struct *child, __u32 __user *data)
151 } 150 }
152 151
153 __get_user(child->thread.fpu.fcr31, data + 64); 152 __get_user(child->thread.fpu.fcr31, data + 64);
153 child->thread.fpu.fcr31 &= ~FPU_CSR_ALL_X;
154 154
155 /* FIR may not be written. */ 155 /* FIR may not be written. */
156 156
@@ -246,36 +246,160 @@ int ptrace_set_watch_regs(struct task_struct *child,
246 246
247/* regset get/set implementations */ 247/* regset get/set implementations */
248 248
249static int gpr_get(struct task_struct *target, 249#if defined(CONFIG_32BIT) || defined(CONFIG_MIPS32_O32)
250 const struct user_regset *regset, 250
251 unsigned int pos, unsigned int count, 251static int gpr32_get(struct task_struct *target,
252 void *kbuf, void __user *ubuf) 252 const struct user_regset *regset,
253 unsigned int pos, unsigned int count,
254 void *kbuf, void __user *ubuf)
253{ 255{
254 struct pt_regs *regs = task_pt_regs(target); 256 struct pt_regs *regs = task_pt_regs(target);
257 u32 uregs[ELF_NGREG] = {};
258 unsigned i;
259
260 for (i = MIPS32_EF_R1; i <= MIPS32_EF_R31; i++) {
261 /* k0/k1 are copied as zero. */
262 if (i == MIPS32_EF_R26 || i == MIPS32_EF_R27)
263 continue;
264
265 uregs[i] = regs->regs[i - MIPS32_EF_R0];
266 }
255 267
256 return user_regset_copyout(&pos, &count, &kbuf, &ubuf, 268 uregs[MIPS32_EF_LO] = regs->lo;
257 regs, 0, sizeof(*regs)); 269 uregs[MIPS32_EF_HI] = regs->hi;
270 uregs[MIPS32_EF_CP0_EPC] = regs->cp0_epc;
271 uregs[MIPS32_EF_CP0_BADVADDR] = regs->cp0_badvaddr;
272 uregs[MIPS32_EF_CP0_STATUS] = regs->cp0_status;
273 uregs[MIPS32_EF_CP0_CAUSE] = regs->cp0_cause;
274
275 return user_regset_copyout(&pos, &count, &kbuf, &ubuf, uregs, 0,
276 sizeof(uregs));
258} 277}
259 278
260static int gpr_set(struct task_struct *target, 279static int gpr32_set(struct task_struct *target,
261 const struct user_regset *regset, 280 const struct user_regset *regset,
262 unsigned int pos, unsigned int count, 281 unsigned int pos, unsigned int count,
263 const void *kbuf, const void __user *ubuf) 282 const void *kbuf, const void __user *ubuf)
264{ 283{
265 struct pt_regs newregs; 284 struct pt_regs *regs = task_pt_regs(target);
266 int ret; 285 u32 uregs[ELF_NGREG];
286 unsigned start, num_regs, i;
287 int err;
288
289 start = pos / sizeof(u32);
290 num_regs = count / sizeof(u32);
291
292 if (start + num_regs > ELF_NGREG)
293 return -EIO;
294
295 err = user_regset_copyin(&pos, &count, &kbuf, &ubuf, uregs, 0,
296 sizeof(uregs));
297 if (err)
298 return err;
299
300 for (i = start; i < num_regs; i++) {
301 /*
302 * Cast all values to signed here so that if this is a 64-bit
303 * kernel, the supplied 32-bit values will be sign extended.
304 */
305 switch (i) {
306 case MIPS32_EF_R1 ... MIPS32_EF_R25:
307 /* k0/k1 are ignored. */
308 case MIPS32_EF_R28 ... MIPS32_EF_R31:
309 regs->regs[i - MIPS32_EF_R0] = (s32)uregs[i];
310 break;
311 case MIPS32_EF_LO:
312 regs->lo = (s32)uregs[i];
313 break;
314 case MIPS32_EF_HI:
315 regs->hi = (s32)uregs[i];
316 break;
317 case MIPS32_EF_CP0_EPC:
318 regs->cp0_epc = (s32)uregs[i];
319 break;
320 }
321 }
322
323 return 0;
324}
325
326#endif /* CONFIG_32BIT || CONFIG_MIPS32_O32 */
327
328#ifdef CONFIG_64BIT
329
330static int gpr64_get(struct task_struct *target,
331 const struct user_regset *regset,
332 unsigned int pos, unsigned int count,
333 void *kbuf, void __user *ubuf)
334{
335 struct pt_regs *regs = task_pt_regs(target);
336 u64 uregs[ELF_NGREG] = {};
337 unsigned i;
338
339 for (i = MIPS64_EF_R1; i <= MIPS64_EF_R31; i++) {
340 /* k0/k1 are copied as zero. */
341 if (i == MIPS64_EF_R26 || i == MIPS64_EF_R27)
342 continue;
343
344 uregs[i] = regs->regs[i - MIPS64_EF_R0];
345 }
346
347 uregs[MIPS64_EF_LO] = regs->lo;
348 uregs[MIPS64_EF_HI] = regs->hi;
349 uregs[MIPS64_EF_CP0_EPC] = regs->cp0_epc;
350 uregs[MIPS64_EF_CP0_BADVADDR] = regs->cp0_badvaddr;
351 uregs[MIPS64_EF_CP0_STATUS] = regs->cp0_status;
352 uregs[MIPS64_EF_CP0_CAUSE] = regs->cp0_cause;
353
354 return user_regset_copyout(&pos, &count, &kbuf, &ubuf, uregs, 0,
355 sizeof(uregs));
356}
267 357
268 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, 358static int gpr64_set(struct task_struct *target,
269 &newregs, 359 const struct user_regset *regset,
270 0, sizeof(newregs)); 360 unsigned int pos, unsigned int count,
271 if (ret) 361 const void *kbuf, const void __user *ubuf)
272 return ret; 362{
363 struct pt_regs *regs = task_pt_regs(target);
364 u64 uregs[ELF_NGREG];
365 unsigned start, num_regs, i;
366 int err;
367
368 start = pos / sizeof(u64);
369 num_regs = count / sizeof(u64);
273 370
274 *task_pt_regs(target) = newregs; 371 if (start + num_regs > ELF_NGREG)
372 return -EIO;
373
374 err = user_regset_copyin(&pos, &count, &kbuf, &ubuf, uregs, 0,
375 sizeof(uregs));
376 if (err)
377 return err;
378
379 for (i = start; i < num_regs; i++) {
380 switch (i) {
381 case MIPS64_EF_R1 ... MIPS64_EF_R25:
382 /* k0/k1 are ignored. */
383 case MIPS64_EF_R28 ... MIPS64_EF_R31:
384 regs->regs[i - MIPS64_EF_R0] = uregs[i];
385 break;
386 case MIPS64_EF_LO:
387 regs->lo = uregs[i];
388 break;
389 case MIPS64_EF_HI:
390 regs->hi = uregs[i];
391 break;
392 case MIPS64_EF_CP0_EPC:
393 regs->cp0_epc = uregs[i];
394 break;
395 }
396 }
275 397
276 return 0; 398 return 0;
277} 399}
278 400
401#endif /* CONFIG_64BIT */
402
279static int fpr_get(struct task_struct *target, 403static int fpr_get(struct task_struct *target,
280 const struct user_regset *regset, 404 const struct user_regset *regset,
281 unsigned int pos, unsigned int count, 405 unsigned int pos, unsigned int count,
@@ -337,14 +461,16 @@ enum mips_regset {
337 REGSET_FPR, 461 REGSET_FPR,
338}; 462};
339 463
464#if defined(CONFIG_32BIT) || defined(CONFIG_MIPS32_O32)
465
340static const struct user_regset mips_regsets[] = { 466static const struct user_regset mips_regsets[] = {
341 [REGSET_GPR] = { 467 [REGSET_GPR] = {
342 .core_note_type = NT_PRSTATUS, 468 .core_note_type = NT_PRSTATUS,
343 .n = ELF_NGREG, 469 .n = ELF_NGREG,
344 .size = sizeof(unsigned int), 470 .size = sizeof(unsigned int),
345 .align = sizeof(unsigned int), 471 .align = sizeof(unsigned int),
346 .get = gpr_get, 472 .get = gpr32_get,
347 .set = gpr_set, 473 .set = gpr32_set,
348 }, 474 },
349 [REGSET_FPR] = { 475 [REGSET_FPR] = {
350 .core_note_type = NT_PRFPREG, 476 .core_note_type = NT_PRFPREG,
@@ -364,14 +490,18 @@ static const struct user_regset_view user_mips_view = {
364 .n = ARRAY_SIZE(mips_regsets), 490 .n = ARRAY_SIZE(mips_regsets),
365}; 491};
366 492
493#endif /* CONFIG_32BIT || CONFIG_MIPS32_O32 */
494
495#ifdef CONFIG_64BIT
496
367static const struct user_regset mips64_regsets[] = { 497static const struct user_regset mips64_regsets[] = {
368 [REGSET_GPR] = { 498 [REGSET_GPR] = {
369 .core_note_type = NT_PRSTATUS, 499 .core_note_type = NT_PRSTATUS,
370 .n = ELF_NGREG, 500 .n = ELF_NGREG,
371 .size = sizeof(unsigned long), 501 .size = sizeof(unsigned long),
372 .align = sizeof(unsigned long), 502 .align = sizeof(unsigned long),
373 .get = gpr_get, 503 .get = gpr64_get,
374 .set = gpr_set, 504 .set = gpr64_set,
375 }, 505 },
376 [REGSET_FPR] = { 506 [REGSET_FPR] = {
377 .core_note_type = NT_PRFPREG, 507 .core_note_type = NT_PRFPREG,
@@ -384,25 +514,26 @@ static const struct user_regset mips64_regsets[] = {
384}; 514};
385 515
386static const struct user_regset_view user_mips64_view = { 516static const struct user_regset_view user_mips64_view = {
387 .name = "mips", 517 .name = "mips64",
388 .e_machine = ELF_ARCH, 518 .e_machine = ELF_ARCH,
389 .ei_osabi = ELF_OSABI, 519 .ei_osabi = ELF_OSABI,
390 .regsets = mips64_regsets, 520 .regsets = mips64_regsets,
391 .n = ARRAY_SIZE(mips_regsets), 521 .n = ARRAY_SIZE(mips64_regsets),
392}; 522};
393 523
524#endif /* CONFIG_64BIT */
525
394const struct user_regset_view *task_user_regset_view(struct task_struct *task) 526const struct user_regset_view *task_user_regset_view(struct task_struct *task)
395{ 527{
396#ifdef CONFIG_32BIT 528#ifdef CONFIG_32BIT
397 return &user_mips_view; 529 return &user_mips_view;
398#endif 530#else
399
400#ifdef CONFIG_MIPS32_O32 531#ifdef CONFIG_MIPS32_O32
401 if (test_thread_flag(TIF_32BIT_REGS)) 532 if (test_tsk_thread_flag(task, TIF_32BIT_REGS))
402 return &user_mips_view; 533 return &user_mips_view;
403#endif 534#endif
404
405 return &user_mips64_view; 535 return &user_mips64_view;
536#endif
406} 537}
407 538
408long arch_ptrace(struct task_struct *child, long request, 539long arch_ptrace(struct task_struct *child, long request,
@@ -480,7 +611,7 @@ long arch_ptrace(struct task_struct *child, long request,
480 break; 611 break;
481 case FPC_EIR: 612 case FPC_EIR:
482 /* implementation / version register */ 613 /* implementation / version register */
483 tmp = current_cpu_data.fpu_id; 614 tmp = boot_cpu_data.fpu_id;
484 break; 615 break;
485 case DSP_BASE ... DSP_BASE + 5: { 616 case DSP_BASE ... DSP_BASE + 5: {
486 dspreg_t *dregs; 617 dspreg_t *dregs;
@@ -565,7 +696,7 @@ long arch_ptrace(struct task_struct *child, long request,
565 break; 696 break;
566#endif 697#endif
567 case FPC_CSR: 698 case FPC_CSR:
568 child->thread.fpu.fcr31 = data; 699 child->thread.fpu.fcr31 = data & ~FPU_CSR_ALL_X;
569 break; 700 break;
570 case DSP_BASE ... DSP_BASE + 5: { 701 case DSP_BASE ... DSP_BASE + 5: {
571 dspreg_t *dregs; 702 dspreg_t *dregs;