Merge commit 'a3feae60aab1fb85fe44b33123e020a9d7c8e18c' into sam-update

This commit is contained in:
Jason Kotzin 2022-08-10 22:26:37 -07:00
commit e43b07172b
9 changed files with 521 additions and 150 deletions

View File

@ -51,12 +51,10 @@ enum gdb_signal {
typedef struct typedef struct
{ {
const char *cmd_prefix; const char *cmd_prefix;
void (*func)(const char *packet,int len); void (*func)(const char *packet, int len);
}cmd_executer; } cmd_executer;
static char pbuf[BUF_SIZE + 1];
static char pbuf[BUF_SIZE+1];
static target *cur_target; static target *cur_target;
static target *last_target; static target *last_target;
@ -119,7 +117,7 @@ int gdb_main_loop(struct target_controller *tc, bool in_syscall)
gdb_putpacket(hexify(pbuf, arm_regs, sizeof(arm_regs)), gdb_putpacket(hexify(pbuf, arm_regs, sizeof(arm_regs)),
sizeof(arm_regs) * 2); sizeof(arm_regs) * 2);
break; break;
} }
case 'm': { /* 'm addr,len': Read len bytes from addr */ case 'm': { /* 'm addr,len': Read len bytes from addr */
uint32_t addr, len; uint32_t addr, len;
ERROR_IF_NO_TARGET(); ERROR_IF_NO_TARGET();
@ -134,9 +132,9 @@ int gdb_main_loop(struct target_controller *tc, bool in_syscall)
if (target_mem_read(cur_target, mem, addr, len)) if (target_mem_read(cur_target, mem, addr, len))
gdb_putpacketz("E01"); gdb_putpacketz("E01");
else else
gdb_putpacket(hexify(pbuf, mem, len), len*2); gdb_putpacket(hexify(pbuf, mem, len), len * 2);
break; break;
} }
case 'G': { /* 'G XX': Write general registers */ case 'G': { /* 'G XX': Write general registers */
ERROR_IF_NO_TARGET(); ERROR_IF_NO_TARGET();
uint8_t arm_regs[target_regs_size(cur_target)]; uint8_t arm_regs[target_regs_size(cur_target)];
@ -144,7 +142,7 @@ int gdb_main_loop(struct target_controller *tc, bool in_syscall)
target_regs_write(cur_target, arm_regs); target_regs_write(cur_target, arm_regs);
gdb_putpacketz("OK"); gdb_putpacketz("OK");
break; break;
} }
case 'M': { /* 'M addr,len:XX': Write len bytes to addr */ case 'M': { /* 'M addr,len:XX': Write len bytes to addr */
uint32_t addr, len; uint32_t addr, len;
int hex; int hex;
@ -163,7 +161,7 @@ int gdb_main_loop(struct target_controller *tc, bool in_syscall)
else else
gdb_putpacketz("OK"); gdb_putpacketz("OK");
break; break;
} }
case 's': /* 's [addr]': Single step [start at addr] */ case 's': /* 's [addr]': Single step [start at addr] */
single_step = true; single_step = true;
/* fall through */ /* fall through */
@ -217,7 +215,7 @@ int gdb_main_loop(struct target_controller *tc, bool in_syscall)
gdb_putpacket_f("T%02X", GDB_SIGTRAP); gdb_putpacket_f("T%02X", GDB_SIGTRAP);
} }
break; break;
} }
/* Optional GDB packet support */ /* Optional GDB packet support */
case 'p': { /* Read single register */ case 'p': { /* Read single register */
@ -226,32 +224,31 @@ int gdb_main_loop(struct target_controller *tc, bool in_syscall)
sscanf(pbuf, "p%" SCNx32, &reg); sscanf(pbuf, "p%" SCNx32, &reg);
uint8_t val[8]; uint8_t val[8];
size_t s = target_reg_read(cur_target, reg, val, sizeof(val)); size_t s = target_reg_read(cur_target, reg, val, sizeof(val));
if (s > 0) { if (s > 0)
gdb_putpacket(hexify(pbuf, val, s), s * 2); gdb_putpacket(hexify(pbuf, val, s), s * 2);
} else { else
gdb_putpacketz("EFF"); gdb_putpacketz("EFF");
}
break; break;
} }
case 'P': { /* Write single register */ case 'P': { /* Write single register */
ERROR_IF_NO_TARGET(); ERROR_IF_NO_TARGET();
uint32_t reg; uint32_t reg;
int n; int n;
sscanf(pbuf, "P%" SCNx32 "=%n", &reg, &n); sscanf(pbuf, "P%" SCNx32 "=%n", &reg, &n);
uint8_t val[strlen(&pbuf[n])/2]; // TODO: FIXME, VLAs considered harmful.
uint8_t val[strlen(&pbuf[n]) / 2];
unhexify(val, pbuf + n, sizeof(val)); unhexify(val, pbuf + n, sizeof(val));
if (target_reg_write(cur_target, reg, val, sizeof(val)) > 0) { if (target_reg_write(cur_target, reg, val, sizeof(val)) > 0)
gdb_putpacketz("OK"); gdb_putpacketz("OK");
} else { else
gdb_putpacketz("EFF"); gdb_putpacketz("EFF");
}
break; break;
} }
case 'F': /* Semihosting call finished */ case 'F': /* Semihosting call finished */
if (in_syscall) { if (in_syscall)
return hostio_reply(tc, pbuf, size); return hostio_reply(tc, pbuf, size);
} else { else {
DEBUG_GDB("*** F packet when not in syscall! '%s'\n", pbuf); DEBUG_GDB("*** F packet when not in syscall! '%s'\n", pbuf);
gdb_putpacketz(""); gdb_putpacketz("");
} }
@ -309,12 +306,12 @@ int gdb_main_loop(struct target_controller *tc, bool in_syscall)
} }
DEBUG_GDB("X packet: addr = %" PRIx32 ", len = %" PRIx32 "\n", DEBUG_GDB("X packet: addr = %" PRIx32 ", len = %" PRIx32 "\n",
addr, len); addr, len);
if (target_mem_write(cur_target, addr, pbuf+bin, len)) if (target_mem_write(cur_target, addr, pbuf + bin, len))
gdb_putpacketz("E01"); gdb_putpacketz("E01");
else else
gdb_putpacketz("OK"); gdb_putpacketz("OK");
break; break;
} }
case 'q': /* General query packet */ case 'q': /* General query packet */
handle_q_packet(pbuf, size); handle_q_packet(pbuf, size);
@ -337,35 +334,36 @@ int gdb_main_loop(struct target_controller *tc, bool in_syscall)
} }
} }
} }
bool exec_command(char *packet, int len, const cmd_executer *exec)
static bool exec_command(char *packet, int len, const cmd_executer *exec)
{ {
while(exec->cmd_prefix) { while (exec->cmd_prefix) {
int l=strlen(exec->cmd_prefix); const int l = strlen(exec->cmd_prefix);
if(!strncmp(packet,exec->cmd_prefix,l)) { if (!strncmp(packet, exec->cmd_prefix, l)) {
exec->func(packet+l,len-l); exec->func(packet + l, len - l);
return true; return true;
} }
exec++; ++exec;
} }
return false; return false;
} }
static void exec_q_rcmd(const char *packet,int len) static void exec_q_rcmd(const char *packet,int len)
{ {
char *data; char *data;
int datalen; int datalen;
/* calculate size and allocate buffer for command */ /* calculate size and allocate buffer for command */
datalen = len/ 2; datalen = len / 2;
data = alloca(datalen+1); data = alloca(datalen + 1);
/* dehexify command */ /* dehexify command */
unhexify(data, packet, datalen); unhexify(data, packet, datalen);
data[datalen] = 0; /* add terminating null */ data[datalen] = 0; /* add terminating null */
int c = command_process(cur_target, data); int c = command_process(cur_target, data);
if(c < 0) if (c < 0)
gdb_putpacketz(""); gdb_putpacketz("");
else if(c == 0) else if (c == 0)
gdb_putpacketz("OK"); gdb_putpacketz("OK");
else else
gdb_putpacket(hexify(pbuf, "Failed\n", strlen("Failed\n")), gdb_putpacket(hexify(pbuf, "Failed\n", strlen("Failed\n")),
@ -376,23 +374,26 @@ static void
handle_q_string_reply(const char *str, const char *param) handle_q_string_reply(const char *str, const char *param)
{ {
unsigned long addr, len; unsigned long addr, len;
const size_t str_len = strlen(str);
if (sscanf(param, "%08lx,%08lx", &addr, &len) != 2) { if (sscanf(param, "%08lx,%08lx", &addr, &len) != 2) {
gdb_putpacketz("E01"); gdb_putpacketz("E01");
return; return;
} }
if (addr > strlen (str)) { else if (addr > str_len) {
gdb_putpacketz("E01"); gdb_putpacketz("E01");
return; return;
} }
if(addr== strlen (str)) { else if (addr == str_len) {
gdb_putpacketz("l"); gdb_putpacketz("l");
return; return;
} }
unsigned long output_len=strlen(str)-addr; unsigned long output_len = str_len - addr;
if(output_len>len) output_len=len; if (output_len > len)
gdb_putpacket2("m",1,str+addr,output_len); output_len = len;
gdb_putpacket2("m", 1, str + addr, output_len);
} }
static void exec_q_supported(const char *packet, int len) static void exec_q_supported(const char *packet, int len)
{ {
(void)packet; (void)packet;
@ -400,12 +401,12 @@ static void exec_q_supported(const char *packet, int len)
gdb_putpacket_f("PacketSize=%X;qXfer:memory-map:read+;qXfer:features:read+", BUF_SIZE); gdb_putpacket_f("PacketSize=%X;qXfer:memory-map:read+;qXfer:features:read+", BUF_SIZE);
} }
static void exec_q_memory_map(const char *packet,int len) static void exec_q_memory_map(const char *packet, int len)
{ {
(void)packet; (void)packet;
(void)len; (void)len;
/* Read target XML memory map */ /* Read target XML memory map */
if((!cur_target) && last_target) { if ((!cur_target) && last_target) {
/* Attach to last target if detached. */ /* Attach to last target if detached. */
cur_target = target_attach(last_target, cur_target = target_attach(last_target,
&gdb_controller); &gdb_controller);
@ -423,7 +424,7 @@ static void exec_q_feature_read(const char *packet, int len)
{ {
(void)len; (void)len;
/* Read target description */ /* Read target description */
if((!cur_target) && last_target) { if ((!cur_target) && last_target) {
/* Attach to last target if detached. */ /* Attach to last target if detached. */
cur_target = target_attach(last_target, &gdb_controller); cur_target = target_attach(last_target, &gdb_controller);
} }
@ -431,7 +432,7 @@ static void exec_q_feature_read(const char *packet, int len)
gdb_putpacketz("E01"); gdb_putpacketz("E01");
return; return;
} }
handle_q_string_reply(target_tdesc(cur_target), packet ); handle_q_string_reply(target_tdesc(cur_target), packet);
} }
static void exec_q_crc(const char *packet, int len) static void exec_q_crc(const char *packet, int len)
@ -439,7 +440,7 @@ static void exec_q_crc(const char *packet, int len)
(void)len; (void)len;
uint32_t addr, alen; uint32_t addr, alen;
if (sscanf(packet, "%" PRIx32 ",%" PRIx32, &addr, &alen) == 2) { if (sscanf(packet, "%" PRIx32 ",%" PRIx32, &addr, &alen) == 2) {
if(!cur_target) { if (!cur_target) {
gdb_putpacketz("E01"); gdb_putpacketz("E01");
return; return;
} }
@ -451,6 +452,7 @@ static void exec_q_crc(const char *packet, int len)
gdb_putpacket_f("C%lx", crc); gdb_putpacket_f("C%lx", crc);
} }
} }
static const cmd_executer q_commands[]= static const cmd_executer q_commands[]=
{ {
{"qRcmd,", exec_q_rcmd}, {"qRcmd,", exec_q_rcmd},
@ -458,16 +460,14 @@ static const cmd_executer q_commands[]=
{"qXfer:memory-map:read::", exec_q_memory_map}, {"qXfer:memory-map:read::", exec_q_memory_map},
{"qXfer:features:read:target.xml:",exec_q_feature_read}, {"qXfer:features:read:target.xml:",exec_q_feature_read},
{"qCRC:", exec_q_crc}, {"qCRC:", exec_q_crc},
{NULL, NULL},
{NULL,NULL},
}; };
static void static void
handle_q_packet(char *packet, int len) handle_q_packet(char *packet, int len)
{ {
if(exec_command(packet,len,q_commands)) { if (exec_command(packet, len, q_commands))
return; return;
}
DEBUG_GDB("*** Unsupported packet: %s\n", packet); DEBUG_GDB("*** Unsupported packet: %s\n", packet);
gdb_putpacket("", 0); gdb_putpacket("", 0);
} }
@ -493,35 +493,37 @@ handle_v_packet(char *packet, int plen)
char cmdline[83]; char cmdline[83];
char *pcmdline = cmdline; char *pcmdline = cmdline;
char *tok = packet + 4; char *tok = packet + 4;
if (*tok == ';') tok++; if (*tok == ';')
*cmdline='\0'; ++tok;
cmdline[0] = '\0';
while(*tok != '\0') { while(*tok != '\0') {
if(strlen(cmdline)+3 >= sizeof(cmdline)) break; if (strlen(cmdline) + 3 >= sizeof(cmdline))
break;
if (*tok == ';') { if (*tok == ';') {
*pcmdline++=' '; *pcmdline++ = ' ';
*pcmdline='\0'; pcmdline[0] = '\0';
tok++; tok++;
continue; continue;
} }
if (isxdigit(*tok) && isxdigit(*(tok+1))) { if (isxdigit(tok[0]) && isxdigit(tok[1])) {
unhexify(pcmdline, tok, 2); unhexify(pcmdline, tok, 2);
if ((*pcmdline == ' ') || (*pcmdline == '\\')) { if ((*pcmdline == ' ') || (*pcmdline == '\\')) {
*(pcmdline+1)=*pcmdline; pcmdline[1] = *pcmdline;
*pcmdline++='\\'; *pcmdline++ = '\\';
} }
pcmdline++; pcmdline++;
tok+=2; tok += 2;
*pcmdline='\0'; pcmdline[0] = '\0';
continue; continue;
} }
break; break;
} }
/* Run target program. For us (embedded) this means reset. */ /* Run target program. For us (embedded) this means reset. */
if(cur_target) { if (cur_target) {
target_set_cmdline(cur_target, cmdline); target_set_cmdline(cur_target, cmdline);
target_reset(cur_target); target_reset(cur_target);
gdb_putpacketz("T05"); gdb_putpacketz("T05");
} else if(last_target) { } else if (last_target) {
cur_target = target_attach(last_target, cur_target = target_attach(last_target,
&gdb_controller); &gdb_controller);
@ -531,24 +533,29 @@ handle_v_packet(char *packet, int plen)
target_reset(cur_target); target_reset(cur_target);
morse(NULL, false); morse(NULL, false);
gdb_putpacketz("T05"); gdb_putpacketz("T05");
} else gdb_putpacketz("E01"); } else
gdb_putpacketz("E01");
} else gdb_putpacketz("E01"); } else
gdb_putpacketz("E01");
} else if (sscanf(packet, "vFlashErase:%08lx,%08lx", &addr, &len) == 2) { } else if (sscanf(packet, "vFlashErase:%08lx,%08lx", &addr, &len) == 2) {
/* Erase Flash Memory */ /* Erase Flash Memory */
DEBUG_GDB("Flash Erase %08lX %08lX\n", addr, len); DEBUG_GDB("Flash Erase %08lX %08lX\n", addr, len);
if(!cur_target) { gdb_putpacketz("EFF"); return; } if (!cur_target) {
gdb_putpacketz("EFF");
return;
}
if(!flash_mode) { if (!flash_mode) {
/* Reset target if first flash command! */ /* Reset target if first flash command! */
/* This saves us if we're interrupted in IRQ context */ /* This saves us if we're interrupted in IRQ context */
target_reset(cur_target); target_reset(cur_target);
flash_mode = 1; flash_mode = 1;
} }
if(target_flash_erase(cur_target, addr, len) == 0) { if (target_flash_erase(cur_target, addr, len) == 0)
gdb_putpacketz("OK"); gdb_putpacketz("OK");
} else { else {
flash_mode = 0; flash_mode = 0;
gdb_putpacketz("EFF"); gdb_putpacketz("EFF");
} }
@ -557,9 +564,9 @@ handle_v_packet(char *packet, int plen)
/* Write Flash Memory */ /* Write Flash Memory */
len = plen - bin; len = plen - bin;
DEBUG_GDB("Flash Write %08lX %08lX\n", addr, len); DEBUG_GDB("Flash Write %08lX %08lX\n", addr, len);
if(cur_target && target_flash_write(cur_target, addr, (void*)packet + bin, len) == 0) { if (cur_target && target_flash_write(cur_target, addr, (void*)packet + bin, len) == 0)
gdb_putpacketz("OK"); gdb_putpacketz("OK");
} else { else {
flash_mode = 0; flash_mode = 0;
gdb_putpacketz("EFF"); gdb_putpacketz("EFF");
} }
@ -591,13 +598,12 @@ handle_z_packet(char *packet, int plen)
else else
ret = target_breakwatch_clear(cur_target, type, addr, len); ret = target_breakwatch_clear(cur_target, type, addr, len);
if (ret < 0) { if (ret < 0)
gdb_putpacketz("E01"); gdb_putpacketz("E01");
} else if (ret > 0) { else if (ret > 0)
gdb_putpacketz(""); gdb_putpacketz("");
} else { else
gdb_putpacketz("OK"); gdb_putpacketz("OK");
}
} }
void gdb_main(void) void gdb_main(void)

View File

@ -37,7 +37,7 @@ int gdb_getpacket(char *packet, int size)
char recv_csum[3]; char recv_csum[3];
int i; int i;
while(1) { while (1) {
/* Wait for packet start */ /* Wait for packet start */
do { do {
/* Spin waiting for a start of packet character - either a gdb /* Spin waiting for a start of packet character - either a gdb
@ -45,38 +45,39 @@ int gdb_getpacket(char *packet, int size)
*/ */
do { do {
packet[0] = gdb_if_getchar(); packet[0] = gdb_if_getchar();
if (packet[0]==0x04) return 1; if (packet[0] == 0x04)
return 1;
} while ((packet[0] != '$') && (packet[0] != REMOTE_SOM)); } while ((packet[0] != '$') && (packet[0] != REMOTE_SOM));
#if PC_HOSTED == 0 #if PC_HOSTED == 0
if (packet[0]==REMOTE_SOM) { if (packet[0] == REMOTE_SOM) {
/* This is probably a remote control packet /* This is probably a remote control packet
* - get and handle it */ * - get and handle it */
i=0; i = 0;
bool gettingRemotePacket=true; bool gettingRemotePacket = true;
while (gettingRemotePacket) { while (gettingRemotePacket) {
c=gdb_if_getchar(); c = gdb_if_getchar();
switch (c) { switch (c) {
case REMOTE_SOM: /* Oh dear, packet restarts */ case REMOTE_SOM: /* Oh dear, packet restarts */
i=0; i = 0;
break; break;
case REMOTE_EOM: /* Complete packet for processing */ case REMOTE_EOM: /* Complete packet for processing */
packet[i]=0; packet[i] = 0;
remotePacketProcess(i,packet); remotePacketProcess(i, packet);
gettingRemotePacket=false; gettingRemotePacket = false;
break; break;
case '$': /* A 'real' gdb packet, best stop squatting now */ case '$': /* A 'real' gdb packet, best stop squatting now */
packet[0]='$'; packet[0] = '$';
gettingRemotePacket=false; gettingRemotePacket = false;
break; break;
default: default:
if (i<size) { if (i < size) {
packet[i++]=c; packet[i++] = c;
} else { } else {
/* Who knows what is going on...return to normality */ /* Who knows what is going on...return to normality */
gettingRemotePacket=false; gettingRemotePacket = false;
} }
break; break;
} }
@ -91,18 +92,20 @@ int gdb_getpacket(char *packet, int size)
#endif #endif
} while (packet[0] != '$'); } while (packet[0] != '$');
i = 0; csum = 0; i = 0;
csum = 0;
/* Capture packet data into buffer */ /* Capture packet data into buffer */
while((c = gdb_if_getchar()) != '#') { while ((c = gdb_if_getchar()) != '#') {
if(i == size) break; /* Oh shit */ if (i == size) /* Oh shit */
break;
if(c == '$') { /* Restart capture */ if (c == '$') { /* Restart capture */
i = 0; i = 0;
csum = 0; csum = 0;
continue; continue;
} }
if(c == '}') { /* escaped char */ if (c == '}') { /* escaped char */
c = gdb_if_getchar(); c = gdb_if_getchar();
csum += c + '}'; csum += c + '}';
packet[i++] = c ^ 0x20; packet[i++] = c ^ 0x20;
@ -116,7 +119,8 @@ int gdb_getpacket(char *packet, int size)
recv_csum[2] = 0; recv_csum[2] = 0;
/* return packet if checksum matches */ /* return packet if checksum matches */
if(csum == strtol(recv_csum, NULL, 16)) break; if (csum == strtol(recv_csum, NULL, 16))
break;
/* get here if checksum fails */ /* get here if checksum fails */
gdb_if_putchar('-', 1); /* send nack */ gdb_if_putchar('-', 1); /* send nack */
@ -140,23 +144,24 @@ int gdb_getpacket(char *packet, int size)
static void gdb_next_char(char c, unsigned char *csum) static void gdb_next_char(char c, unsigned char *csum)
{ {
#if PC_HOSTED == 1 #if PC_HOSTED == 1
if ((c >= 32) && (c < 127)) if ((c >= 32) && (c < 127))
DEBUG_GDB_WIRE("%c", c); DEBUG_GDB_WIRE("%c", c);
else else
DEBUG_GDB_WIRE("\\x%02X", c); DEBUG_GDB_WIRE("\\x%02X", c);
#endif #endif
if((c == '$') || (c == '#') || (c == '}') || (c == '*')) { if ((c == '$') || (c == '#') || (c == '}') || (c == '*')) {
gdb_if_putchar('}', 0); gdb_if_putchar('}', 0);
gdb_if_putchar(c ^ 0x20, 0); gdb_if_putchar(c ^ 0x20, 0);
*csum += '}' + (c ^ 0x20); *csum += '}' + (c ^ 0x20);
} else { }
gdb_if_putchar(c, 0); else {
*csum += c; gdb_if_putchar(c, 0);
} *csum += c;
}
} }
void gdb_putpacket2(const char *packet1, int size1,const char *packet2, int size2) void gdb_putpacket2(const char *packet1, int size1, const char *packet2, int size2)
{ {
int i; int i;
unsigned char csum; unsigned char csum;
@ -168,18 +173,19 @@ void gdb_putpacket2(const char *packet1, int size1,const char *packet2, int size
csum = 0; csum = 0;
gdb_if_putchar('$', 0); gdb_if_putchar('$', 0);
for(i = 0; i < size1; i++) for (i = 0; i < size1; ++i)
gdb_next_char( packet1[i],&csum); gdb_next_char(packet1[i], &csum);
for(i = 0; i < size2; i++) for (i = 0; i < size2; ++i)
gdb_next_char( packet2[i],&csum); gdb_next_char(packet2[i], &csum);
gdb_if_putchar('#', 0); gdb_if_putchar('#', 0);
snprintf(xmit_csum, sizeof(xmit_csum), "%02X", csum); snprintf(xmit_csum, sizeof(xmit_csum), "%02X", csum);
gdb_if_putchar(xmit_csum[0], 0); gdb_if_putchar(xmit_csum[0], 0);
gdb_if_putchar(xmit_csum[1], 1); gdb_if_putchar(xmit_csum[1], 1);
DEBUG_GDB_WIRE("\n"); DEBUG_GDB_WIRE("\n");
} while((gdb_if_getchar_to(2000) != '+') && (tries++ < 3)); } while ((gdb_if_getchar_to(2000) != '+') && (tries++ < 3));
} }
void gdb_putpacket(const char *packet, int size) void gdb_putpacket(const char *packet, int size)
{ {
int i; int i;
@ -191,14 +197,14 @@ void gdb_putpacket(const char *packet, int size)
DEBUG_GDB_WIRE("%s : ", __func__); DEBUG_GDB_WIRE("%s : ", __func__);
csum = 0; csum = 0;
gdb_if_putchar('$', 0); gdb_if_putchar('$', 0);
for(i = 0; i < size; i++) for (i = 0; i < size; ++i)
gdb_next_char(packet[i],&csum); gdb_next_char(packet[i], &csum);
gdb_if_putchar('#', 0); gdb_if_putchar('#', 0);
snprintf(xmit_csum, sizeof(xmit_csum), "%02X", csum); snprintf(xmit_csum, sizeof(xmit_csum), "%02X", csum);
gdb_if_putchar(xmit_csum[0], 0); gdb_if_putchar(xmit_csum[0], 0);
gdb_if_putchar(xmit_csum[1], 1); gdb_if_putchar(xmit_csum[1], 1);
DEBUG_GDB_WIRE("\n"); DEBUG_GDB_WIRE("\n");
} while((gdb_if_getchar_to(2000) != '+') && (tries++ < 3)); } while ((gdb_if_getchar_to(2000) != '+') && (tries++ < 3));
} }
void gdb_putpacket_f(const char *fmt, ...) void gdb_putpacket_f(const char *fmt, ...)
@ -216,12 +222,13 @@ void gdb_putpacket_f(const char *fmt, ...)
void gdb_out(const char *buf) void gdb_out(const char *buf)
{ {
char *hexdata; int l = strlen(buf);
char *hexdata = calloc(1, 2 * l + 1);
int l=strlen(buf); if (!hexdata)
hexdata = alloca(2*l+1); return;
hexify(hexdata, buf, l); hexify(hexdata, buf, l);
gdb_putpacket2("O",1,hexdata, 2*l); gdb_putpacket2("O", 1, hexdata, 2 * l);
free(hexdata);
} }
void gdb_voutf(const char *fmt, va_list ap) void gdb_voutf(const char *fmt, va_list ap)

View File

@ -25,7 +25,7 @@
int gdb_getpacket(char *packet, int size); int gdb_getpacket(char *packet, int size);
void gdb_putpacket(const char *packet, int size); void gdb_putpacket(const char *packet, int size);
void gdb_putpacket2(const char *packet1, int size1,const char *packet2, int size2); void gdb_putpacket2(const char *packet1, int size1, const char *packet2, int size2);
#define gdb_putpacketz(packet) gdb_putpacket((packet), strlen(packet)) #define gdb_putpacketz(packet) gdb_putpacket((packet), strlen(packet))
void gdb_putpacket_f(const char *packet, ...); void gdb_putpacket_f(const char *packet, ...);

View File

@ -429,23 +429,6 @@ static bool cortexm_prepare(ADIv5_AP_t *ap)
return false; return false;
} }
} }
/* Apply device specific settings for successfull Romtable scan
*
* STM32F7 in WFI will not read ROMTABLE when using WFI
*/
if ((ap->dp->targetid >> 1 & 0x7ff) == 0x20) {
uint32_t dbgmcu_cr = 7;
uint32_t dbgmcu_cr_addr = 0xE0042004;
switch ((ap->dp->targetid >> 16) & 0xfff) {
case 0x449:
case 0x451:
case 0x452:
ap->ap_storage = adiv5_mem_read32(ap, dbgmcu_cr_addr);
dbgmcu_cr = ap->ap_storage | 7;
adiv5_mem_write(ap, dbgmcu_cr_addr, &dbgmcu_cr, sizeof(dbgmcu_cr));
break;
}
}
return true; return true;
} }

View File

@ -55,6 +55,9 @@
#include <fcntl.h> #include <fcntl.h>
#endif #endif
#define PROBE(x) \
do { if ((x)(t)) {return true;} else target_check_error(t); } while (0)
static const char cortexm_driver_str[] = "ARM Cortex-M"; static const char cortexm_driver_str[] = "ARM Cortex-M";
static bool cortexm_vector_catch(target *t, int argc, char *argv[]); static bool cortexm_vector_catch(target *t, int argc, char *argv[]);
@ -209,6 +212,17 @@ static const char tdesc_cortex_mf[] =
" </feature>" " </feature>"
"</target>"; "</target>";
/*
Probe STM32F103 clones
*/
static bool stm32f1_clones_probe(target *t)
{
PROBE(ch32f1_probe);
PROBE(stm32f1_probe); /* Care for other STM32F1 clones (?) */
return false;
}
ADIv5_AP_t *cortexm_ap(target *t) ADIv5_AP_t *cortexm_ap(target *t)
{ {
return ((struct cortexm_priv *)t->priv)->ap; return ((struct cortexm_priv *)t->priv)->ap;
@ -378,8 +392,6 @@ bool cortexm_probe(ADIv5_AP_t *ap)
} else { } else {
target_check_error(t); target_check_error(t);
} }
#define PROBE(x) \
do { if ((x)(t)) {return true;} else target_check_error(t); } while (0)
switch (ap->ap_designer) { switch (ap->ap_designer) {
case AP_DESIGNER_FREESCALE: case AP_DESIGNER_FREESCALE:
@ -442,7 +454,7 @@ bool cortexm_probe(ADIv5_AP_t *ap)
PROBE(rp_probe); PROBE(rp_probe);
PROBE(lpc11xx_probe); /* LPC8 */ PROBE(lpc11xx_probe); /* LPC8 */
} else if (ap->ap_partno == 0x4c3) { /* Cortex-M3 ROM */ } else if (ap->ap_partno == 0x4c3) { /* Cortex-M3 ROM */
PROBE(stm32f1_probe); /* Care for STM32F1 clones */ PROBE(stm32f1_clones_probe); /* Care for STM32F1 clones */
PROBE(lpc15xx_probe); /* Thanks to JojoS for testing */ PROBE(lpc15xx_probe); /* Thanks to JojoS for testing */
} else if (ap->ap_partno == 0x471) { /* Cortex-M0 ROM */ } else if (ap->ap_partno == 0x471) { /* Cortex-M0 ROM */
PROBE(lpc11xx_probe); /* LPC24C11 */ PROBE(lpc11xx_probe); /* LPC24C11 */

View File

@ -97,7 +97,9 @@ static int stm32f1_flash_write(struct target_flash *f,
#define FLASHSIZE 0x1FFFF7E0 #define FLASHSIZE 0x1FFFF7E0
#define FLASHSIZE_F0 0x1FFFF7CC #define FLASHSIZE_F0 0x1FFFF7CC
//
#include "stm32f1_ch32.c"
//
static void stm32f1_add_flash(target *t, static void stm32f1_add_flash(target *t,
uint32_t addr, size_t length, size_t erasesize) uint32_t addr, size_t length, size_t erasesize)
{ {

338
src/target/stm32f1_ch32.c Normal file
View File

@ -0,0 +1,338 @@
/*
* This file is part of the Black Magic Debug project.
*
* Copyright (C) 2022 Black Sphere Technologies Ltd.
* See CH32 Sample code from WCH StdPeriphLib_CH32F1/Examples/FLASH/FLASH_Program
*
* The CH32 seems to like the EOP bit to be cleared at the end of erase/flash operation
* The following code works fine in BMP hosted mode
* It does NOT work with a real BMP, only the first 128 bytes block is successfully written
*
*/
#if PC_HOSTED == 1
#define DEBUG_CH DEBUG_INFO
#define ERROR_CH DEBUG_WARN
#else
#define DEBUG_CH(...) {} //DEBUG_WARN //(...) {}
#define ERROR_CH DEBUG_WARN //DEBUG_WARN
#endif
static int ch32f1_flash_erase(struct target_flash *f,
target_addr addr, size_t len);
static int ch32f1_flash_write(struct target_flash *f,
target_addr dest, const void *src, size_t len);
#define FLASH_MODEKEYR_CH32 (FPEC_BASE+0x24) // Fast mode for CH32F10x
#define FLASH_CR_FLOCK_CH32 (1<<15) // fast unlock
#define FLASH_CR_FTPG_CH32 (1<<16) // fast page program
#define FLASH_CR_FTER_CH32 (1<<17) // fast page erase
#define FLASH_CR_BUF_LOAD_CH32 (1<<18) // Buffer load
#define FLASH_CR_BUF_RESET_CH32 (1<<19) // Buffer reset
#define FLASH_SR_EOP (1<<5) // End of programming
#define FLASH_BEGIN_ADDRESS_CH32 0x8000000
#define FLASH_MAGIC (FPEC_BASE+0x34)
static volatile uint32_t magic,sr,ct;
/**
\fn ch32f1_add_flash
\brief "fast" flash driver for CH32F10x chips
*/
static void ch32f1_add_flash(target *t, uint32_t addr, size_t length, size_t erasesize)
{
struct target_flash *f = calloc(1, sizeof(*f));
if (!f) { /* calloc failed: heap exhaustion */
DEBUG_WARN("calloc: failed in %s\n", __func__);
return;
}
f->start = addr;
f->length = length;
f->blocksize = erasesize;
f->erase = ch32f1_flash_erase;
f->write = ch32f1_flash_write;
f->buf_size = erasesize;
f->erased = 0xff;
target_add_flash(t, f);
}
#define WAIT_BUSY() do { \
sr = target_mem_read32(t, FLASH_SR); \
if(target_check_error(t)) { \
ERROR_CH("ch32f1 flash write: comm error\n"); \
return -1; \
} \
} while (sr & FLASH_SR_BSY);
#define WAIT_EOP() do { \
sr = target_mem_read32(t, FLASH_SR); \
if(target_check_error(t)) { \
ERROR_CH("ch32f1 flash write: comm error\n"); \
return -1; \
} \
} while (!(sr & FLASH_SR_EOP));
#define CLEAR_EOP() target_mem_write32(t, FLASH_SR,FLASH_SR_EOP)
#define SET_CR(bit) { ct = target_mem_read32(t, FLASH_CR); \
ct|=(bit); \
target_mem_write32(t, FLASH_CR, ct);}
#define CLEAR_CR(bit) {ct = target_mem_read32(t, FLASH_CR); \
ct&=~(bit); \
target_mem_write32(t, FLASH_CR, ct);}
// Which one is the right value ?
#define MAGIC_WORD 0x100
// #define MAGIC_WORD 0x100
#define MAGIC(adr) { magic=target_mem_read32(t,(adr) ^ MAGIC_WORD); \
target_mem_write32(t, FLASH_MAGIC , magic); }
/**
\fn ch32f1_flash_unlock
\brief unlock ch32f103 in fast mode
*/
static int ch32f1_flash_unlock(target *t)
{
DEBUG_CH("CH32: flash unlock \n");
target_mem_write32(t, FLASH_KEYR , KEY1);
target_mem_write32(t, FLASH_KEYR , KEY2);
// fast mode
target_mem_write32(t, FLASH_MODEKEYR_CH32 , KEY1);
target_mem_write32(t, FLASH_MODEKEYR_CH32 , KEY2);
uint32_t cr = target_mem_read32(t, FLASH_CR);
if (cr & FLASH_CR_FLOCK_CH32)
{
ERROR_CH("Fast unlock failed, cr: 0x%08" PRIx32 "\n", cr);
return -1;
}
return 0;
}
static int ch32f1_flash_lock(target *t)
{
DEBUG_CH("CH32: flash lock \n");
SET_CR(FLASH_CR_LOCK);
return 0;
}
/**
\brief identify the ch32f1 chip
Actually grab all cortex m3 with designer = arm not caught earlier...
*/
bool ch32f1_probe(target *t)
{
t->idcode = target_mem_read32(t, DBGMCU_IDCODE) & 0xfff;
if ((t->cpuid & CPUID_PARTNO_MASK) != CORTEX_M3)
return false;
if(t->idcode !=0x410) { // only ch32f103
return false;
}
// try to flock
ch32f1_flash_lock(t);
// if this fails it is not a CH32 chip
if(ch32f1_flash_unlock(t)) {
return false;
}
uint32_t signature= target_mem_read32(t, FLASHSIZE);
uint32_t flashSize=signature & 0xFFFF;
target_add_ram(t, 0x20000000, 0x5000);
ch32f1_add_flash(t, FLASH_BEGIN_ADDRESS_CH32, flashSize*1024, 128);
target_add_commands(t, stm32f1_cmd_list, "STM32 LD/MD/VL-LD/VL-MD");
t->driver = "CH32F1 medium density (stm32f1 clone)";
// make sure we have 2 wait states
//target_mem_write32(t, FLASH_ACR,2);
return true;
}
/**
\fn ch32f1_flash_erase
\brief fast erase of CH32
*/
int ch32f1_flash_erase (struct target_flash *f, target_addr addr, size_t len)
{
target *t = f->t;
DEBUG_CH("CH32: flash erase \n");
// Make sure we have 2 wait states, prefetch disabled
//target_mem_write32(t, FLASH_ACR , 2);
if (ch32f1_flash_unlock(t)) {
ERROR_CH("CH32: Unlock failed\n");
return -1;
}
// Fast Erase 128 bytes pages (ch32 mode)
while(len) {
SET_CR(FLASH_CR_FTER_CH32);// CH32 PAGE_ER
/* write address to FMA */
target_mem_write32(t, FLASH_AR , addr);
/* Flash page erase start instruction */
SET_CR( FLASH_CR_STRT );
WAIT_EOP();
CLEAR_EOP();
CLEAR_CR( FLASH_CR_STRT );
// Magic
MAGIC(addr);
if (len > 128)
len -= 128;
else
len = 0;
addr += 128;
}
sr = target_mem_read32(t, FLASH_SR);
ch32f1_flash_lock(t);
if ((sr & SR_ERROR_MASK)) {
ERROR_CH("ch32f1 flash erase error 0x%" PRIx32 "\n", sr);
return -1;
}
return 0;
}
/**
\fn waitFlashReady
\brief poll the beginning of a block till it is fffff, meaning we can proceeed
*/
static bool waitFlashReady(target *t,uint32_t adr)
{
// Wait a bit
// the # of cycles needed to do N read access over SWD
// the actual number is around 10
// then check we do read ffff (/!\ even if we read ffff it does not mean its ok
// these are the data from the previous operation and they could be ffff)
uint32_t ff;
for(int i=0;i<32;i++) ff=target_mem_read32(t,adr);
if(ff!=0xffffffffUL) {
ERROR_CH("ch32f1 Not erased properly at %x or flash access issue\n",adr);
return false;
}
return true;
}
/**
\fn ch32f1_flash_write
\brief fast flash for ch32. Load 128 bytes chunk and then flash them
*/
static int upload(target *t, uint32_t dest, const void *src, uint32_t offset)
{
const uint32_t *ss=(const uint32_t *)(src+offset);
uint32_t dd=dest+offset;
SET_CR(FLASH_CR_FTPG_CH32);
target_mem_write32(t, dd+0,ss[0]);
target_mem_write32(t, dd+4,ss[1]);
target_mem_write32(t, dd+8,ss[2]);
target_mem_write32(t, dd+12,ss[3]);
SET_CR(FLASH_CR_BUF_LOAD_CH32); /* BUF LOAD */
WAIT_EOP();
CLEAR_EOP();
CLEAR_CR(FLASH_CR_FTPG_CH32);
MAGIC((dest+offset));
return 0;
}
/**
\fn ch32_buffer_clear
\brief clear the write buffer
*/
int ch32_buffer_clear(target *t)
{
SET_CR(FLASH_CR_FTPG_CH32); // Fast page program 4-
SET_CR(FLASH_CR_BUF_RESET_CH32); // BUF_RESET 5-
WAIT_BUSY(); // 6-
CLEAR_CR(FLASH_CR_FTPG_CH32); // Fast page program 4-
return 0;
}
#define CH32_VERIFY
/**
*/
static int ch32f1_flash_write(struct target_flash *f,
target_addr dest, const void *src, size_t len)
{
target *t = f->t;
size_t length = len;
#ifdef CH32_VERIFY
target_addr orgDest=dest;
const void *orgSrc=src;
#endif
DEBUG_CH("CH32: flash write 0x%x ,size=%d\n",dest,len);
while(length>0)
{
if(ch32f1_flash_unlock(t)) {
ERROR_CH("ch32f1 cannot fast unlock\n");
return -1;
}
WAIT_BUSY();
// Buffer reset...
ch32_buffer_clear(t);
// Load 128 bytes to buffer
if(!waitFlashReady(t,dest)) {
return -1;
}
for(int i=0;i<8;i++) {
if(upload(t,dest,src, 16*i)) {
ERROR_CH("Cannot upload to buffer\n");
return -1;
}
}
// write buffer
SET_CR(FLASH_CR_FTPG_CH32);
target_mem_write32(t, FLASH_AR, dest); // 10
SET_CR(FLASH_CR_STRT); // 11 Start
WAIT_EOP(); // 12
CLEAR_EOP();
CLEAR_CR(FLASH_CR_FTPG_CH32);
MAGIC((dest));
// next
if(length>128)
length-=128;
else
length=0;
dest+=128;
src+=128;
sr = target_mem_read32(t, FLASH_SR); // 13
ch32f1_flash_lock(t);
if ((sr & SR_ERROR_MASK) ) {
ERROR_CH("ch32f1 flash write error 0x%" PRIx32 "\n", sr);
return -1;
}
}
#ifdef CH32_VERIFY
DEBUG_CH("Verifying\n");
int i=0;
for(i=0;i<(int)len;i+=4)
{
uint32_t mem=target_mem_read32(t, orgDest+i);
uint32_t mem2=*(uint32_t *)(orgSrc+i);
if(mem!=mem2)
{
ERROR_CH(">>>>write mistmatch at address 0x%x\n",orgDest+i);
ERROR_CH(">>>>expected 0x%x\n",mem2);
ERROR_CH(">>>>flash 0x%x\n",mem);
return -1;
}
}
#endif
return 0;
}
// EOF

View File

@ -110,6 +110,10 @@ static int stm32f4_flash_write(struct target_flash *f,
#define AXIM_BASE 0x8000000 #define AXIM_BASE 0x8000000
#define ITCM_BASE 0x0200000 #define ITCM_BASE 0x0200000
#define DBGMCU_CR_DBG_SLEEP (0x1U << 0U)
#define DBGMCU_CR_DBG_STOP (0x1U << 1U)
#define DBGMCU_CR_DBG_STANDBY (0x1U << 2U)
struct stm32f4_flash { struct stm32f4_flash {
struct target_flash f; struct target_flash f;
enum align psize; enum align psize;
@ -117,6 +121,10 @@ struct stm32f4_flash {
uint8_t bank_split; uint8_t bank_split;
}; };
struct stm32f4_priv_s {
uint32_t dbgmcu_cr;
};
enum IDS_STM32F247 { enum IDS_STM32F247 {
ID_STM32F20X = 0x411, ID_STM32F20X = 0x411,
ID_STM32F40X = 0x413, ID_STM32F40X = 0x413,
@ -194,10 +202,12 @@ static char *stm32f4_get_chip_name(uint32_t idcode)
} }
} }
static void stm32f7_detach(target *t) static void stm32f4_detach(target *t)
{ {
ADIv5_AP_t *ap = cortexm_ap(t); struct stm32f4_priv_s *ps = (struct stm32f4_priv_s*)t->target_storage;
target_mem_write32(t, DBGMCU_CR, ap->ap_storage);
/*reverse all changes to DBGMCU_CR*/
target_mem_write32(t, DBGMCU_CR, ps->dbgmcu_cr);
cortexm_detach(t); cortexm_detach(t);
} }
@ -214,8 +224,6 @@ bool stm32f4_probe(target *t)
case ID_STM32F74X: /* F74x RM0385 Rev.4 */ case ID_STM32F74X: /* F74x RM0385 Rev.4 */
case ID_STM32F76X: /* F76x F77x RM0410 */ case ID_STM32F76X: /* F76x F77x RM0410 */
case ID_STM32F72X: /* F72x F73x RM0431 */ case ID_STM32F72X: /* F72x F73x RM0431 */
t->detach = stm32f7_detach;
/* fall through */
case ID_STM32F40X: case ID_STM32F40X:
case ID_STM32F42X: /* 427/437 */ case ID_STM32F42X: /* 427/437 */
case ID_STM32F46X: /* 469/479 */ case ID_STM32F46X: /* 469/479 */
@ -226,6 +234,7 @@ bool stm32f4_probe(target *t)
case ID_STM32F412: /* F412 RM0402 Rev.4, 256 kB Ram */ case ID_STM32F412: /* F412 RM0402 Rev.4, 256 kB Ram */
case ID_STM32F401E: /* F401 D/E RM0368 Rev.3 */ case ID_STM32F401E: /* F401 D/E RM0368 Rev.3 */
case ID_STM32F413: /* F413 RM0430 Rev.2, 320 kB Ram, 1.5 MB flash. */ case ID_STM32F413: /* F413 RM0430 Rev.2, 320 kB Ram, 1.5 MB flash. */
t->detach = stm32f4_detach;
t->driver = stm32f4_get_chip_name(t->idcode); t->driver = stm32f4_get_chip_name(t->idcode);
t->attach = stm32f4_attach; t->attach = stm32f4_attach;
target_add_commands(t, stm32f4_cmd_list, t->driver); target_add_commands(t, stm32f4_cmd_list, t->driver);
@ -295,6 +304,19 @@ static bool stm32f4_attach(target *t)
return false; return false;
} }
bool use_dual_bank = false; bool use_dual_bank = false;
/* Save DBGMCU_CR to restore it when detaching*/
struct stm32f4_priv_s *priv_storage = calloc(1, sizeof(*priv_storage));
if (!priv_storage) { /* calloc failed: heap exhaustion */
DEBUG_WARN("calloc: failed in %s\n", __func__);
return false;
}
priv_storage->dbgmcu_cr = target_mem_read32(t, DBGMCU_CR);
t->target_storage = (void*)priv_storage;
/* Enable debugging during all low power modes*/
target_mem_write32(t, DBGMCU_CR, priv_storage->dbgmcu_cr |
DBGMCU_CR_DBG_SLEEP | DBGMCU_CR_DBG_STANDBY | DBGMCU_CR_DBG_STOP);
/* Free previously loaded memory map */
target_mem_map_free(t); target_mem_map_free(t);
if (is_f7) { if (is_f7) {
target_add_ram(t, 0x00000000, 0x4000); /* 16 k ITCM Ram */ target_add_ram(t, 0x00000000, 0x4000); /* 16 k ITCM Ram */

View File

@ -173,6 +173,7 @@ int tc_system(target *t, target_addr cmd, size_t cmdlen);
/* Probe for various targets. /* Probe for various targets.
* Actual functions implemented in their respective drivers. * Actual functions implemented in their respective drivers.
*/ */
bool ch32f1_probe(target *t); // will catch all the clones
bool gd32f1_probe(target *t); bool gd32f1_probe(target *t);
bool stm32f1_probe(target *t); bool stm32f1_probe(target *t);
bool stm32f4_probe(target *t); bool stm32f4_probe(target *t);