xdebug

next generation of mdebug (work in progress)
git clone http://frotz.net/git/xdebug.git
Log | Files | Refs | README

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 }