diff options
Diffstat (limited to 'arch/arm')
-rw-r--r-- | arch/arm/kernel/hw_breakpoint.c | 206 |
1 files changed, 117 insertions, 89 deletions
diff --git a/arch/arm/kernel/hw_breakpoint.c b/arch/arm/kernel/hw_breakpoint.c index eeba38008032..b16c4568cb01 100644 --- a/arch/arm/kernel/hw_breakpoint.c +++ b/arch/arm/kernel/hw_breakpoint.c | |||
@@ -45,6 +45,7 @@ static DEFINE_PER_CPU(struct perf_event *, wp_on_reg[ARM_MAX_WRP]); | |||
45 | 45 | ||
46 | /* Number of BRP/WRP registers on this CPU. */ | 46 | /* Number of BRP/WRP registers on this CPU. */ |
47 | static int core_num_brps; | 47 | static int core_num_brps; |
48 | static int core_num_reserved_brps; | ||
48 | static int core_num_wrps; | 49 | static int core_num_wrps; |
49 | 50 | ||
50 | /* Debug architecture version. */ | 51 | /* Debug architecture version. */ |
@@ -53,87 +54,6 @@ static u8 debug_arch; | |||
53 | /* Maximum supported watchpoint length. */ | 54 | /* Maximum supported watchpoint length. */ |
54 | static u8 max_watchpoint_len; | 55 | static u8 max_watchpoint_len; |
55 | 56 | ||
56 | /* Determine number of BRP registers available. */ | ||
57 | static int get_num_brps(void) | ||
58 | { | ||
59 | u32 didr; | ||
60 | ARM_DBG_READ(c0, 0, didr); | ||
61 | return ((didr >> 24) & 0xf) + 1; | ||
62 | } | ||
63 | |||
64 | /* Determine number of WRP registers available. */ | ||
65 | static int get_num_wrps(void) | ||
66 | { | ||
67 | /* | ||
68 | * FIXME: When a watchpoint fires, the only way to work out which | ||
69 | * watchpoint it was is by disassembling the faulting instruction | ||
70 | * and working out the address of the memory access. | ||
71 | * | ||
72 | * Furthermore, we can only do this if the watchpoint was precise | ||
73 | * since imprecise watchpoints prevent us from calculating register | ||
74 | * based addresses. | ||
75 | * | ||
76 | * For the time being, we only report 1 watchpoint register so we | ||
77 | * always know which watchpoint fired. In the future we can either | ||
78 | * add a disassembler and address generation emulator, or we can | ||
79 | * insert a check to see if the DFAR is set on watchpoint exception | ||
80 | * entry [the ARM ARM states that the DFAR is UNKNOWN, but | ||
81 | * experience shows that it is set on some implementations]. | ||
82 | */ | ||
83 | |||
84 | #if 0 | ||
85 | u32 didr, wrps; | ||
86 | ARM_DBG_READ(c0, 0, didr); | ||
87 | return ((didr >> 28) & 0xf) + 1; | ||
88 | #endif | ||
89 | |||
90 | return 1; | ||
91 | } | ||
92 | |||
93 | int hw_breakpoint_slots(int type) | ||
94 | { | ||
95 | /* | ||
96 | * We can be called early, so don't rely on | ||
97 | * our static variables being initialised. | ||
98 | */ | ||
99 | switch (type) { | ||
100 | case TYPE_INST: | ||
101 | return get_num_brps(); | ||
102 | case TYPE_DATA: | ||
103 | return get_num_wrps(); | ||
104 | default: | ||
105 | pr_warning("unknown slot type: %d\n", type); | ||
106 | return 0; | ||
107 | } | ||
108 | } | ||
109 | |||
110 | /* Determine debug architecture. */ | ||
111 | static u8 get_debug_arch(void) | ||
112 | { | ||
113 | u32 didr; | ||
114 | |||
115 | /* Do we implement the extended CPUID interface? */ | ||
116 | if (((read_cpuid_id() >> 16) & 0xf) != 0xf) { | ||
117 | pr_warning("CPUID feature registers not supported. " | ||
118 | "Assuming v6 debug is present.\n"); | ||
119 | return ARM_DEBUG_ARCH_V6; | ||
120 | } | ||
121 | |||
122 | ARM_DBG_READ(c0, 0, didr); | ||
123 | return (didr >> 16) & 0xf; | ||
124 | } | ||
125 | |||
126 | /* Does this core support mismatch breakpoints? */ | ||
127 | static int core_has_mismatch_bps(void) | ||
128 | { | ||
129 | return debug_arch >= ARM_DEBUG_ARCH_V7_ECP14 && core_num_brps > 1; | ||
130 | } | ||
131 | |||
132 | u8 arch_get_debug_arch(void) | ||
133 | { | ||
134 | return debug_arch; | ||
135 | } | ||
136 | |||
137 | #define READ_WB_REG_CASE(OP2, M, VAL) \ | 57 | #define READ_WB_REG_CASE(OP2, M, VAL) \ |
138 | case ((OP2 << 4) + M): \ | 58 | case ((OP2 << 4) + M): \ |
139 | ARM_DBG_READ(c ## M, OP2, VAL); \ | 59 | ARM_DBG_READ(c ## M, OP2, VAL); \ |
@@ -211,6 +131,111 @@ static void write_wb_reg(int n, u32 val) | |||
211 | isb(); | 131 | isb(); |
212 | } | 132 | } |
213 | 133 | ||
134 | /* Determine debug architecture. */ | ||
135 | static u8 get_debug_arch(void) | ||
136 | { | ||
137 | u32 didr; | ||
138 | |||
139 | /* Do we implement the extended CPUID interface? */ | ||
140 | if (((read_cpuid_id() >> 16) & 0xf) != 0xf) { | ||
141 | pr_warning("CPUID feature registers not supported. " | ||
142 | "Assuming v6 debug is present.\n"); | ||
143 | return ARM_DEBUG_ARCH_V6; | ||
144 | } | ||
145 | |||
146 | ARM_DBG_READ(c0, 0, didr); | ||
147 | return (didr >> 16) & 0xf; | ||
148 | } | ||
149 | |||
150 | u8 arch_get_debug_arch(void) | ||
151 | { | ||
152 | return debug_arch; | ||
153 | } | ||
154 | |||
155 | /* Determine number of BRP register available. */ | ||
156 | static int get_num_brp_resources(void) | ||
157 | { | ||
158 | u32 didr; | ||
159 | ARM_DBG_READ(c0, 0, didr); | ||
160 | return ((didr >> 24) & 0xf) + 1; | ||
161 | } | ||
162 | |||
163 | /* Does this core support mismatch breakpoints? */ | ||
164 | static int core_has_mismatch_brps(void) | ||
165 | { | ||
166 | return (get_debug_arch() >= ARM_DEBUG_ARCH_V7_ECP14 && | ||
167 | get_num_brp_resources() > 1); | ||
168 | } | ||
169 | |||
170 | /* Determine number of usable WRPs available. */ | ||
171 | static int get_num_wrps(void) | ||
172 | { | ||
173 | /* | ||
174 | * FIXME: When a watchpoint fires, the only way to work out which | ||
175 | * watchpoint it was is by disassembling the faulting instruction | ||
176 | * and working out the address of the memory access. | ||
177 | * | ||
178 | * Furthermore, we can only do this if the watchpoint was precise | ||
179 | * since imprecise watchpoints prevent us from calculating register | ||
180 | * based addresses. | ||
181 | * | ||
182 | * Providing we have more than 1 breakpoint register, we only report | ||
183 | * a single watchpoint register for the time being. This way, we always | ||
184 | * know which watchpoint fired. In the future we can either add a | ||
185 | * disassembler and address generation emulator, or we can insert a | ||
186 | * check to see if the DFAR is set on watchpoint exception entry | ||
187 | * [the ARM ARM states that the DFAR is UNKNOWN, but experience shows | ||
188 | * that it is set on some implementations]. | ||
189 | */ | ||
190 | |||
191 | #if 0 | ||
192 | int wrps; | ||
193 | u32 didr; | ||
194 | ARM_DBG_READ(c0, 0, didr); | ||
195 | wrps = ((didr >> 28) & 0xf) + 1; | ||
196 | #endif | ||
197 | int wrps = 1; | ||
198 | |||
199 | if (core_has_mismatch_brps() && wrps >= get_num_brp_resources()) | ||
200 | wrps = get_num_brp_resources() - 1; | ||
201 | |||
202 | return wrps; | ||
203 | } | ||
204 | |||
205 | /* We reserve one breakpoint for each watchpoint. */ | ||
206 | static int get_num_reserved_brps(void) | ||
207 | { | ||
208 | if (core_has_mismatch_brps()) | ||
209 | return get_num_wrps(); | ||
210 | return 0; | ||
211 | } | ||
212 | |||
213 | /* Determine number of usable BRPs available. */ | ||
214 | static int get_num_brps(void) | ||
215 | { | ||
216 | int brps = get_num_brp_resources(); | ||
217 | if (core_has_mismatch_brps()) | ||
218 | brps -= get_num_reserved_brps(); | ||
219 | return brps; | ||
220 | } | ||
221 | |||
222 | int hw_breakpoint_slots(int type) | ||
223 | { | ||
224 | /* | ||
225 | * We can be called early, so don't rely on | ||
226 | * our static variables being initialised. | ||
227 | */ | ||
228 | switch (type) { | ||
229 | case TYPE_INST: | ||
230 | return get_num_brps(); | ||
231 | case TYPE_DATA: | ||
232 | return get_num_wrps(); | ||
233 | default: | ||
234 | pr_warning("unknown slot type: %d\n", type); | ||
235 | return 0; | ||
236 | } | ||
237 | } | ||
238 | |||
214 | /* | 239 | /* |
215 | * In order to access the breakpoint/watchpoint control registers, | 240 | * In order to access the breakpoint/watchpoint control registers, |
216 | * we must be running in debug monitor mode. Unfortunately, we can | 241 | * we must be running in debug monitor mode. Unfortunately, we can |
@@ -326,7 +351,7 @@ int arch_install_hw_breakpoint(struct perf_event *bp) | |||
326 | ctrl_base = ARM_BASE_BCR; | 351 | ctrl_base = ARM_BASE_BCR; |
327 | val_base = ARM_BASE_BVR; | 352 | val_base = ARM_BASE_BVR; |
328 | slots = __get_cpu_var(bp_on_reg); | 353 | slots = __get_cpu_var(bp_on_reg); |
329 | max_slots = core_num_brps - 1; | 354 | max_slots = core_num_brps; |
330 | 355 | ||
331 | if (bp_is_single_step(bp)) { | 356 | if (bp_is_single_step(bp)) { |
332 | info->ctrl.mismatch = 1; | 357 | info->ctrl.mismatch = 1; |
@@ -377,7 +402,7 @@ void arch_uninstall_hw_breakpoint(struct perf_event *bp) | |||
377 | /* Breakpoint */ | 402 | /* Breakpoint */ |
378 | base = ARM_BASE_BCR; | 403 | base = ARM_BASE_BCR; |
379 | slots = __get_cpu_var(bp_on_reg); | 404 | slots = __get_cpu_var(bp_on_reg); |
380 | max_slots = core_num_brps - 1; | 405 | max_slots = core_num_brps; |
381 | 406 | ||
382 | if (bp_is_single_step(bp)) { | 407 | if (bp_is_single_step(bp)) { |
383 | i = max_slots; | 408 | i = max_slots; |
@@ -611,7 +636,7 @@ int arch_validate_hwbkpt_settings(struct perf_event *bp) | |||
611 | * we can use the mismatch feature as a poor-man's hardware single-step. | 636 | * we can use the mismatch feature as a poor-man's hardware single-step. |
612 | */ | 637 | */ |
613 | if (WARN_ONCE(!bp->overflow_handler && | 638 | if (WARN_ONCE(!bp->overflow_handler && |
614 | (arch_check_bp_in_kernelspace(bp) || !core_has_mismatch_bps()), | 639 | (arch_check_bp_in_kernelspace(bp) || !core_has_mismatch_brps()), |
615 | "overflow handler required but none found")) { | 640 | "overflow handler required but none found")) { |
616 | ret = -EINVAL; | 641 | ret = -EINVAL; |
617 | } | 642 | } |
@@ -698,7 +723,7 @@ static void breakpoint_handler(unsigned long unknown, struct pt_regs *regs) | |||
698 | /* The exception entry code places the amended lr in the PC. */ | 723 | /* The exception entry code places the amended lr in the PC. */ |
699 | addr = regs->ARM_pc; | 724 | addr = regs->ARM_pc; |
700 | 725 | ||
701 | for (i = 0; i < core_num_brps; ++i) { | 726 | for (i = 0; i < core_num_brps + core_num_reserved_brps; ++i) { |
702 | rcu_read_lock(); | 727 | rcu_read_lock(); |
703 | 728 | ||
704 | bp = slots[i]; | 729 | bp = slots[i]; |
@@ -801,7 +826,8 @@ static void reset_ctrl_regs(void *unused) | |||
801 | if (enable_monitor_mode()) | 826 | if (enable_monitor_mode()) |
802 | return; | 827 | return; |
803 | 828 | ||
804 | for (i = 0; i < core_num_brps; ++i) { | 829 | /* We must also reset any reserved registers. */ |
830 | for (i = 0; i < core_num_brps + core_num_reserved_brps; ++i) { | ||
805 | write_wb_reg(ARM_BASE_BCR + i, 0UL); | 831 | write_wb_reg(ARM_BASE_BCR + i, 0UL); |
806 | write_wb_reg(ARM_BASE_BVR + i, 0UL); | 832 | write_wb_reg(ARM_BASE_BVR + i, 0UL); |
807 | } | 833 | } |
@@ -839,13 +865,15 @@ static int __init arch_hw_breakpoint_init(void) | |||
839 | 865 | ||
840 | /* Determine how many BRPs/WRPs are available. */ | 866 | /* Determine how many BRPs/WRPs are available. */ |
841 | core_num_brps = get_num_brps(); | 867 | core_num_brps = get_num_brps(); |
868 | core_num_reserved_brps = get_num_reserved_brps(); | ||
842 | core_num_wrps = get_num_wrps(); | 869 | core_num_wrps = get_num_wrps(); |
843 | 870 | ||
844 | pr_info("found %d breakpoint and %d watchpoint registers.\n", | 871 | pr_info("found %d breakpoint and %d watchpoint registers.\n", |
845 | core_num_brps, core_num_wrps); | 872 | core_num_brps + core_num_reserved_brps, core_num_wrps); |
846 | 873 | ||
847 | if (core_has_mismatch_bps()) | 874 | if (core_num_reserved_brps) |
848 | pr_info("1 breakpoint reserved for watchpoint single-step.\n"); | 875 | pr_info("%d breakpoint(s) reserved for watchpoint " |
876 | "single-step.\n", core_num_reserved_brps); | ||
849 | 877 | ||
850 | ARM_DBG_READ(c1, 0, dscr); | 878 | ARM_DBG_READ(c1, 0, dscr); |
851 | if (dscr & ARM_DSCR_HDBGEN) { | 879 | if (dscr & ARM_DSCR_HDBGEN) { |