diff options
Diffstat (limited to 'arch/powerpc/kernel/ptrace.c')
-rw-r--r-- | arch/powerpc/kernel/ptrace.c | 72 |
1 files changed, 66 insertions, 6 deletions
diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c index 8feb93e7890c..a5d0e78779c8 100644 --- a/arch/powerpc/kernel/ptrace.c +++ b/arch/powerpc/kernel/ptrace.c | |||
@@ -703,7 +703,7 @@ void user_enable_single_step(struct task_struct *task) | |||
703 | 703 | ||
704 | if (regs != NULL) { | 704 | if (regs != NULL) { |
705 | #if defined(CONFIG_40x) || defined(CONFIG_BOOKE) | 705 | #if defined(CONFIG_40x) || defined(CONFIG_BOOKE) |
706 | task->thread.dbcr0 = DBCR0_IDM | DBCR0_IC; | 706 | task->thread.dbcr0 |= DBCR0_IDM | DBCR0_IC; |
707 | regs->msr |= MSR_DE; | 707 | regs->msr |= MSR_DE; |
708 | #else | 708 | #else |
709 | regs->msr |= MSR_SE; | 709 | regs->msr |= MSR_SE; |
@@ -716,9 +716,16 @@ void user_disable_single_step(struct task_struct *task) | |||
716 | { | 716 | { |
717 | struct pt_regs *regs = task->thread.regs; | 717 | struct pt_regs *regs = task->thread.regs; |
718 | 718 | ||
719 | |||
720 | #if defined(CONFIG_44x) || defined(CONFIG_BOOKE) | ||
721 | /* If DAC then do not single step, skip */ | ||
722 | if (task->thread.dabr) | ||
723 | return; | ||
724 | #endif | ||
725 | |||
719 | if (regs != NULL) { | 726 | if (regs != NULL) { |
720 | #if defined(CONFIG_40x) || defined(CONFIG_BOOKE) | 727 | #if defined(CONFIG_40x) || defined(CONFIG_BOOKE) |
721 | task->thread.dbcr0 = 0; | 728 | task->thread.dbcr0 &= ~(DBCR0_IC | DBCR0_IDM); |
722 | regs->msr &= ~MSR_DE; | 729 | regs->msr &= ~MSR_DE; |
723 | #else | 730 | #else |
724 | regs->msr &= ~MSR_SE; | 731 | regs->msr &= ~MSR_SE; |
@@ -727,22 +734,75 @@ void user_disable_single_step(struct task_struct *task) | |||
727 | clear_tsk_thread_flag(task, TIF_SINGLESTEP); | 734 | clear_tsk_thread_flag(task, TIF_SINGLESTEP); |
728 | } | 735 | } |
729 | 736 | ||
730 | static int ptrace_set_debugreg(struct task_struct *task, unsigned long addr, | 737 | int ptrace_set_debugreg(struct task_struct *task, unsigned long addr, |
731 | unsigned long data) | 738 | unsigned long data) |
732 | { | 739 | { |
733 | /* We only support one DABR and no IABRS at the moment */ | 740 | /* For ppc64 we support one DABR and no IABR's at the moment (ppc64). |
741 | * For embedded processors we support one DAC and no IAC's at the | ||
742 | * moment. | ||
743 | */ | ||
734 | if (addr > 0) | 744 | if (addr > 0) |
735 | return -EINVAL; | 745 | return -EINVAL; |
736 | 746 | ||
737 | /* The bottom 3 bits are flags */ | ||
738 | if ((data & ~0x7UL) >= TASK_SIZE) | 747 | if ((data & ~0x7UL) >= TASK_SIZE) |
739 | return -EIO; | 748 | return -EIO; |
740 | 749 | ||
741 | /* Ensure translation is on */ | 750 | #ifdef CONFIG_PPC64 |
751 | |||
752 | /* For processors using DABR (i.e. 970), the bottom 3 bits are flags. | ||
753 | * It was assumed, on previous implementations, that 3 bits were | ||
754 | * passed together with the data address, fitting the design of the | ||
755 | * DABR register, as follows: | ||
756 | * | ||
757 | * bit 0: Read flag | ||
758 | * bit 1: Write flag | ||
759 | * bit 2: Breakpoint translation | ||
760 | * | ||
761 | * Thus, we use them here as so. | ||
762 | */ | ||
763 | |||
764 | /* Ensure breakpoint translation bit is set */ | ||
742 | if (data && !(data & DABR_TRANSLATION)) | 765 | if (data && !(data & DABR_TRANSLATION)) |
743 | return -EIO; | 766 | return -EIO; |
744 | 767 | ||
768 | /* Move contents to the DABR register */ | ||
745 | task->thread.dabr = data; | 769 | task->thread.dabr = data; |
770 | |||
771 | #endif | ||
772 | #if defined(CONFIG_44x) || defined(CONFIG_BOOKE) | ||
773 | |||
774 | /* As described above, it was assumed 3 bits were passed with the data | ||
775 | * address, but we will assume only the mode bits will be passed | ||
776 | * as to not cause alignment restrictions for DAC-based processors. | ||
777 | */ | ||
778 | |||
779 | /* DAC's hold the whole address without any mode flags */ | ||
780 | task->thread.dabr = data & ~0x3UL; | ||
781 | |||
782 | if (task->thread.dabr == 0) { | ||
783 | task->thread.dbcr0 &= ~(DBSR_DAC1R | DBSR_DAC1W | DBCR0_IDM); | ||
784 | task->thread.regs->msr &= ~MSR_DE; | ||
785 | return 0; | ||
786 | } | ||
787 | |||
788 | /* Read or Write bits must be set */ | ||
789 | |||
790 | if (!(data & 0x3UL)) | ||
791 | return -EINVAL; | ||
792 | |||
793 | /* Set the Internal Debugging flag (IDM bit 1) for the DBCR0 | ||
794 | register */ | ||
795 | task->thread.dbcr0 = DBCR0_IDM; | ||
796 | |||
797 | /* Check for write and read flags and set DBCR0 | ||
798 | accordingly */ | ||
799 | if (data & 0x1UL) | ||
800 | task->thread.dbcr0 |= DBSR_DAC1R; | ||
801 | if (data & 0x2UL) | ||
802 | task->thread.dbcr0 |= DBSR_DAC1W; | ||
803 | |||
804 | task->thread.regs->msr |= MSR_DE; | ||
805 | #endif | ||
746 | return 0; | 806 | return 0; |
747 | } | 807 | } |
748 | 808 | ||