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