Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ARM: hw_breakpoint: don't advertise reserved breakpoints

To permit handling of watchpoint exceptions without signalling a
debugger, it is necessary to reserve breakpoint registers for in-kernel
use only.

This patch ensures that we record and subtract the number of reserved
breakpoints from the number of usable breakpoint registers that we
advertise to userspace via the ptrace API.

Signed-off-by: Will Deacon <will.deacon@arm.com>

+117 -89
+117 -89
arch/arm/kernel/hw_breakpoint.c
··· 45 45 46 46 /* Number of BRP/WRP registers on this CPU. */ 47 47 static int core_num_brps; 48 + static int core_num_reserved_brps; 48 49 static int core_num_wrps; 49 50 50 51 /* Debug architecture version. */ ··· 53 52 54 53 /* Maximum supported watchpoint length. */ 55 54 static u8 max_watchpoint_len; 56 - 57 - /* Determine number of BRP registers available. */ 58 - static int get_num_brps(void) 59 - { 60 - u32 didr; 61 - ARM_DBG_READ(c0, 0, didr); 62 - return ((didr >> 24) & 0xf) + 1; 63 - } 64 - 65 - /* Determine number of WRP registers available. */ 66 - static int get_num_wrps(void) 67 - { 68 - /* 69 - * FIXME: When a watchpoint fires, the only way to work out which 70 - * watchpoint it was is by disassembling the faulting instruction 71 - * and working out the address of the memory access. 72 - * 73 - * Furthermore, we can only do this if the watchpoint was precise 74 - * since imprecise watchpoints prevent us from calculating register 75 - * based addresses. 76 - * 77 - * For the time being, we only report 1 watchpoint register so we 78 - * always know which watchpoint fired. In the future we can either 79 - * add a disassembler and address generation emulator, or we can 80 - * insert a check to see if the DFAR is set on watchpoint exception 81 - * entry [the ARM ARM states that the DFAR is UNKNOWN, but 82 - * experience shows that it is set on some implementations]. 83 - */ 84 - 85 - #if 0 86 - u32 didr, wrps; 87 - ARM_DBG_READ(c0, 0, didr); 88 - return ((didr >> 28) & 0xf) + 1; 89 - #endif 90 - 91 - return 1; 92 - } 93 - 94 - int hw_breakpoint_slots(int type) 95 - { 96 - /* 97 - * We can be called early, so don't rely on 98 - * our static variables being initialised. 99 - */ 100 - switch (type) { 101 - case TYPE_INST: 102 - return get_num_brps(); 103 - case TYPE_DATA: 104 - return get_num_wrps(); 105 - default: 106 - pr_warning("unknown slot type: %d\n", type); 107 - return 0; 108 - } 109 - } 110 - 111 - /* Determine debug architecture. */ 112 - static u8 get_debug_arch(void) 113 - { 114 - u32 didr; 115 - 116 - /* Do we implement the extended CPUID interface? */ 117 - if (((read_cpuid_id() >> 16) & 0xf) != 0xf) { 118 - pr_warning("CPUID feature registers not supported. " 119 - "Assuming v6 debug is present.\n"); 120 - return ARM_DEBUG_ARCH_V6; 121 - } 122 - 123 - ARM_DBG_READ(c0, 0, didr); 124 - return (didr >> 16) & 0xf; 125 - } 126 - 127 - /* Does this core support mismatch breakpoints? */ 128 - static int core_has_mismatch_bps(void) 129 - { 130 - return debug_arch >= ARM_DEBUG_ARCH_V7_ECP14 && core_num_brps > 1; 131 - } 132 - 133 - u8 arch_get_debug_arch(void) 134 - { 135 - return debug_arch; 136 - } 137 55 138 56 #define READ_WB_REG_CASE(OP2, M, VAL) \ 139 57 case ((OP2 << 4) + M): \ ··· 129 209 "register %d\n", n); 130 210 } 131 211 isb(); 212 + } 213 + 214 + /* Determine debug architecture. */ 215 + static u8 get_debug_arch(void) 216 + { 217 + u32 didr; 218 + 219 + /* Do we implement the extended CPUID interface? */ 220 + if (((read_cpuid_id() >> 16) & 0xf) != 0xf) { 221 + pr_warning("CPUID feature registers not supported. " 222 + "Assuming v6 debug is present.\n"); 223 + return ARM_DEBUG_ARCH_V6; 224 + } 225 + 226 + ARM_DBG_READ(c0, 0, didr); 227 + return (didr >> 16) & 0xf; 228 + } 229 + 230 + u8 arch_get_debug_arch(void) 231 + { 232 + return debug_arch; 233 + } 234 + 235 + /* Determine number of BRP register available. */ 236 + static int get_num_brp_resources(void) 237 + { 238 + u32 didr; 239 + ARM_DBG_READ(c0, 0, didr); 240 + return ((didr >> 24) & 0xf) + 1; 241 + } 242 + 243 + /* Does this core support mismatch breakpoints? */ 244 + static int core_has_mismatch_brps(void) 245 + { 246 + return (get_debug_arch() >= ARM_DEBUG_ARCH_V7_ECP14 && 247 + get_num_brp_resources() > 1); 248 + } 249 + 250 + /* Determine number of usable WRPs available. */ 251 + static int get_num_wrps(void) 252 + { 253 + /* 254 + * FIXME: When a watchpoint fires, the only way to work out which 255 + * watchpoint it was is by disassembling the faulting instruction 256 + * and working out the address of the memory access. 257 + * 258 + * Furthermore, we can only do this if the watchpoint was precise 259 + * since imprecise watchpoints prevent us from calculating register 260 + * based addresses. 261 + * 262 + * Providing we have more than 1 breakpoint register, we only report 263 + * a single watchpoint register for the time being. This way, we always 264 + * know which watchpoint fired. In the future we can either add a 265 + * disassembler and address generation emulator, or we can insert a 266 + * check to see if the DFAR is set on watchpoint exception entry 267 + * [the ARM ARM states that the DFAR is UNKNOWN, but experience shows 268 + * that it is set on some implementations]. 269 + */ 270 + 271 + #if 0 272 + int wrps; 273 + u32 didr; 274 + ARM_DBG_READ(c0, 0, didr); 275 + wrps = ((didr >> 28) & 0xf) + 1; 276 + #endif 277 + int wrps = 1; 278 + 279 + if (core_has_mismatch_brps() && wrps >= get_num_brp_resources()) 280 + wrps = get_num_brp_resources() - 1; 281 + 282 + return wrps; 283 + } 284 + 285 + /* We reserve one breakpoint for each watchpoint. */ 286 + static int get_num_reserved_brps(void) 287 + { 288 + if (core_has_mismatch_brps()) 289 + return get_num_wrps(); 290 + return 0; 291 + } 292 + 293 + /* Determine number of usable BRPs available. */ 294 + static int get_num_brps(void) 295 + { 296 + int brps = get_num_brp_resources(); 297 + if (core_has_mismatch_brps()) 298 + brps -= get_num_reserved_brps(); 299 + return brps; 300 + } 301 + 302 + int hw_breakpoint_slots(int type) 303 + { 304 + /* 305 + * We can be called early, so don't rely on 306 + * our static variables being initialised. 307 + */ 308 + switch (type) { 309 + case TYPE_INST: 310 + return get_num_brps(); 311 + case TYPE_DATA: 312 + return get_num_wrps(); 313 + default: 314 + pr_warning("unknown slot type: %d\n", type); 315 + return 0; 316 + } 132 317 } 133 318 134 319 /* ··· 351 326 ctrl_base = ARM_BASE_BCR; 352 327 val_base = ARM_BASE_BVR; 353 328 slots = __get_cpu_var(bp_on_reg); 354 - max_slots = core_num_brps - 1; 329 + max_slots = core_num_brps; 355 330 356 331 if (bp_is_single_step(bp)) { 357 332 info->ctrl.mismatch = 1; ··· 402 377 /* Breakpoint */ 403 378 base = ARM_BASE_BCR; 404 379 slots = __get_cpu_var(bp_on_reg); 405 - max_slots = core_num_brps - 1; 380 + max_slots = core_num_brps; 406 381 407 382 if (bp_is_single_step(bp)) { 408 383 i = max_slots; ··· 636 611 * we can use the mismatch feature as a poor-man's hardware single-step. 637 612 */ 638 613 if (WARN_ONCE(!bp->overflow_handler && 639 - (arch_check_bp_in_kernelspace(bp) || !core_has_mismatch_bps()), 614 + (arch_check_bp_in_kernelspace(bp) || !core_has_mismatch_brps()), 640 615 "overflow handler required but none found")) { 641 616 ret = -EINVAL; 642 617 } ··· 723 698 /* The exception entry code places the amended lr in the PC. */ 724 699 addr = regs->ARM_pc; 725 700 726 - for (i = 0; i < core_num_brps; ++i) { 701 + for (i = 0; i < core_num_brps + core_num_reserved_brps; ++i) { 727 702 rcu_read_lock(); 728 703 729 704 bp = slots[i]; ··· 826 801 if (enable_monitor_mode()) 827 802 return; 828 803 829 - for (i = 0; i < core_num_brps; ++i) { 804 + /* We must also reset any reserved registers. */ 805 + for (i = 0; i < core_num_brps + core_num_reserved_brps; ++i) { 830 806 write_wb_reg(ARM_BASE_BCR + i, 0UL); 831 807 write_wb_reg(ARM_BASE_BVR + i, 0UL); 832 808 } ··· 865 839 866 840 /* Determine how many BRPs/WRPs are available. */ 867 841 core_num_brps = get_num_brps(); 842 + core_num_reserved_brps = get_num_reserved_brps(); 868 843 core_num_wrps = get_num_wrps(); 869 844 870 845 pr_info("found %d breakpoint and %d watchpoint registers.\n", 871 - core_num_brps, core_num_wrps); 846 + core_num_brps + core_num_reserved_brps, core_num_wrps); 872 847 873 - if (core_has_mismatch_bps()) 874 - pr_info("1 breakpoint reserved for watchpoint single-step.\n"); 848 + if (core_num_reserved_brps) 849 + pr_info("%d breakpoint(s) reserved for watchpoint " 850 + "single-step.\n", core_num_reserved_brps); 875 851 876 852 ARM_DBG_READ(c1, 0, dscr); 877 853 if (dscr & ARM_DSCR_HDBGEN) {