diff options
Diffstat (limited to 'arch/powerpc/kernel/traps.c')
| -rw-r--r-- | arch/powerpc/kernel/traps.c | 91 |
1 files changed, 72 insertions, 19 deletions
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c index 4e293b75f951..987437e04e61 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c | |||
| @@ -1034,9 +1034,68 @@ void SoftwareEmulation(struct pt_regs *regs) | |||
| 1034 | #endif /* CONFIG_8xx */ | 1034 | #endif /* CONFIG_8xx */ |
| 1035 | 1035 | ||
| 1036 | #ifdef CONFIG_PPC_ADV_DEBUG_REGS | 1036 | #ifdef CONFIG_PPC_ADV_DEBUG_REGS |
| 1037 | static void handle_debug(struct pt_regs *regs, unsigned long debug_status) | ||
| 1038 | { | ||
| 1039 | int changed = 0; | ||
| 1040 | /* | ||
| 1041 | * Determine the cause of the debug event, clear the | ||
| 1042 | * event flags and send a trap to the handler. Torez | ||
| 1043 | */ | ||
| 1044 | if (debug_status & (DBSR_DAC1R | DBSR_DAC1W)) { | ||
| 1045 | dbcr_dac(current) &= ~(DBCR_DAC1R | DBCR_DAC1W); | ||
| 1046 | #ifdef CONFIG_PPC_ADV_DEBUG_DAC_RANGE | ||
| 1047 | current->thread.dbcr2 &= ~DBCR2_DAC12MODE; | ||
| 1048 | #endif | ||
| 1049 | do_send_trap(regs, mfspr(SPRN_DAC1), debug_status, TRAP_HWBKPT, | ||
| 1050 | 5); | ||
| 1051 | changed |= 0x01; | ||
| 1052 | } else if (debug_status & (DBSR_DAC2R | DBSR_DAC2W)) { | ||
| 1053 | dbcr_dac(current) &= ~(DBCR_DAC2R | DBCR_DAC2W); | ||
| 1054 | do_send_trap(regs, mfspr(SPRN_DAC2), debug_status, TRAP_HWBKPT, | ||
| 1055 | 6); | ||
| 1056 | changed |= 0x01; | ||
| 1057 | } else if (debug_status & DBSR_IAC1) { | ||
| 1058 | current->thread.dbcr0 &= ~DBCR0_IAC1; | ||
| 1059 | dbcr_iac_range(current) &= ~DBCR_IAC12MODE; | ||
| 1060 | do_send_trap(regs, mfspr(SPRN_IAC1), debug_status, TRAP_HWBKPT, | ||
| 1061 | 1); | ||
| 1062 | changed |= 0x01; | ||
| 1063 | } else if (debug_status & DBSR_IAC2) { | ||
| 1064 | current->thread.dbcr0 &= ~DBCR0_IAC2; | ||
| 1065 | do_send_trap(regs, mfspr(SPRN_IAC2), debug_status, TRAP_HWBKPT, | ||
| 1066 | 2); | ||
| 1067 | changed |= 0x01; | ||
| 1068 | } else if (debug_status & DBSR_IAC3) { | ||
| 1069 | current->thread.dbcr0 &= ~DBCR0_IAC3; | ||
| 1070 | dbcr_iac_range(current) &= ~DBCR_IAC34MODE; | ||
| 1071 | do_send_trap(regs, mfspr(SPRN_IAC3), debug_status, TRAP_HWBKPT, | ||
| 1072 | 3); | ||
| 1073 | changed |= 0x01; | ||
| 1074 | } else if (debug_status & DBSR_IAC4) { | ||
| 1075 | current->thread.dbcr0 &= ~DBCR0_IAC4; | ||
| 1076 | do_send_trap(regs, mfspr(SPRN_IAC4), debug_status, TRAP_HWBKPT, | ||
| 1077 | 4); | ||
| 1078 | changed |= 0x01; | ||
| 1079 | } | ||
| 1080 | /* | ||
| 1081 | * At the point this routine was called, the MSR(DE) was turned off. | ||
| 1082 | * Check all other debug flags and see if that bit needs to be turned | ||
| 1083 | * back on or not. | ||
| 1084 | */ | ||
| 1085 | if (DBCR_ACTIVE_EVENTS(current->thread.dbcr0, current->thread.dbcr1)) | ||
| 1086 | regs->msr |= MSR_DE; | ||
| 1087 | else | ||
| 1088 | /* Make sure the IDM flag is off */ | ||
| 1089 | current->thread.dbcr0 &= ~DBCR0_IDM; | ||
| 1090 | |||
| 1091 | if (changed & 0x01) | ||
| 1092 | mtspr(SPRN_DBCR0, current->thread.dbcr0); | ||
| 1093 | } | ||
| 1037 | 1094 | ||
| 1038 | void __kprobes DebugException(struct pt_regs *regs, unsigned long debug_status) | 1095 | void __kprobes DebugException(struct pt_regs *regs, unsigned long debug_status) |
| 1039 | { | 1096 | { |
| 1097 | current->thread.dbsr = debug_status; | ||
| 1098 | |||
| 1040 | /* Hack alert: On BookE, Branch Taken stops on the branch itself, while | 1099 | /* Hack alert: On BookE, Branch Taken stops on the branch itself, while |
| 1041 | * on server, it stops on the target of the branch. In order to simulate | 1100 | * on server, it stops on the target of the branch. In order to simulate |
| 1042 | * the server behaviour, we thus restart right away with a single step | 1101 | * the server behaviour, we thus restart right away with a single step |
| @@ -1080,27 +1139,21 @@ void __kprobes DebugException(struct pt_regs *regs, unsigned long debug_status) | |||
| 1080 | if (debugger_sstep(regs)) | 1139 | if (debugger_sstep(regs)) |
| 1081 | return; | 1140 | return; |
| 1082 | 1141 | ||
| 1083 | if (user_mode(regs)) | ||
| 1084 | current->thread.dbcr0 &= ~(DBCR0_IC); | ||
| 1085 | |||
| 1086 | _exception(SIGTRAP, regs, TRAP_TRACE, regs->nip); | ||
| 1087 | } else if (debug_status & (DBSR_DAC1R | DBSR_DAC1W)) { | ||
| 1088 | regs->msr &= ~MSR_DE; | ||
| 1089 | |||
| 1090 | if (user_mode(regs)) { | 1142 | if (user_mode(regs)) { |
| 1091 | current->thread.dbcr0 &= ~(DBSR_DAC1R | DBSR_DAC1W | | 1143 | current->thread.dbcr0 &= ~DBCR0_IC; |
| 1092 | DBCR0_IDM); | 1144 | #ifdef CONFIG_PPC_ADV_DEBUG_REGS |
| 1093 | } else { | 1145 | if (DBCR_ACTIVE_EVENTS(current->thread.dbcr0, |
| 1094 | /* Disable DAC interupts */ | 1146 | current->thread.dbcr1)) |
| 1095 | mtspr(SPRN_DBCR0, mfspr(SPRN_DBCR0) & ~(DBSR_DAC1R | | 1147 | regs->msr |= MSR_DE; |
| 1096 | DBSR_DAC1W | DBCR0_IDM)); | 1148 | else |
| 1097 | 1149 | /* Make sure the IDM bit is off */ | |
| 1098 | /* Clear the DAC event */ | 1150 | current->thread.dbcr0 &= ~DBCR0_IDM; |
| 1099 | mtspr(SPRN_DBSR, (DBSR_DAC1R | DBSR_DAC1W)); | 1151 | #endif |
| 1100 | } | 1152 | } |
| 1101 | /* Setup and send the trap to the handler */ | 1153 | |
| 1102 | do_dabr(regs, mfspr(SPRN_DAC1), debug_status); | 1154 | _exception(SIGTRAP, regs, TRAP_TRACE, regs->nip); |
| 1103 | } | 1155 | } else |
| 1156 | handle_debug(regs, debug_status); | ||
| 1104 | } | 1157 | } |
| 1105 | #endif /* CONFIG_PPC_ADV_DEBUG_REGS */ | 1158 | #endif /* CONFIG_PPC_ADV_DEBUG_REGS */ |
| 1106 | 1159 | ||
