diff options
author | Dave Kleikamp <shaggy@linux.vnet.ibm.com> | 2010-02-08 06:51:18 -0500 |
---|---|---|
committer | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2010-02-16 22:03:17 -0500 |
commit | 3bffb6529cf10d48a97ac0d6d789986894c25c37 (patch) | |
tree | 6e86d39604f753b0597374c31e4a2fba2a8d55f0 /arch/powerpc/kernel/traps.c | |
parent | 99396ac105f54fe3584374c7c70a5cb6def766e6 (diff) |
powerpc/booke: Add support for advanced debug registers
powerpc/booke: Add support for advanced debug registers
From: Dave Kleikamp <shaggy@linux.vnet.ibm.com>
Based on patches originally written by Torez Smith.
This patch defines context switch and trap related functionality
for BookE specific Debug Registers. It adds support to ptrace()
for setting and getting BookE related Debug Registers
Signed-off-by: Dave Kleikamp <shaggy@linux.vnet.ibm.com>
Cc: Torez Smith <lnxtorez@linux.vnet.ibm.com>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: David Gibson <dwg@au1.ibm.com>
Cc: Josh Boyer <jwboyer@linux.vnet.ibm.com>
Cc: Kumar Gala <galak@kernel.crashing.org>
Cc: Sergio Durigan Junior <sergiodj@br.ibm.com>
Cc: Thiago Jung Bauermann <bauerman@br.ibm.com>
Cc: linuxppc-dev list <Linuxppc-dev@ozlabs.org>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
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 | ||