diff options
Diffstat (limited to 'arch/mips/kernel/ptrace.c')
-rw-r--r-- | arch/mips/kernel/ptrace.c | 161 |
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) | |||
114 | int ptrace_getfpregs(struct task_struct *child, __u32 __user *data) | 114 | int 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 | ||
159 | int ptrace_setfpregs(struct task_struct *child, __u32 __user *data) | 137 | int 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 | ||
309 | static int fpr_set(struct task_struct *target, | 307 | static 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 | ||
320 | enum mips_regset { | 335 | enum 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 | */ |
665 | asmlinkage void syscall_trace_enter(struct pt_regs *regs) | 637 | asmlinkage 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 | /* |