transport-arm-debug.c (6178B)
1 // Copyright 2023, Brian Swetland <swetland@frotz.net> 2 // Licensed under the Apache License, Version 2.0. 3 4 #include "transport.h" 5 #include "transport-private.h" 6 7 #include "arm-debug.h" 8 #include "arm-v7-debug.h" 9 10 static void dc_q_map_csw_wr(DC* dc, uint32_t val) { 11 if (val != dc->map_csw_cache) { 12 dc->map_csw_cache = val; 13 dc_q_ap_wr(dc, MAP_CSW, val | dc->map_csw_keep); 14 } 15 } 16 17 static void dc_q_map_tar_wr(DC* dc, uint32_t val) { 18 if (val != dc->map_tar_cache) { 19 dc->map_tar_cache = val; 20 dc_q_ap_wr(dc, MAP_TAR, val); 21 } 22 } 23 24 25 void dc_q_mem_rd32(DC* dc, uint32_t addr, uint32_t* val) { 26 if (addr & 3) { 27 dc->qerror = DC_ERR_BAD_PARAMS; 28 } else { 29 dc_q_map_csw_wr(dc, MAP_CSW_SZ_32 | MAP_CSW_INC_OFF | MAP_CSW_DEVICE_EN); 30 dc_q_map_tar_wr(dc, addr); 31 dc_q_ap_rd(dc, MAP_DRW, val); 32 } 33 } 34 35 void dc_q_mem_match32(DC* dc, uint32_t addr, uint32_t val) { 36 if (addr & 3) { 37 dc->qerror = DC_ERR_BAD_PARAMS; 38 } else { 39 dc_q_map_csw_wr(dc, MAP_CSW_SZ_32 | MAP_CSW_INC_OFF | MAP_CSW_DEVICE_EN); 40 dc_q_map_tar_wr(dc, addr); 41 dc_q_ap_match(dc, MAP_DRW, val); 42 } 43 } 44 45 void dc_q_mem_wr32(DC* dc, uint32_t addr, uint32_t val) { 46 if (addr & 3) { 47 dc->qerror = DC_ERR_BAD_PARAMS; 48 } else { 49 dc_q_map_csw_wr(dc, MAP_CSW_SZ_32 | MAP_CSW_INC_OFF | MAP_CSW_DEVICE_EN); 50 dc_q_map_tar_wr(dc, addr); 51 dc_q_ap_wr(dc, MAP_DRW, val); 52 } 53 } 54 55 int dc_mem_rd32(DC* dc, uint32_t addr, uint32_t* val) { 56 dc_q_init(dc); 57 dc_q_mem_rd32(dc, addr, val); 58 return dc_q_exec(dc); 59 } 60 61 int dc_mem_wr32(DC* dc, uint32_t addr, uint32_t val) { 62 dc_q_init(dc); 63 dc_q_mem_wr32(dc, addr, val); 64 return dc_q_exec(dc); 65 } 66 67 68 69 #if 0 70 int dc_mem_rd_words(dctx_t* dc, uint32_t addr, uint32_t num, uint32_t* ptr) { 71 while (num > 0) { 72 dc_q_mem_rd32(dc, addr, ptr); 73 num--; 74 addr += 4; 75 ptr++; 76 } 77 return dc_q_exec(dc); 78 } 79 80 int dc_mem_wr_words(dctx_t* dc, uint32_t addr, uint32_t num, const uint32_t* ptr) { 81 while (num > 0) { 82 dc_q_mem_wr32(dc, addr, *ptr); 83 num--; 84 addr += 4; 85 ptr++; 86 } 87 return dc_q_exec(dc); 88 } 89 #else 90 // some implementations support >10 bits, but 10 is the minimum required 91 // by spec (and some targets like rp2040 are limited to this) 92 #define WRAPSIZE 0x400 93 #define WRAPMASK (WRAPSIZE - 1) 94 95 int dc_mem_rd_words(dctx_t* dc, uint32_t addr, uint32_t num, uint32_t* ptr) { 96 while (num > 0) { 97 uint32_t xfer = (WRAPSIZE - (addr & WRAPMASK)) / 4; 98 if (xfer > num) { 99 xfer = num; 100 } 101 dc_q_init(dc); 102 dc_q_map_csw_wr(dc, MAP_CSW_SZ_32 | MAP_CSW_INC_SINGLE | MAP_CSW_DEVICE_EN); 103 dc_q_map_tar_wr(dc, addr); 104 num -= xfer; 105 addr += xfer * 4; 106 while (xfer > 0) { 107 dc_q_ap_rd(dc, MAP_DRW, ptr++); 108 xfer--; 109 } 110 int r = dc_q_exec(dc); 111 if (r != DC_OK) { 112 return r; 113 } 114 } 115 return DC_OK; 116 } 117 118 int dc_mem_wr_words(dctx_t* dc, uint32_t addr, uint32_t num, const uint32_t* ptr) { 119 while (num > 0) { 120 uint32_t xfer = (WRAPSIZE - (addr & WRAPMASK)) / 4; 121 if (xfer > num) { 122 xfer = num; 123 } 124 dc_q_init(dc); 125 dc_q_map_csw_wr(dc, MAP_CSW_SZ_32 | MAP_CSW_INC_SINGLE | MAP_CSW_DEVICE_EN); 126 dc_q_map_tar_wr(dc, addr); 127 num -= xfer; 128 addr += xfer * 4; 129 while (xfer > 0) { 130 dc_q_ap_wr(dc, MAP_DRW, *ptr++); 131 xfer--; 132 } 133 int r = dc_q_exec(dc); 134 if (r != DC_OK) { 135 return r; 136 } 137 } 138 return DC_OK; 139 } 140 #endif 141 142 int dc_core_check_halt(dctx_t* dc) { 143 uint32_t val; 144 int r; 145 if ((r = dc_mem_rd32(dc, DHCSR, &val)) < 0) { 146 return r; 147 } 148 if (val & DHCSR_S_HALT) { 149 return 1; 150 } 151 return 0; 152 } 153 154 int dc_core_halt(DC* dc) { 155 uint32_t val; 156 int r; 157 if ((r = dc_mem_rd32(dc, DHCSR, &val)) < 0) { 158 return r; 159 } 160 if (val & DHCSR_C_DEBUGEN) { 161 // preserve C_MASKINTS 162 val &= DHCSR_C_MASKINTS; 163 } else { 164 // when setting C_DEBUGEN to 1 (from 0), 165 // must write 0 to C_MASKINTS 166 val = 0; 167 } 168 // set C_HALT and C_DEBUGEN 169 val |= DHCSR_C_HALT | DHCSR_C_DEBUGEN | DHCSR_DBGKEY; 170 if ((r = dc_mem_wr32(dc, DHCSR, val)) < 0) { 171 return r; 172 } 173 for (unsigned n = 0; n < 64; n++) { 174 if (dc_core_check_halt(dc) == 1) { 175 return 0; 176 } 177 } 178 return DC_ERR_TIMEOUT; 179 } 180 181 int dc_core_resume(DC* dc){ 182 uint32_t val; 183 int r; 184 if ((r = dc_mem_rd32(dc, DHCSR, &val)) < 0) { 185 return r; 186 } 187 if (val & DHCSR_C_DEBUGEN) { 188 // preserve C_MASKINTS 189 val &= DHCSR_C_MASKINTS; 190 } else { 191 // when setting C_DEBUGEN to 1 (from 0), 192 // must write 0 to C_MASKINTS 193 val = 0; 194 } 195 // clear C_HALT 196 val |= DHCSR_C_DEBUGEN | DHCSR_DBGKEY; 197 if ((r = dc_mem_wr32(dc, DHCSR, val)) < 0) { 198 return r; 199 } 200 for (unsigned n = 0; n < 64; n++) { 201 if (dc_core_check_halt(dc) == 0) { 202 return 0; 203 } 204 } 205 return DC_ERR_TIMEOUT; 206 } 207 208 int dc_core_step(DC* dc) { 209 uint32_t val; 210 int r; 211 if ((r = dc_mem_rd32(dc, DHCSR, &val)) < 0) { 212 return r; 213 } 214 val &= (DHCSR_C_DEBUGEN | DHCSR_C_HALT | DHCSR_C_MASKINTS); 215 val |= DHCSR_DBGKEY; 216 217 if (!(val & DHCSR_C_HALT)) { 218 val |= DHCSR_C_HALT | DHCSR_C_DEBUGEN; 219 if ((r = dc_mem_wr32(dc, DHCSR, val)) < 0) { 220 return r; 221 } 222 } else { 223 val = (val & (~DHCSR_C_HALT)) | DHCSR_C_STEP; 224 if ((r = dc_mem_wr32(dc, DHCSR, val)) < 0) { 225 return r; 226 } 227 } 228 return 0; 229 } 230 231 int dc_core_wait_halt(DC* dc) { 232 uint32_t last = dc_get_attn_value(dc); 233 uint32_t val; 234 int r; 235 for (;;) { 236 if ((r = dc_mem_rd32(dc, DHCSR, &val)) < 0) { 237 return r; 238 } 239 if (val & DHCSR_S_HALT) { 240 return 0; 241 } 242 if (last != dc_get_attn_value(dc)) { 243 return DC_ERR_INTERRUPTED; 244 } 245 } 246 return 0; 247 } 248 249 static void dc_q_core_reg_rd(DC* dc, unsigned id, uint32_t* val) { 250 dc_q_mem_wr32(dc, DCRSR, DCRSR_RD | (id & DCRSR_ID_MASK)); 251 dc_q_set_mask(dc, DHCSR_S_REGRDY); 252 dc_q_mem_match32(dc, DHCSR, DHCSR_S_REGRDY); 253 dc_q_mem_rd32(dc, DCRDR, val); 254 } 255 static void dc_q_core_reg_wr(DC* dc, unsigned id, uint32_t val) { 256 dc_q_mem_wr32(dc, DCRDR, val); 257 dc_q_mem_wr32(dc, DCRSR, DCRSR_WR | (id & DCRSR_ID_MASK)); 258 dc_q_set_mask(dc, DHCSR_S_REGRDY); 259 dc_q_mem_match32(dc, DHCSR, DHCSR_S_REGRDY); 260 } 261 262 int dc_core_reg_rd(DC* dc, unsigned id, uint32_t* val) { 263 dc_q_init(dc); 264 dc_q_core_reg_rd(dc, id, val); 265 return dc_q_exec(dc); 266 } 267 int dc_core_reg_wr(DC* dc, unsigned id, uint32_t val) { 268 dc_q_init(dc); 269 dc_q_core_reg_wr(dc, id, val); 270 return dc_q_exec(dc); 271 } 272 int dc_core_reg_rd_list(DC* dc, uint32_t* id, uint32_t* val, unsigned count) { 273 dc_q_init(dc); 274 while (count > 0) { 275 dc_q_core_reg_rd(dc, *id++, val++); 276 count--; 277 } 278 return dc_q_exec(dc); 279 }