diff --git a/src/gdb_main.c b/src/gdb_main.c index 7901f215..7e84d24c 100644 --- a/src/gdb_main.c +++ b/src/gdb_main.c @@ -51,12 +51,10 @@ enum gdb_signal { typedef struct { const char *cmd_prefix; - void (*func)(const char *packet,int len); -}cmd_executer; + void (*func)(const char *packet, int len); +} cmd_executer; - - -static char pbuf[BUF_SIZE+1]; +static char pbuf[BUF_SIZE + 1]; static target *cur_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)), sizeof(arm_regs) * 2); break; - } + } case 'm': { /* 'm addr,len': Read len bytes from addr */ uint32_t addr, len; 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)) gdb_putpacketz("E01"); else - gdb_putpacket(hexify(pbuf, mem, len), len*2); + 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)]; @@ -144,7 +142,7 @@ int gdb_main_loop(struct target_controller *tc, bool in_syscall) 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; @@ -163,7 +161,7 @@ int gdb_main_loop(struct target_controller *tc, bool in_syscall) else gdb_putpacketz("OK"); break; - } + } case 's': /* 's [addr]': Single step [start at addr] */ single_step = true; /* fall through */ @@ -217,7 +215,7 @@ int gdb_main_loop(struct target_controller *tc, bool in_syscall) gdb_putpacket_f("T%02X", GDB_SIGTRAP); } break; - } + } /* Optional GDB packet support */ case 'p': { /* Read single register */ @@ -226,32 +224,31 @@ int gdb_main_loop(struct target_controller *tc, bool in_syscall) sscanf(pbuf, "p%" SCNx32, ®); uint8_t val[8]; 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); - } else { + else gdb_putpacketz("EFF"); - } break; - } + } case 'P': { /* Write single register */ ERROR_IF_NO_TARGET(); uint32_t reg; int n; sscanf(pbuf, "P%" SCNx32 "=%n", ®, &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)); - 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"); - } else { + else gdb_putpacketz("EFF"); - } break; - } + } case 'F': /* Semihosting call finished */ - if (in_syscall) { + if (in_syscall) return hostio_reply(tc, pbuf, size); - } else { + else { DEBUG_GDB("*** F packet when not in syscall! '%s'\n", pbuf); 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", 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"); else gdb_putpacketz("OK"); break; - } + } case 'q': /* General query packet */ 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) { - int l=strlen(exec->cmd_prefix); - if(!strncmp(packet,exec->cmd_prefix,l)) { - exec->func(packet+l,len-l); + while (exec->cmd_prefix) { + const int l = strlen(exec->cmd_prefix); + if (!strncmp(packet, exec->cmd_prefix, l)) { + exec->func(packet + l, len - l); return true; } - exec++; + ++exec; } return false; } static void exec_q_rcmd(const char *packet,int len) { -char *data; -int datalen; + char *data; + int datalen; /* calculate size and allocate buffer for command */ - datalen = len/ 2; - data = alloca(datalen+1); + datalen = len / 2; + data = alloca(datalen + 1); /* dehexify command */ unhexify(data, packet, datalen); data[datalen] = 0; /* add terminating null */ int c = command_process(cur_target, data); - if(c < 0) + if (c < 0) gdb_putpacketz(""); - else if(c == 0) + else if (c == 0) gdb_putpacketz("OK"); else 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) { unsigned long addr, len; + const size_t str_len = strlen(str); if (sscanf(param, "%08lx,%08lx", &addr, &len) != 2) { gdb_putpacketz("E01"); return; } - if (addr > strlen (str)) { + else if (addr > str_len) { gdb_putpacketz("E01"); return; } - if(addr== strlen (str)) { + else if (addr == str_len) { gdb_putpacketz("l"); return; } - unsigned long output_len=strlen(str)-addr; - if(output_len>len) output_len=len; - gdb_putpacket2("m",1,str+addr,output_len); + unsigned long output_len = str_len - addr; + if (output_len > len) + output_len = len; + gdb_putpacket2("m", 1, str + addr, output_len); } + static void exec_q_supported(const char *packet, int len) { (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); } -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)len; /* Read target XML memory map */ - if((!cur_target) && last_target) { + if ((!cur_target) && last_target) { /* Attach to last target if detached. */ cur_target = target_attach(last_target, &gdb_controller); @@ -423,7 +424,7 @@ static void exec_q_feature_read(const char *packet, int len) { (void)len; /* Read target description */ - if((!cur_target) && last_target) { + if ((!cur_target) && last_target) { /* Attach to last target if detached. */ 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"); 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) @@ -439,7 +440,7 @@ static void exec_q_crc(const char *packet, int len) (void)len; uint32_t addr, alen; if (sscanf(packet, "%" PRIx32 ",%" PRIx32, &addr, &alen) == 2) { - if(!cur_target) { + if (!cur_target) { gdb_putpacketz("E01"); return; } @@ -451,6 +452,7 @@ static void exec_q_crc(const char *packet, int len) gdb_putpacket_f("C%lx", crc); } } + static const cmd_executer q_commands[]= { {"qRcmd,", exec_q_rcmd}, @@ -458,16 +460,14 @@ static const cmd_executer q_commands[]= {"qXfer:memory-map:read::", exec_q_memory_map}, {"qXfer:features:read:target.xml:",exec_q_feature_read}, {"qCRC:", exec_q_crc}, - - {NULL,NULL}, + {NULL, NULL}, }; static void handle_q_packet(char *packet, int len) { - if(exec_command(packet,len,q_commands)) { + if (exec_command(packet, len, q_commands)) return; - } DEBUG_GDB("*** Unsupported packet: %s\n", packet); gdb_putpacket("", 0); } @@ -493,35 +493,37 @@ handle_v_packet(char *packet, int plen) char cmdline[83]; char *pcmdline = cmdline; char *tok = packet + 4; - if (*tok == ';') tok++; - *cmdline='\0'; + if (*tok == ';') + ++tok; + cmdline[0] = '\0'; while(*tok != '\0') { - if(strlen(cmdline)+3 >= sizeof(cmdline)) break; + if (strlen(cmdline) + 3 >= sizeof(cmdline)) + break; if (*tok == ';') { - *pcmdline++=' '; - *pcmdline='\0'; + *pcmdline++ = ' '; + pcmdline[0] = '\0'; tok++; continue; } - if (isxdigit(*tok) && isxdigit(*(tok+1))) { + if (isxdigit(tok[0]) && isxdigit(tok[1])) { unhexify(pcmdline, tok, 2); if ((*pcmdline == ' ') || (*pcmdline == '\\')) { - *(pcmdline+1)=*pcmdline; - *pcmdline++='\\'; + pcmdline[1] = *pcmdline; + *pcmdline++ = '\\'; } pcmdline++; - tok+=2; - *pcmdline='\0'; + tok += 2; + pcmdline[0] = '\0'; continue; } break; } /* Run target program. For us (embedded) this means reset. */ - if(cur_target) { + if (cur_target) { target_set_cmdline(cur_target, cmdline); target_reset(cur_target); gdb_putpacketz("T05"); - } else if(last_target) { + } else if (last_target) { cur_target = target_attach(last_target, &gdb_controller); @@ -531,24 +533,29 @@ handle_v_packet(char *packet, int plen) target_reset(cur_target); morse(NULL, false); 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) { /* Erase Flash Memory */ 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! */ /* This saves us if we're interrupted in IRQ context */ target_reset(cur_target); flash_mode = 1; } - if(target_flash_erase(cur_target, addr, len) == 0) { + if (target_flash_erase(cur_target, addr, len) == 0) gdb_putpacketz("OK"); - } else { + else { flash_mode = 0; gdb_putpacketz("EFF"); } @@ -557,9 +564,9 @@ handle_v_packet(char *packet, int plen) /* Write Flash Memory */ len = plen - bin; 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"); - } else { + else { flash_mode = 0; gdb_putpacketz("EFF"); } @@ -591,13 +598,12 @@ handle_z_packet(char *packet, int plen) else ret = target_breakwatch_clear(cur_target, type, addr, len); - if (ret < 0) { + if (ret < 0) gdb_putpacketz("E01"); - } else if (ret > 0) { + else if (ret > 0) gdb_putpacketz(""); - } else { + else gdb_putpacketz("OK"); - } } void gdb_main(void) diff --git a/src/gdb_packet.c b/src/gdb_packet.c index e25cd5c9..33dada53 100644 --- a/src/gdb_packet.c +++ b/src/gdb_packet.c @@ -37,7 +37,7 @@ int gdb_getpacket(char *packet, int size) char recv_csum[3]; int i; - while(1) { + while (1) { /* Wait for packet start */ do { /* Spin waiting for a start of packet character - either a gdb @@ -45,38 +45,39 @@ int gdb_getpacket(char *packet, int size) */ do { packet[0] = gdb_if_getchar(); - if (packet[0]==0x04) return 1; + if (packet[0] == 0x04) + return 1; } while ((packet[0] != '$') && (packet[0] != REMOTE_SOM)); #if PC_HOSTED == 0 - if (packet[0]==REMOTE_SOM) { + if (packet[0] == REMOTE_SOM) { /* This is probably a remote control packet * - get and handle it */ - i=0; - bool gettingRemotePacket=true; + i = 0; + bool gettingRemotePacket = true; while (gettingRemotePacket) { - c=gdb_if_getchar(); + c = gdb_if_getchar(); switch (c) { case REMOTE_SOM: /* Oh dear, packet restarts */ - i=0; + i = 0; break; case REMOTE_EOM: /* Complete packet for processing */ - packet[i]=0; - remotePacketProcess(i,packet); - gettingRemotePacket=false; + packet[i] = 0; + remotePacketProcess(i, packet); + gettingRemotePacket = false; break; case '$': /* A 'real' gdb packet, best stop squatting now */ - packet[0]='$'; - gettingRemotePacket=false; + packet[0] = '$'; + gettingRemotePacket = false; break; default: - if (i= 32) && (c < 127)) - DEBUG_GDB_WIRE("%c", c); - else - DEBUG_GDB_WIRE("\\x%02X", c); - #endif - if((c == '$') || (c == '#') || (c == '}') || (c == '*')) { - gdb_if_putchar('}', 0); - gdb_if_putchar(c ^ 0x20, 0); - *csum += '}' + (c ^ 0x20); - } else { - gdb_if_putchar(c, 0); - *csum += c; - } +#if PC_HOSTED == 1 + if ((c >= 32) && (c < 127)) + DEBUG_GDB_WIRE("%c", c); + else + DEBUG_GDB_WIRE("\\x%02X", c); +#endif + if ((c == '$') || (c == '#') || (c == '}') || (c == '*')) { + gdb_if_putchar('}', 0); + gdb_if_putchar(c ^ 0x20, 0); + *csum += '}' + (c ^ 0x20); + } + else { + 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; unsigned char csum; @@ -168,18 +173,19 @@ void gdb_putpacket2(const char *packet1, int size1,const char *packet2, int size csum = 0; gdb_if_putchar('$', 0); - for(i = 0; i < size1; i++) - gdb_next_char( packet1[i],&csum); - for(i = 0; i < size2; i++) - gdb_next_char( packet2[i],&csum); + for (i = 0; i < size1; ++i) + gdb_next_char(packet1[i], &csum); + for (i = 0; i < size2; ++i) + gdb_next_char(packet2[i], &csum); gdb_if_putchar('#', 0); snprintf(xmit_csum, sizeof(xmit_csum), "%02X", csum); gdb_if_putchar(xmit_csum[0], 0); gdb_if_putchar(xmit_csum[1], 1); 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) { int i; @@ -191,14 +197,14 @@ void gdb_putpacket(const char *packet, int size) DEBUG_GDB_WIRE("%s : ", __func__); csum = 0; gdb_if_putchar('$', 0); - for(i = 0; i < size; i++) - gdb_next_char(packet[i],&csum); + for (i = 0; i < size; ++i) + gdb_next_char(packet[i], &csum); gdb_if_putchar('#', 0); snprintf(xmit_csum, sizeof(xmit_csum), "%02X", csum); gdb_if_putchar(xmit_csum[0], 0); gdb_if_putchar(xmit_csum[1], 1); 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, ...) @@ -216,12 +222,13 @@ void gdb_putpacket_f(const char *fmt, ...) void gdb_out(const char *buf) { - char *hexdata; - - int l=strlen(buf); - hexdata = alloca(2*l+1); + int l = strlen(buf); + char *hexdata = calloc(1, 2 * l + 1); + if (!hexdata) + return; 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) diff --git a/src/include/gdb_packet.h b/src/include/gdb_packet.h index c36981c6..af23c5b2 100644 --- a/src/include/gdb_packet.h +++ b/src/include/gdb_packet.h @@ -25,7 +25,7 @@ int gdb_getpacket(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)) void gdb_putpacket_f(const char *packet, ...); diff --git a/src/target/adiv5.c b/src/target/adiv5.c index 7d167093..af6251a7 100644 --- a/src/target/adiv5.c +++ b/src/target/adiv5.c @@ -429,23 +429,6 @@ static bool cortexm_prepare(ADIv5_AP_t *ap) 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; } diff --git a/src/target/cortexm.c b/src/target/cortexm.c index 2288063e..b686d46b 100644 --- a/src/target/cortexm.c +++ b/src/target/cortexm.c @@ -55,6 +55,9 @@ #include #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 bool cortexm_vector_catch(target *t, int argc, char *argv[]); @@ -209,6 +212,17 @@ static const char tdesc_cortex_mf[] = " " ""; +/* + 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) { return ((struct cortexm_priv *)t->priv)->ap; @@ -378,8 +392,6 @@ bool cortexm_probe(ADIv5_AP_t *ap) } else { target_check_error(t); } -#define PROBE(x) \ - do { if ((x)(t)) {return true;} else target_check_error(t); } while (0) switch (ap->ap_designer) { case AP_DESIGNER_FREESCALE: @@ -442,7 +454,7 @@ bool cortexm_probe(ADIv5_AP_t *ap) PROBE(rp_probe); PROBE(lpc11xx_probe); /* LPC8 */ } 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 */ } else if (ap->ap_partno == 0x471) { /* Cortex-M0 ROM */ PROBE(lpc11xx_probe); /* LPC24C11 */ diff --git a/src/target/stm32f1.c b/src/target/stm32f1.c index 76bfb1ad..13425d1e 100644 --- a/src/target/stm32f1.c +++ b/src/target/stm32f1.c @@ -97,7 +97,9 @@ static int stm32f1_flash_write(struct target_flash *f, #define FLASHSIZE 0x1FFFF7E0 #define FLASHSIZE_F0 0x1FFFF7CC - +// +#include "stm32f1_ch32.c" +// static void stm32f1_add_flash(target *t, uint32_t addr, size_t length, size_t erasesize) { diff --git a/src/target/stm32f1_ch32.c b/src/target/stm32f1_ch32.c new file mode 100644 index 00000000..b8f5cfc1 --- /dev/null +++ b/src/target/stm32f1_ch32.c @@ -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 diff --git a/src/target/stm32f4.c b/src/target/stm32f4.c index a2bd45b2..b73c3ee9 100644 --- a/src/target/stm32f4.c +++ b/src/target/stm32f4.c @@ -110,6 +110,10 @@ static int stm32f4_flash_write(struct target_flash *f, #define AXIM_BASE 0x8000000 #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 target_flash f; enum align psize; @@ -117,6 +121,10 @@ struct stm32f4_flash { uint8_t bank_split; }; +struct stm32f4_priv_s { + uint32_t dbgmcu_cr; +}; + enum IDS_STM32F247 { ID_STM32F20X = 0x411, 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); - target_mem_write32(t, DBGMCU_CR, ap->ap_storage); + struct stm32f4_priv_s *ps = (struct stm32f4_priv_s*)t->target_storage; + + /*reverse all changes to DBGMCU_CR*/ + target_mem_write32(t, DBGMCU_CR, ps->dbgmcu_cr); cortexm_detach(t); } @@ -214,8 +224,6 @@ bool stm32f4_probe(target *t) case ID_STM32F74X: /* F74x RM0385 Rev.4 */ case ID_STM32F76X: /* F76x F77x RM0410 */ case ID_STM32F72X: /* F72x F73x RM0431 */ - t->detach = stm32f7_detach; - /* fall through */ case ID_STM32F40X: case ID_STM32F42X: /* 427/437 */ 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_STM32F401E: /* F401 D/E RM0368 Rev.3 */ 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->attach = stm32f4_attach; target_add_commands(t, stm32f4_cmd_list, t->driver); @@ -295,6 +304,19 @@ static bool stm32f4_attach(target *t) return 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); if (is_f7) { target_add_ram(t, 0x00000000, 0x4000); /* 16 k ITCM Ram */ diff --git a/src/target/target_internal.h b/src/target/target_internal.h index 17f95800..b92e1411 100644 --- a/src/target/target_internal.h +++ b/src/target/target_internal.h @@ -173,6 +173,7 @@ int tc_system(target *t, target_addr cmd, size_t cmdlen); /* Probe for various targets. * Actual functions implemented in their respective drivers. */ +bool ch32f1_probe(target *t); // will catch all the clones bool gd32f1_probe(target *t); bool stm32f1_probe(target *t); bool stm32f4_probe(target *t);