/* Program flash */ static int msp432_flash_write(struct target_flash *f, target_addr dest, const void *src, size_t len) { struct msp432_flash *mf = (struct msp432_flash *)f; target *t = f->t; /* Prepare RAM buffer in target */ target_mem_write(t, SRAM_WRITE_BUFFER, src, len); /* Unprotect sector, len is always < SECTOR_SIZE */ uint32_t old_prot = msp432_sector_unprotect(mf, dest); DEBUG("Flash protect: 0x%08"PRIX32"\n", target_mem_read32(t, mf->flash_protect_register)); /* Prepare input data */ uint32_t regs[t->regs_size / sizeof(uint32_t)]; // Use of VLA target_regs_read(t, regs); regs[0] = SRAM_WRITE_BUFFER; // Address of buffer to be flashed in R0 regs[1] = dest; // Flash address to be write to in R1 regs[2] = len; // Size of buffer to be flashed in R2 DEBUG("Writing 0x%04" PRIX32 " bytes at 0x%08" PRI_SIZET "\n", dest, len); /* Call ROM */ msp432_call_ROM(t, mf->FlashCtl_programMemory, regs); /* Restore original protection */ target_mem_write32(t, mf->flash_protect_register, old_prot); DEBUG("ROM return value: %"PRIu32"\n", regs[0]); // Result value in R0 is true for success return !regs[0]; }
/* Erase a single sector at addr calling the ROM routine*/ static bool msp432_sector_erase(struct target_flash *f, target_addr addr) { target *t = f->t; struct msp432_flash *mf = (struct msp432_flash *)f; /* Unprotect sector */ uint32_t old_prot = msp432_sector_unprotect(mf, addr); DEBUG("Flash protect: 0x%08"PRIX32"\n", target_mem_read32(t, mf->flash_protect_register)); /* Prepare input data */ uint32_t regs[t->regs_size / sizeof(uint32_t)]; // Use of VLA target_regs_read(t, regs); regs[0] = addr; // Address of sector to erase in R0 DEBUG("Erasing sector at 0x%08"PRIX32"\n", addr); /* Call ROM */ msp432_call_ROM(t, mf->FlashCtl_eraseSector, regs); // Result value in R0 is true for success DEBUG("ROM return value: %"PRIu32"\n", regs[0]); /* Restore original protection */ target_mem_write32(t, mf->flash_protect_register, old_prot); return !regs[0]; }
/* MSP432 ROM routine invocation */ static void msp432_call_ROM(target *t, uint32_t address, uint32_t regs[]) { /* Kill watchdog */ target_mem_write16(t, WDT_A_WTDCTL, WDT_A_HOLD); /* Breakpoint at the beginning of CODE SRAM alias area */ target_mem_write16(t, SRAM_CODE_BASE, ARM_THUMB_BREAKPOINT); /* Prepare registers */ regs[REG_MSP] = SRAM_STACK_PTR; /* Stack space */ regs[REG_LR] = SRAM_CODE_BASE | 1; /* Return to beginning of SRAM CODE alias */ regs[REG_PC] = address; /* Start at given address */ target_regs_write(t, regs); /* Call ROM */ /* start the target and wait for it to halt again */ target_halt_resume(t, false); while (!target_halt_poll(t, NULL)); // Read registers to get result target_regs_read(t, regs); }
void gdb_main(void) { int size; bool single_step = false; char last_activity = 0; DEBUG("Entring GDB protocol main loop\n"); /* GDB protocol main loop */ while(1) { SET_IDLE_STATE(1); size = gdb_getpacket(pbuf, BUF_SIZE); SET_IDLE_STATE(0); continue_activity: switch(pbuf[0]) { /* Implementation of these is mandatory! */ case 'g': { /* 'g': Read general registers */ ERROR_IF_NO_TARGET(); uint8_t arm_regs[target_regs_size(cur_target)]; target_regs_read(cur_target, arm_regs); gdb_putpacket(hexify(pbuf, arm_regs, sizeof(arm_regs)), sizeof(arm_regs) * 2); break; } case 'm': { /* 'm addr,len': Read len bytes from addr */ uint32_t addr, len; ERROR_IF_NO_TARGET(); sscanf(pbuf, "m%" SCNx32 ",%" SCNx32, &addr, &len); DEBUG("m packet: addr = %" PRIx32 ", len = %" PRIx32 "\n", addr, len); uint8_t mem[len]; target_mem_read(cur_target, mem, addr, len); if(target_check_error(cur_target)) gdb_putpacketz("E01"); else gdb_putpacket(hexify(pbuf, mem, len), len*2); break; } case 'G': { /* 'G XX': Write general registers */ ERROR_IF_NO_TARGET(); uint8_t arm_regs[target_regs_size(cur_target)]; unhexify(arm_regs, &pbuf[1], sizeof(arm_regs)); target_regs_write(cur_target, arm_regs); gdb_putpacketz("OK"); break; } case 'M': { /* 'M addr,len:XX': Write len bytes to addr */ uint32_t addr, len; int hex; ERROR_IF_NO_TARGET(); sscanf(pbuf, "M%" SCNx32 ",%" SCNx32 ":%n", &addr, &len, &hex); DEBUG("M packet: addr = %" PRIx32 ", len = %" PRIx32 "\n", addr, len); uint8_t mem[len]; unhexify(mem, pbuf + hex, len); target_mem_write(cur_target, addr, mem, len); if(target_check_error(cur_target)) gdb_putpacketz("E01"); else gdb_putpacketz("OK"); break; } case 's': /* 's [addr]': Single step [start at addr] */ single_step = true; // Fall through to resume target case 'c': /* 'c [addr]': Continue [at addr] */ if(!cur_target) { gdb_putpacketz("X1D"); break; } target_halt_resume(cur_target, single_step); SET_RUN_STATE(1); single_step = false; // Fall through to wait for target halt case '?': { /* '?': Request reason for target halt */ /* This packet isn't documented as being mandatory, * but GDB doesn't work without it. */ uint32_t watch_addr; int sig; if(!cur_target) { /* Report "target exited" if no target */ gdb_putpacketz("W00"); break; } last_activity = pbuf[0]; /* Wait for target halt */ while(!(sig = target_halt_wait(cur_target))) { unsigned char c = gdb_if_getchar_to(0); if((c == '\x03') || (c == '\x04')) { target_halt_request(cur_target); last_activity = 's'; } } SET_RUN_STATE(0); /* Negative signal indicates we're in a syscall */ if (sig < 0) break; /* Target disappeared */ if (cur_target == NULL) { gdb_putpacket_f("X%02X", sig); break; } /* Report reason for halt */ if(target_check_hw_wp(cur_target, &watch_addr)) { /* Watchpoint hit */ gdb_putpacket_f("T%02Xwatch:%08X;", sig, watch_addr); } else { gdb_putpacket_f("T%02X", sig); } break; } case 'F': { /* Semihosting call finished */ int retcode, errcode, items; char c, *p; if (pbuf[1] == '-') p = &pbuf[2]; else p = &pbuf[1]; items = sscanf(p, "%x,%x,%c", &retcode, &errcode, &c); if (pbuf[1] == '-') retcode = -retcode; target_hostio_reply(cur_target, retcode, errcode); /* if break is requested */ if (items == 3 && c == 'C') { gdb_putpacketz("T02"); break; } pbuf[0] = last_activity; goto continue_activity; } /* Optional GDB packet support */ case '!': /* Enable Extended GDB Protocol. */ /* This doesn't do anything, we support the extended * protocol anyway, but GDB will never send us a 'R' * packet unless we answer 'OK' here. */ gdb_putpacketz("OK"); break; case 0x04: case 'D': /* GDB 'detach' command. */ if(cur_target) target_detach(cur_target); last_target = cur_target; cur_target = NULL; gdb_putpacketz("OK"); break; case 'k': /* Kill the target */ if(cur_target) { target_reset(cur_target); target_detach(cur_target); last_target = cur_target; cur_target = NULL; } break; case 'r': /* Reset the target system */ case 'R': /* Restart the target program */ if(cur_target) target_reset(cur_target); else if(last_target) { cur_target = target_attach(last_target, gdb_target_destroy_callback); target_reset(cur_target); } break; case 'X': { /* 'X addr,len:XX': Write binary data to addr */ uint32_t addr, len; int bin; ERROR_IF_NO_TARGET(); sscanf(pbuf, "X%" SCNx32 ",%" SCNx32 ":%n", &addr, &len, &bin); DEBUG("X packet: addr = %" PRIx32 ", len = %" PRIx32 "\n", addr, len); target_mem_write(cur_target, addr, pbuf+bin, len); if(target_check_error(cur_target)) gdb_putpacketz("E01"); else gdb_putpacketz("OK"); break; } case 'q': /* General query packet */ handle_q_packet(pbuf, size); break; case 'v': /* General query packet */ handle_v_packet(pbuf, size); break; /* These packet implement hardware break-/watchpoints */ case 'Z': /* Z type,addr,len: Set breakpoint packet */ case 'z': /* z type,addr,len: Clear breakpoint packet */ ERROR_IF_NO_TARGET(); handle_z_packet(pbuf, size); break; default: /* Packet not implemented */ DEBUG("*** Unsupported packet: %s\n", pbuf); gdb_putpacketz(""); } } }
int gdb_main_loop(struct target_controller *tc, bool in_syscall) { int size; bool single_step = false; /* GDB protocol main loop */ while(1) { SET_IDLE_STATE(1); size = gdb_getpacket(pbuf, BUF_SIZE); SET_IDLE_STATE(0); switch(pbuf[0]) { /* Implementation of these is mandatory! */ case 'g': { /* 'g': Read general registers */ ERROR_IF_NO_TARGET(); uint8_t arm_regs[target_regs_size(cur_target)]; target_regs_read(cur_target, arm_regs); gdb_putpacket(hexify(pbuf, arm_regs, sizeof(arm_regs)), sizeof(arm_regs) * 2); break; } case 'm': { /* 'm addr,len': Read len bytes from addr */ uint32_t addr, len; ERROR_IF_NO_TARGET(); sscanf(pbuf, "m%" SCNx32 ",%" SCNx32, &addr, &len); if (len > sizeof(pbuf) / 2) { gdb_putpacketz("E02"); break; } DEBUG("m packet: addr = %" PRIx32 ", len = %" PRIx32 "\n", addr, len); uint8_t mem[len]; if (target_mem_read(cur_target, mem, addr, len)) gdb_putpacketz("E01"); else gdb_putpacket(hexify(pbuf, mem, len), len*2); break; } case 'G': { /* 'G XX': Write general registers */ ERROR_IF_NO_TARGET(); uint8_t arm_regs[target_regs_size(cur_target)]; unhexify(arm_regs, &pbuf[1], sizeof(arm_regs)); target_regs_write(cur_target, arm_regs); gdb_putpacketz("OK"); break; } case 'M': { /* 'M addr,len:XX': Write len bytes to addr */ uint32_t addr, len; int hex; ERROR_IF_NO_TARGET(); sscanf(pbuf, "M%" SCNx32 ",%" SCNx32 ":%n", &addr, &len, &hex); if (len > (unsigned)(size - hex) / 2) { gdb_putpacketz("E02"); break; } DEBUG("M packet: addr = %" PRIx32 ", len = %" PRIx32 "\n", addr, len); uint8_t mem[len]; unhexify(mem, pbuf + hex, len); if (target_mem_write(cur_target, addr, mem, len)) gdb_putpacketz("E01"); else gdb_putpacketz("OK"); break; } case 's': /* 's [addr]': Single step [start at addr] */ single_step = true; /* fall through */ case 'c': /* 'c [addr]': Continue [at addr] */ if(!cur_target) { gdb_putpacketz("X1D"); break; } target_halt_resume(cur_target, single_step); SET_RUN_STATE(1); single_step = false; /* fall through */ case '?': { /* '?': Request reason for target halt */ /* This packet isn't documented as being mandatory, * but GDB doesn't work without it. */ target_addr watch; enum target_halt_reason reason; if(!cur_target) { /* Report "target exited" if no target */ gdb_putpacketz("W00"); break; } /* Wait for target halt */ while(!(reason = target_halt_poll(cur_target, &watch))) { unsigned char c = gdb_if_getchar_to(0); if((c == '\x03') || (c == '\x04')) { target_halt_request(cur_target); } } SET_RUN_STATE(0); /* Translate reason to GDB signal */ switch (reason) { case TARGET_HALT_ERROR: gdb_putpacket_f("X%02X", GDB_SIGLOST); morse("TARGET LOST.", true); break; case TARGET_HALT_REQUEST: gdb_putpacket_f("T%02X", GDB_SIGINT); break; case TARGET_HALT_WATCHPOINT: gdb_putpacket_f("T%02Xwatch:%08X;", GDB_SIGTRAP, watch); break; case TARGET_HALT_FAULT: gdb_putpacket_f("T%02X", GDB_SIGSEGV); break; default: gdb_putpacket_f("T%02X", GDB_SIGTRAP); } break; } case 'F': /* Semihosting call finished */ if (in_syscall) { return hostio_reply(tc, pbuf, size); } else { DEBUG("*** F packet when not in syscall! '%s'\n", pbuf); gdb_putpacketz(""); } break; /* Optional GDB packet support */ case '!': /* Enable Extended GDB Protocol. */ /* This doesn't do anything, we support the extended * protocol anyway, but GDB will never send us a 'R' * packet unless we answer 'OK' here. */ gdb_putpacketz("OK"); break; case 0x04: case 'D': /* GDB 'detach' command. */ if(cur_target) target_detach(cur_target); last_target = cur_target; cur_target = NULL; gdb_putpacketz("OK"); break; case 'k': /* Kill the target */ if(cur_target) { target_reset(cur_target); target_detach(cur_target); last_target = cur_target; cur_target = NULL; } break; case 'r': /* Reset the target system */ case 'R': /* Restart the target program */ if(cur_target) target_reset(cur_target); else if(last_target) { cur_target = target_attach(last_target, &gdb_controller); target_reset(cur_target); } break; case 'X': { /* 'X addr,len:XX': Write binary data to addr */ uint32_t addr, len; int bin; ERROR_IF_NO_TARGET(); sscanf(pbuf, "X%" SCNx32 ",%" SCNx32 ":%n", &addr, &len, &bin); if (len > (unsigned)(size - bin)) { gdb_putpacketz("E02"); break; } DEBUG("X packet: addr = %" PRIx32 ", len = %" PRIx32 "\n", addr, len); if (target_mem_write(cur_target, addr, pbuf+bin, len)) gdb_putpacketz("E01"); else gdb_putpacketz("OK"); break; } case 'q': /* General query packet */ handle_q_packet(pbuf, size); break; case 'v': /* General query packet */ handle_v_packet(pbuf, size); break; /* These packet implement hardware break-/watchpoints */ case 'Z': /* Z type,addr,len: Set breakpoint packet */ case 'z': /* z type,addr,len: Clear breakpoint packet */ ERROR_IF_NO_TARGET(); handle_z_packet(pbuf, size); break; default: /* Packet not implemented */ DEBUG("*** Unsupported packet: %s\n", pbuf); gdb_putpacketz(""); } } }