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.c161
1 files changed, 67 insertions, 94 deletions
diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c
index 7da9b76db4d9..7271e5a83081 100644
--- a/arch/mips/kernel/ptrace.c
+++ b/arch/mips/kernel/ptrace.c
@@ -114,51 +114,30 @@ int ptrace_setregs(struct task_struct *child, __s64 __user *data)
114int ptrace_getfpregs(struct task_struct *child, __u32 __user *data) 114int ptrace_getfpregs(struct task_struct *child, __u32 __user *data)
115{ 115{
116 int i; 116 int i;
117 unsigned int tmp;
118 117
119 if (!access_ok(VERIFY_WRITE, data, 33 * 8)) 118 if (!access_ok(VERIFY_WRITE, data, 33 * 8))
120 return -EIO; 119 return -EIO;
121 120
122 if (tsk_used_math(child)) { 121 if (tsk_used_math(child)) {
123 fpureg_t *fregs = get_fpu_regs(child); 122 union fpureg *fregs = get_fpu_regs(child);
124 for (i = 0; i < 32; i++) 123 for (i = 0; i < 32; i++)
125 __put_user(fregs[i], i + (__u64 __user *) data); 124 __put_user(get_fpr64(&fregs[i], 0),
125 i + (__u64 __user *)data);
126 } else { 126 } else {
127 for (i = 0; i < 32; i++) 127 for (i = 0; i < 32; i++)
128 __put_user((__u64) -1, i + (__u64 __user *) data); 128 __put_user((__u64) -1, i + (__u64 __user *) data);
129 } 129 }
130 130
131 __put_user(child->thread.fpu.fcr31, data + 64); 131 __put_user(child->thread.fpu.fcr31, data + 64);
132 132 __put_user(current_cpu_data.fpu_id, data + 65);
133 preempt_disable();
134 if (cpu_has_fpu) {
135 unsigned int flags;
136
137 if (cpu_has_mipsmt) {
138 unsigned int vpflags = dvpe();
139 flags = read_c0_status();
140 __enable_fpu(FPU_AS_IS);
141 __asm__ __volatile__("cfc1\t%0,$0" : "=r" (tmp));
142 write_c0_status(flags);
143 evpe(vpflags);
144 } else {
145 flags = read_c0_status();
146 __enable_fpu(FPU_AS_IS);
147 __asm__ __volatile__("cfc1\t%0,$0" : "=r" (tmp));
148 write_c0_status(flags);
149 }
150 } else {
151 tmp = 0;
152 }
153 preempt_enable();
154 __put_user(tmp, data + 65);
155 133
156 return 0; 134 return 0;
157} 135}
158 136
159int ptrace_setfpregs(struct task_struct *child, __u32 __user *data) 137int ptrace_setfpregs(struct task_struct *child, __u32 __user *data)
160{ 138{
161 fpureg_t *fregs; 139 union fpureg *fregs;
140 u64 fpr_val;
162 int i; 141 int i;
163 142
164 if (!access_ok(VERIFY_READ, data, 33 * 8)) 143 if (!access_ok(VERIFY_READ, data, 33 * 8))
@@ -166,8 +145,10 @@ int ptrace_setfpregs(struct task_struct *child, __u32 __user *data)
166 145
167 fregs = get_fpu_regs(child); 146 fregs = get_fpu_regs(child);
168 147
169 for (i = 0; i < 32; i++) 148 for (i = 0; i < 32; i++) {
170 __get_user(fregs[i], i + (__u64 __user *) data); 149 __get_user(fpr_val, i + (__u64 __user *)data);
150 set_fpr64(&fregs[i], 0, fpr_val);
151 }
171 152
172 __get_user(child->thread.fpu.fcr31, data + 64); 153 __get_user(child->thread.fpu.fcr31, data + 64);
173 154
@@ -300,10 +281,27 @@ static int fpr_get(struct task_struct *target,
300 unsigned int pos, unsigned int count, 281 unsigned int pos, unsigned int count,
301 void *kbuf, void __user *ubuf) 282 void *kbuf, void __user *ubuf)
302{ 283{
303 return user_regset_copyout(&pos, &count, &kbuf, &ubuf, 284 unsigned i;
304 &target->thread.fpu, 285 int err;
305 0, sizeof(elf_fpregset_t)); 286 u64 fpr_val;
287
306 /* XXX fcr31 */ 288 /* XXX fcr31 */
289
290 if (sizeof(target->thread.fpu.fpr[i]) == sizeof(elf_fpreg_t))
291 return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
292 &target->thread.fpu,
293 0, sizeof(elf_fpregset_t));
294
295 for (i = 0; i < NUM_FPU_REGS; i++) {
296 fpr_val = get_fpr64(&target->thread.fpu.fpr[i], 0);
297 err = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
298 &fpr_val, i * sizeof(elf_fpreg_t),
299 (i + 1) * sizeof(elf_fpreg_t));
300 if (err)
301 return err;
302 }
303
304 return 0;
307} 305}
308 306
309static int fpr_set(struct task_struct *target, 307static int fpr_set(struct task_struct *target,
@@ -311,10 +309,27 @@ static int fpr_set(struct task_struct *target,
311 unsigned int pos, unsigned int count, 309 unsigned int pos, unsigned int count,
312 const void *kbuf, const void __user *ubuf) 310 const void *kbuf, const void __user *ubuf)
313{ 311{
314 return user_regset_copyin(&pos, &count, &kbuf, &ubuf, 312 unsigned i;
315 &target->thread.fpu, 313 int err;
316 0, sizeof(elf_fpregset_t)); 314 u64 fpr_val;
315
317 /* XXX fcr31 */ 316 /* XXX fcr31 */
317
318 if (sizeof(target->thread.fpu.fpr[i]) == sizeof(elf_fpreg_t))
319 return user_regset_copyin(&pos, &count, &kbuf, &ubuf,
320 &target->thread.fpu,
321 0, sizeof(elf_fpregset_t));
322
323 for (i = 0; i < NUM_FPU_REGS; i++) {
324 err = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
325 &fpr_val, i * sizeof(elf_fpreg_t),
326 (i + 1) * sizeof(elf_fpreg_t));
327 if (err)
328 return err;
329 set_fpr64(&target->thread.fpu.fpr[i], 0, fpr_val);
330 }
331
332 return 0;
318} 333}
319 334
320enum mips_regset { 335enum mips_regset {
@@ -408,7 +423,7 @@ long arch_ptrace(struct task_struct *child, long request,
408 /* Read the word at location addr in the USER area. */ 423 /* Read the word at location addr in the USER area. */
409 case PTRACE_PEEKUSR: { 424 case PTRACE_PEEKUSR: {
410 struct pt_regs *regs; 425 struct pt_regs *regs;
411 fpureg_t *fregs; 426 union fpureg *fregs;
412 unsigned long tmp = 0; 427 unsigned long tmp = 0;
413 428
414 regs = task_pt_regs(child); 429 regs = task_pt_regs(child);
@@ -433,14 +448,12 @@ long arch_ptrace(struct task_struct *child, long request,
433 * order bits of the values stored in the even 448 * order bits of the values stored in the even
434 * registers - unless we're using r2k_switch.S. 449 * registers - unless we're using r2k_switch.S.
435 */ 450 */
436 if (addr & 1) 451 tmp = get_fpr32(&fregs[(addr & ~1) - FPR_BASE],
437 tmp = fregs[(addr & ~1) - 32] >> 32; 452 addr & 1);
438 else
439 tmp = fregs[addr - 32];
440 break; 453 break;
441 } 454 }
442#endif 455#endif
443 tmp = fregs[addr - FPR_BASE]; 456 tmp = get_fpr32(&fregs[addr - FPR_BASE], 0);
444 break; 457 break;
445 case PC: 458 case PC:
446 tmp = regs->cp0_epc; 459 tmp = regs->cp0_epc;
@@ -465,44 +478,10 @@ long arch_ptrace(struct task_struct *child, long request,
465 case FPC_CSR: 478 case FPC_CSR:
466 tmp = child->thread.fpu.fcr31; 479 tmp = child->thread.fpu.fcr31;
467 break; 480 break;
468 case FPC_EIR: { /* implementation / version register */ 481 case FPC_EIR:
469 unsigned int flags; 482 /* implementation / version register */
470#ifdef CONFIG_MIPS_MT_SMTC 483 tmp = current_cpu_data.fpu_id;
471 unsigned long irqflags;
472 unsigned int mtflags;
473#endif /* CONFIG_MIPS_MT_SMTC */
474
475 preempt_disable();
476 if (!cpu_has_fpu) {
477 preempt_enable();
478 break;
479 }
480
481#ifdef CONFIG_MIPS_MT_SMTC
482 /* Read-modify-write of Status must be atomic */
483 local_irq_save(irqflags);
484 mtflags = dmt();
485#endif /* CONFIG_MIPS_MT_SMTC */
486 if (cpu_has_mipsmt) {
487 unsigned int vpflags = dvpe();
488 flags = read_c0_status();
489 __enable_fpu(FPU_AS_IS);
490 __asm__ __volatile__("cfc1\t%0,$0": "=r" (tmp));
491 write_c0_status(flags);
492 evpe(vpflags);
493 } else {
494 flags = read_c0_status();
495 __enable_fpu(FPU_AS_IS);
496 __asm__ __volatile__("cfc1\t%0,$0": "=r" (tmp));
497 write_c0_status(flags);
498 }
499#ifdef CONFIG_MIPS_MT_SMTC
500 emt(mtflags);
501 local_irq_restore(irqflags);
502#endif /* CONFIG_MIPS_MT_SMTC */
503 preempt_enable();
504 break; 484 break;
505 }
506 case DSP_BASE ... DSP_BASE + 5: { 485 case DSP_BASE ... DSP_BASE + 5: {
507 dspreg_t *dregs; 486 dspreg_t *dregs;
508 487
@@ -548,7 +527,7 @@ long arch_ptrace(struct task_struct *child, long request,
548 regs->regs[addr] = data; 527 regs->regs[addr] = data;
549 break; 528 break;
550 case FPR_BASE ... FPR_BASE + 31: { 529 case FPR_BASE ... FPR_BASE + 31: {
551 fpureg_t *fregs = get_fpu_regs(child); 530 union fpureg *fregs = get_fpu_regs(child);
552 531
553 if (!tsk_used_math(child)) { 532 if (!tsk_used_math(child)) {
554 /* FP not yet used */ 533 /* FP not yet used */
@@ -563,19 +542,12 @@ long arch_ptrace(struct task_struct *child, long request,
563 * order bits of the values stored in the even 542 * order bits of the values stored in the even
564 * registers - unless we're using r2k_switch.S. 543 * registers - unless we're using r2k_switch.S.
565 */ 544 */
566 if (addr & 1) { 545 set_fpr32(&fregs[(addr & ~1) - FPR_BASE],
567 fregs[(addr & ~1) - FPR_BASE] &= 546 addr & 1, data);
568 0xffffffff;
569 fregs[(addr & ~1) - FPR_BASE] |=
570 ((u64)data) << 32;
571 } else {
572 fregs[addr - FPR_BASE] &= ~0xffffffffLL;
573 fregs[addr - FPR_BASE] |= data;
574 }
575 break; 547 break;
576 } 548 }
577#endif 549#endif
578 fregs[addr - FPR_BASE] = data; 550 set_fpr64(&fregs[addr - FPR_BASE], 0, data);
579 break; 551 break;
580 } 552 }
581 case PC: 553 case PC:
@@ -662,13 +634,13 @@ long arch_ptrace(struct task_struct *child, long request,
662 * Notification of system call entry/exit 634 * Notification of system call entry/exit
663 * - triggered by current->work.syscall_trace 635 * - triggered by current->work.syscall_trace
664 */ 636 */
665asmlinkage void syscall_trace_enter(struct pt_regs *regs) 637asmlinkage long syscall_trace_enter(struct pt_regs *regs, long syscall)
666{ 638{
667 long ret = 0; 639 long ret = 0;
668 user_exit(); 640 user_exit();
669 641
670 /* do the secure computing check first */ 642 if (secure_computing(syscall) == -1)
671 secure_computing_strict(regs->regs[2]); 643 return -1;
672 644
673 if (test_thread_flag(TIF_SYSCALL_TRACE) && 645 if (test_thread_flag(TIF_SYSCALL_TRACE) &&
674 tracehook_report_syscall_entry(regs)) 646 tracehook_report_syscall_entry(regs))
@@ -677,10 +649,11 @@ asmlinkage void syscall_trace_enter(struct pt_regs *regs)
677 if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT))) 649 if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT)))
678 trace_sys_enter(regs, regs->regs[2]); 650 trace_sys_enter(regs, regs->regs[2]);
679 651
680 audit_syscall_entry(__syscall_get_arch(), 652 audit_syscall_entry(syscall_get_arch(current, regs),
681 regs->regs[2], 653 syscall,
682 regs->regs[4], regs->regs[5], 654 regs->regs[4], regs->regs[5],
683 regs->regs[6], regs->regs[7]); 655 regs->regs[6], regs->regs[7]);
656 return syscall;
684} 657}
685 658
686/* 659/*