xdebug

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

commands-agent.c (7355B)


      1 // Copyright 2023, Brian Swetland <swetland@frotz.net>
      2 // Licensed under the Apache License, Version 2.0.
      3 
      4 #include <string.h>
      5 #include <stdio.h>
      6 #include <stdlib.h>
      7 
      8 #include "xdebug.h"
      9 #include "transport.h"
     10 #include "arm-v7-debug.h"
     11 #include "arm-v7-system-control.h"
     12 
     13 #define _AGENT_HOST_
     14 #include <agent/flash.h>
     15 
     16 static flash_agent *AGENT = NULL;
     17 static uint32_t AGENT_sz = 0;
     18 static char *AGENT_arch = NULL;
     19 
     20 static void *load_agent(const char *arch, size_t *_sz) {
     21 	void *data;
     22 	size_t sz;
     23 	char name[1024];
     24 
     25 	if (arch == NULL) return NULL;
     26 
     27 	name[sizeof(name)-1] = 0;
     28 	snprintf(name, sizeof(name)-1, "%s.bin", arch);
     29 	if ((data = get_builtin_file(name, &sz))) {
     30 		void *copy = malloc(sz + 4);
     31 		if (copy == NULL) return NULL;
     32 		memcpy(copy, data, sz);
     33 		*_sz = sz;
     34 		return copy;
     35 	}
     36 
     37 	snprintf(name, sizeof(name)-1, "out/agents/%s.bin", arch);
     38 	return load_file(name, _sz);
     39 }
     40 
     41 int do_setarch(DC* dc, CC* cc) {
     42 	char *agent_name = NULL;
     43 	flash_agent *agent = NULL;
     44 	size_t agent_sz = 0;
     45 	const char *name;
     46 
     47 	cmd_arg_str_opt(cc, 1, &name, NULL);
     48 	if (name == NULL) {
     49 		if (AGENT_arch) {
     50 			INFO("current flash agent is '%s'\n", AGENT_arch);
     51 		} else {
     52 			INFO("no flash agent selected\n");
     53 		}
     54 fail_load:
     55 		INFO("set architecture with: arch <name> (omit the .bin)\n");
     56 		for (unsigned n = 0; (name = get_builtin_filename(n)) != NULL; n++) {
     57 			INFO("   %s\n", name);
     58 		}
     59 		goto fail;
     60 	}
     61 	if ((agent_name = malloc(strlen(name)+1)) == NULL) {
     62 		goto fail;
     63 	}
     64 	memcpy(agent_name, name, strlen(name)+1);
     65 	if ((agent = load_agent(name, &agent_sz)) == NULL) {
     66 		ERROR("cannot load flash agent for architecture '%s'\n", name);
     67 		goto fail_load;
     68 	}
     69 
     70 	// sanity check
     71 	if ((agent_sz < sizeof(flash_agent)) ||
     72 		(agent->magic != AGENT_MAGIC) ||
     73 		(agent->version != AGENT_VERSION)) {
     74 		ERROR("invalid agent image\n");
     75 		goto fail;
     76 	}
     77 
     78 	INFO("flash agent '%s' loaded.\n", agent_name);
     79 	if (AGENT) {
     80 		free(AGENT);
     81 		free(AGENT_arch);
     82 	}
     83 	AGENT = agent;
     84 	AGENT_sz = agent_sz;
     85 	AGENT_arch = agent_name;
     86 	return 0;
     87 
     88 fail:
     89 	if (agent) {
     90 		free(agent);
     91 	}
     92 	if (agent_name) {
     93 		free(agent_name);
     94 	}
     95 	return DBG_ERR;
     96 }
     97 
     98 static int invoke(DC* dc, uint32_t agent, uint32_t func,
     99 	uint32_t r0, uint32_t r1, uint32_t r2, uint32_t r3) {
    100 	// TODO: improve error handling
    101 	dc_core_reg_wr(dc, 0, r0);
    102 	dc_core_reg_wr(dc, 1, r1);
    103 	dc_core_reg_wr(dc, 2, r2);
    104 	dc_core_reg_wr(dc, 3, r3);
    105 	dc_core_reg_wr(dc, 13, agent - 4);
    106 	dc_core_reg_wr(dc, 14, agent | 1); // include T bit
    107 	dc_core_reg_wr(dc, 15, func | 1); // include T bit
    108 
    109 	// if the target has bogus data at 0, the processor may be in
    110 	// pending-exception state after reset-stop, so we will clear
    111 	// any exceptions and then set the PSR to something reasonable
    112 	dc_mem_wr32(dc, AIRCR, AIRCR_VECTKEY | AIRCR_VECTCLRACTIVE);
    113 	dc_core_reg_wr(dc, 16, 0x01000000);
    114 
    115 	// todo: readback and verify?
    116 
    117 	INFO("agent: call <func@%08x>(0x%x,0x%x,0x%x,0x%x)\n", func, r0, r1, r2, r3);
    118 	dc_core_resume(dc);
    119 	// todo: timeout after a few seconds?
    120 	if (dc_core_wait_halt(dc)) {
    121 		ERROR("agent: interrupted\n");
    122 		return DBG_ERR;
    123 	}
    124 
    125 	uint32_t pc = 0xeeeeeeee, res = 0xeeeeeeee;
    126 	dc_core_reg_rd(dc, 0, &res);
    127 	dc_core_reg_rd(dc, 15, &pc);
    128 	if (pc != agent) {
    129 		ERROR("pc (%08x) is not at %08x\n", pc, agent);
    130 		return -1;
    131 	}
    132 	if (res) {
    133 		if (res == ERR_INVALID) {
    134 			ERROR("agent: unsupported part\n");
    135 		} else {
    136 			ERROR("agent: failure %d\n", res);
    137 		}
    138 		return DBG_ERR;
    139 	}
    140 	return 0;
    141 }
    142 
    143 static int run_flash_agent(DC* dc, uint32_t flashaddr, void *data, uint32_t data_sz) {
    144 	uint8_t buffer[4096];
    145 	flash_agent *agent;
    146 	uint32_t agent_sz;
    147 	int r;
    148 
    149 	if (AGENT == NULL) {
    150 		ERROR("no flash agent selected\n");
    151 		ERROR("set architecture with: arch <name>\n");
    152 		goto fail;
    153 	}
    154 	if (AGENT_sz > sizeof(buffer)) {
    155 		ERROR("flash agent too large\n");
    156 		goto fail;
    157 	}
    158 
    159 	memcpy(buffer, AGENT, AGENT_sz);
    160 	agent_sz = AGENT_sz;
    161 	agent = (void*) buffer;
    162 
    163 	// replace magic with bkpt instructions
    164 	agent->magic = 0xbe00be00;
    165 
    166 	if (do_attach(dc,0)) {
    167 		ERROR("failed to attach\n");
    168 		goto fail;
    169 	}
    170 	if (do_reset_stop(dc,0)) {
    171 		goto fail;
    172 	}
    173 
    174 	if (agent->flags & FLAG_BOOT_ROM_HACK) {
    175 	// TODO: wire this back up
    176 #if 1
    177 		ERROR("agent: BOOT ROM HACK unsupported\n");
    178 		return DBG_ERR;
    179 #else
    180 		xprintf(XCORE, "executing boot rom\n");
    181 		if (swdp_watchpoint_rw(0, 0)) {
    182 			goto fail;
    183 		}
    184 		swdp_core_resume();
    185 		swdp_core_wait_for_halt();
    186 		swdp_watchpoint_disable(0);
    187 		// todo: timeout?
    188 		// todo: confirm halted
    189 #endif
    190 	}
    191 
    192 	if (dc_mem_wr_words(dc, agent->load_addr, agent_sz / 4, (void*) agent)) {
    193 		ERROR("failed to download agent\n");
    194 		goto fail;
    195 	}
    196 	INFO("agent: loaded @%08x (%d bytes)\n", agent->load_addr, agent_sz);
    197 
    198 	if (invoke(dc, agent->load_addr, agent->setup, agent->load_addr, 0, 0, 0)) {
    199 		goto fail;
    200 	if (r != 0) {
    201 		}
    202 		goto fail;
    203 	}
    204 	if (dc_mem_rd_words(dc, agent->load_addr + 16, 4, (void*) &agent->data_addr)) {
    205 		goto fail;
    206 	}
    207 	INFO("agent: info: buffer %dK @%08x, flash %dK @%08x\n",
    208 		agent->data_size / 1024, agent->data_addr,
    209 		agent->flash_size / 1024, agent->flash_addr);
    210 
    211 	if ((flashaddr == 0) && (data == NULL) && (data_sz == 0xFFFFFFFF)) {
    212 		// erase all
    213 		flashaddr = agent->flash_addr;
    214 		data_sz = agent->flash_size;
    215 	}
    216 
    217 	if ((flashaddr < agent->flash_addr) ||
    218 		(data_sz > agent->flash_size) ||
    219 		((flashaddr + data_sz) > (agent->flash_addr + agent->flash_size))) {
    220 		ERROR("invalid flash address %08x..%08x\n",
    221 			flashaddr, flashaddr + data_sz);
    222 		goto fail;
    223 	}
    224 
    225 	if (data == NULL) {
    226 		// erase
    227 		if (invoke(dc, agent->load_addr, agent->erase, flashaddr, data_sz, 0, 0)) {
    228 			ERROR("failed to erase %d bytes at %08x\n", data_sz, flashaddr);
    229 			goto fail;
    230 		}
    231 		INFO("erase: OK\n");
    232 	} else {
    233 		// write
    234 		uint8_t *ptr = (void*) data;
    235 		uint32_t xfer;
    236 		INFO("flash: writing %d bytes at %08x...\n", data_sz, flashaddr);
    237 		if (invoke(dc, agent->load_addr, agent->erase, flashaddr, data_sz, 0, 0)) {
    238 			ERROR("failed to erase %d bytes at %08x\n", data_sz, flashaddr);
    239 			goto fail;
    240 		}
    241 		while (data_sz > 0) {
    242 			if (data_sz > agent->data_size) {
    243 				xfer = agent->data_size;
    244 			} else {
    245 				xfer = data_sz;
    246 			}
    247 			if (dc_mem_wr_words(dc, agent->data_addr, xfer / 4, (void*) ptr)) {
    248 				ERROR("download to %08x failed\n", agent->data_addr);
    249 				goto fail;
    250 			}
    251 			if (invoke(dc, agent->load_addr, agent->write,
    252 				flashaddr, agent->data_addr, xfer, 0)) {
    253 				ERROR("failed to flash %d bytes to %08x\n", xfer, flashaddr);
    254 				goto fail;
    255 			}
    256 			ptr += xfer;
    257 			data_sz -= xfer;
    258 			flashaddr += xfer;
    259 		}
    260 		INFO("flash: OK\n");
    261 	}
    262 
    263 	if (data) free(data);
    264 	return 0;
    265 fail:
    266 	if (data) free(data);
    267 	return -1;
    268 }
    269 
    270 int do_flash(DC* dc, CC* cc) {
    271 	void *data = NULL;
    272 	size_t sz;
    273 	const char *fn;
    274 	uint32_t addr;
    275 	uint32_t data_sz;
    276 	if (cmd_arg_str(cc, 1, &fn)) return DBG_ERR;
    277 	if (cmd_arg_u32(cc, 2, &addr)) return DBG_ERR;
    278 
    279 	if ((data = load_file(fn, &sz)) == NULL) {
    280 		ERROR("cannot load '%s'\n", fn);
    281 		return -1;
    282 	}
    283 	if (sz > (1024*1024)) {
    284 		ERROR("too large\n");
    285 		return DBG_ERR;
    286 	}
    287 
    288 	// word align
    289 	data_sz = (sz + 3) & ~3;
    290 	return run_flash_agent(dc, addr, data, data_sz);
    291 }
    292 
    293 int do_erase(DC* dc, CC* cc) {
    294 	const char* s;
    295 	uint32_t addr;
    296 	uint32_t len;
    297 	cmd_arg_str_opt(cc, 1, &s, "");
    298 	if (!strcmp(s, "all")) {
    299 		return run_flash_agent(dc, 0, NULL, 0xFFFFFFFF);
    300 	}
    301 	if (cmd_arg_u32(cc, 1, &addr)) return DBG_ERR;
    302 	if (cmd_arg_u32(cc, 2, &len)) return DBG_ERR;
    303 	return run_flash_agent(dc, addr, NULL, len);
    304 }
    305