| 1 | /* |
| 2 | * ARM implementation of KVM and HVF hooks, 64 bit specific code |
| 3 | * |
| 4 | * Copyright Mian-M. Hamayun 2013, Virtual Open Systems |
| 5 | * Copyright Alex Bennée 2014, Linaro |
| 6 | * |
| 7 | * This work is licensed under the terms of the GNU GPL, version 2 or later. |
| 8 | * See the COPYING file in the top-level directory. |
| 9 | * |
| 10 | */ |
| 11 | |
| 12 | #include "qemu/osdep.h" |
| 13 | #include "cpu.h" |
| 14 | #include "internals.h" |
| 15 | #include "gdbstub/enums.h" |
| 16 | |
| 17 | /* Maximum and current break/watch point counts */ |
| 18 | int max_hw_bps, max_hw_wps; |
| 19 | GArray *hw_breakpoints, *hw_watchpoints; |
| 20 | |
| 21 | /** |
| 22 | * insert_hw_breakpoint() |
| 23 | * @addr: address of breakpoint |
| 24 | * |
| 25 | * See ARM ARM D2.9.1 for details but here we are only going to create |
| 26 | * simple un-linked breakpoints (i.e. we don't chain breakpoints |
| 27 | * together to match address and context or vmid). The hardware is |
| 28 | * capable of fancier matching but that will require exposing that |
| 29 | * fanciness to GDB's interface |
| 30 | * |
| 31 | * DBGBCR<n>_EL1, Debug Breakpoint Control Registers |
| 32 | * |
| 33 | * 31 24 23 20 19 16 15 14 13 12 9 8 5 4 3 2 1 0 |
| 34 | * +------+------+-------+-----+----+------+-----+------+-----+---+ |
| 35 | * | RES0 | BT | LBN | SSC | HMC| RES0 | BAS | RES0 | PMC | E | |
| 36 | * +------+------+-------+-----+----+------+-----+------+-----+---+ |
| 37 | * |
| 38 | * BT: Breakpoint type (0 = unlinked address match) |
| 39 | * LBN: Linked BP number (0 = unused) |
| 40 | * SSC/HMC/PMC: Security, Higher and Priv access control (Table D-12) |
| 41 | * BAS: Byte Address Select (RES1 for AArch64) |
| 42 | * E: Enable bit |
| 43 | * |
| 44 | * DBGBVR<n>_EL1, Debug Breakpoint Value Registers |
| 45 | * |
| 46 | * 63 53 52 49 48 2 1 0 |
| 47 | * +------+-----------+----------+-----+ |
| 48 | * | RESS | VA[52:49] | VA[48:2] | 0 0 | |
| 49 | * +------+-----------+----------+-----+ |
| 50 | * |
| 51 | * Depending on the addressing mode bits the top bits of the register |
| 52 | * are a sign extension of the highest applicable VA bit. Some |
| 53 | * versions of GDB don't do it correctly so we ensure they are correct |
| 54 | * here so future PC comparisons will work properly. |
| 55 | */ |
| 56 | |
| 57 | int insert_hw_breakpoint(vaddr addr) |
| 58 | { |
| 59 | HWBreakpoint brk = { |
| 60 | .bcr = 0x1, /* BCR E=1, enable */ |
| 61 | .bvr = sextract64(addr, 0, 53) |
| 62 | }; |
| 63 | |
| 64 | if (cur_hw_bps >= max_hw_bps) { |
| 65 | return -ENOBUFS; |
| 66 | } |
| 67 | |
| 68 | brk.bcr = deposit32(brk.bcr, 1, 2, 0x3); /* PMC = 11 */ |
| 69 | brk.bcr = deposit32(brk.bcr, 5, 4, 0xf); /* BAS = RES1 */ |
| 70 | |
| 71 | g_array_append_val(hw_breakpoints, brk); |
| 72 | |
| 73 | return 0; |
| 74 | } |
| 75 | |
| 76 | /** |
| 77 | * delete_hw_breakpoint() |
| 78 | * @pc: address of breakpoint |
| 79 | * |
| 80 | * Delete a breakpoint and shuffle any above down |
| 81 | */ |
| 82 | |
| 83 | int delete_hw_breakpoint(vaddr pc) |
| 84 | { |
| 85 | int i; |
| 86 | for (i = 0; i < hw_breakpoints->len; i++) { |
| 87 | HWBreakpoint *brk = get_hw_bp(i); |
| 88 | if (brk->bvr == pc) { |
| 89 | g_array_remove_index(hw_breakpoints, i); |
| 90 | return 0; |
| 91 | } |
| 92 | } |
| 93 | return -ENOENT; |
| 94 | } |
| 95 | |
| 96 | /** |
| 97 | * insert_gdbstub_hw_watchpoint() |
| 98 | * @addr: address of watch point |
| 99 | * @len: size of area |
| 100 | * @type: type of watch point |
| 101 | * |
| 102 | * See ARM ARM D2.10. As with the breakpoints we can do some advanced |
| 103 | * stuff if we want to. The watch points can be linked with the break |
| 104 | * points above to make them context aware. However for simplicity |
| 105 | * currently we only deal with simple read/write watch points. |
| 106 | * |
| 107 | * D7.3.11 DBGWCR<n>_EL1, Debug Watchpoint Control Registers |
| 108 | * |
| 109 | * 31 29 28 24 23 21 20 19 16 15 14 13 12 5 4 3 2 1 0 |
| 110 | * +------+-------+------+----+-----+-----+-----+-----+-----+-----+---+ |
| 111 | * | RES0 | MASK | RES0 | WT | LBN | SSC | HMC | BAS | LSC | PAC | E | |
| 112 | * +------+-------+------+----+-----+-----+-----+-----+-----+-----+---+ |
| 113 | * |
| 114 | * MASK: num bits addr mask (0=none,01/10=res,11=3 bits (8 bytes)) |
| 115 | * WT: 0 - unlinked, 1 - linked (not currently used) |
| 116 | * LBN: Linked BP number (not currently used) |
| 117 | * SSC/HMC/PAC: Security, Higher and Priv access control (Table D2-11) |
| 118 | * BAS: Byte Address Select |
| 119 | * LSC: Load/Store control (01: load, 10: store, 11: both) |
| 120 | * E: Enable |
| 121 | * |
| 122 | * The bottom 2 bits of the value register are masked. Therefore to |
| 123 | * break on any sizes smaller than an unaligned word you need to set |
| 124 | * MASK=0, BAS=bit per byte in question. For larger regions (^2) you |
| 125 | * need to ensure you mask the address as required and set BAS=0xff |
| 126 | */ |
| 127 | |
| 128 | int insert_gdbstub_hw_watchpoint(vaddr addr, vaddr len, GdbBreakpointType type) |
| 129 | { |
| 130 | HWWatchpoint wp = { |
| 131 | .wcr = R_DBGWCR_E_MASK, /* E=1, enable */ |
| 132 | .wvr = addr & (~0x7ULL), |
| 133 | .details = { .vaddr = addr, .len = len } |
| 134 | }; |
| 135 | |
| 136 | if (cur_hw_wps >= max_hw_wps) { |
| 137 | return -ENOBUFS; |
| 138 | } |
| 139 | |
| 140 | /* |
| 141 | * HMC=0 SSC=0 PAC=3 will hit EL0 or EL1, any security state, |
| 142 | * valid whether EL3 is implemented or not |
| 143 | */ |
| 144 | wp.wcr = FIELD_DP64(wp.wcr, DBGWCR, PAC, 3); |
| 145 | |
| 146 | switch (type) { |
| 147 | case GDB_WATCHPOINT_READ: |
| 148 | wp.wcr = FIELD_DP64(wp.wcr, DBGWCR, LSC, 1); |
| 149 | wp.details.flags = BP_MEM_READ; |
| 150 | break; |
| 151 | case GDB_WATCHPOINT_WRITE: |
| 152 | wp.wcr = FIELD_DP64(wp.wcr, DBGWCR, LSC, 2); |
| 153 | wp.details.flags = BP_MEM_WRITE; |
| 154 | break; |
| 155 | case GDB_WATCHPOINT_ACCESS: |
| 156 | wp.wcr = FIELD_DP64(wp.wcr, DBGWCR, LSC, 3); |
| 157 | wp.details.flags = BP_MEM_ACCESS; |
| 158 | break; |
| 159 | default: |
| 160 | g_assert_not_reached(); |
| 161 | } |
| 162 | if (len <= 8) { |
| 163 | /* we align the address and set the bits in BAS */ |
| 164 | int off = addr & 0x7; |
| 165 | int bas = (1 << len) - 1; |
| 166 | |
| 167 | wp.wcr = deposit32(wp.wcr, 5 + off, 8 - off, bas); |
| 168 | } else { |
| 169 | /* For ranges above 8 bytes we need to be a power of 2 */ |
| 170 | if (is_power_of_2(len)) { |
| 171 | int bits = ctz64(len); |
| 172 | |
| 173 | wp.wvr &= ~((1 << bits) - 1); |
| 174 | wp.wcr = FIELD_DP64(wp.wcr, DBGWCR, MASK, bits); |
| 175 | wp.wcr = FIELD_DP64(wp.wcr, DBGWCR, BAS, 0xff); |
| 176 | } else { |
| 177 | return -ENOBUFS; |
| 178 | } |
| 179 | } |
| 180 | |
| 181 | g_array_append_val(hw_watchpoints, wp); |
| 182 | return 0; |
| 183 | } |
| 184 | |
| 185 | bool check_watchpoint_in_range(int i, vaddr addr) |
| 186 | { |
| 187 | HWWatchpoint *wp = get_hw_wp(i); |
| 188 | uint64_t addr_top, addr_bottom = wp->wvr; |
| 189 | int bas = extract32(wp->wcr, 5, 8); |
| 190 | int mask = extract32(wp->wcr, 24, 4); |
| 191 | |
| 192 | if (mask) { |
| 193 | addr_top = addr_bottom + (1 << mask); |
| 194 | } else { |
| 195 | /* |
| 196 | * BAS must be contiguous but can offset against the base |
| 197 | * address in DBGWVR |
| 198 | */ |
| 199 | addr_bottom = addr_bottom + ctz32(bas); |
| 200 | addr_top = addr_bottom + clo32(bas); |
| 201 | } |
| 202 | |
| 203 | if (addr >= addr_bottom && addr <= addr_top) { |
| 204 | return true; |
| 205 | } |
| 206 | |
| 207 | return false; |
| 208 | } |
| 209 | |
| 210 | /** |
| 211 | * delete_gdbstub_hw_watchpoint() |
| 212 | * @addr: address of breakpoint |
| 213 | * |
| 214 | * Delete a breakpoint and shuffle any above down |
| 215 | */ |
| 216 | |
| 217 | int delete_gdbstub_hw_watchpoint(vaddr addr, vaddr len, GdbBreakpointType type) |
| 218 | { |
| 219 | int i; |
| 220 | for (i = 0; i < cur_hw_wps; i++) { |
| 221 | if (check_watchpoint_in_range(i, addr)) { |
| 222 | g_array_remove_index(hw_watchpoints, i); |
| 223 | return 0; |
| 224 | } |
| 225 | } |
| 226 | return -ENOENT; |
| 227 | } |
| 228 | |
| 229 | bool find_hw_breakpoint(CPUState *cpu, vaddr pc) |
| 230 | { |
| 231 | int i; |
| 232 | |
| 233 | for (i = 0; i < cur_hw_bps; i++) { |
| 234 | HWBreakpoint *bp = get_hw_bp(i); |
| 235 | if (bp->bvr == pc) { |
| 236 | return true; |
| 237 | } |
| 238 | } |
| 239 | return false; |
| 240 | } |
| 241 | |
| 242 | CPUWatchpoint *find_hw_watchpoint(CPUState *cpu, vaddr addr) |
| 243 | { |
| 244 | int i; |
| 245 | |
| 246 | for (i = 0; i < cur_hw_wps; i++) { |
| 247 | if (check_watchpoint_in_range(i, addr)) { |
| 248 | return &get_hw_wp(i)->details; |
| 249 | } |
| 250 | } |
| 251 | return NULL; |
| 252 | } |