diff options
| -rw-r--r-- | arch/powerpc/kernel/ptrace.c | 162 |
1 files changed, 162 insertions, 0 deletions
diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c index eb00274e84ba..60de9ee3701d 100644 --- a/arch/powerpc/kernel/ptrace.c +++ b/arch/powerpc/kernel/ptrace.c | |||
| @@ -501,8 +501,170 @@ static const struct user_regset_view user_ppc_native_view = { | |||
| 501 | .regsets = native_regsets, .n = ARRAY_SIZE(native_regsets) | 501 | .regsets = native_regsets, .n = ARRAY_SIZE(native_regsets) |
| 502 | }; | 502 | }; |
| 503 | 503 | ||
| 504 | #ifdef CONFIG_PPC64 | ||
| 505 | #include <linux/compat.h> | ||
| 506 | |||
| 507 | static int gpr32_get(struct task_struct *target, | ||
| 508 | const struct user_regset *regset, | ||
| 509 | unsigned int pos, unsigned int count, | ||
| 510 | void *kbuf, void __user *ubuf) | ||
| 511 | { | ||
| 512 | const unsigned long *regs = &target->thread.regs->gpr[0]; | ||
| 513 | compat_ulong_t *k = kbuf; | ||
| 514 | compat_ulong_t __user *u = ubuf; | ||
| 515 | compat_ulong_t reg; | ||
| 516 | |||
| 517 | if (target->thread.regs == NULL) | ||
| 518 | return -EIO; | ||
| 519 | |||
| 520 | CHECK_FULL_REGS(target->thread.regs); | ||
| 521 | |||
| 522 | pos /= sizeof(reg); | ||
| 523 | count /= sizeof(reg); | ||
| 524 | |||
| 525 | if (kbuf) | ||
| 526 | for (; count > 0 && pos < PT_MSR; --count) | ||
| 527 | *k++ = regs[pos++]; | ||
| 528 | else | ||
| 529 | for (; count > 0 && pos < PT_MSR; --count) | ||
| 530 | if (__put_user((compat_ulong_t) regs[pos++], u++)) | ||
| 531 | return -EFAULT; | ||
| 532 | |||
| 533 | if (count > 0 && pos == PT_MSR) { | ||
| 534 | reg = get_user_msr(target); | ||
| 535 | if (kbuf) | ||
| 536 | *k++ = reg; | ||
| 537 | else if (__put_user(reg, u++)) | ||
| 538 | return -EFAULT; | ||
| 539 | ++pos; | ||
| 540 | --count; | ||
| 541 | } | ||
| 542 | |||
| 543 | if (kbuf) | ||
| 544 | for (; count > 0 && pos < PT_REGS_COUNT; --count) | ||
| 545 | *k++ = regs[pos++]; | ||
| 546 | else | ||
| 547 | for (; count > 0 && pos < PT_REGS_COUNT; --count) | ||
| 548 | if (__put_user((compat_ulong_t) regs[pos++], u++)) | ||
| 549 | return -EFAULT; | ||
| 550 | |||
| 551 | kbuf = k; | ||
| 552 | ubuf = u; | ||
| 553 | pos *= sizeof(reg); | ||
| 554 | count *= sizeof(reg); | ||
| 555 | return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, | ||
| 556 | PT_REGS_COUNT * sizeof(reg), -1); | ||
| 557 | } | ||
| 558 | |||
| 559 | static int gpr32_set(struct task_struct *target, | ||
| 560 | const struct user_regset *regset, | ||
| 561 | unsigned int pos, unsigned int count, | ||
| 562 | const void *kbuf, const void __user *ubuf) | ||
| 563 | { | ||
| 564 | unsigned long *regs = &target->thread.regs->gpr[0]; | ||
| 565 | const compat_ulong_t *k = kbuf; | ||
| 566 | const compat_ulong_t __user *u = ubuf; | ||
| 567 | compat_ulong_t reg; | ||
| 568 | |||
| 569 | if (target->thread.regs == NULL) | ||
| 570 | return -EIO; | ||
| 571 | |||
| 572 | CHECK_FULL_REGS(target->thread.regs); | ||
| 573 | |||
| 574 | pos /= sizeof(reg); | ||
| 575 | count /= sizeof(reg); | ||
| 576 | |||
| 577 | if (kbuf) | ||
| 578 | for (; count > 0 && pos < PT_MSR; --count) | ||
| 579 | regs[pos++] = *k++; | ||
| 580 | else | ||
| 581 | for (; count > 0 && pos < PT_MSR; --count) { | ||
| 582 | if (__get_user(reg, u++)) | ||
| 583 | return -EFAULT; | ||
| 584 | regs[pos++] = reg; | ||
| 585 | } | ||
| 586 | |||
| 587 | |||
| 588 | if (count > 0 && pos == PT_MSR) { | ||
| 589 | if (kbuf) | ||
| 590 | reg = *k++; | ||
| 591 | else if (__get_user(reg, u++)) | ||
| 592 | return -EFAULT; | ||
| 593 | set_user_msr(target, reg); | ||
| 594 | ++pos; | ||
| 595 | --count; | ||
| 596 | } | ||
| 597 | |||
| 598 | if (kbuf) | ||
| 599 | for (; count > 0 && pos <= PT_MAX_PUT_REG; --count) | ||
| 600 | regs[pos++] = *k++; | ||
| 601 | else | ||
| 602 | for (; count > 0 && pos <= PT_MAX_PUT_REG; --count) { | ||
| 603 | if (__get_user(reg, u++)) | ||
| 604 | return -EFAULT; | ||
| 605 | regs[pos++] = reg; | ||
| 606 | } | ||
| 607 | |||
| 608 | if (count > 0 && pos == PT_TRAP) { | ||
| 609 | if (kbuf) | ||
| 610 | reg = *k++; | ||
| 611 | else if (__get_user(reg, u++)) | ||
| 612 | return -EFAULT; | ||
| 613 | set_user_trap(target, reg); | ||
| 614 | ++pos; | ||
| 615 | --count; | ||
| 616 | } | ||
| 617 | |||
| 618 | kbuf = k; | ||
| 619 | ubuf = u; | ||
| 620 | pos *= sizeof(reg); | ||
| 621 | count *= sizeof(reg); | ||
| 622 | return user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, | ||
| 623 | (PT_TRAP + 1) * sizeof(reg), -1); | ||
| 624 | } | ||
| 625 | |||
| 626 | /* | ||
| 627 | * These are the regset flavors matching the CONFIG_PPC32 native set. | ||
| 628 | */ | ||
| 629 | static const struct user_regset compat_regsets[] = { | ||
| 630 | [REGSET_GPR] = { | ||
| 631 | .core_note_type = NT_PRSTATUS, .n = ELF_NGREG, | ||
| 632 | .size = sizeof(compat_long_t), .align = sizeof(compat_long_t), | ||
| 633 | .get = gpr32_get, .set = gpr32_set | ||
| 634 | }, | ||
| 635 | [REGSET_FPR] = { | ||
| 636 | .core_note_type = NT_PRFPREG, .n = ELF_NFPREG, | ||
| 637 | .size = sizeof(double), .align = sizeof(double), | ||
| 638 | .get = fpr_get, .set = fpr_set | ||
| 639 | }, | ||
| 640 | #ifdef CONFIG_ALTIVEC | ||
| 641 | [REGSET_VMX] = { | ||
| 642 | .core_note_type = NT_PPC_VMX, .n = 34, | ||
| 643 | .size = sizeof(vector128), .align = sizeof(vector128), | ||
| 644 | .active = vr_active, .get = vr_get, .set = vr_set | ||
| 645 | }, | ||
| 646 | #endif | ||
| 647 | #ifdef CONFIG_SPE | ||
| 648 | [REGSET_SPE] = { | ||
| 649 | .n = 35, | ||
| 650 | .size = sizeof(u32), .align = sizeof(u32), | ||
| 651 | .active = evr_active, .get = evr_get, .set = evr_set | ||
| 652 | }, | ||
| 653 | #endif | ||
| 654 | }; | ||
| 655 | |||
| 656 | static const struct user_regset_view user_ppc_compat_view = { | ||
| 657 | .name = "ppc", .e_machine = EM_PPC, .ei_osabi = ELF_OSABI, | ||
| 658 | .regsets = compat_regsets, .n = ARRAY_SIZE(compat_regsets) | ||
| 659 | }; | ||
| 660 | #endif /* CONFIG_PPC64 */ | ||
| 661 | |||
| 504 | const struct user_regset_view *task_user_regset_view(struct task_struct *task) | 662 | const struct user_regset_view *task_user_regset_view(struct task_struct *task) |
| 505 | { | 663 | { |
| 664 | #ifdef CONFIG_PPC64 | ||
| 665 | if (test_tsk_thread_flag(task, TIF_32BIT)) | ||
| 666 | return &user_ppc_compat_view; | ||
| 667 | #endif | ||
| 506 | return &user_ppc_native_view; | 668 | return &user_ppc_native_view; |
| 507 | } | 669 | } |
| 508 | 670 | ||
