From 563df2d35464bee022b8133ea4f7bc53bd40a399 Mon Sep 17 00:00:00 2001 From: Uwe Bonnes Date: Sat, 18 Apr 2020 12:24:40 +0200 Subject: [PATCH 01/13] Detour ADIv5 high-level functions. --- src/platforms/libftdi/platform.c | 5 + src/platforms/pc-hosted/platform.c | 5 + src/platforms/pc-stlinkv2/stlinkv2.c | 43 ++++---- src/target/adiv5.c | 56 +++++++--- src/target/adiv5.h | 52 ++++++++-- src/target/cortexm.c | 150 ++++++++++++++------------- 6 files changed, 198 insertions(+), 113 deletions(-) diff --git a/src/platforms/libftdi/platform.c b/src/platforms/libftdi/platform.c index 93c89e9e..e2ceb59a 100644 --- a/src/platforms/libftdi/platform.c +++ b/src/platforms/libftdi/platform.c @@ -310,3 +310,8 @@ const char *platform_target_voltage(void) { return "not supported"; } + +void platform_adiv5_dp_defaults(void *arg) +{ + (void) arg; +} diff --git a/src/platforms/pc-hosted/platform.c b/src/platforms/pc-hosted/platform.c index 53f95ba2..4be4cde4 100644 --- a/src/platforms/pc-hosted/platform.c +++ b/src/platforms/pc-hosted/platform.c @@ -181,3 +181,8 @@ const char *platform_target_voltage(void) return (char *)&construct[1]; } + +void platform_adiv5_dp_defaults(void *arg) +{ + (void) arg; +} diff --git a/src/platforms/pc-stlinkv2/stlinkv2.c b/src/platforms/pc-stlinkv2/stlinkv2.c index b69b66a7..0d5012fd 100644 --- a/src/platforms/pc-stlinkv2/stlinkv2.c +++ b/src/platforms/pc-stlinkv2/stlinkv2.c @@ -1150,7 +1150,7 @@ uint32_t stlink_dp_low_access(ADIv5_DP_t *dp, uint8_t RnW, return response; } -bool adiv5_ap_setup(int ap) +static bool stlink_ap_setup(int ap) { if (ap > 7) return false; @@ -1172,7 +1172,7 @@ bool adiv5_ap_setup(int ap) return true; } -void adiv5_ap_cleanup(int ap) +static void stlink_ap_cleanup(int ap) { uint8_t cmd[16] = { STLINK_DEBUG_COMMAND, @@ -1195,7 +1195,7 @@ static int stlink_usb_get_rw_status(bool verbose) return stlink_usb_error_check(data, verbose); } -void stlink_readmem(ADIv5_AP_t *ap, void *dest, uint32_t src, size_t len) +static void stlink_readmem(ADIv5_AP_t *ap, void *dest, uint32_t src, size_t len) { if (len == 0) return; @@ -1246,7 +1246,7 @@ void stlink_readmem(ADIv5_AP_t *ap, void *dest, uint32_t src, size_t len) DEBUG_STLINK("\n"); } -void stlink_writemem8(ADIv5_AP_t *ap, uint32_t addr, size_t len, +static void stlink_writemem8(ADIv5_AP_t *ap, uint32_t addr, size_t len, uint8_t *buffer) { DEBUG_STLINK("Mem Write8 AP %d len %zu addr 0x%08" PRIx32 ": ", @@ -1275,7 +1275,7 @@ void stlink_writemem8(ADIv5_AP_t *ap, uint32_t addr, size_t len, } } -void stlink_writemem16(ADIv5_AP_t *ap, uint32_t addr, size_t len, +static void stlink_writemem16(ADIv5_AP_t *ap, uint32_t addr, size_t len, uint16_t *buffer) { DEBUG_STLINK("Mem Write16 AP %d len %zu addr 0x%08" PRIx32 ": ", @@ -1295,7 +1295,7 @@ void stlink_writemem16(ADIv5_AP_t *ap, uint32_t addr, size_t len, stlink_usb_get_rw_status(true); } -void stlink_writemem32(ADIv5_AP_t *ap, uint32_t addr, size_t len, +static void stlink_writemem32(ADIv5_AP_t *ap, uint32_t addr, size_t len, uint32_t *buffer) { DEBUG_STLINK("Mem Write32 AP %d len %zu addr 0x%08" PRIx32 ": ", @@ -1350,15 +1350,9 @@ void stlink_reg_write(ADIv5_AP_t *ap, int num, uint32_t val) stlink_usb_error_check(res, true); } -void -adiv5_mem_read(ADIv5_AP_t *ap, void *dest, uint32_t src, size_t len) -{ - stlink_readmem(ap, dest, src, len); -} - -void -adiv5_mem_write_sized(ADIv5_AP_t *ap, uint32_t dest, const void *src, - size_t len, enum align align) +static void stlink_mem_write_sized( ADIv5_AP_t *ap, uint32_t dest, + const void *src, size_t len, + enum align align) { if (len == 0) return; @@ -1374,12 +1368,12 @@ adiv5_mem_write_sized(ADIv5_AP_t *ap, uint32_t dest, const void *src, } } -void adiv5_ap_write(ADIv5_AP_t *ap, uint16_t addr, uint32_t value) +static void stlink_ap_write(ADIv5_AP_t *ap, uint16_t addr, uint32_t value) { - stlink_write_dp_register(ap->apsel, addr, value); + stlink_write_dp_register(ap->apsel, addr, value); } -uint32_t adiv5_ap_read(ADIv5_AP_t *ap, uint16_t addr) +static uint32_t stlink_ap_read(ADIv5_AP_t *ap, uint16_t addr) { uint32_t ret; stlink_read_dp_register(ap->apsel, addr, &ret); @@ -1426,3 +1420,16 @@ int platform_jtag_dp_init(ADIv5_DP_t *dp) return true; } + +void platform_adiv5_dp_defaults(ADIv5_DP_t *dp) +{ + dp->ap_regs_read = stlink_regs_read; + dp->ap_reg_read = stlink_reg_read; + dp->ap_reg_write = stlink_reg_write; + dp->ap_setup = stlink_ap_setup; + dp->ap_cleanup = stlink_ap_cleanup; + dp->ap_write = stlink_ap_write; + dp->ap_read = stlink_ap_read; + dp->mem_read = stlink_readmem; + dp->mem_write_sized = stlink_mem_write_sized; +} diff --git a/src/target/adiv5.c b/src/target/adiv5.c index 5f0de60b..edac3c78 100644 --- a/src/target/adiv5.c +++ b/src/target/adiv5.c @@ -399,8 +399,6 @@ static bool adiv5_component_probe(ADIv5_AP_t *ap, uint32_t addr, int recursion, } return res; } -bool adiv5_ap_setup(int i); -void adiv5_ap_cleanup(int i); ADIv5_AP_t *adiv5_new_ap(ADIv5_DP_t *dp, uint8_t apsel) { @@ -441,12 +439,32 @@ ADIv5_AP_t *adiv5_new_ap(ADIv5_DP_t *dp, uint8_t apsel) return ap; } +static void ap_write(ADIv5_AP_t *ap, uint16_t addr, uint32_t value); +static uint32_t ap_read(ADIv5_AP_t *ap, uint16_t addr); +static void mem_read(ADIv5_AP_t *ap, void *dest, uint32_t src, size_t len); +static void mem_write_sized(ADIv5_AP_t *ap, uint32_t dest, const void *src, + size_t len, enum align align); void adiv5_dp_init(ADIv5_DP_t *dp) { volatile bool probed = false; volatile uint32_t ctrlstat = 0; adiv5_dp_ref(dp); - +#if PC_HOSTED == 1 + platform_adiv5_dp_defaults(dp); + if (!dp->ap_write) + dp->ap_write = ap_write; + if (!dp->ap_read) + dp->ap_read = ap_read; + if (!dp->mem_read) + dp->mem_read = mem_read; + if (!dp->mem_write_sized) + dp->mem_write_sized = mem_write_sized; +#else + dp->ap_write = ap_write; + dp->ap_read = ap_read; + dp->mem_read = mem_read; + dp->mem_write_sized = mem_write_sized; +#endif volatile struct exception e; TRY_CATCH (e, EXCEPTION_TIMEOUT) { ctrlstat = adiv5_dp_read(dp, ADIV5_DP_CTRLSTAT); @@ -507,11 +525,18 @@ void adiv5_dp_init(ADIv5_DP_t *dp) int void_aps = 0; for(int i = 0; (i < 256) && (void_aps < 8); i++) { ADIv5_AP_t *ap = NULL; - if (adiv5_ap_setup(i)) +#if PC_HOSTED == 1 + if ((!dp->ap_setup) || dp->ap_setup(i)) ap = adiv5_new_ap(dp, i); +#else + ap = adiv5_new_ap(dp, i); +#endif if (ap == NULL) { void_aps++; - adiv5_ap_cleanup(i); +#if PC_HOSTED == 1 + if (dp->ap_cleanup) + dp->ap_cleanup(i); +#endif if (i == 0) return; else @@ -519,7 +544,10 @@ void adiv5_dp_init(ADIv5_DP_t *dp) } if (ap->base == last_base) { DEBUG("AP %d: Duplicate base\n", i); - adiv5_ap_cleanup(i); +#if PC_HOSTED == 1 + if (dp->ap_cleanup) + dp->ap_cleanup(i); +#endif free(ap); /* FIXME: Should we expect valid APs behind duplicate ones? */ return; @@ -562,11 +590,6 @@ void adiv5_dp_init(ADIv5_DP_t *dp) #define ALIGNOF(x) (((x) & 3) == 0 ? ALIGN_WORD : \ (((x) & 1) == 0 ? ALIGN_HALFWORD : ALIGN_BYTE)) -#if !defined(JTAG_HL) - -bool adiv5_ap_setup(int i) {(void)i; return true;} -void adiv5_ap_cleanup(int i) {(void)i;} - /* Program the CSW and TAR for sequencial access at a given width */ static void ap_mem_access_setup(ADIv5_AP_t *ap, uint32_t addr, enum align align) { @@ -606,7 +629,7 @@ void * extract(void *dest, uint32_t src, uint32_t val, enum align align) return (uint8_t *)dest + (1 << align); } -void adiv5_mem_read(ADIv5_AP_t *ap, void *dest, uint32_t src, size_t len) +static void mem_read(ADIv5_AP_t *ap, void *dest, uint32_t src, size_t len) { uint32_t tmp; uint32_t osrc = src; @@ -636,8 +659,8 @@ void adiv5_mem_read(ADIv5_AP_t *ap, void *dest, uint32_t src, size_t len) extract(dest, src, tmp, align); } -void adiv5_mem_write_sized(ADIv5_AP_t *ap, uint32_t dest, const void *src, - size_t len, enum align align) +static void mem_write_sized(ADIv5_AP_t *ap, uint32_t dest, const void *src, + size_t len, enum align align) { uint32_t odest = dest; @@ -671,14 +694,14 @@ void adiv5_mem_write_sized(ADIv5_AP_t *ap, uint32_t dest, const void *src, } } -void adiv5_ap_write(ADIv5_AP_t *ap, uint16_t addr, uint32_t value) +static void ap_write(ADIv5_AP_t *ap, uint16_t addr, uint32_t value) { adiv5_dp_write(ap->dp, ADIV5_DP_SELECT, ((uint32_t)ap->apsel << 24)|(addr & 0xF0)); adiv5_dp_write(ap->dp, addr, value); } -uint32_t adiv5_ap_read(ADIv5_AP_t *ap, uint16_t addr) +static uint32_t ap_read(ADIv5_AP_t *ap, uint16_t addr) { uint32_t ret; adiv5_dp_write(ap->dp, ADIV5_DP_SELECT, @@ -686,7 +709,6 @@ uint32_t adiv5_ap_read(ADIv5_AP_t *ap, uint16_t addr) ret = adiv5_dp_read(ap->dp, addr); return ret; } -#endif void adiv5_mem_write(ADIv5_AP_t *ap, uint32_t dest, const void *src, size_t len) { diff --git a/src/target/adiv5.h b/src/target/adiv5.h index cbab7a6b..d592921c 100644 --- a/src/target/adiv5.h +++ b/src/target/adiv5.h @@ -129,6 +129,8 @@ enum align { ALIGN_DWORD = 3 }; +typedef struct ADIv5_AP_s ADIv5_AP_t; + /* Try to keep this somewhat absract for later adding SW-DP */ typedef struct ADIv5_DP_s { int refcnt; @@ -142,6 +144,23 @@ typedef struct ADIv5_DP_s { uint16_t addr, uint32_t value); void (*abort)(struct ADIv5_DP_s *dp, uint32_t abort); +#if PC_HOSTED == 1 + bool (*ap_setup)(int i); + void (*ap_cleanup)(int i); + void (*ap_regs_read)(ADIv5_AP_t *ap, void *data); + uint32_t(*ap_reg_read)(ADIv5_AP_t *ap, int num); + void (*ap_reg_write)(ADIv5_AP_t *ap, int num, uint32_t value); + void (*read_block)(uint32_t addr, uint8_t *data, int size); + void (*dap_write_block_sized)(uint32_t addr, uint8_t *data, + int size, enum align align); + +#endif + uint32_t (*ap_read)(ADIv5_AP_t *ap, uint16_t addr); + void (*ap_write)(ADIv5_AP_t *ap, uint16_t addr, uint32_t value); + + void (*mem_read)(ADIv5_AP_t *ap, void *dest, uint32_t src, size_t len); + void (*mem_write_sized)(ADIv5_AP_t *ap, uint32_t dest, const void *src, + size_t len, enum align align); #if PC_HOSTED == 1 jtag_dev_t *dev; uint8_t fault; @@ -174,7 +193,7 @@ static inline void adiv5_dp_abort(struct ADIv5_DP_s *dp, uint32_t abort) return dp->abort(dp, abort); } -typedef struct ADIv5_AP_s { +struct ADIv5_AP_s { int refcnt; ADIv5_DP_t *dp; @@ -183,25 +202,42 @@ typedef struct ADIv5_AP_s { uint32_t idr; uint32_t base; uint32_t csw; -} ADIv5_AP_t; +}; + +static inline uint32_t adiv5_ap_read(ADIv5_AP_t *ap, uint16_t addr) +{ + return ap->dp->ap_read(ap, addr); +} + +static inline void adiv5_ap_write(ADIv5_AP_t *ap, uint16_t addr, uint32_t value) +{ + return ap->dp->ap_write(ap, addr, value); +} + +static inline void adiv5_mem_read(ADIv5_AP_t *ap, void *dest, uint32_t src, + size_t len) +{ + return ap->dp->mem_read(ap, dest, src, len); +} +static inline void adiv5_mem_write_sized(ADIv5_AP_t *ap, uint32_t dest, + const void *src, size_t len, enum align align) +{ + return ap->dp->mem_write_sized(ap, dest, src, len, align); +} -void adiv5_dp_init(ADIv5_DP_t *dp); void adiv5_dp_write(ADIv5_DP_t *dp, uint16_t addr, uint32_t value); - +void adiv5_dp_init(ADIv5_DP_t *dp); +void platform_adiv5_dp_defaults(ADIv5_DP_t *dp); ADIv5_AP_t *adiv5_new_ap(ADIv5_DP_t *dp, uint8_t apsel); void adiv5_ap_ref(ADIv5_AP_t *ap); void adiv5_ap_unref(ADIv5_AP_t *ap); void adiv5_ap_write(ADIv5_AP_t *ap, uint16_t addr, uint32_t value); -uint32_t adiv5_ap_read(ADIv5_AP_t *ap, uint16_t addr); void adiv5_jtag_dp_handler(jtag_dev_t *dev); int platform_jtag_dp_init(ADIv5_DP_t *dp); -void adiv5_mem_read(ADIv5_AP_t *ap, void *dest, uint32_t src, size_t len); void adiv5_mem_write(ADIv5_AP_t *ap, uint32_t dest, const void *src, size_t len); -void adiv5_mem_write_sized(ADIv5_AP_t *ap, uint32_t dest, const void *src, - size_t len, enum align align); uint64_t adiv5_ap_read_pidr(ADIv5_AP_t *ap, uint32_t addr); void * extract(void *dest, uint32_t src, uint32_t val, enum align align); #endif diff --git a/src/target/cortexm.c b/src/target/cortexm.c index 051befdf..a0abf852 100644 --- a/src/target/cortexm.c +++ b/src/target/cortexm.c @@ -478,88 +478,98 @@ static void cortexm_regs_read(target *t, void *data) uint32_t *regs = data; ADIv5_AP_t *ap = cortexm_ap(t); unsigned i; -#if defined(STLINKV2) - uint32_t base_regs[21]; - extern void stlink_regs_read(ADIv5_AP_t *ap, void *data); - extern uint32_t stlink_reg_read(ADIv5_AP_t *ap, int idx); - stlink_regs_read(ap, base_regs); - for(i = 0; i < sizeof(regnum_cortex_m) / 4; i++) - *regs++ = base_regs[regnum_cortex_m[i]]; - if (t->target_options & TOPT_FLAVOUR_V7MF) - for(size_t t = 0; t < sizeof(regnum_cortex_mf) / 4; t++) - *regs++ = stlink_reg_read(ap, regnum_cortex_mf[t]); -#else - /* FIXME: Describe what's really going on here */ - adiv5_ap_write(ap, ADIV5_AP_CSW, ap->csw | ADIV5_AP_CSW_SIZE_WORD); - - /* Map the banked data registers (0x10-0x1c) to the - * debug registers DHCSR, DCRSR, DCRDR and DEMCR respectively */ - adiv5_dp_low_access(ap->dp, ADIV5_LOW_WRITE, ADIV5_AP_TAR, CORTEXM_DHCSR); - - /* Walk the regnum_cortex_m array, reading the registers it - * calls out. */ - adiv5_ap_write(ap, ADIV5_AP_DB(DB_DCRSR), regnum_cortex_m[0]); /* Required to switch banks */ - *regs++ = adiv5_dp_read(ap->dp, ADIV5_AP_DB(DB_DCRDR)); - for(i = 1; i < sizeof(regnum_cortex_m) / 4; i++) { - adiv5_dp_low_access(ap->dp, ADIV5_LOW_WRITE, ADIV5_AP_DB(DB_DCRSR), - regnum_cortex_m[i]); - *regs++ = adiv5_dp_read(ap->dp, ADIV5_AP_DB(DB_DCRDR)); +#if PC_HOSTED == 1 + if ((ap->dp->ap_reg_read) && (ap->dp->ap_regs_read)) { + uint32_t base_regs[21]; + ap->dp->ap_regs_read(ap, base_regs); + for(i = 0; i < sizeof(regnum_cortex_m) / 4; i++) + *regs++ = base_regs[regnum_cortex_m[i]]; + if (t->target_options & TOPT_FLAVOUR_V7MF) + for(size_t t = 0; t < sizeof(regnum_cortex_mf) / 4; t++) + *regs++ = ap->dp->ap_reg_read(ap, regnum_cortex_mf[t]); } - if (t->target_options & TOPT_FLAVOUR_V7MF) - for(i = 0; i < sizeof(regnum_cortex_mf) / 4; i++) { - adiv5_dp_low_access(ap->dp, ADIV5_LOW_WRITE, - ADIV5_AP_DB(DB_DCRSR), - regnum_cortex_mf[i]); - *regs++ = adiv5_dp_read(ap->dp, ADIV5_AP_DB(DB_DCRDR)); - } +#else + if (0) {} #endif + else { + /* FIXME: Describe what's really going on here */ + adiv5_ap_write(ap, ADIV5_AP_CSW, ap->csw | ADIV5_AP_CSW_SIZE_WORD); + + /* Map the banked data registers (0x10-0x1c) to the + * debug registers DHCSR, DCRSR, DCRDR and DEMCR respectively */ + adiv5_dp_low_access(ap->dp, ADIV5_LOW_WRITE, ADIV5_AP_TAR, + CORTEXM_DHCSR); + + /* Walk the regnum_cortex_m array, reading the registers it + * calls out. */ + adiv5_ap_write(ap, ADIV5_AP_DB(DB_DCRSR), regnum_cortex_m[0]); + /* Required to switch banks */ + *regs++ = adiv5_dp_read(ap->dp, ADIV5_AP_DB(DB_DCRDR)); + for(i = 1; i < sizeof(regnum_cortex_m) / 4; i++) { + adiv5_dp_low_access(ap->dp, ADIV5_LOW_WRITE, ADIV5_AP_DB(DB_DCRSR), + regnum_cortex_m[i]); + *regs++ = adiv5_dp_read(ap->dp, ADIV5_AP_DB(DB_DCRDR)); + } + if (t->target_options & TOPT_FLAVOUR_V7MF) + for(i = 0; i < sizeof(regnum_cortex_mf) / 4; i++) { + adiv5_dp_low_access(ap->dp, ADIV5_LOW_WRITE, + ADIV5_AP_DB(DB_DCRSR), + regnum_cortex_mf[i]); + *regs++ = adiv5_dp_read(ap->dp, ADIV5_AP_DB(DB_DCRDR)); + } + } } static void cortexm_regs_write(target *t, const void *data) { const uint32_t *regs = data; ADIv5_AP_t *ap = cortexm_ap(t); -#if defined(STLINKV2) - extern void stlink_reg_write(ADIv5_AP_t *ap, int num, uint32_t val); - for(size_t z = 0; z < sizeof(regnum_cortex_m) / 4; z++) { - stlink_reg_write(ap, regnum_cortex_m[z], *regs); - regs++; - } - if (t->target_options & TOPT_FLAVOUR_V7MF) - for(size_t z = 0; z < sizeof(regnum_cortex_mf) / 4; z++) { - stlink_reg_write(ap, regnum_cortex_mf[z], *regs); +#if PC_HOSTED == 1 + if (ap->dp->ap_reg_write) { + for (size_t z = 0; z < sizeof(regnum_cortex_m) / 4; z++) { + ap->dp->ap_reg_write(ap, regnum_cortex_m[z], *regs); regs++; + } + if (t->target_options & TOPT_FLAVOUR_V7MF) + for(size_t z = 0; z < sizeof(regnum_cortex_mf) / 4; z++) { + ap->dp->ap_reg_write(ap, regnum_cortex_mf[z], *regs); + regs++; + } } #else - unsigned i; - - /* FIXME: Describe what's really going on here */ - adiv5_ap_write(ap, ADIV5_AP_CSW, ap->csw | ADIV5_AP_CSW_SIZE_WORD); - - /* Map the banked data registers (0x10-0x1c) to the - * debug registers DHCSR, DCRSR, DCRDR and DEMCR respectively */ - adiv5_dp_low_access(ap->dp, ADIV5_LOW_WRITE, ADIV5_AP_TAR, CORTEXM_DHCSR); - - /* Walk the regnum_cortex_m array, writing the registers it - * calls out. */ - adiv5_ap_write(ap, ADIV5_AP_DB(DB_DCRDR), *regs++); /* Required to switch banks */ - adiv5_dp_low_access(ap->dp, ADIV5_LOW_WRITE, ADIV5_AP_DB(DB_DCRSR), - 0x10000 | regnum_cortex_m[0]); - for(i = 1; i < sizeof(regnum_cortex_m) / 4; i++) { - adiv5_dp_low_access(ap->dp, ADIV5_LOW_WRITE, - ADIV5_AP_DB(DB_DCRDR), *regs++); - adiv5_dp_low_access(ap->dp, ADIV5_LOW_WRITE, ADIV5_AP_DB(DB_DCRSR), - 0x10000 | regnum_cortex_m[i]); - } - if (t->target_options & TOPT_FLAVOUR_V7MF) - for(i = 0; i < sizeof(regnum_cortex_mf) / 4; i++) { - adiv5_dp_low_access(ap->dp, ADIV5_LOW_WRITE, - ADIV5_AP_DB(DB_DCRDR), *regs++); - adiv5_dp_low_access(ap->dp, ADIV5_LOW_WRITE, - ADIV5_AP_DB(DB_DCRSR), - 0x10000 | regnum_cortex_mf[i]); - } + if (0) {} #endif + else { + unsigned i; + + /* FIXME: Describe what's really going on here */ + adiv5_ap_write(ap, ADIV5_AP_CSW, ap->csw | ADIV5_AP_CSW_SIZE_WORD); + + /* Map the banked data registers (0x10-0x1c) to the + * debug registers DHCSR, DCRSR, DCRDR and DEMCR respectively */ + adiv5_dp_low_access(ap->dp, ADIV5_LOW_WRITE, ADIV5_AP_TAR, + CORTEXM_DHCSR); + /* Walk the regnum_cortex_m array, writing the registers it + * calls out. */ + adiv5_ap_write(ap, ADIV5_AP_DB(DB_DCRDR), *regs++); + /* Required to switch banks */ + adiv5_dp_low_access(ap->dp, ADIV5_LOW_WRITE, ADIV5_AP_DB(DB_DCRSR), + 0x10000 | regnum_cortex_m[0]); + for(i = 1; i < sizeof(regnum_cortex_m) / 4; i++) { + adiv5_dp_low_access(ap->dp, ADIV5_LOW_WRITE, + ADIV5_AP_DB(DB_DCRDR), *regs++); + adiv5_dp_low_access(ap->dp, ADIV5_LOW_WRITE, ADIV5_AP_DB(DB_DCRSR), + 0x10000 | regnum_cortex_m[i]); + } + if (t->target_options & TOPT_FLAVOUR_V7MF) + for(i = 0; i < sizeof(regnum_cortex_mf) / 4; i++) { + adiv5_dp_low_access(ap->dp, ADIV5_LOW_WRITE, + ADIV5_AP_DB(DB_DCRDR), *regs++); + adiv5_dp_low_access(ap->dp, ADIV5_LOW_WRITE, + ADIV5_AP_DB(DB_DCRSR), + 0x10000 | regnum_cortex_mf[i]); + } + } } int cortexm_mem_write_sized( From 9a46c6fd25cf41bca5a6073b8c0ea101ebb85cf9 Mon Sep 17 00:00:00 2001 From: Uwe Bonnes Date: Sat, 18 Apr 2020 14:17:03 +0200 Subject: [PATCH 02/13] Allow BOARD_IDENT as function --- src/command.c | 2 +- src/platforms/libftdi/platform.h | 2 +- src/platforms/pc-hosted/platform.h | 2 +- src/platforms/pc-stlinkv2/platform.h | 2 +- src/remote.c | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/command.c b/src/command.c index 4d0d1e50..9f9878da 100644 --- a/src/command.c +++ b/src/command.c @@ -136,7 +136,7 @@ bool cmd_version(target *t, int argc, char **argv) (void)argc; (void)argv; #if PC_HOSTED == 1 - gdb_outf("Black Magic Probe, PC-Hosted for " PLATFORM_IDENT + gdb_outf("Black Magic Probe, PC-Hosted for " PLATFORM_IDENT() ", Version " FIRMWARE_VERSION "\n"); #else gdb_outf("Black Magic Probe (Firmware " FIRMWARE_VERSION ") (Hardware Version %d)\n", platform_hwversion()); diff --git a/src/platforms/libftdi/platform.h b/src/platforms/libftdi/platform.h index 122cdced..d174aaf8 100644 --- a/src/platforms/libftdi/platform.h +++ b/src/platforms/libftdi/platform.h @@ -38,7 +38,7 @@ #define PLATFORM_HAS_DEBUG -#define PLATFORM_IDENT "FTDI/MPSSE" +#define PLATFORM_IDENT() "FTDI/MPSSE" #define SET_RUN_STATE(state) #define SET_IDLE_STATE(state) #define SET_ERROR_STATE(state) diff --git a/src/platforms/pc-hosted/platform.h b/src/platforms/pc-hosted/platform.h index 8b1c71b9..535e9ea0 100644 --- a/src/platforms/pc-hosted/platform.h +++ b/src/platforms/pc-hosted/platform.h @@ -35,7 +35,7 @@ #define PLATFORM_HAS_DEBUG #define PLATFORM_HAS_POWER_SWITCH #define PLATFORM_MAX_MSG_SIZE (256) -#define PLATFORM_IDENT "PC-HOSTED" +#define PLATFORM_IDENT() "PC-HOSTED" #define BOARD_IDENT PLATFORM_IDENT #define SET_RUN_STATE(state) #define SET_IDLE_STATE(state) diff --git a/src/platforms/pc-stlinkv2/platform.h b/src/platforms/pc-stlinkv2/platform.h index c3f0bba3..4535c74d 100644 --- a/src/platforms/pc-stlinkv2/platform.h +++ b/src/platforms/pc-stlinkv2/platform.h @@ -35,7 +35,7 @@ #define PLATFORM_HAS_DEBUG -#define PLATFORM_IDENT "StlinkV2/3" +#define PLATFORM_IDENT() "StlinkV2/3" #define SET_RUN_STATE(state) void stlink_check_detach(int state); #define SET_IDLE_STATE(state) stlink_check_detach(state) diff --git a/src/remote.c b/src/remote.c index 30cd0757..a1ade3b1 100644 --- a/src/remote.c +++ b/src/remote.c @@ -243,7 +243,7 @@ void remotePacketProcessGEN(uint8_t i, char *packet) break; #if !defined(BOARD_IDENT) && defined(PLATFORM_IDENT) -# define BOARD_IDENT PLATFORM_IDENT +# define BOARD_IDENT() PLATFORM_IDENT #endif case REMOTE_START: _respondS(REMOTE_RESP_OK, BOARD_IDENT " " FIRMWARE_VERSION); From c3d509e6c0ec25c9e1cc766970e446cc9bba2f9b Mon Sep 17 00:00:00 2001 From: Uwe Bonnes Date: Sat, 18 Apr 2020 17:38:17 +0200 Subject: [PATCH 03/13] Clean up PLATFORM_HAS_DEBUG Use only for firmware platforms. --- src/platforms/libftdi/platform.h | 2 -- src/platforms/pc-hosted/platform.h | 1 - src/platforms/pc-stlinkv2/platform.h | 2 -- src/target/adiv5.c | 10 +++++----- src/target/efm32.c | 2 +- 5 files changed, 6 insertions(+), 11 deletions(-) diff --git a/src/platforms/libftdi/platform.h b/src/platforms/libftdi/platform.h index d174aaf8..d4368baf 100644 --- a/src/platforms/libftdi/platform.h +++ b/src/platforms/libftdi/platform.h @@ -36,8 +36,6 @@ #define FT2232_VID 0x0403 #define FT2232_PID 0x6010 -#define PLATFORM_HAS_DEBUG - #define PLATFORM_IDENT() "FTDI/MPSSE" #define SET_RUN_STATE(state) #define SET_IDLE_STATE(state) diff --git a/src/platforms/pc-hosted/platform.h b/src/platforms/pc-hosted/platform.h index 535e9ea0..696639bb 100644 --- a/src/platforms/pc-hosted/platform.h +++ b/src/platforms/pc-hosted/platform.h @@ -32,7 +32,6 @@ # endif #endif -#define PLATFORM_HAS_DEBUG #define PLATFORM_HAS_POWER_SWITCH #define PLATFORM_MAX_MSG_SIZE (256) #define PLATFORM_IDENT() "PC-HOSTED" diff --git a/src/platforms/pc-stlinkv2/platform.h b/src/platforms/pc-stlinkv2/platform.h index 4535c74d..b63b0e1f 100644 --- a/src/platforms/pc-stlinkv2/platform.h +++ b/src/platforms/pc-stlinkv2/platform.h @@ -33,8 +33,6 @@ # endif #endif -#define PLATFORM_HAS_DEBUG - #define PLATFORM_IDENT() "StlinkV2/3" #define SET_RUN_STATE(state) void stlink_check_detach(int state); diff --git a/src/target/adiv5.c b/src/target/adiv5.c index edac3c78..973870ef 100644 --- a/src/target/adiv5.c +++ b/src/target/adiv5.c @@ -74,7 +74,7 @@ enum cid_class { cidc_unknown = 0x10 }; -#ifdef PLATFORM_HAS_DEBUG +#ifdef ENABLE_DEBUG /* The reserved ones only have an R in them, to save a bit of space. */ static const char * const cidc_debug_strings[] = { @@ -111,7 +111,7 @@ enum arm_arch { aa_end }; -#ifdef PLATFORM_HAS_DEBUG +#ifdef ENABLE_DEBUG #define PIDR_PN_BIT_STRINGS(...) __VA_ARGS__ #else #define PIDR_PN_BIT_STRINGS(...) @@ -155,7 +155,7 @@ static const struct { uint16_t part_number; enum arm_arch arch; enum cid_class cidc; -#ifdef PLATFORM_HAS_DEBUG +#ifdef ENABLE_DEBUG const char *type; const char *full; #endif @@ -277,7 +277,7 @@ static bool adiv5_component_probe(ADIv5_AP_t *ap, uint32_t addr, int recursion, uint64_t pidr = adiv5_ap_read_pidr(ap, addr); uint32_t cidr = adiv5_ap_read_id(ap, addr + CIDR0_OFFSET); bool res = false; -#if defined(ENABLE_DEBUG) && defined(PLATFORM_HAS_DEBUG) +#if defined(ENABLE_DEBUG) char indent[recursion + 1]; for(int i = 0; i < recursion; i++) indent[i] = ' '; @@ -303,7 +303,7 @@ static bool adiv5_component_probe(ADIv5_AP_t *ap, uint32_t addr, int recursion, /* ROM table */ if (cid_class == cidc_romtab) { /* Check SYSMEM bit */ -#if defined(ENABLE_DEBUG) && defined(PLATFORM_HAS_DEBUG) +#if defined(ENABLE_DEBUG) uint32_t memtype = adiv5_mem_read32(ap, addr | ADIV5_ROM_MEMTYPE) & ADIV5_ROM_MEMTYPE_SYSMEM; diff --git a/src/target/efm32.c b/src/target/efm32.c index ba40b430..82125e36 100644 --- a/src/target/efm32.c +++ b/src/target/efm32.c @@ -720,7 +720,7 @@ static int efm32_flash_write(struct target_flash *f, int ret = cortexm_run_stub(t, SRAM_BASE, dest, STUB_BUFFER_BASE, len, device->msc_addr); -#ifdef PLATFORM_HAS_DEBUG +#ifdef ENABLE_DEBUG /* Check the MSC_IF */ uint32_t msc = device->msc_addr; uint32_t msc_if = target_mem_read32(t, EFM32_MSC_IF(msc)); From 3290def5f844866837f7d4422ffcc5f01b747e9c Mon Sep 17 00:00:00 2001 From: Uwe Bonnes Date: Sat, 18 Apr 2020 16:50:23 +0200 Subject: [PATCH 04/13] Add empty compilable project. --- src/platforms/hosted/Makefile.inc | 12 ++++ src/platforms/hosted/jtagtap.c | 0 src/platforms/hosted/platform.c | 92 +++++++++++++++++++++++++++++++ src/platforms/hosted/platform.h | 11 ++++ src/platforms/hosted/swdptap.c | 0 5 files changed, 115 insertions(+) create mode 100644 src/platforms/hosted/Makefile.inc create mode 100644 src/platforms/hosted/jtagtap.c create mode 100644 src/platforms/hosted/platform.c create mode 100644 src/platforms/hosted/platform.h create mode 100644 src/platforms/hosted/swdptap.c diff --git a/src/platforms/hosted/Makefile.inc b/src/platforms/hosted/Makefile.inc new file mode 100644 index 00000000..7c96aa88 --- /dev/null +++ b/src/platforms/hosted/Makefile.inc @@ -0,0 +1,12 @@ +SYS = $(shell $(CC) -dumpmachine) +CFLAGS += -DSTLINKV2 -DJTAG_HL -DENABLE_DEBUG +CFLAGS +=-I ./target -I./platforms/pc +LDFLAGS += -lusb-1.0 +ifneq (, $(findstring mingw, $(SYS))) +LDFLAGS += -lws2_32 +else ifneq (, $(findstring cygwin, $(SYS))) +LDFLAGS += -lws2_32 +endif +VPATH += platforms/pc +SRC += timing.c cl_utils.c utils.c +PC_HOSTED = 1 diff --git a/src/platforms/hosted/jtagtap.c b/src/platforms/hosted/jtagtap.c new file mode 100644 index 00000000..e69de29b diff --git a/src/platforms/hosted/platform.c b/src/platforms/hosted/platform.c new file mode 100644 index 00000000..3c7df6d1 --- /dev/null +++ b/src/platforms/hosted/platform.c @@ -0,0 +1,92 @@ +/* + * This file is part of the Black Magic Debug project. + * + * Copyright (C) 2019 + * Written by Uwe Bonnes (bon@elektron.ikp.physik.tu-darmstadt.de) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* Handle different BMP pc-hosted platforms/ + */ + +#include "general.h" +#include "swdptap.h" +#include "jtagtap.h" + +typedef enum bmp_t{ + BMP_TYPE_NONE = 0 +}bmp_t; + +bmp_t active_bmp = BMP_TYPE_NONE; +swd_proc_t swd_proc; +jtag_proc_t jtag_proc; + +void platform_init(int argc, char **argv) +{ + (void) argc; + (void) argv; + exit(-1); +} + +int platform_adiv5_swdp_scan(void) +{ + return -1; +} + +int platform_swdptap_init(void) +{ + return -1; +} + +int platform_jtag_scan(const uint8_t *lrlens) +{ + (void) lrlens; + return -1; +} + +int platform_jtagtap_init(void) +{ + return 0; +} + +int platform_adiv5_dp_defaults(void *arg) +{ + (void)arg; + return -1; +} + +int platform_jtag_dp_init() +{ + return 0; +} + +char *platform_ident(void) +{ + switch (active_bmp) { + case BMP_TYPE_NONE: + return "NONE"; + } + return NULL; +} + +const char *platform_target_voltage(void) +{ + return NULL; +} + +void platform_srst_set_val(bool assert) {(void) assert;} + +bool platform_srst_get_val(void) { return false;} +void platform_buffer_flush(void) {} diff --git a/src/platforms/hosted/platform.h b/src/platforms/hosted/platform.h new file mode 100644 index 00000000..545d7c1f --- /dev/null +++ b/src/platforms/hosted/platform.h @@ -0,0 +1,11 @@ +#ifndef __PLATFORM_H +#include "timing.h" + +char *platform_ident(void); +void platform_buffer_flush(void); + +#define PLATFORM_IDENT() "NONE" +#define SET_IDLE_STATE(x) +#define SET_RUN_STATE(x) + +#endif diff --git a/src/platforms/hosted/swdptap.c b/src/platforms/hosted/swdptap.c new file mode 100644 index 00000000..e69de29b From 386a4bfce78dc79101d4a9a8b82e4d2f12eda1de Mon Sep 17 00:00:00 2001 From: Uwe Bonnes Date: Sat, 18 Apr 2020 17:54:00 +0200 Subject: [PATCH 05/13] hosted: Device detection and selection. --- src/Makefile | 2 +- src/platforms/hosted/Makefile.inc | 2 +- src/platforms/hosted/platform.c | 189 ++++++++++++++++++++++++++++-- src/platforms/hosted/platform.h | 22 ++++ 4 files changed, 205 insertions(+), 10 deletions(-) diff --git a/src/Makefile b/src/Makefile index 94305013..6c9d931d 100644 --- a/src/Makefile +++ b/src/Makefile @@ -62,7 +62,7 @@ SRC = \ include $(PLATFORM_DIR)/Makefile.inc -OPT_FLAGS ?= -O2 +OPT_FLAGS ?= -Og CFLAGS += $(OPT_FLAGS) LDFLAGS += $(OPT_FLAGS) diff --git a/src/platforms/hosted/Makefile.inc b/src/platforms/hosted/Makefile.inc index 7c96aa88..fc00abe2 100644 --- a/src/platforms/hosted/Makefile.inc +++ b/src/platforms/hosted/Makefile.inc @@ -1,5 +1,5 @@ SYS = $(shell $(CC) -dumpmachine) -CFLAGS += -DSTLINKV2 -DJTAG_HL -DENABLE_DEBUG +CFLAGS += -DENABLE_DEBUG -DPLATFORM_HAS_DEBUG CFLAGS +=-I ./target -I./platforms/pc LDFLAGS += -lusb-1.0 ifneq (, $(findstring mingw, $(SYS))) diff --git a/src/platforms/hosted/platform.c b/src/platforms/hosted/platform.c index 3c7df6d1..a10a7a33 100644 --- a/src/platforms/hosted/platform.c +++ b/src/platforms/hosted/platform.c @@ -1,7 +1,7 @@ /* * This file is part of the Black Magic Debug project. * - * Copyright (C) 2019 + * Copyright (C) 2020 * Written by Uwe Bonnes (bon@elektron.ikp.physik.tu-darmstadt.de) * * This program is free software: you can redistribute it and/or modify @@ -24,19 +24,182 @@ #include "general.h" #include "swdptap.h" #include "jtagtap.h" +#include "timing.h" +#include "cl_utils.h" +#include -typedef enum bmp_t{ - BMP_TYPE_NONE = 0 -}bmp_t; +#define VENDOR_ID_BMP 0x1d50 +#define PRODUCT_ID_BMP 0x6018 + +#define VENDOR_ID_STLINK 0x0483 +#define PRODUCT_ID_STLINK_MASK 0xffe0 +#define PRODUCT_ID_STLINK_GROUP 0x3740 +#define PRODUCT_ID_STLINKV1 0x3744 +#define PRODUCT_ID_STLINKV2 0x3748 +#define PRODUCT_ID_STLINKV21 0x374b +#define PRODUCT_ID_STLINKV21_MSD 0x3752 +#define PRODUCT_ID_STLINKV3 0x374f +#define PRODUCT_ID_STLINKV3E 0x374e + +bmp_info_t info; -bmp_t active_bmp = BMP_TYPE_NONE; swd_proc_t swd_proc; jtag_proc_t jtag_proc; +static void exit_function(void) +{ + libusb_exit(info.libusb_ctx); + fprintf(stderr, "INFO: Cleanup\n"); +} + +/* SIGTERM handler. */ +static void sigterm_handler(int sig) +{ + (void)sig; + exit(0); +} + +static int find_debuggers( BMP_CL_OPTIONS_t *cl_opts,bmp_info_t *info) +{ + libusb_device **devs; + int n_devs = libusb_get_device_list(info->libusb_ctx, &devs); + if (n_devs < 0) { + fprintf(stderr, "WARN:libusb_get_device_list() failed"); + return -1; + } + bool report = false; + int found_debuggers; + struct libusb_device_descriptor desc; + char serial[64]; + char manufacturer[128]; + char product[128]; + bmp_type_t type = BMP_TYPE_NONE; + rescan: + found_debuggers = 0; + for (int i = 0; devs[i]; i++) { + libusb_device *dev = devs[i]; + int res = libusb_get_device_descriptor(dev, &desc); + if (res < 0) { + fprintf(stderr, "WARN: libusb_get_device_descriptor() failed: %s", + libusb_strerror(res)); + libusb_free_device_list(devs, 0); + continue; + } + libusb_device_handle *handle; + res = libusb_open(dev, &handle); + if (res != LIBUSB_SUCCESS) { + fprintf(stderr,"WARN: Open failed\n"); + continue; + } + res = libusb_get_string_descriptor_ascii( + handle, desc.iSerialNumber, (uint8_t*)serial, + sizeof(serial)); + if (res <= 0) { + /* This can fail for many devices. Continue silent!*/ + libusb_close(handle); + continue; + } + if (cl_opts->opt_serial && !strstr(serial, cl_opts->opt_serial)) { + libusb_close(handle); + continue; + } + res = libusb_get_string_descriptor_ascii( + handle, desc.iManufacturer, (uint8_t*)manufacturer, + sizeof(manufacturer)); + if (res > 0) { + res = libusb_get_string_descriptor_ascii( + handle, desc.iProduct, (uint8_t*)product, + sizeof(product)); + if (res <= 0) { + fprintf(stderr, "WARN:" + "libusb_get_string_descriptor_ascii " + "for ident_string failed: %s\n", + libusb_strerror(res)); + libusb_close(handle); + continue; + } + } + if (cl_opts->opt_ident_string) { + char *match_manu = NULL; + char *match_product = NULL; + match_manu = strstr(manufacturer, cl_opts->opt_ident_string); + match_product = strstr(product, cl_opts->opt_ident_string); + if (!match_manu && !match_product) { + libusb_close(handle); + continue; + } + } + /* Either serial and/or ident_string match or are not given. + * Check type.*/ + if ((desc.idVendor == VENDOR_ID_BMP) && + (desc.idProduct == PRODUCT_ID_BMP)) { + type = BMP_TYPE_BMP; + } else if (desc.idVendor == VENDOR_ID_STLINK) { + if (desc.idProduct == PRODUCT_ID_STLINKV1) { + fprintf(stderr, "INFO: STLINKV1 not supported\n"); + continue; + } + if ((desc.idProduct == PRODUCT_ID_STLINKV2) || + (desc.idProduct == PRODUCT_ID_STLINKV21) || + (desc.idProduct == PRODUCT_ID_STLINKV21_MSD) || + (desc.idProduct == PRODUCT_ID_STLINKV3) || + (desc.idProduct == PRODUCT_ID_STLINKV3E)) { + type = BMP_TYPE_STLINKV2; + } + } else { + continue; + } + found_debuggers ++; + if (report) { + printf("%2d: %s, %s, %s\n", found_debuggers, + serial, + manufacturer,product); + } + info->vid = desc.idVendor; + info->pid = desc.idProduct; + info->bmp_type = type; + strncpy(info->serial, serial, sizeof(info->serial)); + strncpy(info->product, product, sizeof(info->product)); + strncpy(info->manufacturer, manufacturer, sizeof(info->manufacturer)); + if (cl_opts->opt_position && + (cl_opts->opt_position == found_debuggers)) { + found_debuggers = 1; + break; + } + } + if (found_debuggers > 1) { + if (!report) { + printf("%d debuggers found! Select with -P , -s " + "and/or -S \n", + found_debuggers); + report = true; + goto rescan; + } + } + libusb_free_device_list(devs, 0); + return 0; +} + void platform_init(int argc, char **argv) { - (void) argc; - (void) argv; + BMP_CL_OPTIONS_t cl_opts = {0}; + cl_opts.opt_idstring = "Blackmagic PC-Hosted"; + cl_init(&cl_opts, argc, argv); + atexit(exit_function); + signal(SIGTERM, sigterm_handler); + signal(SIGINT, sigterm_handler); + int res = libusb_init(&info.libusb_ctx); + if (res) { + fprintf(stderr, "Fatal: Failed to get USB context: %s\n", + libusb_strerror(res)); + exit(-1); + } + if (find_debuggers(&cl_opts, &info)) { + exit(-1); + } + printf("Using %s %s %s\n", info.serial, + info.manufacturer, + info.product); exit(-1); } @@ -74,9 +237,19 @@ int platform_jtag_dp_init() char *platform_ident(void) { - switch (active_bmp) { + switch (info.bmp_type) { case BMP_TYPE_NONE: return "NONE"; + case BMP_TYPE_BMP: + return "BMP"; + case BMP_TYPE_STLINKV2: + return "STLINKV2"; + case BMP_TYPE_LIBFTDI: + return "LIBFTDI"; + case BMP_TYPE_CMSIS_DAP: + return "CMSIS_DAP"; + case BMP_TYPE_JLINK: + return "JLINK"; } return NULL; } diff --git a/src/platforms/hosted/platform.h b/src/platforms/hosted/platform.h index 545d7c1f..0a281105 100644 --- a/src/platforms/hosted/platform.h +++ b/src/platforms/hosted/platform.h @@ -1,4 +1,6 @@ #ifndef __PLATFORM_H +#define __PLATFORM_H +#include #include "timing.h" char *platform_ident(void); @@ -8,4 +10,24 @@ void platform_buffer_flush(void); #define SET_IDLE_STATE(x) #define SET_RUN_STATE(x) +typedef enum bmp_type_s { + BMP_TYPE_NONE = 0, + BMP_TYPE_BMP, + BMP_TYPE_STLINKV2, + BMP_TYPE_LIBFTDI, + BMP_TYPE_CMSIS_DAP, + BMP_TYPE_JLINK +} bmp_type_t; + +typedef struct bmp_info_s { + bmp_type_t bmp_type; + libusb_context *libusb_ctx; + unsigned int vid; + unsigned int pid; + char dev; + char serial[64]; + char manufacturer[128]; + char product[128]; +} bmp_info_t; + #endif From 52739def0187596c605145ab271f194947485389 Mon Sep 17 00:00:00 2001 From: Uwe Bonnes Date: Sun, 19 Apr 2020 11:55:56 +0200 Subject: [PATCH 06/13] Copy relevant stlink files. --- src/platforms/hosted/stlinkv2.c | 1437 +++++++++++++++++++++++++++++++ src/platforms/hosted/stlinkv2.h | 52 ++ 2 files changed, 1489 insertions(+) create mode 100644 src/platforms/hosted/stlinkv2.c create mode 100644 src/platforms/hosted/stlinkv2.h diff --git a/src/platforms/hosted/stlinkv2.c b/src/platforms/hosted/stlinkv2.c new file mode 100644 index 00000000..5f141d2b --- /dev/null +++ b/src/platforms/hosted/stlinkv2.c @@ -0,0 +1,1437 @@ +/* + * This file is part of the Black Magic Debug project. + * + * Copyright (C) 2019 Uwe Bonnes + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +/* Much code and ideas shamelessly taken form + * https://github.com/texane/stlink.git + * git://git.code.sf.net/p/openocd/code + * https://github.com/pavelrevak/pystlink + * https://github.com/pavelrevak/pystlink + * + * with some contribution. + */ +#include "general.h" +#include "gdb_if.h" +#include "adiv5.h" +#include "stlinkv2.h" +#include "exception.h" +#include "jtag_devs.h" +#include "target.h" + +#include +#include +#include +#include +#include + +#include "cl_utils.h" + +#if !defined(timersub) +/* This is a copy from GNU C Library (GNU LGPL 2.1), sys/time.h. */ +# define timersub(a, b, result) \ + do { \ + (result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \ + (result)->tv_usec = (a)->tv_usec - (b)->tv_usec; \ + if ((result)->tv_usec < 0) { \ + --(result)->tv_sec; \ + (result)->tv_usec += 1000000; \ + } \ + } while (0) +#endif + +#define VENDOR_ID_STLINK 0x483 +#define PRODUCT_ID_STLINK_MASK 0xffe0 +#define PRODUCT_ID_STLINK_GROUP 0x3740 +#define PRODUCT_ID_STLINKV1 0x3744 +#define PRODUCT_ID_STLINKV2 0x3748 +#define PRODUCT_ID_STLINKV21 0x374b +#define PRODUCT_ID_STLINKV21_MSD 0x3752 +#define PRODUCT_ID_STLINKV3 0x374f +#define PRODUCT_ID_STLINKV3E 0x374e + +#define STLINK_SWIM_ERR_OK 0x00 +#define STLINK_SWIM_BUSY 0x01 +#define STLINK_DEBUG_ERR_OK 0x80 +#define STLINK_DEBUG_ERR_FAULT 0x81 +#define STLINK_JTAG_UNKNOWN_JTAG_CHAIN 0x04 +#define STLINK_NO_DEVICE_CONNECTED 0x05 +#define STLINK_JTAG_COMMAND_ERROR 0x08 +#define STLINK_JTAG_COMMAND_ERROR 0x08 +#define STLINK_JTAG_GET_IDCODE_ERROR 0x09 +#define STLINK_JTAG_DBG_POWER_ERROR 0x0b +#define STLINK_SWD_AP_WAIT 0x10 +#define STLINK_SWD_AP_FAULT 0x11 +#define STLINK_SWD_AP_ERROR 0x12 +#define STLINK_SWD_AP_PARITY_ERROR 0x13 +#define STLINK_JTAG_WRITE_ERROR 0x0c +#define STLINK_JTAG_WRITE_VERIF_ERROR 0x0d +#define STLINK_SWD_DP_WAIT 0x14 +#define STLINK_SWD_DP_FAULT 0x15 +#define STLINK_SWD_DP_ERROR 0x16 +#define STLINK_SWD_DP_PARITY_ERROR 0x17 + +#define STLINK_SWD_AP_WDATA_ERROR 0x18 +#define STLINK_SWD_AP_STICKY_ERROR 0x19 +#define STLINK_SWD_AP_STICKYORUN_ERROR 0x1a +#define STLINK_BAD_AP_ERROR 0x1d +#define STLINK_TOO_MANY_AP_ERROR 0x29 +#define STLINK_JTAG_UNKNOWN_CMD 0x42 + +#define STLINK_CORE_RUNNING 0x80 +#define STLINK_CORE_HALTED 0x81 +#define STLINK_CORE_STAT_UNKNOWN -1 + +#define STLINK_GET_VERSION 0xF1 +#define STLINK_DEBUG_COMMAND 0xF2 +#define STLINK_DFU_COMMAND 0xF3 +#define STLINK_SWIM_COMMAND 0xF4 +#define STLINK_GET_CURRENT_MODE 0xF5 +#define STLINK_GET_TARGET_VOLTAGE 0xF7 + +#define STLINK_DEV_DFU_MODE 0x00 +#define STLINK_DEV_MASS_MODE 0x01 +#define STLINK_DEV_DEBUG_MODE 0x02 +#define STLINK_DEV_SWIM_MODE 0x03 +#define STLINK_DEV_BOOTLOADER_MODE 0x04 +#define STLINK_DEV_UNKNOWN_MODE -1 + +#define STLINK_DFU_EXIT 0x07 + +#define STLINK_SWIM_ENTER 0x00 +#define STLINK_SWIM_EXIT 0x01 +#define STLINK_SWIM_READ_CAP 0x02 +#define STLINK_SWIM_SPEED 0x03 +#define STLINK_SWIM_ENTER_SEQ 0x04 +#define STLINK_SWIM_GEN_RST 0x05 +#define STLINK_SWIM_RESET 0x06 +#define STLINK_SWIM_ASSERT_RESET 0x07 +#define STLINK_SWIM_DEASSERT_RESET 0x08 +#define STLINK_SWIM_READSTATUS 0x09 +#define STLINK_SWIM_WRITEMEM 0x0a +#define STLINK_SWIM_READMEM 0x0b +#define STLINK_SWIM_READBUF 0x0c + +#define STLINK_DEBUG_GETSTATUS 0x01 +#define STLINK_DEBUG_FORCEDEBUG 0x02 +#define STLINK_DEBUG_APIV1_RESETSYS 0x03 +#define STLINK_DEBUG_APIV1_READALLREGS 0x04 +#define STLINK_DEBUG_APIV1_READREG 0x05 +#define STLINK_DEBUG_APIV1_WRITEREG 0x06 +#define STLINK_DEBUG_READMEM_32BIT 0x07 +#define STLINK_DEBUG_WRITEMEM_32BIT 0x08 +#define STLINK_DEBUG_RUNCORE 0x09 +#define STLINK_DEBUG_STEPCORE 0x0a +#define STLINK_DEBUG_APIV1_SETFP 0x0b +#define STLINK_DEBUG_READMEM_8BIT 0x0c +#define STLINK_DEBUG_WRITEMEM_8BIT 0x0d +#define STLINK_DEBUG_APIV1_CLEARFP 0x0e +#define STLINK_DEBUG_APIV1_WRITEDEBUGREG 0x0f +#define STLINK_DEBUG_APIV1_SETWATCHPOINT 0x10 + +#define STLINK_DEBUG_ENTER_JTAG_RESET 0x00 +#define STLINK_DEBUG_ENTER_SWD_NO_RESET 0xa3 +#define STLINK_DEBUG_ENTER_JTAG_NO_RESET 0xa4 + +#define STLINK_DEBUG_APIV1_ENTER 0x20 +#define STLINK_DEBUG_EXIT 0x21 +#define STLINK_DEBUG_READCOREID 0x22 + +#define STLINK_DEBUG_APIV2_ENTER 0x30 +#define STLINK_DEBUG_APIV2_READ_IDCODES 0x31 +#define STLINK_DEBUG_APIV2_RESETSYS 0x32 +#define STLINK_DEBUG_APIV2_READREG 0x33 +#define STLINK_DEBUG_APIV2_WRITEREG 0x34 +#define STLINK_DEBUG_APIV2_WRITEDEBUGREG 0x35 +#define STLINK_DEBUG_APIV2_READDEBUGREG 0x36 + +#define STLINK_DEBUG_APIV2_READALLREGS 0x3A +#define STLINK_DEBUG_APIV2_GETLASTRWSTATUS 0x3B +#define STLINK_DEBUG_APIV2_DRIVE_NRST 0x3C + +#define STLINK_DEBUG_APIV2_GETLASTRWSTATUS2 0x3E + +#define STLINK_DEBUG_APIV2_START_TRACE_RX 0x40 +#define STLINK_DEBUG_APIV2_STOP_TRACE_RX 0x41 +#define STLINK_DEBUG_APIV2_GET_TRACE_NB 0x42 +#define STLINK_DEBUG_APIV2_SWD_SET_FREQ 0x43 +#define STLINK_DEBUG_APIV2_JTAG_SET_FREQ 0x44 +#define STLINK_DEBUG_APIV2_READ_DAP_REG 0x45 +#define STLINK_DEBUG_APIV2_WRITE_DAP_REG 0x46 +#define STLINK_DEBUG_APIV2_READMEM_16BIT 0x47 +#define STLINK_DEBUG_APIV2_WRITEMEM_16BIT 0x48 + +#define STLINK_DEBUG_APIV2_INIT_AP 0x4B +#define STLINK_DEBUG_APIV2_CLOSE_AP_DBG 0x4C + +#define STLINK_APIV3_SET_COM_FREQ 0x61 +#define STLINK_APIV3_GET_COM_FREQ 0x62 + +#define STLINK_APIV3_GET_VERSION_EX 0xFB + +#define STLINK_DEBUG_APIV2_DRIVE_NRST_LOW 0x00 +#define STLINK_DEBUG_APIV2_DRIVE_NRST_HIGH 0x01 +#define STLINK_DEBUG_APIV2_DRIVE_NRST_PULSE 0x02 + + +#define STLINK_TRACE_SIZE 4096 +#define STLINK_TRACE_MAX_HZ 2000000 + +#define STLINK_V3_MAX_FREQ_NB 10 + +/** */ +enum stlink_mode { + STLINK_MODE_UNKNOWN = 0, + STLINK_MODE_DFU, + STLINK_MODE_MASS, + STLINK_MODE_DEBUG_JTAG, + STLINK_MODE_DEBUG_SWD, + STLINK_MODE_DEBUG_SWIM +}; + +enum transport_mode_t{ + STLINK_MODE_SWD = 0, + STLINK_MODE_JTAG +}; + +typedef struct { + libusb_context* libusb_ctx; + uint16_t vid; + uint16_t pid; + uint8_t transport_mode; + char serial[32]; + uint8_t dap_select; + uint8_t ep_tx; + uint8_t ver_hw; /* 20, 21 or 31 deciphered from USB PID.*/ + uint8_t ver_stlink; /* 2 or 3 from API.*/ + uint8_t ver_api; + uint8_t ver_jtag; + uint8_t ver_mass; + uint8_t ver_swim; + uint8_t ver_bridge; + uint16_t block_size; + bool ap_error; + libusb_device_handle *handle; + struct libusb_transfer* req_trans; + struct libusb_transfer* rep_trans; +} stlink; + +stlink Stlink; + +static int stlink_usb_get_rw_status(bool verbose); + +static void exit_function(void) +{ + libusb_exit(NULL); + DEBUG("Cleanup\n"); +} + +/* SIGTERM handler. */ +static void sigterm_handler(int sig) +{ + (void)sig; + exit(0); +} + +struct trans_ctx { +#define TRANS_FLAGS_IS_DONE (1 << 0) +#define TRANS_FLAGS_HAS_ERROR (1 << 1) + volatile unsigned long flags; +}; + +int debug_level = 0; +bool has_attached = false; + +static int LIBUSB_CALL hotplug_callback_attach( + libusb_context *ctx, libusb_device *dev, libusb_hotplug_event event, + void *user_data) +{ + (void)ctx; + (void)dev; + (void)event; + (void)user_data; + has_attached = true; + return 1; /* deregister Callback*/ +} + +int device_detached = 0; +static int LIBUSB_CALL hotplug_callback_detach( + libusb_context *ctx, libusb_device *dev, libusb_hotplug_event event, + void *user_data) +{ + (void)ctx; + (void)dev; + (void)event; + (void)user_data; + device_detached = 1; + return 1; /* deregister Callback*/ +} + +void stlink_check_detach(int state) +{ + if (state == 1) { + /* Check for hotplug events */ + struct timeval tv = {0,0}; + libusb_handle_events_timeout_completed( + Stlink.libusb_ctx, &tv, &device_detached); + if (device_detached) { + DEBUG("Dongle was detached\n"); + exit(0); + } + } +} + +static void LIBUSB_CALL on_trans_done(struct libusb_transfer * trans) +{ + struct trans_ctx * const ctx = trans->user_data; + + if (trans->status != LIBUSB_TRANSFER_COMPLETED) + { + DEBUG("on_trans_done: "); + if(trans->status == LIBUSB_TRANSFER_TIMED_OUT) + { + DEBUG("Timeout\n"); + } else if (trans->status == LIBUSB_TRANSFER_CANCELLED) { + DEBUG("cancelled\n"); + } else if (trans->status == LIBUSB_TRANSFER_NO_DEVICE) { + DEBUG("no device\n"); + } else { + DEBUG("unknown\n"); + } + ctx->flags |= TRANS_FLAGS_HAS_ERROR; + } + ctx->flags |= TRANS_FLAGS_IS_DONE; +} + +static int submit_wait(struct libusb_transfer * trans) { + struct timeval start; + struct timeval now; + struct timeval diff; + struct trans_ctx trans_ctx; + enum libusb_error error; + + trans_ctx.flags = 0; + + /* brief intrusion inside the libusb interface */ + trans->callback = on_trans_done; + trans->user_data = &trans_ctx; + + if ((error = libusb_submit_transfer(trans))) { + DEBUG("libusb_submit_transfer(%d): %s\n", error, + libusb_strerror(error)); + exit(-1); + } + + gettimeofday(&start, NULL); + + while (trans_ctx.flags == 0) { + struct timeval timeout; + timeout.tv_sec = 1; + timeout.tv_usec = 0; + if (libusb_handle_events_timeout(Stlink.libusb_ctx, &timeout)) { + DEBUG("libusb_handle_events()\n"); + return -1; + } + + gettimeofday(&now, NULL); + timersub(&now, &start, &diff); + if (diff.tv_sec >= 1) { + libusb_cancel_transfer(trans); + DEBUG("libusb_handle_events() timeout\n"); + return -1; + } + } + + if (trans_ctx.flags & TRANS_FLAGS_HAS_ERROR) { + DEBUG("libusb_handle_events() | has_error\n"); + return -1; + } + + return 0; +} +#define STLINK_ERROR_DP_FAULT -2 +static int send_recv(uint8_t *txbuf, size_t txsize, + uint8_t *rxbuf, size_t rxsize) +{ + int res = 0; + stlink_check_detach(1); + if( txsize) { + int txlen = txsize; + libusb_fill_bulk_transfer(Stlink.req_trans, Stlink.handle, + Stlink.ep_tx | LIBUSB_ENDPOINT_OUT, + txbuf, txlen, + NULL, NULL, + 0 + ); + DEBUG_USB(" Send (%d): ", txlen); + for (int i = 0; i < txlen && i < 32 ; i++) { + DEBUG_USB("%02x", txbuf[i]); + if ((i & 7) == 7) + DEBUG_USB("."); + } + if (submit_wait(Stlink.req_trans)) { + DEBUG_USB("clear 2\n"); + libusb_clear_halt(Stlink.handle,2); + return -1; + } + } + /* send_only */ + if (rxsize != 0) { + /* read the response */ + libusb_fill_bulk_transfer(Stlink.rep_trans, Stlink.handle, + 0x01| LIBUSB_ENDPOINT_IN, + rxbuf, rxsize, NULL, NULL, 0); + + if (submit_wait(Stlink.rep_trans)) { + DEBUG("clear 1\n"); + libusb_clear_halt(Stlink.handle,1); + return -1; + } + res = Stlink.rep_trans->actual_length; + if (res >0) { + int i; + uint8_t *p = rxbuf; + DEBUG_USB(" Rec (%zu/%d)", rxsize, res); + for (i = 0; i < res && i < 32 ; i++) { + if ( i && ((i & 7) == 0)) + DEBUG_USB("."); + DEBUG_USB("%02x", p[i]); + } + } + } + DEBUG_USB("\n"); + return res; +} + +/** + Converts an STLINK status code held in the first byte of a response to + readable error +*/ +static int stlink_usb_error_check(uint8_t *data, bool verbose) +{ + switch (data[0]) { + case STLINK_DEBUG_ERR_OK: + return STLINK_ERROR_OK; + case STLINK_DEBUG_ERR_FAULT: + if (verbose) + DEBUG("SWD fault response (0x%x)\n", STLINK_DEBUG_ERR_FAULT); + return STLINK_ERROR_FAIL; + case STLINK_JTAG_UNKNOWN_JTAG_CHAIN: + if (verbose) + DEBUG("Unknown JTAG chain\n"); + return STLINK_ERROR_FAIL; + case STLINK_NO_DEVICE_CONNECTED: + if (verbose) + DEBUG("No device connected\n"); + return STLINK_ERROR_FAIL; + case STLINK_JTAG_COMMAND_ERROR: + if (verbose) + DEBUG("Command error\n"); + return STLINK_ERROR_FAIL; + case STLINK_JTAG_GET_IDCODE_ERROR: + if (verbose) + DEBUG("Failure reading IDCODE\n"); + return STLINK_ERROR_FAIL; + case STLINK_JTAG_DBG_POWER_ERROR: + if (verbose) + DEBUG("Failure powering DBG\n"); + return STLINK_ERROR_WAIT; + case STLINK_SWD_AP_WAIT: + if (verbose) + DEBUG("wait status SWD_AP_WAIT (0x%x)\n", STLINK_SWD_AP_WAIT); + return STLINK_ERROR_WAIT; + case STLINK_SWD_DP_WAIT: + if (verbose) + DEBUG("wait status SWD_DP_WAIT (0x%x)\n", STLINK_SWD_DP_WAIT); + return STLINK_ERROR_WAIT; + case STLINK_JTAG_WRITE_ERROR: + if (verbose) + DEBUG("Write error\n"); + return STLINK_ERROR_FAIL; + case STLINK_JTAG_WRITE_VERIF_ERROR: + if (verbose) + DEBUG("Write verify error, ignoring\n"); + return STLINK_ERROR_OK; + case STLINK_SWD_AP_FAULT: + /* git://git.ac6.fr/openocd commit 657e3e885b9ee10 + * returns STLINK_ERROR_OK with the comment: + * Change in error status when reading outside RAM. + * This fix allows CDT plugin to visualize memory. + */ + Stlink.ap_error = true; + if (verbose) + DEBUG("STLINK_SWD_AP_FAULT\n"); + return STLINK_ERROR_DP_FAULT; + case STLINK_SWD_AP_ERROR: + if (verbose) + DEBUG("STLINK_SWD_AP_ERROR\n"); + return STLINK_ERROR_FAIL; + case STLINK_SWD_AP_PARITY_ERROR: + if (verbose) + DEBUG("STLINK_SWD_AP_PARITY_ERROR\n"); + return STLINK_ERROR_FAIL; + case STLINK_SWD_DP_FAULT: + if (verbose) + DEBUG("STLINK_SWD_DP_FAULT\n"); + return STLINK_ERROR_FAIL; + case STLINK_SWD_DP_ERROR: + if (verbose) + DEBUG("STLINK_SWD_DP_ERROR\n"); + raise_exception(EXCEPTION_ERROR, "STLINK_SWD_DP_ERROR"); + return STLINK_ERROR_FAIL; + case STLINK_SWD_DP_PARITY_ERROR: + if (verbose) + DEBUG("STLINK_SWD_DP_PARITY_ERROR\n"); + return STLINK_ERROR_FAIL; + case STLINK_SWD_AP_WDATA_ERROR: + if (verbose) + DEBUG("STLINK_SWD_AP_WDATA_ERROR\n"); + return STLINK_ERROR_FAIL; + case STLINK_SWD_AP_STICKY_ERROR: + if (verbose) + DEBUG("STLINK_SWD_AP_STICKY_ERROR\n"); + return STLINK_ERROR_FAIL; + case STLINK_SWD_AP_STICKYORUN_ERROR: + if (verbose) + DEBUG("STLINK_SWD_AP_STICKYORUN_ERROR\n"); + return STLINK_ERROR_FAIL; + case STLINK_BAD_AP_ERROR: + /* ADIV5 probe 256 APs, most of them are non exisitant.*/ + return STLINK_ERROR_FAIL; + case STLINK_TOO_MANY_AP_ERROR: + /* TI TM4C duplicates AP. Error happens at AP9.*/ + if (verbose) + DEBUG("STLINK_TOO_MANY_AP_ERROR\n"); + return STLINK_ERROR_FAIL; + case STLINK_JTAG_UNKNOWN_CMD : + if (verbose) + DEBUG("STLINK_JTAG_UNKNOWN_CMD\n"); + return STLINK_ERROR_FAIL; + default: + if (verbose) + DEBUG("unknown/unexpected STLINK status code 0x%x\n", data[0]); + return STLINK_ERROR_FAIL; + } +} + +static int send_recv_retry(uint8_t *txbuf, size_t txsize, + uint8_t *rxbuf, size_t rxsize) +{ + struct timeval start; + struct timeval now; + struct timeval diff; + gettimeofday(&start, NULL); + int res; + while(1) { + send_recv(txbuf, txsize, rxbuf, rxsize); + res = stlink_usb_error_check(rxbuf, false); + if (res == STLINK_ERROR_OK) + return res; + gettimeofday(&now, NULL); + timersub(&now, &start, &diff); + if ((diff.tv_sec >= 1) || (res != STLINK_ERROR_WAIT)) { + DEBUG("write_retry failed. "); + return res; + } + } + return res; +} + +static int read_retry(uint8_t *txbuf, size_t txsize, + uint8_t *rxbuf, size_t rxsize) +{ + struct timeval start; + struct timeval now; + struct timeval diff; + gettimeofday(&start, NULL); + int res; + while(1) { + send_recv(txbuf, txsize, rxbuf, rxsize); + res = stlink_usb_get_rw_status(false); + if (res == STLINK_ERROR_OK) + return res; + gettimeofday(&now, NULL); + timersub(&now, &start, &diff); + if ((diff.tv_sec >= 1) || (res != STLINK_ERROR_WAIT)) { + DEBUG("read_retry failed. "); + stlink_usb_get_rw_status(true); + return res; + } + } + return res; +} + +static int write_retry(uint8_t *cmdbuf, size_t cmdsize, + uint8_t *txbuf, size_t txsize) +{ + struct timeval start; + struct timeval now; + struct timeval diff; + gettimeofday(&start, NULL); + int res; + while(1) { + send_recv(cmdbuf, cmdsize, NULL, 0); + send_recv(txbuf, txsize, NULL, 0); + res = stlink_usb_get_rw_status(false); + if (res == STLINK_ERROR_OK) + return res; + gettimeofday(&now, NULL); + timersub(&now, &start, &diff); + if ((diff.tv_sec >= 1) || (res != STLINK_ERROR_WAIT)) { + stlink_usb_get_rw_status(true); + return res; + } + } + return res; +} + +static void stlink_version(void) +{ + if (Stlink.ver_hw == 30) { + uint8_t cmd[16] = {STLINK_APIV3_GET_VERSION_EX}; + uint8_t data[12]; + int size = send_recv(cmd, 16, data, 12); + if (size == -1) { + printf("[!] send_recv STLINK_APIV3_GET_VERSION_EX\n"); + } + Stlink.ver_stlink = data[0]; + Stlink.ver_swim = data[1]; + Stlink.ver_jtag = data[2]; + Stlink.ver_mass = data[3]; + Stlink.ver_bridge = data[4]; + Stlink.block_size = 512; + Stlink.vid = data[3] << 9 | data[8]; + Stlink.pid = data[5] << 11 | data[10]; + } else { + uint8_t cmd[16] = {STLINK_GET_VERSION}; + uint8_t data[6]; + int size = send_recv(cmd, 16, data, 6); + if (size == -1) { + printf("[!] send_recv STLINK_GET_VERSION_EX\n"); + } + Stlink.vid = data[3] << 8 | data[2]; + Stlink.pid = data[5] << 8 | data[4]; + int version = data[0] << 8 | data[1]; /* Big endian here!*/ + Stlink.block_size = 64; + Stlink.ver_stlink = (version >> 12) & 0x0f; + Stlink.ver_jtag = (version >> 6) & 0x3f; + if ((Stlink.pid == PRODUCT_ID_STLINKV21_MSD) || + (Stlink.pid == PRODUCT_ID_STLINKV21)) { + Stlink.ver_mass = (version >> 0) & 0x3f; + } else { + Stlink.ver_swim = (version >> 0) & 0x3f; + } + } + DEBUG("V%dJ%d",Stlink.ver_stlink, Stlink.ver_jtag); + if (Stlink.ver_hw == 30) { + DEBUG("M%dB%dS%d", Stlink.ver_mass, Stlink.ver_bridge, Stlink.ver_swim); + } else if (Stlink.ver_hw == 20) { + DEBUG("S%d", Stlink.ver_swim); + } else if (Stlink.ver_hw == 21) { + DEBUG("M%d", Stlink.ver_mass); + } + DEBUG("\n"); +} + +void stlink_leave_state(void) +{ + uint8_t cmd[16] = {STLINK_GET_CURRENT_MODE}; + uint8_t data[2]; + send_recv(cmd, 16, data, 2); + if (data[0] == STLINK_DEV_DFU_MODE) { + uint8_t dfu_cmd[16] = {STLINK_DFU_COMMAND, STLINK_DFU_EXIT}; + DEBUG("Leaving DFU Mode\n"); + send_recv(dfu_cmd, 16, NULL, 0); + } else if (data[0] == STLINK_DEV_SWIM_MODE) { + uint8_t swim_cmd[16] = {STLINK_SWIM_COMMAND, STLINK_SWIM_EXIT}; + DEBUG("Leaving SWIM Mode\n"); + send_recv(swim_cmd, 16, NULL, 0); + } else if (data[0] == STLINK_DEV_DEBUG_MODE) { + uint8_t dbg_cmd[16] = {STLINK_DEBUG_COMMAND, STLINK_DEBUG_EXIT}; + DEBUG("Leaving DEBUG Mode\n"); + send_recv(dbg_cmd, 16, NULL, 0); + } else if (data[0] == STLINK_DEV_BOOTLOADER_MODE) { + DEBUG("Leaving BOOTLOADER Mode\n"); + } else if (data[0] == STLINK_DEV_MASS_MODE) { + DEBUG("Leaving MASS Mode\n"); + } else { + DEBUG("Unknown Mode %02x\n", data[0]); + } +} + +const char *stlink_target_voltage(void) +{ + uint8_t cmd[16] = {STLINK_GET_TARGET_VOLTAGE}; + uint8_t data[8]; + send_recv(cmd, 16, data, 8); + uint16_t adc[2]; + adc[0] = data[0] | data[1] << 8; /* Calibration value? */ + adc[1] = data[4] | data[5] << 8; /* Measured value?*/ + float result = 0.0; + if (adc[0]) + result = 2.0 * adc[1] * 1.2 / adc[0]; + static char res[6]; + sprintf(res, "%4.2fV", result); + return res; +} + +static void stlink_resetsys(void) +{ + uint8_t cmd[16] = {STLINK_DEBUG_COMMAND ,STLINK_DEBUG_APIV2_RESETSYS}; + uint8_t data[2]; + send_recv(cmd, 16, data, 2); +} + +void stlink_init(int argc, char **argv) +{ + BMP_CL_OPTIONS_t cl_opts = {0}; + cl_opts.opt_idstring = "Blackmagic Debug Probe on StlinkV2/3"; + cl_init(&cl_opts, argc, argv); + libusb_device **devs, *dev; + int r; + int ret = -1; + atexit(exit_function); + signal(SIGTERM, sigterm_handler); + signal(SIGINT, sigterm_handler); + libusb_init(&Stlink.libusb_ctx); + r = libusb_init(NULL); + if (r < 0) + DEBUG("Failed: %s", libusb_strerror(r)); + bool hotplug = true; + if (!libusb_has_capability (LIBUSB_CAP_HAS_HOTPLUG)) { + printf("Hotplug capabilites are not supported on this platform\n"); + hotplug = false; + } + ssize_t cnt; + rescan: + has_attached = 0; + memset(&Stlink, 0, sizeof(Stlink)); + cnt = libusb_get_device_list(NULL, &devs); + if (cnt < 0) { + DEBUG("Failed: %s", libusb_strerror(r)); + goto error; + } + int i = 0; + int nr_stlinks = 0; + while ((dev = devs[i++]) != NULL) { + struct libusb_device_descriptor desc; + int r = libusb_get_device_descriptor(dev, &desc); + if (r < 0) { + fprintf(stderr, "libusb_get_device_descriptor failed %s", + libusb_strerror(r)); + goto error; + } + if ((desc.idVendor == VENDOR_ID_STLINK) && + ((desc.idProduct & PRODUCT_ID_STLINK_MASK) == + PRODUCT_ID_STLINK_GROUP)) { + if (desc.idProduct == PRODUCT_ID_STLINKV1) { /* Reject V1 devices.*/ + DEBUG("STLINKV1 not supported\n"); + continue; + } + Stlink.vid = desc.idVendor; + Stlink.pid = desc.idProduct; + r = libusb_open(dev, &Stlink.handle); + if (r == LIBUSB_SUCCESS) { + uint8_t data[32]; + uint16_t lang; + libusb_get_string_descriptor( + Stlink.handle, 0, 0, data, sizeof(data)); + lang = data[2] << 8 | data[3]; + unsigned char sernum[32]; + if (desc.iSerialNumber) { + r = libusb_get_string_descriptor + (Stlink.handle, desc.iSerialNumber, lang, + sernum, sizeof(sernum)); + } else { + DEBUG("No serial number\n"); + } + /* Older devices have hex values instead of ascii + * in the serial string. Recode eventually!*/ + bool readable = true; + uint16_t *p = (uint16_t *)sernum; + for (p += 1; *p; p++) { + bool isr = isalnum(*p); + readable &= isr; + } + char *s = Stlink.serial; + p = (uint16_t *)sernum; + for (p += 1; *p; p++, s++) { + if (readable) + *s = *p; + else + snprintf(s, 3, "%02x", *p & 0xff); + } + if (cl_opts.opt_serial && (!strncmp(Stlink.serial, cl_opts.opt_serial, + strlen(cl_opts.opt_serial)))) + DEBUG("Found "); + if (desc.idProduct == PRODUCT_ID_STLINKV2) { + DEBUG("STLINKV20 serial %s\n", Stlink.serial); + Stlink.ver_hw = 20; + Stlink.ep_tx = 2; + } else if (desc.idProduct == PRODUCT_ID_STLINKV21) { + DEBUG("STLINKV21 serial %s\n", Stlink.serial); + Stlink.ver_hw = 21; + Stlink.ep_tx = 1; + } else if (desc.idProduct == PRODUCT_ID_STLINKV21_MSD) { + DEBUG("STLINKV21_MSD serial %s\n", Stlink.serial); + Stlink.ver_hw = 21; + Stlink.ep_tx = 1; + } else if (desc.idProduct == PRODUCT_ID_STLINKV3E) { + DEBUG("STLINKV3E serial %s\n", Stlink.serial); + Stlink.ver_hw = 30; + Stlink.ep_tx = 1; + } else if (desc.idProduct == PRODUCT_ID_STLINKV3) { + DEBUG("STLINKV3 serial %s\n", Stlink.serial); + Stlink.ver_hw = 30; + Stlink.ep_tx = 1; + } else { + DEBUG("Unknown STLINK variant, serial %s\n", Stlink.serial); + } + nr_stlinks++; + if (cl_opts.opt_serial) { + if (!strncmp(Stlink.serial, cl_opts.opt_serial, + strlen(cl_opts.opt_serial))) { + break; + } else { + libusb_close(Stlink.handle); + Stlink.handle = 0; + } + } + } else { + DEBUG("Open failed %s\n", libusb_strerror(r)); + } + } + } + libusb_free_device_list(devs, 1); + if (!Stlink.handle) { + if (nr_stlinks && cl_opts.opt_serial) { + DEBUG("No Stlink with given serial number %s\n", cl_opts.opt_serial); + } else if (nr_stlinks > 1) { + DEBUG("Multiple Stlinks. Please specify serial number\n"); + goto error; + } else { + DEBUG("No Stlink device found!\n"); + } + if (hotplug && !cl_opts.opt_no_wait) { + libusb_hotplug_callback_handle hp; + int rc = libusb_hotplug_register_callback + (NULL, LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED, 0, + VENDOR_ID_STLINK, LIBUSB_HOTPLUG_MATCH_ANY, + LIBUSB_HOTPLUG_MATCH_ANY, + hotplug_callback_attach, NULL, &hp); + if (LIBUSB_SUCCESS != rc) { + DEBUG("Error registering attach callback\n"); + goto error; + } + DEBUG("Waiting for %sST device%s%s to attach\n", + (cl_opts.opt_serial)? "" : "some ", + (cl_opts.opt_serial)? " with serial ": "", + (cl_opts.opt_serial)? cl_opts.opt_serial: ""); + DEBUG("Terminate with ^C\n"); + while (has_attached == 0) { + rc = libusb_handle_events (NULL); + if (rc < 0) + printf("libusb_handle_events() failed: %s\n", + libusb_error_name(rc)); + } + goto rescan; + } + goto error; + } + int config; + r = libusb_get_configuration(Stlink.handle, &config); + if (r) { + DEBUG("libusb_get_configuration failed %d: %s", r, libusb_strerror(r)); + goto error_1; + } + DEBUG("Config %d\n", config); + if (config != 1) { + r = libusb_set_configuration(Stlink.handle, 0); + if (r) { + DEBUG("libusb_set_configuration failed %d: %s", + r, libusb_strerror(r)); + goto error_1; + } + } + r = libusb_claim_interface(Stlink.handle, 0); + if (r) + { + DEBUG("libusb_claim_interface failed %s\n", libusb_strerror(r)); + goto error_1; + } + if (hotplug) { /* Allow gracefully exit when stlink is unplugged*/ + libusb_hotplug_callback_handle hp; + int rc = libusb_hotplug_register_callback + (NULL, LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT, 0, Stlink.vid, Stlink.pid, + LIBUSB_HOTPLUG_MATCH_ANY, hotplug_callback_detach, NULL, &hp); + if (LIBUSB_SUCCESS != rc) { + DEBUG("Error registering detach callback\n"); + goto error; + } + } + Stlink.req_trans = libusb_alloc_transfer(0); + Stlink.rep_trans = libusb_alloc_transfer(0); + stlink_version(); + if ((Stlink.ver_stlink < 3 && Stlink.ver_jtag < 32) || + (Stlink.ver_stlink == 3 && Stlink.ver_jtag < 3)) { + /* Maybe the adapter is in some strange state. Try to reset */ + int result = libusb_reset_device(Stlink.handle); + DEBUG("Trying reset\n"); + if (result == LIBUSB_ERROR_BUSY) { /* Try again */ + platform_delay(50); + result = libusb_reset_device(Stlink.handle); + } + if (result != LIBUSB_SUCCESS) { + DEBUG("libusb_reset_device failed\n"); + goto error_1; + } + stlink_version(); + } + if ((Stlink.ver_stlink < 3 && Stlink.ver_jtag < 32) || + (Stlink.ver_stlink == 3 && Stlink.ver_jtag < 3)) { + DEBUG("Please update Firmware\n"); + goto error_1; + } + stlink_leave_state(); + stlink_resetsys(); + if (cl_opts.opt_mode != BMP_MODE_DEBUG) { + ret = cl_execute(&cl_opts); + } else { + assert(gdb_if_init() == 0); + return; + } + error_1: + libusb_close(Stlink.handle); + error: + libusb_exit(Stlink.libusb_ctx); + exit(ret); +} + +void stlink_srst_set_val(bool assert) +{ + uint8_t cmd[16] = {STLINK_DEBUG_COMMAND, + STLINK_DEBUG_APIV2_DRIVE_NRST, + (assert)? STLINK_DEBUG_APIV2_DRIVE_NRST_LOW + : STLINK_DEBUG_APIV2_DRIVE_NRST_HIGH}; + uint8_t data[2]; + send_recv(cmd, 16, data, 2); + stlink_usb_error_check(data, true); +} + +bool stlink_set_freq_divisor(uint16_t divisor) +{ + uint8_t cmd[16] = {STLINK_DEBUG_COMMAND, + STLINK_DEBUG_APIV2_SWD_SET_FREQ, + divisor & 0xff, divisor >> 8}; + uint8_t data[2]; + send_recv(cmd, 16, data, 2); + if (stlink_usb_error_check(data, false)) + return false; + return true; +} + +bool stlink3_set_freq_divisor(uint16_t divisor) +{ + uint8_t cmd[16] = {STLINK_DEBUG_COMMAND, + STLINK_APIV3_GET_COM_FREQ, + Stlink.transport_mode}; + uint8_t data[52]; + send_recv(cmd, 16, data, 52); + stlink_usb_error_check(data, true); + int size = data[8]; + if (divisor > size) + divisor = size; + uint8_t *p = data + 12 + divisor * sizeof(uint32_t); + uint32_t freq = p[0] | p[1] << 8 | p[2] << 16 | p[3] << 24; + DEBUG("Selected %" PRId32 " khz\n", freq); + cmd[1] = STLINK_APIV3_SET_COM_FREQ; + cmd[2] = Stlink.transport_mode; + cmd[3] = 0; + p = data + 12 + divisor * sizeof(uint32_t); + cmd[4] = p[0]; + cmd[5] = p[1]; + cmd[6] = p[2]; + cmd[7] = p[3]; + send_recv(cmd, 16, data, 8); + return true; +} + +int stlink_hwversion(void) +{ + return Stlink.ver_stlink; +} + +int stlink_enter_debug_swd(void) +{ + stlink_leave_state(); + Stlink.transport_mode = STLINK_MODE_SWD; + if (Stlink.ver_stlink == 3) + stlink3_set_freq_divisor(2); + else + stlink_set_freq_divisor(1); + uint8_t cmd[16] = {STLINK_DEBUG_COMMAND, + STLINK_DEBUG_APIV2_ENTER, + STLINK_DEBUG_ENTER_SWD_NO_RESET}; + uint8_t data[2]; + DEBUG("Enter SWD\n"); + send_recv_retry(cmd, 16, data, 2); + return stlink_usb_error_check(data, true); +} + +int stlink_enter_debug_jtag(void) +{ + stlink_leave_state(); + Stlink.transport_mode = STLINK_MODE_JTAG; + if (Stlink.ver_stlink == 3) + stlink3_set_freq_divisor(4); + else + stlink_set_freq_divisor(1); + uint8_t cmd[16] = {STLINK_DEBUG_COMMAND, + STLINK_DEBUG_APIV2_ENTER, + STLINK_DEBUG_ENTER_JTAG_NO_RESET}; + uint8_t data[2]; + DEBUG("Enter JTAG\n"); + send_recv(cmd, 16, data, 2); + return stlink_usb_error_check(data, true); +} + +uint32_t stlink_read_coreid(void) +{ + uint8_t cmd[16] = {STLINK_DEBUG_COMMAND, + STLINK_DEBUG_READCOREID}; + uint8_t data[4]; + send_recv(cmd, 16, data, 4); + uint32_t id = data[0] | data[1] << 8 | data[2] << 16 | data[3] << 24; + DEBUG("Read Core ID: 0x%08" PRIx32 "\n", id); + return id; +} + +int stlink_read_idcodes(uint32_t *idcodes) +{ + uint8_t cmd[16] = {STLINK_DEBUG_COMMAND, + STLINK_DEBUG_APIV2_READ_IDCODES}; + uint8_t data[12]; + send_recv(cmd, 16, data, 12); + if (stlink_usb_error_check(data, true)) + return 0; + uint8_t *p = data + 4; + idcodes[0] = p[0] | p[1] << 8 | p[2] << 16 | p[3] << 24; + p += 4; + idcodes[1] = p[0] | p[1] << 8 | p[2] << 16 | p[3] << 24; + return 2; +} + +uint32_t stlink_dp_read(ADIv5_DP_t *dp, uint16_t addr) +{ + if (addr & ADIV5_APnDP) { + DEBUG_STLINK("AP read addr 0x%04" PRIx16 "\n", addr); + stlink_dp_low_access(dp, ADIV5_LOW_READ, addr, 0); + return stlink_dp_low_access(dp, ADIV5_LOW_READ, + ADIV5_DP_RDBUFF, 0); + } else { + DEBUG_STLINK("DP read addr 0x%04" PRIx16 "\n", addr); + return stlink_dp_low_access(dp, ADIV5_LOW_READ, addr, 0); + } +} + +uint32_t stlink_dp_error(ADIv5_DP_t *dp) +{ + uint32_t err, clr = 0; + + err = stlink_dp_read(dp, ADIV5_DP_CTRLSTAT) & + (ADIV5_DP_CTRLSTAT_STICKYORUN | ADIV5_DP_CTRLSTAT_STICKYCMP | + ADIV5_DP_CTRLSTAT_STICKYERR | ADIV5_DP_CTRLSTAT_WDATAERR); + + if(err & ADIV5_DP_CTRLSTAT_STICKYORUN) + clr |= ADIV5_DP_ABORT_ORUNERRCLR; + if(err & ADIV5_DP_CTRLSTAT_STICKYCMP) + clr |= ADIV5_DP_ABORT_STKCMPCLR; + if(err & ADIV5_DP_CTRLSTAT_STICKYERR) + clr |= ADIV5_DP_ABORT_STKERRCLR; + if(err & ADIV5_DP_CTRLSTAT_WDATAERR) + clr |= ADIV5_DP_ABORT_WDERRCLR; + + adiv5_dp_write(dp, ADIV5_DP_ABORT, clr); + dp->fault = 0; + if (err) + DEBUG("stlink_dp_error %d\n", err); + err |= Stlink.ap_error; + Stlink.ap_error = false; + return err; +} + +void stlink_dp_abort(ADIv5_DP_t *dp, uint32_t abort) +{ + adiv5_dp_write(dp, ADIV5_DP_ABORT, abort); +} + +int stlink_read_dp_register(uint16_t port, uint16_t addr, uint32_t *reg) +{ + uint8_t cmd[16] = {STLINK_DEBUG_COMMAND, + STLINK_DEBUG_APIV2_READ_DAP_REG, + port & 0xff, port >> 8, + addr & 0xff, addr >> 8}; + if (port == STLINK_DEBUG_PORT_ACCESS && Stlink.dap_select) + cmd[4] = ((Stlink.dap_select & 0xf) << 4) | (addr & 0xf); + else + cmd[4] = addr & 0xff; + DEBUG_STLINK("Read DP, Addr 0x%04" PRIx16 ": \n", addr); + uint8_t data[8]; + int res = send_recv_retry(cmd, 16, data, 8); + if (res == STLINK_ERROR_OK) { + uint32_t ret = data[4] | data[5] << 8 | data[6] << 16 | data[7] << 24; + DEBUG_STLINK("0x%08" PRIx32" \n", ret); + *reg = ret; + } else { + DEBUG_STLINK("failed, res %d\n", res); + } + return res; +} + +int stlink_write_dp_register(uint16_t port, uint16_t addr, uint32_t val) +{ + if (port == STLINK_DEBUG_PORT_ACCESS && addr == 8) { + Stlink.dap_select = val; + DEBUG_STLINK("Caching SELECT 0x%02" PRIx32 "\n", val); + return STLINK_ERROR_OK; + } else { + uint8_t cmd[16] = { + STLINK_DEBUG_COMMAND, STLINK_DEBUG_APIV2_WRITE_DAP_REG, + port & 0xff, port >> 8, + addr & 0xff, addr >> 8, + val & 0xff, (val >> 8) & 0xff, (val >> 16) & 0xff, + (val >> 24) & 0xff}; + uint8_t data[2]; + send_recv_retry(cmd, 16, data, 2); + DEBUG_STLINK("Write DP, Addr 0x%04" PRIx16 ": 0x%08" PRIx32 + " \n", addr, val); + return stlink_usb_error_check(data, true); + } +} + +uint32_t stlink_dp_low_access(ADIv5_DP_t *dp, uint8_t RnW, + uint16_t addr, uint32_t value) +{ + uint32_t response = 0; + int res; + if (RnW) { + res = stlink_read_dp_register( + STLINK_DEBUG_PORT_ACCESS, addr, &response); + DEBUG_STLINK("SWD read addr %04" PRIx16 ": %08" PRIx32 "\n", + addr, response); + } else { + DEBUG_STLINK("SWD write addr %04" PRIx16 ": %08" PRIx32 "\n", + addr, value); + res = stlink_write_dp_register(STLINK_DEBUG_PORT_ACCESS, addr, value); + } + if (res == STLINK_ERROR_WAIT) + raise_exception(EXCEPTION_TIMEOUT, "DP ACK timeout"); + + if(res == STLINK_ERROR_DP_FAULT) { + dp->fault = 1; + return 0; + } + if(res == STLINK_ERROR_FAIL) + raise_exception(EXCEPTION_ERROR, "SWDP invalid ACK"); + + return response; +} + +static bool stlink_ap_setup(int ap) +{ + if (ap > 7) + return false; + uint8_t cmd[16] = { + STLINK_DEBUG_COMMAND, + STLINK_DEBUG_APIV2_INIT_AP, + ap, + }; + uint8_t data[2]; + send_recv_retry(cmd, 16, data, 2); + DEBUG_STLINK("Open AP %d\n", ap); + int res = stlink_usb_error_check(data, true); + if (res) { + if (Stlink.ver_hw == 30) { + DEBUG("STLINKV3 only connects to STM8/32!\n"); + } + return false; + } + return true; +} + +static void stlink_ap_cleanup(int ap) +{ + uint8_t cmd[16] = { + STLINK_DEBUG_COMMAND, + STLINK_DEBUG_APIV2_CLOSE_AP_DBG, + ap, + }; + uint8_t data[2]; + send_recv(cmd, 16, data, 2); + DEBUG_STLINK("Close AP %d\n", ap); + stlink_usb_error_check(data, true); +} +static int stlink_usb_get_rw_status(bool verbose) +{ + uint8_t cmd[16] = { + STLINK_DEBUG_COMMAND, + STLINK_DEBUG_APIV2_GETLASTRWSTATUS2 + }; + uint8_t data[12]; + send_recv(cmd, 16, data, 12); + return stlink_usb_error_check(data, verbose); +} + +static void stlink_readmem(ADIv5_AP_t *ap, void *dest, uint32_t src, size_t len) +{ + if (len == 0) + return; + size_t read_len = len; + uint8_t type; + char *CMD; + if (src & 1 || len & 1) { + CMD = "READMEM_8BIT"; + type = STLINK_DEBUG_READMEM_8BIT; + if (len > Stlink.block_size) { + DEBUG(" Too large!\n"); + return; + } + if (len == 1) + read_len ++; /* Fix read length as in openocd*/ + } else if (src & 3 || len & 3) { + CMD = "READMEM_16BIT"; + type = STLINK_DEBUG_APIV2_READMEM_16BIT; + } else { + CMD = "READMEM_32BIT"; + type = STLINK_DEBUG_READMEM_32BIT; + + } + DEBUG_STLINK("%s len %zu addr 0x%08" PRIx32 " AP %d : ", + CMD, len, src, ap->apsel); + uint8_t cmd[16] = { + STLINK_DEBUG_COMMAND, + type, + src & 0xff, (src >> 8) & 0xff, (src >> 16) & 0xff, + (src >> 24) & 0xff, + len & 0xff, len >> 8, ap->apsel}; + int res = read_retry(cmd, 16, dest, read_len); + if (res == STLINK_ERROR_OK) { + uint8_t *p = (uint8_t*)dest; + for (size_t i = 0; i < len ; i++) { + DEBUG_STLINK("%02x", *p++); + } + } else { + /* FIXME: What is the right measure when failing? + * + * E.g. TM4C129 gets here when NRF probe reads 0x10000010 + * Approach taken: + * Fill the memory with some fixed pattern so hopefully + * the caller notices the error*/ + DEBUG("stlink_readmem failed\n"); + memset(dest, 0xff, len); + } + DEBUG_STLINK("\n"); +} + +static void stlink_writemem8(ADIv5_AP_t *ap, uint32_t addr, size_t len, + uint8_t *buffer) +{ + DEBUG_STLINK("Mem Write8 AP %d len %zu addr 0x%08" PRIx32 ": ", + ap->apsel, len, addr); + for (size_t t = 0; t < len; t++) { + DEBUG_STLINK("%02x", buffer[t]); + } + DEBUG_STLINK("\n"); + while (len) { + size_t length; + if (len > Stlink.block_size) + length = Stlink.block_size; + else + length = len; + uint8_t cmd[16] = { + STLINK_DEBUG_COMMAND, + STLINK_DEBUG_WRITEMEM_8BIT, + addr & 0xff, (addr >> 8) & 0xff, (addr >> 16) & 0xff, + (addr >> 24) & 0xff, + length & 0xff, length >> 8, ap->apsel}; + send_recv(cmd, 16, NULL, 0); + send_recv((void*)buffer, length, NULL, 0); + stlink_usb_get_rw_status(true); + len -= length; + addr += length; + } +} + +static void stlink_writemem16(ADIv5_AP_t *ap, uint32_t addr, size_t len, + uint16_t *buffer) +{ + DEBUG_STLINK("Mem Write16 AP %d len %zu addr 0x%08" PRIx32 ": ", + ap->apsel, len, addr); + for (size_t t = 0; t < len; t+=2) { + DEBUG_STLINK("%04x", buffer[t]); + } + DEBUG_STLINK("\n"); + uint8_t cmd[16] = { + STLINK_DEBUG_COMMAND, + STLINK_DEBUG_APIV2_WRITEMEM_16BIT, + addr & 0xff, (addr >> 8) & 0xff, (addr >> 16) & 0xff, + (addr >> 24) & 0xff, + len & 0xff, len >> 8, ap->apsel}; + send_recv(cmd, 16, NULL, 0); + send_recv((void*)buffer, len, NULL, 0); + stlink_usb_get_rw_status(true); +} + +static void stlink_writemem32(ADIv5_AP_t *ap, uint32_t addr, size_t len, + uint32_t *buffer) +{ + DEBUG_STLINK("Mem Write32 AP %d len %zu addr 0x%08" PRIx32 ": ", + ap->apsel, len, addr); + for (size_t t = 0; t < len; t+=4) { + DEBUG_STLINK("%04x", buffer[t]); + } + DEBUG_STLINK("\n"); + uint8_t cmd[16] = { + STLINK_DEBUG_COMMAND, + STLINK_DEBUG_WRITEMEM_32BIT, + addr & 0xff, (addr >> 8) & 0xff, (addr >> 16) & 0xff, + (addr >> 24) & 0xff, + len & 0xff, len >> 8, ap->apsel}; + write_retry(cmd, 16, (void*)buffer, len); +} + +void stlink_regs_read(ADIv5_AP_t *ap, void *data) +{ + uint8_t cmd[16] = {STLINK_DEBUG_COMMAND, STLINK_DEBUG_APIV2_READALLREGS, + ap->apsel}; + uint8_t res[88]; + DEBUG_STLINK("AP %d: Read all core registers\n", ap->apsel); + send_recv(cmd, 16, res, 88); + stlink_usb_error_check(res, true); + memcpy(data, res + 4, 84); +} + +uint32_t stlink_reg_read(ADIv5_AP_t *ap, int num) +{ + uint8_t cmd[16] = {STLINK_DEBUG_COMMAND, STLINK_DEBUG_APIV2_READREG, num, + ap->apsel}; + uint8_t res[8]; + send_recv(cmd, 16, res, 8); + stlink_usb_error_check(res, true); + uint32_t ret = res[0] | res[1] << 8 | res[2] << 16 | res[3] << 24; + DEBUG_STLINK("AP %d: Read reg %02" PRId32 " val 0x%08" PRIx32 "\n", + ap->apsel, num, ret); + return ret; +} + +void stlink_reg_write(ADIv5_AP_t *ap, int num, uint32_t val) +{ + uint8_t cmd[16] = { + STLINK_DEBUG_COMMAND, STLINK_DEBUG_APIV2_WRITEREG, num, + val & 0xff, (val >> 8) & 0xff, (val >> 16) & 0xff, + (val >> 24) & 0xff, ap->apsel}; + uint8_t res[2]; + send_recv(cmd, 16, res, 2); + DEBUG_STLINK("AP %d: Write reg %02" PRId32 " val 0x%08" PRIx32 "\n", + ap->apsel, num, val); + stlink_usb_error_check(res, true); +} + +static void stlink_mem_write_sized( ADIv5_AP_t *ap, uint32_t dest, + const void *src, size_t len, + enum align align) +{ + if (len == 0) + return; + switch(align) { + case ALIGN_BYTE: stlink_writemem8(ap, dest, len, (uint8_t *) src); + break; + case ALIGN_HALFWORD: stlink_writemem16(ap, dest, len, (uint16_t *) src); + break; + case ALIGN_WORD: stlink_writemem32(ap, dest, len, (uint32_t *) src); + break; + case ALIGN_DWORD: stlink_writemem32(ap, dest, len, (uint32_t *) src); + break; + } +} + +static void stlink_ap_write(ADIv5_AP_t *ap, uint16_t addr, uint32_t value) +{ + stlink_write_dp_register(ap->apsel, addr, value); +} + +static uint32_t stlink_ap_read(ADIv5_AP_t *ap, uint16_t addr) +{ + uint32_t ret; + stlink_read_dp_register(ap->apsel, addr, &ret); + return ret; +} + +struct jtag_dev_s jtag_devs[JTAG_MAX_DEVS+1]; +int jtag_dev_count; +jtag_proc_t jtag_proc; + +int jtag_scan_stlinkv2(const uint8_t *irlens) +{ + uint32_t idcodes[JTAG_MAX_DEVS+1]; + (void) *irlens; + target_list_free(); + + jtag_dev_count = 0; + memset(&jtag_devs, 0, sizeof(jtag_devs)); + if (stlink_enter_debug_jtag()) + return 0; + jtag_dev_count = stlink_read_idcodes(idcodes); + /* Check for known devices and handle accordingly */ + for(int i = 0; i < jtag_dev_count; i++) + jtag_devs[i].idcode = idcodes[i]; + for(int i = 0; i < jtag_dev_count; i++) + for(int j = 0; dev_descr[j].idcode; j++) + if((jtag_devs[i].idcode & dev_descr[j].idmask) == + dev_descr[j].idcode) { + if(dev_descr[j].handler) + dev_descr[j].handler(&jtag_devs[i]); + break; + } + + return jtag_dev_count; +} + +int platform_jtag_dp_init(ADIv5_DP_t *dp) +{ + dp->dp_read = stlink_dp_read; + dp->error = stlink_dp_error; + dp->low_access = stlink_dp_low_access; + dp->abort = stlink_dp_abort; + + return true; + +} + +int platform_adiv5_dp_defaults(ADIv5_DP_t *dp) +{ + dp->ap_regs_read = stlink_regs_read; + dp->ap_reg_read = stlink_reg_read; + dp->ap_reg_write = stlink_reg_write; + dp->ap_setup = stlink_ap_setup; + dp->ap_cleanup = stlink_ap_cleanup; + dp->ap_write = stlink_ap_write; + dp->ap_read = stlink_ap_read; + dp->mem_read = stlink_readmem; + dp->mem_write_sized = stlink_mem_write_sized; + + return 0; +} diff --git a/src/platforms/hosted/stlinkv2.h b/src/platforms/hosted/stlinkv2.h new file mode 100644 index 00000000..dea9a8b7 --- /dev/null +++ b/src/platforms/hosted/stlinkv2.h @@ -0,0 +1,52 @@ +/* + * This file is part of the Black Magic Debug project. + * + * Copyright (C) 2019 Uwe Bonnes + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#if !defined(__STLINKV2_H_) + +#define STLINK_ERROR_FAIL -1 +#define STLINK_ERROR_OK 0 +#define STLINK_ERROR_WAIT 1 + +#define STLINK_DEBUG_PORT_ACCESS 0xffff + +void stlink_init(int argc, char **argv); +int stlink_hwversion(void); +void stlink_leave_state(void); +const char *stlink_target_voltage(void); +void stlink_srst_set_val(bool assert); +int stlink_enter_debug_swd(void); +int stlink_enter_debug_jtag(void); +int stlink_read_idcodes(uint32_t *); +uint32_t stlink_read_coreid(void); +int stlink_read_dp_register(uint16_t port, uint16_t addr, uint32_t *res); +int stlink_write_dp_register(uint16_t port, uint16_t addr, uint32_t val); + +uint32_t stlink_dp_low_access(ADIv5_DP_t *dp, uint8_t RnW, + uint16_t addr, uint32_t value); +uint32_t stlink_dp_read(ADIv5_DP_t *dp, uint16_t addr); +uint32_t stlink_dp_error(ADIv5_DP_t *dp); +void stlink_dp_abort(ADIv5_DP_t *dp, uint32_t abort); +int stlink_open_ap(uint8_t ap); +void stlink_close_ap(uint8_t ap); +void stlink_regs_read(ADIv5_AP_t *ap, void *data); +uint32_t stlink_reg_read(ADIv5_AP_t *ap, int idx); +void stlink_reg_write(ADIv5_AP_t *ap, int num, uint32_t val); +extern int debug_level; +# define DEBUG_STLINK if (debug_level > 0) printf +# define DEBUG_USB if (debug_level > 1) printf +#endif From dd022fcb4416bb4a3021f24d34540473c07ee4a9 Mon Sep 17 00:00:00 2001 From: Uwe Bonnes Date: Sat, 25 Apr 2020 14:39:53 +0200 Subject: [PATCH 07/13] platforms/pc: Add common usb utilities. --- src/platforms/hosted/Makefile.inc | 2 +- src/platforms/pc/cl_utils.h | 1 + src/platforms/pc/libusb_utils.c | 144 ++++++++++++++++++++++++++++++ src/platforms/pc/libusb_utils.h | 41 +++++++++ src/platforms/pc/serial_unix.c | 2 +- src/platforms/pc/serial_win.c | 1 - 6 files changed, 188 insertions(+), 3 deletions(-) create mode 100644 src/platforms/pc/libusb_utils.c create mode 100644 src/platforms/pc/libusb_utils.h diff --git a/src/platforms/hosted/Makefile.inc b/src/platforms/hosted/Makefile.inc index fc00abe2..d11199fa 100644 --- a/src/platforms/hosted/Makefile.inc +++ b/src/platforms/hosted/Makefile.inc @@ -8,5 +8,5 @@ else ifneq (, $(findstring cygwin, $(SYS))) LDFLAGS += -lws2_32 endif VPATH += platforms/pc -SRC += timing.c cl_utils.c utils.c +SRC += timing.c cl_utils.c utils.c libusb_utils.c PC_HOSTED = 1 diff --git a/src/platforms/pc/cl_utils.h b/src/platforms/pc/cl_utils.h index f25bd3ff..676fbfb2 100644 --- a/src/platforms/pc/cl_utils.h +++ b/src/platforms/pc/cl_utils.h @@ -53,6 +53,7 @@ typedef struct BMP_CL_OPTIONS_s { char *opt_idstring; }BMP_CL_OPTIONS_t; +extern int cl_debuglevel; void cl_init(BMP_CL_OPTIONS_t *opt, int argc, char **argv); int cl_execute(BMP_CL_OPTIONS_t *opt); int serial_open(BMP_CL_OPTIONS_t *opt); diff --git a/src/platforms/pc/libusb_utils.c b/src/platforms/pc/libusb_utils.c new file mode 100644 index 00000000..26c95a02 --- /dev/null +++ b/src/platforms/pc/libusb_utils.c @@ -0,0 +1,144 @@ +/* + * This file is part of the Black Magic Debug project. + * + * Copyright (C) 2020 Uwe Bonnes (bon@elektron.ikp.physik.tu-darmstadt.de) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include "general.h" +#include "cl_utils.h" +#include + +static void LIBUSB_CALL on_trans_done(struct libusb_transfer *trans) +{ + struct trans_ctx * const ctx = trans->user_data; + + if (trans->status != LIBUSB_TRANSFER_COMPLETED) + { + fprintf(stderr, "on_trans_done: "); + if(trans->status == LIBUSB_TRANSFER_TIMED_OUT) { + fprintf(stderr, " Timeout\n"); + } else if (trans->status == LIBUSB_TRANSFER_CANCELLED) { + fprintf(stderr, " cancelled\n"); + } else if (trans->status == LIBUSB_TRANSFER_NO_DEVICE) { + fprintf(stderr, " no device\n"); + } else { + fprintf(stderr, " unknown\n"); + } + ctx->flags |= TRANS_FLAGS_HAS_ERROR; + } + ctx->flags |= TRANS_FLAGS_IS_DONE; +} + +static int submit_wait(usb_link_t *link, struct libusb_transfer *trans) { + struct trans_ctx trans_ctx; + enum libusb_error error; + + trans_ctx.flags = 0; + + /* brief intrusion inside the libusb interface */ + trans->callback = on_trans_done; + trans->user_data = &trans_ctx; + + if ((error = libusb_submit_transfer(trans))) { + fprintf(stderr, "libusb_submit_transfer(%d): %s\n", error, + libusb_strerror(error)); + exit(-1); + } + + uint32_t start_time = platform_time_ms(); + while (trans_ctx.flags == 0) { + struct timeval timeout; + timeout.tv_sec = 1; + timeout.tv_usec = 0; + if (libusb_handle_events_timeout(link->ul_libusb_ctx, &timeout)) { + fprintf(stderr, "libusb_handle_events()\n"); + return -1; + } + uint32_t now = platform_time_ms(); + if (now - start_time > 1000) { + libusb_cancel_transfer(trans); + fprintf(stderr, "libusb_handle_events() timeout\n"); + return -1; + } + } + if (trans_ctx.flags & TRANS_FLAGS_HAS_ERROR) { + fprintf(stderr, "libusb_handle_events() | has_error\n"); + return -1; + } + + return 0; +} + +/* One USB transaction */ +int send_recv(usb_link_t *link, + uint8_t *txbuf, size_t txsize, + uint8_t *rxbuf, size_t rxsize) +{ + int res = 0; + if( txsize) { + int txlen = txsize; + libusb_fill_bulk_transfer(link->req_trans, + link->ul_libusb_device_handle, + link->ep_tx | LIBUSB_ENDPOINT_OUT, + txbuf, txlen, + NULL, NULL, 0); + if (cl_debuglevel > 0) { + int i = 0; + printf(" Send (%3d): ", txlen); + for (; i < txlen; i++) { + printf("%02x", txbuf[i]); + if ((i & 7) == 7) + printf("."); + if ((i & 31) == 31) + printf("\n "); + } + if (!(i & 31)) + printf("\n"); + } + if (submit_wait(link, link->req_trans)) { + libusb_clear_halt(link->ul_libusb_device_handle, link->ep_tx); + return -1; + } + } + /* send_only */ + if (rxsize != 0) { + /* read the response */ + libusb_fill_bulk_transfer(link->rep_trans, link->ul_libusb_device_handle, + link->ep_rx | LIBUSB_ENDPOINT_IN, + rxbuf, rxsize, NULL, NULL, 0); + + if (submit_wait(link, link->rep_trans)) { + DEBUG("clear 1\n"); + libusb_clear_halt(link->ul_libusb_device_handle, link->ep_rx); + return -1; + } + res = link->rep_trans->actual_length; + if (res >0) { + int i; + uint8_t *p = rxbuf; + if (cl_debuglevel > 0) { + printf(" Rec (%zu/%d)", rxsize, res); + for (i = 0; i < res && i < 32 ; i++) { + if ( i && ((i & 7) == 0)) + printf("."); + printf("%02x", p[i]); + } + } + } + } + if (cl_debuglevel > 0) + printf("\n"); + return res; +} diff --git a/src/platforms/pc/libusb_utils.h b/src/platforms/pc/libusb_utils.h new file mode 100644 index 00000000..8f6d868c --- /dev/null +++ b/src/platforms/pc/libusb_utils.h @@ -0,0 +1,41 @@ +/* + * This file is part of the Black Magic Debug project. + * + * Copyright (C) 2020 Uwe Bonnes (bon@elektron.ikp.physik.tu-darmstadt.de) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#if !defined(__LIBUSB_UTILS_H) +#define __LIBUSB_UTILS_H +#include + +struct trans_ctx { +#define TRANS_FLAGS_IS_DONE (1 << 0) +#define TRANS_FLAGS_HAS_ERROR (1 << 1) + volatile unsigned long flags; +}; + +typedef struct { + libusb_context *ul_libusb_ctx; + libusb_device_handle *ul_libusb_device_handle; + unsigned char ep_tx; + unsigned char ep_rx; + struct libusb_transfer* req_trans; + struct libusb_transfer* rep_trans; + void *priv; +} usb_link_t; + +int send_recv(usb_link_t *link, uint8_t *txbuf, size_t txsize, + uint8_t *rxbuf, size_t rxsize); +#endif diff --git a/src/platforms/pc/serial_unix.c b/src/platforms/pc/serial_unix.c index cc186578..214bcc1d 100644 --- a/src/platforms/pc/serial_unix.c +++ b/src/platforms/pc/serial_unix.c @@ -31,7 +31,7 @@ #include "cl_utils.h" static int fd; /* File descriptor for connection to GDB remote */ -extern int cl_debuglevel; + /* A nice routine grabbed from * https://stackoverflow.com/questions/6947413/how-to-open-read-and-write-from-serial-port-in-c */ diff --git a/src/platforms/pc/serial_win.c b/src/platforms/pc/serial_win.c index a39d1a1a..f9da89fc 100644 --- a/src/platforms/pc/serial_win.c +++ b/src/platforms/pc/serial_win.c @@ -24,7 +24,6 @@ #include "cl_utils.h" HANDLE hComm; -extern int cl_debuglevel; int serial_open(BMP_CL_OPTIONS_t *opt) { From a09104c281a092ed5d69f2179980e0de33c5c380 Mon Sep 17 00:00:00 2001 From: Uwe Bonnes Date: Mon, 20 Apr 2020 17:36:21 +0200 Subject: [PATCH 08/13] Build firmware executables as *.elf file --- .gitignore | 1 + src/Makefile | 14 ++++++++++---- src/platforms/native/Makefile.inc | 2 +- src/platforms/stlink/Makefile.inc | 8 ++++---- src/platforms/swlink/Makefile.inc | 4 ++-- 5 files changed, 18 insertions(+), 11 deletions(-) diff --git a/.gitignore b/.gitignore index 945fd3d9..322deda3 100644 --- a/.gitignore +++ b/.gitignore @@ -16,4 +16,5 @@ tags *.b#* blackmagic_upgrade *.exe +*.elf .vscode diff --git a/src/Makefile b/src/Makefile index 6c9d931d..35ec8f2f 100644 --- a/src/Makefile +++ b/src/Makefile @@ -67,7 +67,11 @@ CFLAGS += $(OPT_FLAGS) LDFLAGS += $(OPT_FLAGS) ifndef TARGET -TARGET=blackmagic +ifdef PC_HOSTED +TARGET = blackmagic +else +TARGET = blackmagic.elf +endif endif ifdef NO_OWN_LL @@ -96,19 +100,21 @@ $(TARGET): include/version.h $(OBJ) @echo " AS $<" $(Q)$(CC) $(CFLAGS) -c $< -o $@ -%.bin: % +ifndef PC_HOSTED +%.bin: %.elf @echo " OBJCOPY $@" $(Q)$(OBJCOPY) -O binary $^ $@ -%.hex: % +%.hex: %.elf @echo " OBJCOPY $@" $(Q)$(OBJCOPY) -O ihex $^ $@ +endif .PHONY: clean host_clean all_platforms FORCE clean: host_clean $(Q)echo " CLEAN" - -$(Q)$(RM) *.o *.d *~ blackmagic $(HOSTFILES) + -$(Q)$(RM) *.o *.d *.elf *~ $(TARGET) $(HOSTFILES) -$(Q)$(RM) platforms/*/*.o platforms/*/*.d mapfile include/version.h all_platforms: diff --git a/src/platforms/native/Makefile.inc b/src/platforms/native/Makefile.inc index d3cef33c..6d3e8ea4 100644 --- a/src/platforms/native/Makefile.inc +++ b/src/platforms/native/Makefile.inc @@ -30,7 +30,7 @@ SRC += cdcacm.c \ all: blackmagic.bin blackmagic_dfu.bin blackmagic_dfu.hex -blackmagic_dfu: usbdfu.o dfucore.o dfu_f1.o +blackmagic_dfu.elf: usbdfu.o dfucore.o dfu_f1.o @echo " LD $@" $(Q)$(CC) $^ -o $@ $(LDFLAGS_BOOT) diff --git a/src/platforms/stlink/Makefile.inc b/src/platforms/stlink/Makefile.inc index a0cf7def..66feef6b 100644 --- a/src/platforms/stlink/Makefile.inc +++ b/src/platforms/stlink/Makefile.inc @@ -37,18 +37,18 @@ SRC += cdcacm.c \ stlink_common.c \ ifeq ($(ST_BOOTLOADER), 1) -all: blackmagic.bin blackmagic_dfu.bin blackmagic_dfu.hex +all: blackmagic.bin else all: blackmagic.bin blackmagic_dfu.bin blackmagic_dfu.hex dfu_upgrade.bin dfu_upgrade.hex endif -blackmagic_dfu: usbdfu.o dfucore.o dfu_f1.o stlink_common.o +blackmagic_dfu.elf: usbdfu.o dfucore.o dfu_f1.o stlink_common.o @echo " LD $@" $(Q)$(CC) $^ -o $@ $(LDFLAGS_BOOT) -dfu_upgrade: dfu_upgrade.o dfucore.o dfu_f1.o stlink_common.o +dfu_upgrade.elf: dfu_upgrade.o dfucore.o dfu_f1.o stlink_common.o @echo " LD $@" $(Q)$(CC) $^ -o $@ $(LDFLAGS) host_clean: - -$(Q)$(RM) blackmagic.bin blackmagic_dfu blackmagic_dfu.bin blackmagic_dfu.hex dfu_upgrade dfu_upgrade.bin dfu_upgrade.hex + -$(Q)$(RM) *.bin *elf *hex diff --git a/src/platforms/swlink/Makefile.inc b/src/platforms/swlink/Makefile.inc index b3831f7c..5ac76ec7 100644 --- a/src/platforms/swlink/Makefile.inc +++ b/src/platforms/swlink/Makefile.inc @@ -31,11 +31,11 @@ SRC += cdcacm.c \ all: blackmagic.bin blackmagic_dfu.bin blackmagic_dfu.hex dfu_upgrade.bin dfu_upgrade.hex -blackmagic_dfu: usbdfu.o dfucore.o dfu_f1.o platform_common.o +blackmagic_dfu.elf: usbdfu.o dfucore.o dfu_f1.o platform_common.o @echo " LD $@" $(Q)$(CC) $^ -o $@ $(LDFLAGS_BOOT) -dfu_upgrade: dfu_upgrade.o dfucore.o dfu_f1.o platform_common.o +dfu_upgrade.elf: dfu_upgrade.o dfucore.o dfu_f1.o platform_common.o @echo " LD $@" $(Q)$(CC) $^ -o $@ $(LDFLAGS) From 8fea3f6baa5fa26999d9113f6a83e36b6685b061 Mon Sep 17 00:00:00 2001 From: Uwe Bonnes Date: Sun, 19 Apr 2020 16:10:02 +0200 Subject: [PATCH 09/13] pc/serial_xx: Change arguments for the open call. --- src/platforms/hosted/platform.c | 4 +++- src/platforms/pc-hosted/platform.c | 2 +- src/platforms/pc/cl_utils.h | 4 +++- src/platforms/pc/serial_unix.c | 13 ++++++------- src/platforms/pc/serial_win.c | 12 +++++++----- 5 files changed, 20 insertions(+), 15 deletions(-) diff --git a/src/platforms/hosted/platform.c b/src/platforms/hosted/platform.c index a10a7a33..8f256f78 100644 --- a/src/platforms/hosted/platform.c +++ b/src/platforms/hosted/platform.c @@ -194,7 +194,9 @@ void platform_init(int argc, char **argv) libusb_strerror(res)); exit(-1); } - if (find_debuggers(&cl_opts, &info)) { + if (cl_opts.opt_device) { + info.bmp_type = BMP_TYPE_BMP; + } else if (find_debuggers(&cl_opts, &info)) { exit(-1); } printf("Using %s %s %s\n", info.serial, diff --git a/src/platforms/pc-hosted/platform.c b/src/platforms/pc-hosted/platform.c index 4be4cde4..849b926a 100644 --- a/src/platforms/pc-hosted/platform.c +++ b/src/platforms/pc-hosted/platform.c @@ -60,7 +60,7 @@ void platform_init(int argc, char **argv) printf("License GPLv3+: GNU GPL version 3 or later " "\n\n"); - if (serial_open(&cl_opts)) + if (serial_open(cl_opts.opt_device, cl_opts.opt_serial)) exit(-1); int c=snprintf(construct,PLATFORM_MAX_MSG_SIZE,"%s",REMOTE_START_STR); platform_buffer_write((uint8_t *)construct,c); diff --git a/src/platforms/pc/cl_utils.h b/src/platforms/pc/cl_utils.h index 676fbfb2..5c485b78 100644 --- a/src/platforms/pc/cl_utils.h +++ b/src/platforms/pc/cl_utils.h @@ -24,6 +24,8 @@ #if !defined(__CL_UTILS_H) #define __CL_UTILS_H +#define RESP_TIMEOUT (100) + enum bmp_cl_mode { BMP_MODE_DEBUG, BMP_MODE_TEST, @@ -56,6 +58,6 @@ typedef struct BMP_CL_OPTIONS_s { extern int cl_debuglevel; void cl_init(BMP_CL_OPTIONS_t *opt, int argc, char **argv); int cl_execute(BMP_CL_OPTIONS_t *opt); -int serial_open(BMP_CL_OPTIONS_t *opt); +int serial_open(BMP_CL_OPTIONS_t *opt, char *serial); void serial_close(void); #endif diff --git a/src/platforms/pc/serial_unix.c b/src/platforms/pc/serial_unix.c index 214bcc1d..2d362591 100644 --- a/src/platforms/pc/serial_unix.c +++ b/src/platforms/pc/serial_unix.c @@ -69,10 +69,10 @@ static int set_interface_attribs(void) } #define BMP_IDSTRING "usb-Black_Sphere_Technologies_Black_Magic_Probe" #define DEVICE_BY_ID "/dev/serial/by-id/" -int serial_open(BMP_CL_OPTIONS_t *opt) +int serial_open(BMP_CL_OPTIONS_t *cl_opts, char *serial) { char name[4096]; - if (!opt->opt_device) { + if (!cl_opts->opt_device) { /* Try to find some BMP if0*/ struct dirent *dp; DIR *dir = opendir(DEVICE_BY_ID); @@ -86,8 +86,7 @@ int serial_open(BMP_CL_OPTIONS_t *opt) if ((strstr(dp->d_name, BMP_IDSTRING)) && (strstr(dp->d_name, "-if00"))) { num_total++; - if (((opt->opt_serial) && - (!strstr(dp->d_name, opt->opt_serial)))) + if ((serial) && (!strstr(dp->d_name, serial))) continue; num_devices++; strcpy(name, DEVICE_BY_ID); @@ -108,8 +107,8 @@ int serial_open(BMP_CL_OPTIONS_t *opt) fprintf(stderr, "%s\n", dp->d_name); } closedir(dir); - if (opt->opt_serial) - fprintf(stderr, "Do no match given serial \"%s\"\n", opt->opt_serial); + if (serial) + fprintf(stderr, "Do no match given serial \"%s\"\n", serial); else fprintf(stderr, "Select Probe with -s <(Partial) Serial Number\n"); } else { @@ -118,7 +117,7 @@ int serial_open(BMP_CL_OPTIONS_t *opt) return -1; } } else { - strncpy(name, opt->opt_device, sizeof(name) - 1); + strncpy(name, cl_opts->opt_device, sizeof(name) - 1); } fd = open(name, O_RDWR | O_SYNC | O_NOCTTY); if (fd < 0) { diff --git a/src/platforms/pc/serial_win.c b/src/platforms/pc/serial_win.c index f9da89fc..3baec321 100644 --- a/src/platforms/pc/serial_win.c +++ b/src/platforms/pc/serial_win.c @@ -25,18 +25,20 @@ HANDLE hComm; -int serial_open(BMP_CL_OPTIONS_t *opt) +int serial_open(BMP_CL_OPTIONS_t *cl_opts, char * serial) { - if (!opt->opt_device) { + (void) serial; /* FIXME: Does Windows allow open with USB serial no? */ + if (!cl_opts->opt_device) { fprintf(stderr,"Specify the serial device to use!\n"); return -1; } char device[256]; - if (strstr(opt->opt_device, "\\\\.\\")) { - strncpy(device, opt->opt_device, sizeof(device) - 1); + if (strstr(device, "\\\\.\\")) { + strncpy(device, cl_opts->opt_device, sizeof(cl_opts->opt_device) - 1); } else { strcpy(device, "\\\\.\\"); - strncat(device, opt->opt_device, sizeof(device) - strlen(device) - 1); + strncat(device, cl_opts->opt_device, + sizeof(cl_opts->opt_device) - strlen(cl_opts->opt_device) - 1); } hComm = CreateFile(device, //port name GENERIC_READ | GENERIC_WRITE, //Read/Write From 09602a9e74c0649995137e2833de85040e026a4f Mon Sep 17 00:00:00 2001 From: Uwe Bonnes Date: Sun, 3 May 2020 17:12:01 +0200 Subject: [PATCH 10/13] serial_unix: Simplify timeout setting. --- src/platforms/pc/serial_unix.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/platforms/pc/serial_unix.c b/src/platforms/pc/serial_unix.c index 2d362591..fd63dc1b 100644 --- a/src/platforms/pc/serial_unix.c +++ b/src/platforms/pc/serial_unix.c @@ -155,15 +155,13 @@ int platform_buffer_read(uint8_t *data, int maxsize) uint8_t *c; int s; int ret; - uint32_t endTime; fd_set rset; struct timeval tv; c = data; tv.tv_sec = 0; - endTime = platform_time_ms() + RESP_TIMEOUT; - tv.tv_usec = 1000 * (endTime - platform_time_ms()); + tv.tv_usec = 1000 * RESP_TIMEOUT; /* Look for start of response */ do { From 13c3c934d2bdc3fd8a3ec008395179345b0cc84d Mon Sep 17 00:00:00 2001 From: Uwe Bonnes Date: Sun, 19 Apr 2020 15:50:50 +0200 Subject: [PATCH 11/13] Hosted: Add Stlink, remove old pc-stlinkv2 platform --- src/platforms/hosted/Makefile.inc | 1 + src/platforms/hosted/platform.c | 146 ++- src/platforms/hosted/platform.h | 6 + src/platforms/hosted/stlinkv2.c | 671 ++++------- src/platforms/hosted/stlinkv2.h | 30 +- src/platforms/pc-stlinkv2/Makefile.inc | 14 - src/platforms/pc-stlinkv2/README.md | 25 - src/platforms/pc-stlinkv2/jtagtap.c | 0 src/platforms/pc-stlinkv2/platform.c | 115 -- src/platforms/pc-stlinkv2/platform.h | 46 - src/platforms/pc-stlinkv2/stlinkv2.c | 1435 ------------------------ src/platforms/pc-stlinkv2/stlinkv2.h | 52 - src/platforms/pc-stlinkv2/swdptap.c | 0 src/platforms/pc/cl_utils.c | 23 +- src/platforms/pc/cl_utils.h | 1 - src/platforms/pc/libusb_utils.c | 1 - 16 files changed, 340 insertions(+), 2226 deletions(-) delete mode 100644 src/platforms/pc-stlinkv2/Makefile.inc delete mode 100644 src/platforms/pc-stlinkv2/README.md delete mode 100644 src/platforms/pc-stlinkv2/jtagtap.c delete mode 100644 src/platforms/pc-stlinkv2/platform.c delete mode 100644 src/platforms/pc-stlinkv2/platform.h delete mode 100644 src/platforms/pc-stlinkv2/stlinkv2.c delete mode 100644 src/platforms/pc-stlinkv2/stlinkv2.h delete mode 100644 src/platforms/pc-stlinkv2/swdptap.c diff --git a/src/platforms/hosted/Makefile.inc b/src/platforms/hosted/Makefile.inc index d11199fa..94ed44bf 100644 --- a/src/platforms/hosted/Makefile.inc +++ b/src/platforms/hosted/Makefile.inc @@ -9,4 +9,5 @@ LDFLAGS += -lws2_32 endif VPATH += platforms/pc SRC += timing.c cl_utils.c utils.c libusb_utils.c +SRC += stlinkv2.c PC_HOSTED = 1 diff --git a/src/platforms/hosted/platform.c b/src/platforms/hosted/platform.c index 8f256f78..69f340b3 100644 --- a/src/platforms/hosted/platform.c +++ b/src/platforms/hosted/platform.c @@ -24,9 +24,14 @@ #include "general.h" #include "swdptap.h" #include "jtagtap.h" +#include "target.h" +#include "target_internal.h" +#include "adiv5.h" #include "timing.h" #include "cl_utils.h" +#include "gdb_if.h" #include +#include "stlinkv2.h" #define VENDOR_ID_BMP 0x1d50 #define PRODUCT_ID_BMP 0x6018 @@ -48,8 +53,20 @@ jtag_proc_t jtag_proc; static void exit_function(void) { - libusb_exit(info.libusb_ctx); - fprintf(stderr, "INFO: Cleanup\n"); + if(info.usb_link) { + libusb_free_transfer(info.usb_link->req_trans); + libusb_free_transfer(info.usb_link->rep_trans); + if (info.usb_link->ul_libusb_device_handle) { + libusb_release_interface ( + info.usb_link->ul_libusb_device_handle, 0); + libusb_close(info.usb_link->ul_libusb_device_handle); + } + } + switch (info.bmp_type) { + default: + break; + } + fflush(stdout); } /* SIGTERM handler. */ @@ -82,7 +99,7 @@ static int find_debuggers( BMP_CL_OPTIONS_t *cl_opts,bmp_info_t *info) if (res < 0) { fprintf(stderr, "WARN: libusb_get_device_descriptor() failed: %s", libusb_strerror(res)); - libusb_free_device_list(devs, 0); + libusb_free_device_list(devs, 1); continue; } libusb_device_handle *handle; @@ -119,13 +136,13 @@ static int find_debuggers( BMP_CL_OPTIONS_t *cl_opts,bmp_info_t *info) continue; } } + libusb_close(handle); if (cl_opts->opt_ident_string) { char *match_manu = NULL; char *match_product = NULL; match_manu = strstr(manufacturer, cl_opts->opt_ident_string); match_product = strstr(product, cl_opts->opt_ident_string); if (!match_manu && !match_product) { - libusb_close(handle); continue; } } @@ -135,16 +152,16 @@ static int find_debuggers( BMP_CL_OPTIONS_t *cl_opts,bmp_info_t *info) (desc.idProduct == PRODUCT_ID_BMP)) { type = BMP_TYPE_BMP; } else if (desc.idVendor == VENDOR_ID_STLINK) { - if (desc.idProduct == PRODUCT_ID_STLINKV1) { - fprintf(stderr, "INFO: STLINKV1 not supported\n"); - continue; - } if ((desc.idProduct == PRODUCT_ID_STLINKV2) || (desc.idProduct == PRODUCT_ID_STLINKV21) || (desc.idProduct == PRODUCT_ID_STLINKV21_MSD) || (desc.idProduct == PRODUCT_ID_STLINKV3) || (desc.idProduct == PRODUCT_ID_STLINKV3E)) { type = BMP_TYPE_STLINKV2; + } else { + if (desc.idProduct == PRODUCT_ID_STLINKV1) + fprintf(stderr, "INFO: STLINKV1 not supported\n"); + continue; } } else { continue; @@ -176,8 +193,8 @@ static int find_debuggers( BMP_CL_OPTIONS_t *cl_opts,bmp_info_t *info) goto rescan; } } - libusb_free_device_list(devs, 0); - return 0; + libusb_free_device_list(devs, 1); + return (found_debuggers == 1) ? 0 : -1; } void platform_init(int argc, char **argv) @@ -202,39 +219,98 @@ void platform_init(int argc, char **argv) printf("Using %s %s %s\n", info.serial, info.manufacturer, info.product); - exit(-1); + switch (info.bmp_type) { + case BMP_TYPE_STLINKV2: + if (stlink_init( &info)) + exit(-1); + break; + default: + exit(-1); + } + int ret = -1; + if (cl_opts.opt_mode != BMP_MODE_DEBUG) { + ret = cl_execute(&cl_opts); + } else { + gdb_if_init(); + return; + } + exit(ret); } int platform_adiv5_swdp_scan(void) { - return -1; + switch (info.bmp_type) { + case BMP_TYPE_STLINKV2: + { + target_list_free(); + ADIv5_DP_t *dp = (void*)calloc(1, sizeof(*dp)); + if (!stlink_enter_debug_swd(&info, dp)) { + adiv5_dp_init(dp); + if (target_list) + return 1; + } + free(dp); + break; + } + default: + return 0; + } + return 0; } int platform_swdptap_init(void) { + switch (info.bmp_type) { + case BMP_TYPE_STLINKV2: + return 0; + break; + default: + return -1; + } return -1; } int platform_jtag_scan(const uint8_t *lrlens) { - (void) lrlens; + switch (info.bmp_type) { + case BMP_TYPE_STLINKV2: + return jtag_scan_stlinkv2(&info, lrlens); + default: + return -1; + } return -1; } int platform_jtagtap_init(void) { - return 0; -} - -int platform_adiv5_dp_defaults(void *arg) -{ - (void)arg; + switch (info.bmp_type) { + case BMP_TYPE_STLINKV2: + return 0; + default: + return -1; + } return -1; } -int platform_jtag_dp_init() +void platform_adiv5_dp_defaults(ADIv5_DP_t *dp) { - return 0; + switch (info.bmp_type) { + case BMP_TYPE_STLINKV2: + return stlink_adiv5_dp_defaults(dp); + default: + break; + } +} + +int platform_jtag_dp_init(ADIv5_DP_t *dp) +{ + switch (info.bmp_type) { + case BMP_TYPE_STLINKV2: + return stlink_jtag_dp_init(dp); + default: + return -1; + } + return 0; } char *platform_ident(void) @@ -258,10 +334,34 @@ char *platform_ident(void) const char *platform_target_voltage(void) { + switch (info.bmp_type) { + case BMP_TYPE_STLINKV2: + return stlink_target_voltage(&info); + default: + break;; + } return NULL; } -void platform_srst_set_val(bool assert) {(void) assert;} +void platform_srst_set_val(bool assert) +{ + switch (info.bmp_type) { + case BMP_TYPE_STLINKV2: + return stlink_srst_set_val(&info, assert); + default: + break; + } +} + +bool platform_srst_get_val(void) +{ + switch (info.bmp_type) { + case BMP_TYPE_STLINKV2: + return stlink_srst_get_val(); + default: + break; + } + return false; +} -bool platform_srst_get_val(void) { return false;} void platform_buffer_flush(void) {} diff --git a/src/platforms/hosted/platform.h b/src/platforms/hosted/platform.h index 0a281105..5a9cea27 100644 --- a/src/platforms/hosted/platform.h +++ b/src/platforms/hosted/platform.h @@ -1,6 +1,8 @@ #ifndef __PLATFORM_H #define __PLATFORM_H #include +#include "libusb_utils.h" + #include "timing.h" char *platform_ident(void); @@ -22,6 +24,8 @@ typedef enum bmp_type_s { typedef struct bmp_info_s { bmp_type_t bmp_type; libusb_context *libusb_ctx; + struct ftdi_context *ftdic; + usb_link_t *usb_link; unsigned int vid; unsigned int pid; char dev; @@ -30,4 +34,6 @@ typedef struct bmp_info_s { char product[128]; } bmp_info_t; +extern bmp_info_t info; + #endif diff --git a/src/platforms/hosted/stlinkv2.c b/src/platforms/hosted/stlinkv2.c index 5f141d2b..133606fc 100644 --- a/src/platforms/hosted/stlinkv2.c +++ b/src/platforms/hosted/stlinkv2.c @@ -40,19 +40,6 @@ #include "cl_utils.h" -#if !defined(timersub) -/* This is a copy from GNU C Library (GNU LGPL 2.1), sys/time.h. */ -# define timersub(a, b, result) \ - do { \ - (result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \ - (result)->tv_usec = (a)->tv_usec - (b)->tv_usec; \ - if ((result)->tv_usec < 0) { \ - --(result)->tv_sec; \ - (result)->tv_usec += 1000000; \ - } \ - } while (0) -#endif - #define VENDOR_ID_STLINK 0x483 #define PRODUCT_ID_STLINK_MASK 0xffe0 #define PRODUCT_ID_STLINK_GROUP 0x3740 @@ -212,7 +199,7 @@ typedef struct { uint16_t vid; uint16_t pid; uint8_t transport_mode; - char serial[32]; + bool srst; uint8_t dap_select; uint8_t ep_tx; uint8_t ver_hw; /* 20, 21 or 31 deciphered from USB PID.*/ @@ -224,197 +211,15 @@ typedef struct { uint8_t ver_bridge; uint16_t block_size; bool ap_error; - libusb_device_handle *handle; - struct libusb_transfer* req_trans; - struct libusb_transfer* rep_trans; } stlink; stlink Stlink; static int stlink_usb_get_rw_status(bool verbose); -static void exit_function(void) -{ - libusb_exit(NULL); - DEBUG("Cleanup\n"); -} - -/* SIGTERM handler. */ -static void sigterm_handler(int sig) -{ - (void)sig; - exit(0); -} - -struct trans_ctx { -#define TRANS_FLAGS_IS_DONE (1 << 0) -#define TRANS_FLAGS_HAS_ERROR (1 << 1) - volatile unsigned long flags; -}; - int debug_level = 0; -bool has_attached = false; -static int LIBUSB_CALL hotplug_callback_attach( - libusb_context *ctx, libusb_device *dev, libusb_hotplug_event event, - void *user_data) -{ - (void)ctx; - (void)dev; - (void)event; - (void)user_data; - has_attached = true; - return 1; /* deregister Callback*/ -} - -int device_detached = 0; -static int LIBUSB_CALL hotplug_callback_detach( - libusb_context *ctx, libusb_device *dev, libusb_hotplug_event event, - void *user_data) -{ - (void)ctx; - (void)dev; - (void)event; - (void)user_data; - device_detached = 1; - return 1; /* deregister Callback*/ -} - -void stlink_check_detach(int state) -{ - if (state == 1) { - /* Check for hotplug events */ - struct timeval tv = {0,0}; - libusb_handle_events_timeout_completed( - Stlink.libusb_ctx, &tv, &device_detached); - if (device_detached) { - DEBUG("Dongle was detached\n"); - exit(0); - } - } -} - -static void LIBUSB_CALL on_trans_done(struct libusb_transfer * trans) -{ - struct trans_ctx * const ctx = trans->user_data; - - if (trans->status != LIBUSB_TRANSFER_COMPLETED) - { - DEBUG("on_trans_done: "); - if(trans->status == LIBUSB_TRANSFER_TIMED_OUT) - { - DEBUG("Timeout\n"); - } else if (trans->status == LIBUSB_TRANSFER_CANCELLED) { - DEBUG("cancelled\n"); - } else if (trans->status == LIBUSB_TRANSFER_NO_DEVICE) { - DEBUG("no device\n"); - } else { - DEBUG("unknown\n"); - } - ctx->flags |= TRANS_FLAGS_HAS_ERROR; - } - ctx->flags |= TRANS_FLAGS_IS_DONE; -} - -static int submit_wait(struct libusb_transfer * trans) { - struct timeval start; - struct timeval now; - struct timeval diff; - struct trans_ctx trans_ctx; - enum libusb_error error; - - trans_ctx.flags = 0; - - /* brief intrusion inside the libusb interface */ - trans->callback = on_trans_done; - trans->user_data = &trans_ctx; - - if ((error = libusb_submit_transfer(trans))) { - DEBUG("libusb_submit_transfer(%d): %s\n", error, - libusb_strerror(error)); - exit(-1); - } - - gettimeofday(&start, NULL); - - while (trans_ctx.flags == 0) { - struct timeval timeout; - timeout.tv_sec = 1; - timeout.tv_usec = 0; - if (libusb_handle_events_timeout(Stlink.libusb_ctx, &timeout)) { - DEBUG("libusb_handle_events()\n"); - return -1; - } - - gettimeofday(&now, NULL); - timersub(&now, &start, &diff); - if (diff.tv_sec >= 1) { - libusb_cancel_transfer(trans); - DEBUG("libusb_handle_events() timeout\n"); - return -1; - } - } - - if (trans_ctx.flags & TRANS_FLAGS_HAS_ERROR) { - DEBUG("libusb_handle_events() | has_error\n"); - return -1; - } - - return 0; -} #define STLINK_ERROR_DP_FAULT -2 -static int send_recv(uint8_t *txbuf, size_t txsize, - uint8_t *rxbuf, size_t rxsize) -{ - int res = 0; - stlink_check_detach(1); - if( txsize) { - int txlen = txsize; - libusb_fill_bulk_transfer(Stlink.req_trans, Stlink.handle, - Stlink.ep_tx | LIBUSB_ENDPOINT_OUT, - txbuf, txlen, - NULL, NULL, - 0 - ); - DEBUG_USB(" Send (%d): ", txlen); - for (int i = 0; i < txlen && i < 32 ; i++) { - DEBUG_USB("%02x", txbuf[i]); - if ((i & 7) == 7) - DEBUG_USB("."); - } - if (submit_wait(Stlink.req_trans)) { - DEBUG_USB("clear 2\n"); - libusb_clear_halt(Stlink.handle,2); - return -1; - } - } - /* send_only */ - if (rxsize != 0) { - /* read the response */ - libusb_fill_bulk_transfer(Stlink.rep_trans, Stlink.handle, - 0x01| LIBUSB_ENDPOINT_IN, - rxbuf, rxsize, NULL, NULL, 0); - - if (submit_wait(Stlink.rep_trans)) { - DEBUG("clear 1\n"); - libusb_clear_halt(Stlink.handle,1); - return -1; - } - res = Stlink.rep_trans->actual_length; - if (res >0) { - int i; - uint8_t *p = rxbuf; - DEBUG_USB(" Rec (%zu/%d)", rxsize, res); - for (i = 0; i < res && i < 32 ; i++) { - if ( i && ((i & 7) == 0)) - DEBUG_USB("."); - DEBUG_USB("%02x", p[i]); - } - } - } - DEBUG_USB("\n"); - return res; -} /** Converts an STLINK status code held in the first byte of a response to @@ -530,19 +335,16 @@ static int stlink_usb_error_check(uint8_t *data, bool verbose) static int send_recv_retry(uint8_t *txbuf, size_t txsize, uint8_t *rxbuf, size_t rxsize) { - struct timeval start; - struct timeval now; - struct timeval diff; - gettimeofday(&start, NULL); + uint32_t start = platform_time_ms(); int res; + usb_link_t *link = info.usb_link; while(1) { - send_recv(txbuf, txsize, rxbuf, rxsize); + send_recv(link, txbuf, txsize, rxbuf, rxsize); res = stlink_usb_error_check(rxbuf, false); if (res == STLINK_ERROR_OK) return res; - gettimeofday(&now, NULL); - timersub(&now, &start, &diff); - if ((diff.tv_sec >= 1) || (res != STLINK_ERROR_WAIT)) { + uint32_t now = platform_time_ms(); + if (((now - start) > 1000) || (res != STLINK_ERROR_WAIT)) { DEBUG("write_retry failed. "); return res; } @@ -553,19 +355,15 @@ static int send_recv_retry(uint8_t *txbuf, size_t txsize, static int read_retry(uint8_t *txbuf, size_t txsize, uint8_t *rxbuf, size_t rxsize) { - struct timeval start; - struct timeval now; - struct timeval diff; - gettimeofday(&start, NULL); + uint32_t start = platform_time_ms(); int res; while(1) { - send_recv(txbuf, txsize, rxbuf, rxsize); + send_recv(info.usb_link, txbuf, txsize, rxbuf, rxsize); res = stlink_usb_get_rw_status(false); if (res == STLINK_ERROR_OK) return res; - gettimeofday(&now, NULL); - timersub(&now, &start, &diff); - if ((diff.tv_sec >= 1) || (res != STLINK_ERROR_WAIT)) { + uint32_t now = platform_time_ms(); + if (((now -start) > 1000) || (res != STLINK_ERROR_WAIT)) { DEBUG("read_retry failed. "); stlink_usb_get_rw_status(true); return res; @@ -577,20 +375,17 @@ static int read_retry(uint8_t *txbuf, size_t txsize, static int write_retry(uint8_t *cmdbuf, size_t cmdsize, uint8_t *txbuf, size_t txsize) { - struct timeval start; - struct timeval now; - struct timeval diff; - gettimeofday(&start, NULL); + uint32_t start = platform_time_ms(); int res; + usb_link_t *link = info.usb_link; while(1) { - send_recv(cmdbuf, cmdsize, NULL, 0); - send_recv(txbuf, txsize, NULL, 0); + send_recv(link, cmdbuf, cmdsize, NULL, 0); + send_recv(link, txbuf, txsize, NULL, 0); res = stlink_usb_get_rw_status(false); if (res == STLINK_ERROR_OK) return res; - gettimeofday(&now, NULL); - timersub(&now, &start, &diff); - if ((diff.tv_sec >= 1) || (res != STLINK_ERROR_WAIT)) { + uint32_t now = platform_time_ms(); + if (((now - start) > 1000) || (res != STLINK_ERROR_WAIT)) { stlink_usb_get_rw_status(true); return res; } @@ -598,12 +393,12 @@ static int write_retry(uint8_t *cmdbuf, size_t cmdsize, return res; } -static void stlink_version(void) +static void stlink_version(bmp_info_t *info) { if (Stlink.ver_hw == 30) { uint8_t cmd[16] = {STLINK_APIV3_GET_VERSION_EX}; uint8_t data[12]; - int size = send_recv(cmd, 16, data, 12); + int size = send_recv(info->usb_link, cmd, 16, data, 12); if (size == -1) { printf("[!] send_recv STLINK_APIV3_GET_VERSION_EX\n"); } @@ -618,7 +413,7 @@ static void stlink_version(void) } else { uint8_t cmd[16] = {STLINK_GET_VERSION}; uint8_t data[6]; - int size = send_recv(cmd, 16, data, 6); + int size = send_recv(info->usb_link, cmd, 16, data, 6); if (size == -1) { printf("[!] send_recv STLINK_GET_VERSION_EX\n"); } @@ -646,23 +441,24 @@ static void stlink_version(void) DEBUG("\n"); } -void stlink_leave_state(void) +static bool stlink_leave_state(bmp_info_t *info) { uint8_t cmd[16] = {STLINK_GET_CURRENT_MODE}; uint8_t data[2]; - send_recv(cmd, 16, data, 2); + send_recv(info->usb_link,cmd, 16, data, 2); if (data[0] == STLINK_DEV_DFU_MODE) { uint8_t dfu_cmd[16] = {STLINK_DFU_COMMAND, STLINK_DFU_EXIT}; DEBUG("Leaving DFU Mode\n"); - send_recv(dfu_cmd, 16, NULL, 0); + send_recv(info->usb_link, dfu_cmd, 16, NULL, 0); + return true; } else if (data[0] == STLINK_DEV_SWIM_MODE) { uint8_t swim_cmd[16] = {STLINK_SWIM_COMMAND, STLINK_SWIM_EXIT}; DEBUG("Leaving SWIM Mode\n"); - send_recv(swim_cmd, 16, NULL, 0); + send_recv(info->usb_link, swim_cmd, 16, NULL, 0); } else if (data[0] == STLINK_DEV_DEBUG_MODE) { uint8_t dbg_cmd[16] = {STLINK_DEBUG_COMMAND, STLINK_DEBUG_EXIT}; DEBUG("Leaving DEBUG Mode\n"); - send_recv(dbg_cmd, 16, NULL, 0); + send_recv(info->usb_link, dbg_cmd, 16, NULL, 0); } else if (data[0] == STLINK_DEV_BOOTLOADER_MODE) { DEBUG("Leaving BOOTLOADER Mode\n"); } else if (data[0] == STLINK_DEV_MASS_MODE) { @@ -670,13 +466,14 @@ void stlink_leave_state(void) } else { DEBUG("Unknown Mode %02x\n", data[0]); } + return false; } -const char *stlink_target_voltage(void) +const char *stlink_target_voltage(bmp_info_t *info) { uint8_t cmd[16] = {STLINK_GET_TARGET_VOLTAGE}; uint8_t data[8]; - send_recv(cmd, 16, data, 8); + send_recv(info->usb_link, cmd, 16, data, 8); uint16_t adc[2]; adc[0] = data[0] | data[1] << 8; /* Calibration value? */ adc[1] = data[4] | data[5] << 8; /* Measured value?*/ @@ -688,268 +485,161 @@ const char *stlink_target_voltage(void) return res; } -static void stlink_resetsys(void) +static void stlink_resetsys(bmp_info_t *info) { uint8_t cmd[16] = {STLINK_DEBUG_COMMAND ,STLINK_DEBUG_APIV2_RESETSYS}; uint8_t data[2]; - send_recv(cmd, 16, data, 2); + send_recv(info->usb_link, cmd, 16, data, 2); } -void stlink_init(int argc, char **argv) +int stlink_init(bmp_info_t *info) { - BMP_CL_OPTIONS_t cl_opts = {0}; - cl_opts.opt_idstring = "Blackmagic Debug Probe on StlinkV2/3"; - cl_init(&cl_opts, argc, argv); + usb_link_t *sl = calloc(1, sizeof(usb_link_t)); + if (!sl) + return -1; + info->usb_link = sl; + sl->ul_libusb_ctx = info->libusb_ctx; libusb_device **devs, *dev; - int r; - int ret = -1; - atexit(exit_function); - signal(SIGTERM, sigterm_handler); - signal(SIGINT, sigterm_handler); - libusb_init(&Stlink.libusb_ctx); - r = libusb_init(NULL); - if (r < 0) - DEBUG("Failed: %s", libusb_strerror(r)); - bool hotplug = true; - if (!libusb_has_capability (LIBUSB_CAP_HAS_HOTPLUG)) { - printf("Hotplug capabilites are not supported on this platform\n"); - hotplug = false; - } ssize_t cnt; - rescan: - has_attached = 0; - memset(&Stlink, 0, sizeof(Stlink)); - cnt = libusb_get_device_list(NULL, &devs); + cnt = libusb_get_device_list(info->libusb_ctx, &devs); if (cnt < 0) { - DEBUG("Failed: %s", libusb_strerror(r)); - goto error; + fprintf(stderr, "FATAL: Stlink libusb_get_device_list failed\n"); + return -1; } int i = 0; - int nr_stlinks = 0; + bool found = false; while ((dev = devs[i++]) != NULL) { struct libusb_device_descriptor desc; int r = libusb_get_device_descriptor(dev, &desc); if (r < 0) { fprintf(stderr, "libusb_get_device_descriptor failed %s", libusb_strerror(r)); - goto error; + return -1; } - if ((desc.idVendor == VENDOR_ID_STLINK) && - ((desc.idProduct & PRODUCT_ID_STLINK_MASK) == - PRODUCT_ID_STLINK_GROUP)) { - if (desc.idProduct == PRODUCT_ID_STLINKV1) { /* Reject V1 devices.*/ - DEBUG("STLINKV1 not supported\n"); - continue; - } - Stlink.vid = desc.idVendor; - Stlink.pid = desc.idProduct; - r = libusb_open(dev, &Stlink.handle); - if (r == LIBUSB_SUCCESS) { - uint8_t data[32]; - uint16_t lang; - libusb_get_string_descriptor( - Stlink.handle, 0, 0, data, sizeof(data)); - lang = data[2] << 8 | data[3]; - unsigned char sernum[32]; - if (desc.iSerialNumber) { - r = libusb_get_string_descriptor - (Stlink.handle, desc.iSerialNumber, lang, - sernum, sizeof(sernum)); - } else { - DEBUG("No serial number\n"); - } - /* Older devices have hex values instead of ascii - * in the serial string. Recode eventually!*/ - bool readable = true; - uint16_t *p = (uint16_t *)sernum; - for (p += 1; *p; p++) { - bool isr = isalnum(*p); - readable &= isr; - } - char *s = Stlink.serial; - p = (uint16_t *)sernum; - for (p += 1; *p; p++, s++) { - if (readable) - *s = *p; - else - snprintf(s, 3, "%02x", *p & 0xff); - } - if (cl_opts.opt_serial && (!strncmp(Stlink.serial, cl_opts.opt_serial, - strlen(cl_opts.opt_serial)))) - DEBUG("Found "); - if (desc.idProduct == PRODUCT_ID_STLINKV2) { - DEBUG("STLINKV20 serial %s\n", Stlink.serial); - Stlink.ver_hw = 20; - Stlink.ep_tx = 2; - } else if (desc.idProduct == PRODUCT_ID_STLINKV21) { - DEBUG("STLINKV21 serial %s\n", Stlink.serial); - Stlink.ver_hw = 21; - Stlink.ep_tx = 1; - } else if (desc.idProduct == PRODUCT_ID_STLINKV21_MSD) { - DEBUG("STLINKV21_MSD serial %s\n", Stlink.serial); - Stlink.ver_hw = 21; - Stlink.ep_tx = 1; - } else if (desc.idProduct == PRODUCT_ID_STLINKV3E) { - DEBUG("STLINKV3E serial %s\n", Stlink.serial); - Stlink.ver_hw = 30; - Stlink.ep_tx = 1; - } else if (desc.idProduct == PRODUCT_ID_STLINKV3) { - DEBUG("STLINKV3 serial %s\n", Stlink.serial); - Stlink.ver_hw = 30; - Stlink.ep_tx = 1; - } else { - DEBUG("Unknown STLINK variant, serial %s\n", Stlink.serial); - } - nr_stlinks++; - if (cl_opts.opt_serial) { - if (!strncmp(Stlink.serial, cl_opts.opt_serial, - strlen(cl_opts.opt_serial))) { - break; - } else { - libusb_close(Stlink.handle); - Stlink.handle = 0; - } - } - } else { - DEBUG("Open failed %s\n", libusb_strerror(r)); - } + if ((desc.idVendor != info->vid) || + (desc.idProduct != info->pid) || + (libusb_open(dev, &sl->ul_libusb_device_handle) + != LIBUSB_SUCCESS)) { + continue; } + char serial[64]; + r = libusb_get_string_descriptor_ascii( + sl->ul_libusb_device_handle, desc.iSerialNumber, + (uint8_t*)serial,sizeof(serial)); + if (r <= 0 || !strstr(serial, info->serial)) { + libusb_close(sl->ul_libusb_device_handle); + continue; + } + found = true; + break; } libusb_free_device_list(devs, 1); - if (!Stlink.handle) { - if (nr_stlinks && cl_opts.opt_serial) { - DEBUG("No Stlink with given serial number %s\n", cl_opts.opt_serial); - } else if (nr_stlinks > 1) { - DEBUG("Multiple Stlinks. Please specify serial number\n"); - goto error; - } else { - DEBUG("No Stlink device found!\n"); - } - if (hotplug && !cl_opts.opt_no_wait) { - libusb_hotplug_callback_handle hp; - int rc = libusb_hotplug_register_callback - (NULL, LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED, 0, - VENDOR_ID_STLINK, LIBUSB_HOTPLUG_MATCH_ANY, - LIBUSB_HOTPLUG_MATCH_ANY, - hotplug_callback_attach, NULL, &hp); - if (LIBUSB_SUCCESS != rc) { - DEBUG("Error registering attach callback\n"); - goto error; - } - DEBUG("Waiting for %sST device%s%s to attach\n", - (cl_opts.opt_serial)? "" : "some ", - (cl_opts.opt_serial)? " with serial ": "", - (cl_opts.opt_serial)? cl_opts.opt_serial: ""); - DEBUG("Terminate with ^C\n"); - while (has_attached == 0) { - rc = libusb_handle_events (NULL); - if (rc < 0) - printf("libusb_handle_events() failed: %s\n", - libusb_error_name(rc)); - } - goto rescan; - } - goto error; + if (!found) + return 0; + if (info->pid == PRODUCT_ID_STLINKV2) { + Stlink.ver_hw = 20; + info->usb_link->ep_tx = 2; + Stlink.ep_tx = 2; + } else if ((info->pid == PRODUCT_ID_STLINKV21)|| + (info->pid == PRODUCT_ID_STLINKV21_MSD)) { + Stlink.ver_hw = 21; + info->usb_link->ep_tx = 1; + Stlink.ep_tx = 1; + } else if ((info->pid == PRODUCT_ID_STLINKV3) || + (info->pid == PRODUCT_ID_STLINKV3E)) { + Stlink.ver_hw = 30; + info->usb_link->ep_tx = 1; + Stlink.ep_tx = 1; } + info->usb_link->ep_rx = 1; int config; - r = libusb_get_configuration(Stlink.handle, &config); + int r = libusb_get_configuration(sl->ul_libusb_device_handle, &config); if (r) { - DEBUG("libusb_get_configuration failed %d: %s", r, libusb_strerror(r)); - goto error_1; + fprintf(stderr, "FATAL: Stlink libusb_get_configuration failed %d: %s", + r, libusb_strerror(r)); + return -1; } - DEBUG("Config %d\n", config); if (config != 1) { - r = libusb_set_configuration(Stlink.handle, 0); + r = libusb_set_configuration(sl->ul_libusb_device_handle, 0); if (r) { - DEBUG("libusb_set_configuration failed %d: %s", - r, libusb_strerror(r)); - goto error_1; + fprintf(stderr, "FATAL: Stlinklibusb_set_configuration " + "failed %d: %s", r, libusb_strerror(r)); + return -1; } } - r = libusb_claim_interface(Stlink.handle, 0); - if (r) - { - DEBUG("libusb_claim_interface failed %s\n", libusb_strerror(r)); - goto error_1; + r = libusb_claim_interface(sl->ul_libusb_device_handle, 0); + if (r) { + fprintf(stderr, "FATAL: Stlink libusb_claim_interface failed %s\n", + libusb_strerror(r)); + return -1; } - if (hotplug) { /* Allow gracefully exit when stlink is unplugged*/ - libusb_hotplug_callback_handle hp; - int rc = libusb_hotplug_register_callback - (NULL, LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT, 0, Stlink.vid, Stlink.pid, - LIBUSB_HOTPLUG_MATCH_ANY, hotplug_callback_detach, NULL, &hp); - if (LIBUSB_SUCCESS != rc) { - DEBUG("Error registering detach callback\n"); - goto error; - } - } - Stlink.req_trans = libusb_alloc_transfer(0); - Stlink.rep_trans = libusb_alloc_transfer(0); - stlink_version(); + sl->req_trans = libusb_alloc_transfer(0); + sl->rep_trans = libusb_alloc_transfer(0); + stlink_version(info); if ((Stlink.ver_stlink < 3 && Stlink.ver_jtag < 32) || (Stlink.ver_stlink == 3 && Stlink.ver_jtag < 3)) { /* Maybe the adapter is in some strange state. Try to reset */ - int result = libusb_reset_device(Stlink.handle); - DEBUG("Trying reset\n"); + int result = libusb_reset_device(sl->ul_libusb_device_handle); + fprintf(stderr, "INFO: Trying Stlink reset\n"); if (result == LIBUSB_ERROR_BUSY) { /* Try again */ platform_delay(50); - result = libusb_reset_device(Stlink.handle); + result = libusb_reset_device(sl->ul_libusb_device_handle); } if (result != LIBUSB_SUCCESS) { - DEBUG("libusb_reset_device failed\n"); - goto error_1; + fprintf(stderr, "FATAL: Stlink libusb_reset_device failed\n"); + return -1; } - stlink_version(); + stlink_version(info); } if ((Stlink.ver_stlink < 3 && Stlink.ver_jtag < 32) || (Stlink.ver_stlink == 3 && Stlink.ver_jtag < 3)) { DEBUG("Please update Firmware\n"); - goto error_1; + return -1; } - stlink_leave_state(); - stlink_resetsys(); - if (cl_opts.opt_mode != BMP_MODE_DEBUG) { - ret = cl_execute(&cl_opts); - } else { - assert(gdb_if_init() == 0); - return; + if (stlink_leave_state(info)) { + printf("Stlink board was in DFU mode. Restart\n"); + return -1; } - error_1: - libusb_close(Stlink.handle); - error: - libusb_exit(Stlink.libusb_ctx); - exit(ret); + stlink_resetsys(info); + return 0; } -void stlink_srst_set_val(bool assert) +void stlink_srst_set_val(bmp_info_t *info, bool assert) { uint8_t cmd[16] = {STLINK_DEBUG_COMMAND, STLINK_DEBUG_APIV2_DRIVE_NRST, (assert)? STLINK_DEBUG_APIV2_DRIVE_NRST_LOW : STLINK_DEBUG_APIV2_DRIVE_NRST_HIGH}; uint8_t data[2]; - send_recv(cmd, 16, data, 2); + Stlink.srst = assert; + send_recv(info->usb_link, cmd, 16, data, 2); stlink_usb_error_check(data, true); } -bool stlink_set_freq_divisor(uint16_t divisor) +bool stlink_srst_get_val(void) +{ + return Stlink.srst; +} + +static bool stlink_set_freq_divisor(bmp_info_t *info, uint16_t divisor) { uint8_t cmd[16] = {STLINK_DEBUG_COMMAND, STLINK_DEBUG_APIV2_SWD_SET_FREQ, divisor & 0xff, divisor >> 8}; uint8_t data[2]; - send_recv(cmd, 16, data, 2); + send_recv(info->usb_link, cmd, 16, data, 2); if (stlink_usb_error_check(data, false)) return false; return true; } -bool stlink3_set_freq_divisor(uint16_t divisor) +static bool stlink3_set_freq_divisor(bmp_info_t *info, uint16_t divisor) { uint8_t cmd[16] = {STLINK_DEBUG_COMMAND, STLINK_APIV3_GET_COM_FREQ, Stlink.transport_mode}; uint8_t data[52]; - send_recv(cmd, 16, data, 52); + send_recv(info->usb_link, cmd, 16, data, 52); stlink_usb_error_check(data, true); int size = data[8]; if (divisor > size) @@ -965,7 +655,7 @@ bool stlink3_set_freq_divisor(uint16_t divisor) cmd[5] = p[1]; cmd[6] = p[2]; cmd[7] = p[3]; - send_recv(cmd, 16, data, 8); + send_recv(info->usb_link, cmd, 16, data, 8); return true; } @@ -974,57 +664,40 @@ int stlink_hwversion(void) return Stlink.ver_stlink; } -int stlink_enter_debug_swd(void) +static int stlink_enter_debug_jtag(bmp_info_t *info) { - stlink_leave_state(); - Stlink.transport_mode = STLINK_MODE_SWD; - if (Stlink.ver_stlink == 3) - stlink3_set_freq_divisor(2); - else - stlink_set_freq_divisor(1); - uint8_t cmd[16] = {STLINK_DEBUG_COMMAND, - STLINK_DEBUG_APIV2_ENTER, - STLINK_DEBUG_ENTER_SWD_NO_RESET}; - uint8_t data[2]; - DEBUG("Enter SWD\n"); - send_recv_retry(cmd, 16, data, 2); - return stlink_usb_error_check(data, true); -} - -int stlink_enter_debug_jtag(void) -{ - stlink_leave_state(); + stlink_leave_state(info); Stlink.transport_mode = STLINK_MODE_JTAG; if (Stlink.ver_stlink == 3) - stlink3_set_freq_divisor(4); + stlink3_set_freq_divisor(info, 4); else - stlink_set_freq_divisor(1); + stlink_set_freq_divisor(info, 1); uint8_t cmd[16] = {STLINK_DEBUG_COMMAND, STLINK_DEBUG_APIV2_ENTER, STLINK_DEBUG_ENTER_JTAG_NO_RESET}; uint8_t data[2]; DEBUG("Enter JTAG\n"); - send_recv(cmd, 16, data, 2); + send_recv(info->usb_link, cmd, 16, data, 2); return stlink_usb_error_check(data, true); } -uint32_t stlink_read_coreid(void) +static uint32_t stlink_read_coreid(void) { uint8_t cmd[16] = {STLINK_DEBUG_COMMAND, STLINK_DEBUG_READCOREID}; uint8_t data[4]; - send_recv(cmd, 16, data, 4); + send_recv(info.usb_link, cmd, 16, data, 4); uint32_t id = data[0] | data[1] << 8 | data[2] << 16 | data[3] << 24; DEBUG("Read Core ID: 0x%08" PRIx32 "\n", id); return id; } -int stlink_read_idcodes(uint32_t *idcodes) +static int stlink_read_idcodes(bmp_info_t *info, uint32_t *idcodes) { uint8_t cmd[16] = {STLINK_DEBUG_COMMAND, STLINK_DEBUG_APIV2_READ_IDCODES}; uint8_t data[12]; - send_recv(cmd, 16, data, 12); + send_recv(info->usb_link, cmd, 16, data, 12); if (stlink_usb_error_check(data, true)) return 0; uint8_t *p = data + 4; @@ -1034,7 +707,10 @@ int stlink_read_idcodes(uint32_t *idcodes) return 2; } -uint32_t stlink_dp_read(ADIv5_DP_t *dp, uint16_t addr) +uint32_t stlink_dp_low_access(ADIv5_DP_t *dp, uint8_t RnW, + uint16_t addr, uint32_t value); + + static uint32_t stlink_dp_read(ADIv5_DP_t *dp, uint16_t addr) { if (addr & ADIV5_APnDP) { DEBUG_STLINK("AP read addr 0x%04" PRIx16 "\n", addr); @@ -1078,7 +754,7 @@ void stlink_dp_abort(ADIv5_DP_t *dp, uint32_t abort) adiv5_dp_write(dp, ADIV5_DP_ABORT, abort); } -int stlink_read_dp_register(uint16_t port, uint16_t addr, uint32_t *reg) +static int stlink_read_dp_register(uint16_t port, uint16_t addr, uint32_t *reg) { uint8_t cmd[16] = {STLINK_DEBUG_COMMAND, STLINK_DEBUG_APIV2_READ_DAP_REG, @@ -1101,7 +777,7 @@ int stlink_read_dp_register(uint16_t port, uint16_t addr, uint32_t *reg) return res; } -int stlink_write_dp_register(uint16_t port, uint16_t addr, uint32_t val) +static int stlink_write_dp_register(uint16_t port, uint16_t addr, uint32_t val) { if (port == STLINK_DEBUG_PORT_ACCESS && addr == 8) { Stlink.dap_select = val; @@ -1160,7 +836,7 @@ static bool stlink_ap_setup(int ap) ap, }; uint8_t data[2]; - send_recv_retry(cmd, 16, data, 2); + send_recv(info.usb_link, cmd, 16, data, 2); DEBUG_STLINK("Open AP %d\n", ap); int res = stlink_usb_error_check(data, true); if (res) { @@ -1180,7 +856,7 @@ static void stlink_ap_cleanup(int ap) ap, }; uint8_t data[2]; - send_recv(cmd, 16, data, 2); + send_recv(info.usb_link, cmd, 16, data, 2); DEBUG_STLINK("Close AP %d\n", ap); stlink_usb_error_check(data, true); } @@ -1191,7 +867,7 @@ static int stlink_usb_get_rw_status(bool verbose) STLINK_DEBUG_APIV2_GETLASTRWSTATUS2 }; uint8_t data[12]; - send_recv(cmd, 16, data, 12); + send_recv(info.usb_link, cmd, 16, data, 12); return stlink_usb_error_check(data, verbose); } @@ -1246,9 +922,10 @@ static void stlink_readmem(ADIv5_AP_t *ap, void *dest, uint32_t src, size_t len) DEBUG_STLINK("\n"); } -static void stlink_writemem8(ADIv5_AP_t *ap, uint32_t addr, size_t len, - uint8_t *buffer) +static void stlink_writemem8(usb_link_t *link, ADIv5_AP_t *ap, uint32_t addr, + size_t len, uint8_t *buffer) { + (void)link; DEBUG_STLINK("Mem Write8 AP %d len %zu addr 0x%08" PRIx32 ": ", ap->apsel, len, addr); for (size_t t = 0; t < len; t++) { @@ -1257,6 +934,7 @@ static void stlink_writemem8(ADIv5_AP_t *ap, uint32_t addr, size_t len, DEBUG_STLINK("\n"); while (len) { size_t length; + /* OpenOCD has some note about writemem8*/ if (len > Stlink.block_size) length = Stlink.block_size; else @@ -1267,17 +945,18 @@ static void stlink_writemem8(ADIv5_AP_t *ap, uint32_t addr, size_t len, addr & 0xff, (addr >> 8) & 0xff, (addr >> 16) & 0xff, (addr >> 24) & 0xff, length & 0xff, length >> 8, ap->apsel}; - send_recv(cmd, 16, NULL, 0); - send_recv((void*)buffer, length, NULL, 0); + send_recv(link, cmd, 16, NULL, 0); + send_recv(link, (void*)buffer, length, NULL, 0); stlink_usb_get_rw_status(true); len -= length; addr += length; } } -static void stlink_writemem16(ADIv5_AP_t *ap, uint32_t addr, size_t len, - uint16_t *buffer) +static void stlink_writemem16(usb_link_t *link, ADIv5_AP_t *ap, uint32_t addr, + size_t len, uint16_t *buffer) { + (void)link; DEBUG_STLINK("Mem Write16 AP %d len %zu addr 0x%08" PRIx32 ": ", ap->apsel, len, addr); for (size_t t = 0; t < len; t+=2) { @@ -1290,14 +969,15 @@ static void stlink_writemem16(ADIv5_AP_t *ap, uint32_t addr, size_t len, addr & 0xff, (addr >> 8) & 0xff, (addr >> 16) & 0xff, (addr >> 24) & 0xff, len & 0xff, len >> 8, ap->apsel}; - send_recv(cmd, 16, NULL, 0); - send_recv((void*)buffer, len, NULL, 0); + send_recv(link, cmd, 16, NULL, 0); + send_recv(link, (void*)buffer, len, NULL, 0); stlink_usb_get_rw_status(true); } -static void stlink_writemem32(ADIv5_AP_t *ap, uint32_t addr, size_t len, - uint32_t *buffer) +static void stlink_writemem32(usb_link_t * link, ADIv5_AP_t *ap, uint32_t addr, + size_t len, uint32_t *buffer) { + (void)link; DEBUG_STLINK("Mem Write32 AP %d len %zu addr 0x%08" PRIx32 ": ", ap->apsel, len, addr); for (size_t t = 0; t < len; t+=4) { @@ -1313,23 +993,23 @@ static void stlink_writemem32(ADIv5_AP_t *ap, uint32_t addr, size_t len, write_retry(cmd, 16, (void*)buffer, len); } -void stlink_regs_read(ADIv5_AP_t *ap, void *data) +static void stlink_regs_read(ADIv5_AP_t *ap, void *data) { uint8_t cmd[16] = {STLINK_DEBUG_COMMAND, STLINK_DEBUG_APIV2_READALLREGS, ap->apsel}; uint8_t res[88]; DEBUG_STLINK("AP %d: Read all core registers\n", ap->apsel); - send_recv(cmd, 16, res, 88); + send_recv(info.usb_link, cmd, 16, res, 88); stlink_usb_error_check(res, true); memcpy(data, res + 4, 84); } -uint32_t stlink_reg_read(ADIv5_AP_t *ap, int num) +static uint32_t stlink_reg_read(ADIv5_AP_t *ap, int num) { uint8_t cmd[16] = {STLINK_DEBUG_COMMAND, STLINK_DEBUG_APIV2_READREG, num, ap->apsel}; uint8_t res[8]; - send_recv(cmd, 16, res, 8); + send_recv(info.usb_link, cmd, 16, res, 8); stlink_usb_error_check(res, true); uint32_t ret = res[0] | res[1] << 8 | res[2] << 16 | res[3] << 24; DEBUG_STLINK("AP %d: Read reg %02" PRId32 " val 0x%08" PRIx32 "\n", @@ -1337,14 +1017,14 @@ uint32_t stlink_reg_read(ADIv5_AP_t *ap, int num) return ret; } -void stlink_reg_write(ADIv5_AP_t *ap, int num, uint32_t val) +static void stlink_reg_write(ADIv5_AP_t *ap, int num, uint32_t val) { uint8_t cmd[16] = { STLINK_DEBUG_COMMAND, STLINK_DEBUG_APIV2_WRITEREG, num, val & 0xff, (val >> 8) & 0xff, (val >> 16) & 0xff, (val >> 24) & 0xff, ap->apsel}; uint8_t res[2]; - send_recv(cmd, 16, res, 2); + send_recv(info.usb_link, cmd, 16, res, 2); DEBUG_STLINK("AP %d: Write reg %02" PRId32 " val 0x%08" PRIx32 "\n", ap->apsel, num, val); stlink_usb_error_check(res, true); @@ -1356,14 +1036,17 @@ static void stlink_mem_write_sized( ADIv5_AP_t *ap, uint32_t dest, { if (len == 0) return; + usb_link_t *link = info.usb_link; switch(align) { - case ALIGN_BYTE: stlink_writemem8(ap, dest, len, (uint8_t *) src); + case ALIGN_BYTE: + stlink_writemem8(link, ap, dest, len, (uint8_t *) src); break; - case ALIGN_HALFWORD: stlink_writemem16(ap, dest, len, (uint16_t *) src); + case ALIGN_HALFWORD: + stlink_writemem16(link,ap, dest, len, (uint16_t *) src); break; - case ALIGN_WORD: stlink_writemem32(ap, dest, len, (uint32_t *) src); - break; - case ALIGN_DWORD: stlink_writemem32(ap, dest, len, (uint32_t *) src); + case ALIGN_WORD: + case ALIGN_DWORD: + stlink_writemem32(link, ap, dest, len, (uint32_t *) src); break; } } @@ -1384,7 +1067,7 @@ struct jtag_dev_s jtag_devs[JTAG_MAX_DEVS+1]; int jtag_dev_count; jtag_proc_t jtag_proc; -int jtag_scan_stlinkv2(const uint8_t *irlens) +int jtag_scan_stlinkv2(bmp_info_t *info, const uint8_t *irlens) { uint32_t idcodes[JTAG_MAX_DEVS+1]; (void) *irlens; @@ -1392,9 +1075,9 @@ int jtag_scan_stlinkv2(const uint8_t *irlens) jtag_dev_count = 0; memset(&jtag_devs, 0, sizeof(jtag_devs)); - if (stlink_enter_debug_jtag()) + if (stlink_enter_debug_jtag(info)) return 0; - jtag_dev_count = stlink_read_idcodes(idcodes); + jtag_dev_count = stlink_read_idcodes(info, idcodes); /* Check for known devices and handle accordingly */ for(int i = 0; i < jtag_dev_count; i++) jtag_devs[i].idcode = idcodes[i]; @@ -1410,7 +1093,7 @@ int jtag_scan_stlinkv2(const uint8_t *irlens) return jtag_dev_count; } -int platform_jtag_dp_init(ADIv5_DP_t *dp) +int stlink_jtag_dp_init(ADIv5_DP_t *dp) { dp->dp_read = stlink_dp_read; dp->error = stlink_dp_error; @@ -1421,7 +1104,7 @@ int platform_jtag_dp_init(ADIv5_DP_t *dp) } -int platform_adiv5_dp_defaults(ADIv5_DP_t *dp) +void stlink_adiv5_dp_defaults(ADIv5_DP_t *dp) { dp->ap_regs_read = stlink_regs_read; dp->ap_reg_read = stlink_reg_read; @@ -1432,6 +1115,30 @@ int platform_adiv5_dp_defaults(ADIv5_DP_t *dp) dp->ap_read = stlink_ap_read; dp->mem_read = stlink_readmem; dp->mem_write_sized = stlink_mem_write_sized; +} +int stlink_enter_debug_swd(bmp_info_t *info, ADIv5_DP_t *dp) +{ + stlink_leave_state(info); + Stlink.transport_mode = STLINK_MODE_SWD; + if (Stlink.ver_stlink == 3) + stlink3_set_freq_divisor(info, 2); + else + stlink_set_freq_divisor(info, 1); + uint8_t cmd[16] = {STLINK_DEBUG_COMMAND, + STLINK_DEBUG_APIV2_ENTER, + STLINK_DEBUG_ENTER_SWD_NO_RESET}; + uint8_t data[2]; + DEBUG("Enter SWD\n"); + send_recv(info->usb_link, cmd, 16, data, 2); + if (stlink_usb_error_check(data, true)) + return -1; + dp->idcode = stlink_read_coreid(); + dp->dp_read = stlink_dp_read; + dp->error = stlink_dp_error; + dp->low_access = stlink_dp_low_access; + dp->abort = stlink_dp_abort; + + stlink_dp_error(dp); return 0; } diff --git a/src/platforms/hosted/stlinkv2.h b/src/platforms/hosted/stlinkv2.h index dea9a8b7..1960a5ba 100644 --- a/src/platforms/hosted/stlinkv2.h +++ b/src/platforms/hosted/stlinkv2.h @@ -24,28 +24,18 @@ #define STLINK_DEBUG_PORT_ACCESS 0xffff -void stlink_init(int argc, char **argv); +int stlink_init(bmp_info_t *info); int stlink_hwversion(void); -void stlink_leave_state(void); -const char *stlink_target_voltage(void); -void stlink_srst_set_val(bool assert); -int stlink_enter_debug_swd(void); -int stlink_enter_debug_jtag(void); -int stlink_read_idcodes(uint32_t *); -uint32_t stlink_read_coreid(void); -int stlink_read_dp_register(uint16_t port, uint16_t addr, uint32_t *res); -int stlink_write_dp_register(uint16_t port, uint16_t addr, uint32_t val); +const char *stlink_target_voltage(bmp_info_t *info); +void stlink_srst_set_val(bmp_info_t *info, bool assert); +bool stlink_srst_get_val(void); +int stlink_enter_debug_swd(bmp_info_t *info, ADIv5_DP_t *dp); -uint32_t stlink_dp_low_access(ADIv5_DP_t *dp, uint8_t RnW, - uint16_t addr, uint32_t value); -uint32_t stlink_dp_read(ADIv5_DP_t *dp, uint16_t addr); -uint32_t stlink_dp_error(ADIv5_DP_t *dp); -void stlink_dp_abort(ADIv5_DP_t *dp, uint32_t abort); -int stlink_open_ap(uint8_t ap); -void stlink_close_ap(uint8_t ap); -void stlink_regs_read(ADIv5_AP_t *ap, void *data); -uint32_t stlink_reg_read(ADIv5_AP_t *ap, int idx); -void stlink_reg_write(ADIv5_AP_t *ap, int num, uint32_t val); +const char *stlink_target_voltage(bmp_info_t *info); +void stlink_adiv5_dp_defaults(ADIv5_DP_t *dp); +int stlink_jtag_dp_init(ADIv5_DP_t *dp); +int jtag_scan_stlinkv2(bmp_info_t *info, const uint8_t *irlens); +void stlink_exit_function(bmp_info_t *info); extern int debug_level; # define DEBUG_STLINK if (debug_level > 0) printf # define DEBUG_USB if (debug_level > 1) printf diff --git a/src/platforms/pc-stlinkv2/Makefile.inc b/src/platforms/pc-stlinkv2/Makefile.inc deleted file mode 100644 index 70f6f8ed..00000000 --- a/src/platforms/pc-stlinkv2/Makefile.inc +++ /dev/null @@ -1,14 +0,0 @@ -TARGET=blackmagic_stlinkv2 -SYS = $(shell $(CC) -dumpmachine) -CFLAGS += -DSTLINKV2 -DJTAG_HL -DENABLE_DEBUG -CFLAGS +=-I ./target -I./platforms/pc -LDFLAGS += -lusb-1.0 -ifneq (, $(findstring mingw, $(SYS))) -LDFLAGS += -lws2_32 -else ifneq (, $(findstring cygwin, $(SYS))) -LDFLAGS += -lws2_32 -endif -VPATH += platforms/pc -SRC += timing.c stlinkv2.c cl_utils.c utils.c -OWN_HL = 1 -PC_HOSTED = 1 diff --git a/src/platforms/pc-stlinkv2/README.md b/src/platforms/pc-stlinkv2/README.md deleted file mode 100644 index d70b4d7b..00000000 --- a/src/platforms/pc-stlinkv2/README.md +++ /dev/null @@ -1,25 +0,0 @@ -ST-Link V2/3 with original STM firmware as Blackmagic Debug Probes - -Recent STM ST-LINK firmware revision (V3 and V2 >= J32) expose all -functionality that BMP needs. This platform implements blackmagic debug -probe for the STM ST-LINK. -Use at your own risk, but report or better fix problems. - -Compile with "make PROBE_HOST=pc-stlinkv2" - -Run the resulting blackmagic_stlinkv2 executable to start the gdb server. - -You can also use on the command line alone, e.g -- "blackmagic_stlinkv2 -t" to scan and display the results of the scan -- "blackmagic_stlinkv2 " to flash at 0x08000000 -- "blackmagic_stlinkv2 -h" for more options - -Cross-compling for windows with mingw succeeds. - -Drawback: -- JTAG does not work for chains with multiple devices. -- ST-LINKV3 seem to only work on STM32 devices. -- St-LINKV3 needs connect under reset on more devices than V2 - -ToDo: -- Implement an SWO server \ No newline at end of file diff --git a/src/platforms/pc-stlinkv2/jtagtap.c b/src/platforms/pc-stlinkv2/jtagtap.c deleted file mode 100644 index e69de29b..00000000 diff --git a/src/platforms/pc-stlinkv2/platform.c b/src/platforms/pc-stlinkv2/platform.c deleted file mode 100644 index 07379b07..00000000 --- a/src/platforms/pc-stlinkv2/platform.c +++ /dev/null @@ -1,115 +0,0 @@ -/* - * This file is part of the Black Magic Debug project. - * - * Copyright (C) 2019 2019 Uwe Bonnes - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -#include "general.h" -#include "gdb_if.h" -#include "version.h" -#include "platform.h" -#include "target.h" -#include "target_internal.h" -#include "swdptap.h" - -#include -#include -#include -#include - -#include "adiv5.h" -#include "stlinkv2.h" - -int platform_hwversion(void) -{ - return stlink_hwversion(); -} - -const char *platform_target_voltage(void) -{ - return stlink_target_voltage(); -} - -int platform_swdptap_init(void) -{ - return 0; -} - -swd_proc_t swd_proc; -jtag_proc_t jtag_proc; - -static int adiv5_swdp_scan_stlinkv2(void) -{ - target_list_free(); - ADIv5_DP_t *dp = (void*)calloc(1, sizeof(*dp)); - if (stlink_enter_debug_swd()) - return 0; - dp->idcode = stlink_read_coreid(); - dp->dp_read = stlink_dp_read; - dp->error = stlink_dp_error; - dp->low_access = stlink_dp_low_access; - dp->abort = stlink_dp_abort; - - stlink_dp_error(dp); - adiv5_dp_init(dp); - - return target_list?1:0; - return 0; -} -int platform_adiv5_swdp_scan(void) -{ - return adiv5_swdp_scan_stlinkv2(); -} - -int platform_jtag_scan(const uint8_t *lrlens) -{ - return jtag_scan_stlinkv2(lrlens); -} - -void platform_init(int argc, char **argv) -{ - stlink_init(argc, argv); -} - -static bool srst_status = false; -void platform_srst_set_val(bool assert) -{ - stlink_srst_set_val(assert); - srst_status = assert; -} - -bool platform_srst_get_val(void) { return srst_status; } - -void platform_buffer_flush(void) -{ -} - -int platform_buffer_write(const uint8_t *data, int size) -{ - (void) data; - (void) size; - return size; -} - -int platform_buffer_read(uint8_t *data, int size) -{ - (void) data; - return size; -} - -int platform_jtagtap_init(void) -{ - return 0; -} diff --git a/src/platforms/pc-stlinkv2/platform.h b/src/platforms/pc-stlinkv2/platform.h deleted file mode 100644 index b63b0e1f..00000000 --- a/src/platforms/pc-stlinkv2/platform.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * This file is part of the Black Magic Debug project. - * - * Copyright (C) 2011 Black Sphere Technologies Ltd. - * Written by Gareth McMullin - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef __PLATFORM_H -#define __PLATFORM_H - -#include - -#include "timing.h" - -#ifndef _WIN32 -# include -#else -# ifndef alloca -# define alloca __builtin_alloca -# endif -#endif - -#define PLATFORM_IDENT() "StlinkV2/3" -#define SET_RUN_STATE(state) -void stlink_check_detach(int state); -#define SET_IDLE_STATE(state) stlink_check_detach(state) -//#define SET_ERROR_STATE(state) - -void platform_buffer_flush(void); -int platform_buffer_write(const uint8_t *data, int size); -int platform_buffer_read(uint8_t *data, int size); -int jtag_scan_stlinkv2(const uint8_t *irlens); -#endif diff --git a/src/platforms/pc-stlinkv2/stlinkv2.c b/src/platforms/pc-stlinkv2/stlinkv2.c deleted file mode 100644 index 0d5012fd..00000000 --- a/src/platforms/pc-stlinkv2/stlinkv2.c +++ /dev/null @@ -1,1435 +0,0 @@ -/* - * This file is part of the Black Magic Debug project. - * - * Copyright (C) 2019 Uwe Bonnes - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -/* Much code and ideas shamelessly taken form - * https://github.com/texane/stlink.git - * git://git.code.sf.net/p/openocd/code - * https://github.com/pavelrevak/pystlink - * https://github.com/pavelrevak/pystlink - * - * with some contribution. - */ -#include "general.h" -#include "gdb_if.h" -#include "adiv5.h" -#include "stlinkv2.h" -#include "exception.h" -#include "jtag_devs.h" -#include "target.h" - -#include -#include -#include -#include -#include - -#include "cl_utils.h" - -#if !defined(timersub) -/* This is a copy from GNU C Library (GNU LGPL 2.1), sys/time.h. */ -# define timersub(a, b, result) \ - do { \ - (result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \ - (result)->tv_usec = (a)->tv_usec - (b)->tv_usec; \ - if ((result)->tv_usec < 0) { \ - --(result)->tv_sec; \ - (result)->tv_usec += 1000000; \ - } \ - } while (0) -#endif - -#define VENDOR_ID_STLINK 0x483 -#define PRODUCT_ID_STLINK_MASK 0xffe0 -#define PRODUCT_ID_STLINK_GROUP 0x3740 -#define PRODUCT_ID_STLINKV1 0x3744 -#define PRODUCT_ID_STLINKV2 0x3748 -#define PRODUCT_ID_STLINKV21 0x374b -#define PRODUCT_ID_STLINKV21_MSD 0x3752 -#define PRODUCT_ID_STLINKV3 0x374f -#define PRODUCT_ID_STLINKV3E 0x374e - -#define STLINK_SWIM_ERR_OK 0x00 -#define STLINK_SWIM_BUSY 0x01 -#define STLINK_DEBUG_ERR_OK 0x80 -#define STLINK_DEBUG_ERR_FAULT 0x81 -#define STLINK_JTAG_UNKNOWN_JTAG_CHAIN 0x04 -#define STLINK_NO_DEVICE_CONNECTED 0x05 -#define STLINK_JTAG_COMMAND_ERROR 0x08 -#define STLINK_JTAG_COMMAND_ERROR 0x08 -#define STLINK_JTAG_GET_IDCODE_ERROR 0x09 -#define STLINK_JTAG_DBG_POWER_ERROR 0x0b -#define STLINK_SWD_AP_WAIT 0x10 -#define STLINK_SWD_AP_FAULT 0x11 -#define STLINK_SWD_AP_ERROR 0x12 -#define STLINK_SWD_AP_PARITY_ERROR 0x13 -#define STLINK_JTAG_WRITE_ERROR 0x0c -#define STLINK_JTAG_WRITE_VERIF_ERROR 0x0d -#define STLINK_SWD_DP_WAIT 0x14 -#define STLINK_SWD_DP_FAULT 0x15 -#define STLINK_SWD_DP_ERROR 0x16 -#define STLINK_SWD_DP_PARITY_ERROR 0x17 - -#define STLINK_SWD_AP_WDATA_ERROR 0x18 -#define STLINK_SWD_AP_STICKY_ERROR 0x19 -#define STLINK_SWD_AP_STICKYORUN_ERROR 0x1a -#define STLINK_BAD_AP_ERROR 0x1d -#define STLINK_TOO_MANY_AP_ERROR 0x29 -#define STLINK_JTAG_UNKNOWN_CMD 0x42 - -#define STLINK_CORE_RUNNING 0x80 -#define STLINK_CORE_HALTED 0x81 -#define STLINK_CORE_STAT_UNKNOWN -1 - -#define STLINK_GET_VERSION 0xF1 -#define STLINK_DEBUG_COMMAND 0xF2 -#define STLINK_DFU_COMMAND 0xF3 -#define STLINK_SWIM_COMMAND 0xF4 -#define STLINK_GET_CURRENT_MODE 0xF5 -#define STLINK_GET_TARGET_VOLTAGE 0xF7 - -#define STLINK_DEV_DFU_MODE 0x00 -#define STLINK_DEV_MASS_MODE 0x01 -#define STLINK_DEV_DEBUG_MODE 0x02 -#define STLINK_DEV_SWIM_MODE 0x03 -#define STLINK_DEV_BOOTLOADER_MODE 0x04 -#define STLINK_DEV_UNKNOWN_MODE -1 - -#define STLINK_DFU_EXIT 0x07 - -#define STLINK_SWIM_ENTER 0x00 -#define STLINK_SWIM_EXIT 0x01 -#define STLINK_SWIM_READ_CAP 0x02 -#define STLINK_SWIM_SPEED 0x03 -#define STLINK_SWIM_ENTER_SEQ 0x04 -#define STLINK_SWIM_GEN_RST 0x05 -#define STLINK_SWIM_RESET 0x06 -#define STLINK_SWIM_ASSERT_RESET 0x07 -#define STLINK_SWIM_DEASSERT_RESET 0x08 -#define STLINK_SWIM_READSTATUS 0x09 -#define STLINK_SWIM_WRITEMEM 0x0a -#define STLINK_SWIM_READMEM 0x0b -#define STLINK_SWIM_READBUF 0x0c - -#define STLINK_DEBUG_GETSTATUS 0x01 -#define STLINK_DEBUG_FORCEDEBUG 0x02 -#define STLINK_DEBUG_APIV1_RESETSYS 0x03 -#define STLINK_DEBUG_APIV1_READALLREGS 0x04 -#define STLINK_DEBUG_APIV1_READREG 0x05 -#define STLINK_DEBUG_APIV1_WRITEREG 0x06 -#define STLINK_DEBUG_READMEM_32BIT 0x07 -#define STLINK_DEBUG_WRITEMEM_32BIT 0x08 -#define STLINK_DEBUG_RUNCORE 0x09 -#define STLINK_DEBUG_STEPCORE 0x0a -#define STLINK_DEBUG_APIV1_SETFP 0x0b -#define STLINK_DEBUG_READMEM_8BIT 0x0c -#define STLINK_DEBUG_WRITEMEM_8BIT 0x0d -#define STLINK_DEBUG_APIV1_CLEARFP 0x0e -#define STLINK_DEBUG_APIV1_WRITEDEBUGREG 0x0f -#define STLINK_DEBUG_APIV1_SETWATCHPOINT 0x10 - -#define STLINK_DEBUG_ENTER_JTAG_RESET 0x00 -#define STLINK_DEBUG_ENTER_SWD_NO_RESET 0xa3 -#define STLINK_DEBUG_ENTER_JTAG_NO_RESET 0xa4 - -#define STLINK_DEBUG_APIV1_ENTER 0x20 -#define STLINK_DEBUG_EXIT 0x21 -#define STLINK_DEBUG_READCOREID 0x22 - -#define STLINK_DEBUG_APIV2_ENTER 0x30 -#define STLINK_DEBUG_APIV2_READ_IDCODES 0x31 -#define STLINK_DEBUG_APIV2_RESETSYS 0x32 -#define STLINK_DEBUG_APIV2_READREG 0x33 -#define STLINK_DEBUG_APIV2_WRITEREG 0x34 -#define STLINK_DEBUG_APIV2_WRITEDEBUGREG 0x35 -#define STLINK_DEBUG_APIV2_READDEBUGREG 0x36 - -#define STLINK_DEBUG_APIV2_READALLREGS 0x3A -#define STLINK_DEBUG_APIV2_GETLASTRWSTATUS 0x3B -#define STLINK_DEBUG_APIV2_DRIVE_NRST 0x3C - -#define STLINK_DEBUG_APIV2_GETLASTRWSTATUS2 0x3E - -#define STLINK_DEBUG_APIV2_START_TRACE_RX 0x40 -#define STLINK_DEBUG_APIV2_STOP_TRACE_RX 0x41 -#define STLINK_DEBUG_APIV2_GET_TRACE_NB 0x42 -#define STLINK_DEBUG_APIV2_SWD_SET_FREQ 0x43 -#define STLINK_DEBUG_APIV2_JTAG_SET_FREQ 0x44 -#define STLINK_DEBUG_APIV2_READ_DAP_REG 0x45 -#define STLINK_DEBUG_APIV2_WRITE_DAP_REG 0x46 -#define STLINK_DEBUG_APIV2_READMEM_16BIT 0x47 -#define STLINK_DEBUG_APIV2_WRITEMEM_16BIT 0x48 - -#define STLINK_DEBUG_APIV2_INIT_AP 0x4B -#define STLINK_DEBUG_APIV2_CLOSE_AP_DBG 0x4C - -#define STLINK_APIV3_SET_COM_FREQ 0x61 -#define STLINK_APIV3_GET_COM_FREQ 0x62 - -#define STLINK_APIV3_GET_VERSION_EX 0xFB - -#define STLINK_DEBUG_APIV2_DRIVE_NRST_LOW 0x00 -#define STLINK_DEBUG_APIV2_DRIVE_NRST_HIGH 0x01 -#define STLINK_DEBUG_APIV2_DRIVE_NRST_PULSE 0x02 - - -#define STLINK_TRACE_SIZE 4096 -#define STLINK_TRACE_MAX_HZ 2000000 - -#define STLINK_V3_MAX_FREQ_NB 10 - -/** */ -enum stlink_mode { - STLINK_MODE_UNKNOWN = 0, - STLINK_MODE_DFU, - STLINK_MODE_MASS, - STLINK_MODE_DEBUG_JTAG, - STLINK_MODE_DEBUG_SWD, - STLINK_MODE_DEBUG_SWIM -}; - -enum transport_mode_t{ - STLINK_MODE_SWD = 0, - STLINK_MODE_JTAG -}; - -typedef struct { - libusb_context* libusb_ctx; - uint16_t vid; - uint16_t pid; - uint8_t transport_mode; - char serial[32]; - uint8_t dap_select; - uint8_t ep_tx; - uint8_t ver_hw; /* 20, 21 or 31 deciphered from USB PID.*/ - uint8_t ver_stlink; /* 2 or 3 from API.*/ - uint8_t ver_api; - uint8_t ver_jtag; - uint8_t ver_mass; - uint8_t ver_swim; - uint8_t ver_bridge; - uint16_t block_size; - bool ap_error; - libusb_device_handle *handle; - struct libusb_transfer* req_trans; - struct libusb_transfer* rep_trans; -} stlink; - -stlink Stlink; - -static int stlink_usb_get_rw_status(bool verbose); - -static void exit_function(void) -{ - libusb_exit(NULL); - DEBUG("Cleanup\n"); -} - -/* SIGTERM handler. */ -static void sigterm_handler(int sig) -{ - (void)sig; - exit(0); -} - -struct trans_ctx { -#define TRANS_FLAGS_IS_DONE (1 << 0) -#define TRANS_FLAGS_HAS_ERROR (1 << 1) - volatile unsigned long flags; -}; - -int debug_level = 0; -bool has_attached = false; - -static int LIBUSB_CALL hotplug_callback_attach( - libusb_context *ctx, libusb_device *dev, libusb_hotplug_event event, - void *user_data) -{ - (void)ctx; - (void)dev; - (void)event; - (void)user_data; - has_attached = true; - return 1; /* deregister Callback*/ -} - -int device_detached = 0; -static int LIBUSB_CALL hotplug_callback_detach( - libusb_context *ctx, libusb_device *dev, libusb_hotplug_event event, - void *user_data) -{ - (void)ctx; - (void)dev; - (void)event; - (void)user_data; - device_detached = 1; - return 1; /* deregister Callback*/ -} - -void stlink_check_detach(int state) -{ - if (state == 1) { - /* Check for hotplug events */ - struct timeval tv = {0,0}; - libusb_handle_events_timeout_completed( - Stlink.libusb_ctx, &tv, &device_detached); - if (device_detached) { - DEBUG("Dongle was detached\n"); - exit(0); - } - } -} - -static void LIBUSB_CALL on_trans_done(struct libusb_transfer * trans) -{ - struct trans_ctx * const ctx = trans->user_data; - - if (trans->status != LIBUSB_TRANSFER_COMPLETED) - { - DEBUG("on_trans_done: "); - if(trans->status == LIBUSB_TRANSFER_TIMED_OUT) - { - DEBUG("Timeout\n"); - } else if (trans->status == LIBUSB_TRANSFER_CANCELLED) { - DEBUG("cancelled\n"); - } else if (trans->status == LIBUSB_TRANSFER_NO_DEVICE) { - DEBUG("no device\n"); - } else { - DEBUG("unknown\n"); - } - ctx->flags |= TRANS_FLAGS_HAS_ERROR; - } - ctx->flags |= TRANS_FLAGS_IS_DONE; -} - -static int submit_wait(struct libusb_transfer * trans) { - struct timeval start; - struct timeval now; - struct timeval diff; - struct trans_ctx trans_ctx; - enum libusb_error error; - - trans_ctx.flags = 0; - - /* brief intrusion inside the libusb interface */ - trans->callback = on_trans_done; - trans->user_data = &trans_ctx; - - if ((error = libusb_submit_transfer(trans))) { - DEBUG("libusb_submit_transfer(%d): %s\n", error, - libusb_strerror(error)); - exit(-1); - } - - gettimeofday(&start, NULL); - - while (trans_ctx.flags == 0) { - struct timeval timeout; - timeout.tv_sec = 1; - timeout.tv_usec = 0; - if (libusb_handle_events_timeout(Stlink.libusb_ctx, &timeout)) { - DEBUG("libusb_handle_events()\n"); - return -1; - } - - gettimeofday(&now, NULL); - timersub(&now, &start, &diff); - if (diff.tv_sec >= 1) { - libusb_cancel_transfer(trans); - DEBUG("libusb_handle_events() timeout\n"); - return -1; - } - } - - if (trans_ctx.flags & TRANS_FLAGS_HAS_ERROR) { - DEBUG("libusb_handle_events() | has_error\n"); - return -1; - } - - return 0; -} -#define STLINK_ERROR_DP_FAULT -2 -static int send_recv(uint8_t *txbuf, size_t txsize, - uint8_t *rxbuf, size_t rxsize) -{ - int res = 0; - stlink_check_detach(1); - if( txsize) { - int txlen = txsize; - libusb_fill_bulk_transfer(Stlink.req_trans, Stlink.handle, - Stlink.ep_tx | LIBUSB_ENDPOINT_OUT, - txbuf, txlen, - NULL, NULL, - 0 - ); - DEBUG_USB(" Send (%d): ", txlen); - for (int i = 0; i < txlen && i < 32 ; i++) { - DEBUG_USB("%02x", txbuf[i]); - if ((i & 7) == 7) - DEBUG_USB("."); - } - if (submit_wait(Stlink.req_trans)) { - DEBUG_USB("clear 2\n"); - libusb_clear_halt(Stlink.handle,2); - return -1; - } - } - /* send_only */ - if (rxsize != 0) { - /* read the response */ - libusb_fill_bulk_transfer(Stlink.rep_trans, Stlink.handle, - 0x01| LIBUSB_ENDPOINT_IN, - rxbuf, rxsize, NULL, NULL, 0); - - if (submit_wait(Stlink.rep_trans)) { - DEBUG("clear 1\n"); - libusb_clear_halt(Stlink.handle,1); - return -1; - } - res = Stlink.rep_trans->actual_length; - if (res >0) { - int i; - uint8_t *p = rxbuf; - DEBUG_USB(" Rec (%zu/%d)", rxsize, res); - for (i = 0; i < res && i < 32 ; i++) { - if ( i && ((i & 7) == 0)) - DEBUG_USB("."); - DEBUG_USB("%02x", p[i]); - } - } - } - DEBUG_USB("\n"); - return res; -} - -/** - Converts an STLINK status code held in the first byte of a response to - readable error -*/ -static int stlink_usb_error_check(uint8_t *data, bool verbose) -{ - switch (data[0]) { - case STLINK_DEBUG_ERR_OK: - return STLINK_ERROR_OK; - case STLINK_DEBUG_ERR_FAULT: - if (verbose) - DEBUG("SWD fault response (0x%x)\n", STLINK_DEBUG_ERR_FAULT); - return STLINK_ERROR_FAIL; - case STLINK_JTAG_UNKNOWN_JTAG_CHAIN: - if (verbose) - DEBUG("Unknown JTAG chain\n"); - return STLINK_ERROR_FAIL; - case STLINK_NO_DEVICE_CONNECTED: - if (verbose) - DEBUG("No device connected\n"); - return STLINK_ERROR_FAIL; - case STLINK_JTAG_COMMAND_ERROR: - if (verbose) - DEBUG("Command error\n"); - return STLINK_ERROR_FAIL; - case STLINK_JTAG_GET_IDCODE_ERROR: - if (verbose) - DEBUG("Failure reading IDCODE\n"); - return STLINK_ERROR_FAIL; - case STLINK_JTAG_DBG_POWER_ERROR: - if (verbose) - DEBUG("Failure powering DBG\n"); - return STLINK_ERROR_WAIT; - case STLINK_SWD_AP_WAIT: - if (verbose) - DEBUG("wait status SWD_AP_WAIT (0x%x)\n", STLINK_SWD_AP_WAIT); - return STLINK_ERROR_WAIT; - case STLINK_SWD_DP_WAIT: - if (verbose) - DEBUG("wait status SWD_DP_WAIT (0x%x)\n", STLINK_SWD_DP_WAIT); - return STLINK_ERROR_WAIT; - case STLINK_JTAG_WRITE_ERROR: - if (verbose) - DEBUG("Write error\n"); - return STLINK_ERROR_FAIL; - case STLINK_JTAG_WRITE_VERIF_ERROR: - if (verbose) - DEBUG("Write verify error, ignoring\n"); - return STLINK_ERROR_OK; - case STLINK_SWD_AP_FAULT: - /* git://git.ac6.fr/openocd commit 657e3e885b9ee10 - * returns STLINK_ERROR_OK with the comment: - * Change in error status when reading outside RAM. - * This fix allows CDT plugin to visualize memory. - */ - Stlink.ap_error = true; - if (verbose) - DEBUG("STLINK_SWD_AP_FAULT\n"); - return STLINK_ERROR_DP_FAULT; - case STLINK_SWD_AP_ERROR: - if (verbose) - DEBUG("STLINK_SWD_AP_ERROR\n"); - return STLINK_ERROR_FAIL; - case STLINK_SWD_AP_PARITY_ERROR: - if (verbose) - DEBUG("STLINK_SWD_AP_PARITY_ERROR\n"); - return STLINK_ERROR_FAIL; - case STLINK_SWD_DP_FAULT: - if (verbose) - DEBUG("STLINK_SWD_DP_FAULT\n"); - return STLINK_ERROR_FAIL; - case STLINK_SWD_DP_ERROR: - if (verbose) - DEBUG("STLINK_SWD_DP_ERROR\n"); - raise_exception(EXCEPTION_ERROR, "STLINK_SWD_DP_ERROR"); - return STLINK_ERROR_FAIL; - case STLINK_SWD_DP_PARITY_ERROR: - if (verbose) - DEBUG("STLINK_SWD_DP_PARITY_ERROR\n"); - return STLINK_ERROR_FAIL; - case STLINK_SWD_AP_WDATA_ERROR: - if (verbose) - DEBUG("STLINK_SWD_AP_WDATA_ERROR\n"); - return STLINK_ERROR_FAIL; - case STLINK_SWD_AP_STICKY_ERROR: - if (verbose) - DEBUG("STLINK_SWD_AP_STICKY_ERROR\n"); - return STLINK_ERROR_FAIL; - case STLINK_SWD_AP_STICKYORUN_ERROR: - if (verbose) - DEBUG("STLINK_SWD_AP_STICKYORUN_ERROR\n"); - return STLINK_ERROR_FAIL; - case STLINK_BAD_AP_ERROR: - /* ADIV5 probe 256 APs, most of them are non exisitant.*/ - return STLINK_ERROR_FAIL; - case STLINK_TOO_MANY_AP_ERROR: - /* TI TM4C duplicates AP. Error happens at AP9.*/ - if (verbose) - DEBUG("STLINK_TOO_MANY_AP_ERROR\n"); - return STLINK_ERROR_FAIL; - case STLINK_JTAG_UNKNOWN_CMD : - if (verbose) - DEBUG("STLINK_JTAG_UNKNOWN_CMD\n"); - return STLINK_ERROR_FAIL; - default: - if (verbose) - DEBUG("unknown/unexpected STLINK status code 0x%x\n", data[0]); - return STLINK_ERROR_FAIL; - } -} - -static int send_recv_retry(uint8_t *txbuf, size_t txsize, - uint8_t *rxbuf, size_t rxsize) -{ - struct timeval start; - struct timeval now; - struct timeval diff; - gettimeofday(&start, NULL); - int res; - while(1) { - send_recv(txbuf, txsize, rxbuf, rxsize); - res = stlink_usb_error_check(rxbuf, false); - if (res == STLINK_ERROR_OK) - return res; - gettimeofday(&now, NULL); - timersub(&now, &start, &diff); - if ((diff.tv_sec >= 1) || (res != STLINK_ERROR_WAIT)) { - DEBUG("write_retry failed. "); - return res; - } - } - return res; -} - -static int read_retry(uint8_t *txbuf, size_t txsize, - uint8_t *rxbuf, size_t rxsize) -{ - struct timeval start; - struct timeval now; - struct timeval diff; - gettimeofday(&start, NULL); - int res; - while(1) { - send_recv(txbuf, txsize, rxbuf, rxsize); - res = stlink_usb_get_rw_status(false); - if (res == STLINK_ERROR_OK) - return res; - gettimeofday(&now, NULL); - timersub(&now, &start, &diff); - if ((diff.tv_sec >= 1) || (res != STLINK_ERROR_WAIT)) { - DEBUG("read_retry failed. "); - stlink_usb_get_rw_status(true); - return res; - } - } - return res; -} - -static int write_retry(uint8_t *cmdbuf, size_t cmdsize, - uint8_t *txbuf, size_t txsize) -{ - struct timeval start; - struct timeval now; - struct timeval diff; - gettimeofday(&start, NULL); - int res; - while(1) { - send_recv(cmdbuf, cmdsize, NULL, 0); - send_recv(txbuf, txsize, NULL, 0); - res = stlink_usb_get_rw_status(false); - if (res == STLINK_ERROR_OK) - return res; - gettimeofday(&now, NULL); - timersub(&now, &start, &diff); - if ((diff.tv_sec >= 1) || (res != STLINK_ERROR_WAIT)) { - stlink_usb_get_rw_status(true); - return res; - } - } - return res; -} - -static void stlink_version(void) -{ - if (Stlink.ver_hw == 30) { - uint8_t cmd[16] = {STLINK_APIV3_GET_VERSION_EX}; - uint8_t data[12]; - int size = send_recv(cmd, 16, data, 12); - if (size == -1) { - printf("[!] send_recv STLINK_APIV3_GET_VERSION_EX\n"); - } - Stlink.ver_stlink = data[0]; - Stlink.ver_swim = data[1]; - Stlink.ver_jtag = data[2]; - Stlink.ver_mass = data[3]; - Stlink.ver_bridge = data[4]; - Stlink.block_size = 512; - Stlink.vid = data[3] << 9 | data[8]; - Stlink.pid = data[5] << 11 | data[10]; - } else { - uint8_t cmd[16] = {STLINK_GET_VERSION}; - uint8_t data[6]; - int size = send_recv(cmd, 16, data, 6); - if (size == -1) { - printf("[!] send_recv STLINK_GET_VERSION_EX\n"); - } - Stlink.vid = data[3] << 8 | data[2]; - Stlink.pid = data[5] << 8 | data[4]; - int version = data[0] << 8 | data[1]; /* Big endian here!*/ - Stlink.block_size = 64; - Stlink.ver_stlink = (version >> 12) & 0x0f; - Stlink.ver_jtag = (version >> 6) & 0x3f; - if ((Stlink.pid == PRODUCT_ID_STLINKV21_MSD) || - (Stlink.pid == PRODUCT_ID_STLINKV21)) { - Stlink.ver_mass = (version >> 0) & 0x3f; - } else { - Stlink.ver_swim = (version >> 0) & 0x3f; - } - } - DEBUG("V%dJ%d",Stlink.ver_stlink, Stlink.ver_jtag); - if (Stlink.ver_hw == 30) { - DEBUG("M%dB%dS%d", Stlink.ver_mass, Stlink.ver_bridge, Stlink.ver_swim); - } else if (Stlink.ver_hw == 20) { - DEBUG("S%d", Stlink.ver_swim); - } else if (Stlink.ver_hw == 21) { - DEBUG("M%d", Stlink.ver_mass); - } - DEBUG("\n"); -} - -void stlink_leave_state(void) -{ - uint8_t cmd[16] = {STLINK_GET_CURRENT_MODE}; - uint8_t data[2]; - send_recv(cmd, 16, data, 2); - if (data[0] == STLINK_DEV_DFU_MODE) { - uint8_t dfu_cmd[16] = {STLINK_DFU_COMMAND, STLINK_DFU_EXIT}; - DEBUG("Leaving DFU Mode\n"); - send_recv(dfu_cmd, 16, NULL, 0); - } else if (data[0] == STLINK_DEV_SWIM_MODE) { - uint8_t swim_cmd[16] = {STLINK_SWIM_COMMAND, STLINK_SWIM_EXIT}; - DEBUG("Leaving SWIM Mode\n"); - send_recv(swim_cmd, 16, NULL, 0); - } else if (data[0] == STLINK_DEV_DEBUG_MODE) { - uint8_t dbg_cmd[16] = {STLINK_DEBUG_COMMAND, STLINK_DEBUG_EXIT}; - DEBUG("Leaving DEBUG Mode\n"); - send_recv(dbg_cmd, 16, NULL, 0); - } else if (data[0] == STLINK_DEV_BOOTLOADER_MODE) { - DEBUG("Leaving BOOTLOADER Mode\n"); - } else if (data[0] == STLINK_DEV_MASS_MODE) { - DEBUG("Leaving MASS Mode\n"); - } else { - DEBUG("Unknown Mode %02x\n", data[0]); - } -} - -const char *stlink_target_voltage(void) -{ - uint8_t cmd[16] = {STLINK_GET_TARGET_VOLTAGE}; - uint8_t data[8]; - send_recv(cmd, 16, data, 8); - uint16_t adc[2]; - adc[0] = data[0] | data[1] << 8; /* Calibration value? */ - adc[1] = data[4] | data[5] << 8; /* Measured value?*/ - float result = 0.0; - if (adc[0]) - result = 2.0 * adc[1] * 1.2 / adc[0]; - static char res[6]; - sprintf(res, "%4.2fV", result); - return res; -} - -static void stlink_resetsys(void) -{ - uint8_t cmd[16] = {STLINK_DEBUG_COMMAND ,STLINK_DEBUG_APIV2_RESETSYS}; - uint8_t data[2]; - send_recv(cmd, 16, data, 2); -} - -void stlink_init(int argc, char **argv) -{ - BMP_CL_OPTIONS_t cl_opts = {0}; - cl_opts.opt_idstring = "Blackmagic Debug Probe on StlinkV2/3"; - cl_init(&cl_opts, argc, argv); - libusb_device **devs, *dev; - int r; - int ret = -1; - atexit(exit_function); - signal(SIGTERM, sigterm_handler); - signal(SIGINT, sigterm_handler); - libusb_init(&Stlink.libusb_ctx); - r = libusb_init(NULL); - if (r < 0) - DEBUG("Failed: %s", libusb_strerror(r)); - bool hotplug = true; - if (!libusb_has_capability (LIBUSB_CAP_HAS_HOTPLUG)) { - printf("Hotplug capabilites are not supported on this platform\n"); - hotplug = false; - } - ssize_t cnt; - rescan: - has_attached = 0; - memset(&Stlink, 0, sizeof(Stlink)); - cnt = libusb_get_device_list(NULL, &devs); - if (cnt < 0) { - DEBUG("Failed: %s", libusb_strerror(r)); - goto error; - } - int i = 0; - int nr_stlinks = 0; - while ((dev = devs[i++]) != NULL) { - struct libusb_device_descriptor desc; - int r = libusb_get_device_descriptor(dev, &desc); - if (r < 0) { - fprintf(stderr, "libusb_get_device_descriptor failed %s", - libusb_strerror(r)); - goto error; - } - if ((desc.idVendor == VENDOR_ID_STLINK) && - ((desc.idProduct & PRODUCT_ID_STLINK_MASK) == - PRODUCT_ID_STLINK_GROUP)) { - if (desc.idProduct == PRODUCT_ID_STLINKV1) { /* Reject V1 devices.*/ - DEBUG("STLINKV1 not supported\n"); - continue; - } - Stlink.vid = desc.idVendor; - Stlink.pid = desc.idProduct; - r = libusb_open(dev, &Stlink.handle); - if (r == LIBUSB_SUCCESS) { - uint8_t data[32]; - uint16_t lang; - libusb_get_string_descriptor( - Stlink.handle, 0, 0, data, sizeof(data)); - lang = data[2] << 8 | data[3]; - unsigned char sernum[32]; - if (desc.iSerialNumber) { - r = libusb_get_string_descriptor - (Stlink.handle, desc.iSerialNumber, lang, - sernum, sizeof(sernum)); - } else { - DEBUG("No serial number\n"); - } - /* Older devices have hex values instead of ascii - * in the serial string. Recode eventually!*/ - bool readable = true; - uint16_t *p = (uint16_t *)sernum; - for (p += 1; *p; p++) { - bool isr = isalnum(*p); - readable &= isr; - } - char *s = Stlink.serial; - p = (uint16_t *)sernum; - for (p += 1; *p; p++, s++) { - if (readable) - *s = *p; - else - snprintf(s, 3, "%02x", *p & 0xff); - } - if (cl_opts.opt_serial && (!strncmp(Stlink.serial, cl_opts.opt_serial, - strlen(cl_opts.opt_serial)))) - DEBUG("Found "); - if (desc.idProduct == PRODUCT_ID_STLINKV2) { - DEBUG("STLINKV20 serial %s\n", Stlink.serial); - Stlink.ver_hw = 20; - Stlink.ep_tx = 2; - } else if (desc.idProduct == PRODUCT_ID_STLINKV21) { - DEBUG("STLINKV21 serial %s\n", Stlink.serial); - Stlink.ver_hw = 21; - Stlink.ep_tx = 1; - } else if (desc.idProduct == PRODUCT_ID_STLINKV21_MSD) { - DEBUG("STLINKV21_MSD serial %s\n", Stlink.serial); - Stlink.ver_hw = 21; - Stlink.ep_tx = 1; - } else if (desc.idProduct == PRODUCT_ID_STLINKV3E) { - DEBUG("STLINKV3E serial %s\n", Stlink.serial); - Stlink.ver_hw = 30; - Stlink.ep_tx = 1; - } else if (desc.idProduct == PRODUCT_ID_STLINKV3) { - DEBUG("STLINKV3 serial %s\n", Stlink.serial); - Stlink.ver_hw = 30; - Stlink.ep_tx = 1; - } else { - DEBUG("Unknown STLINK variant, serial %s\n", Stlink.serial); - } - nr_stlinks++; - if (cl_opts.opt_serial) { - if (!strncmp(Stlink.serial, cl_opts.opt_serial, - strlen(cl_opts.opt_serial))) { - break; - } else { - libusb_close(Stlink.handle); - Stlink.handle = 0; - } - } - } else { - DEBUG("Open failed %s\n", libusb_strerror(r)); - } - } - } - libusb_free_device_list(devs, 1); - if (!Stlink.handle) { - if (nr_stlinks && cl_opts.opt_serial) { - DEBUG("No Stlink with given serial number %s\n", cl_opts.opt_serial); - } else if (nr_stlinks > 1) { - DEBUG("Multiple Stlinks. Please specify serial number\n"); - goto error; - } else { - DEBUG("No Stlink device found!\n"); - } - if (hotplug && !cl_opts.opt_no_wait) { - libusb_hotplug_callback_handle hp; - int rc = libusb_hotplug_register_callback - (NULL, LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED, 0, - VENDOR_ID_STLINK, LIBUSB_HOTPLUG_MATCH_ANY, - LIBUSB_HOTPLUG_MATCH_ANY, - hotplug_callback_attach, NULL, &hp); - if (LIBUSB_SUCCESS != rc) { - DEBUG("Error registering attach callback\n"); - goto error; - } - DEBUG("Waiting for %sST device%s%s to attach\n", - (cl_opts.opt_serial)? "" : "some ", - (cl_opts.opt_serial)? " with serial ": "", - (cl_opts.opt_serial)? cl_opts.opt_serial: ""); - DEBUG("Terminate with ^C\n"); - while (has_attached == 0) { - rc = libusb_handle_events (NULL); - if (rc < 0) - printf("libusb_handle_events() failed: %s\n", - libusb_error_name(rc)); - } - goto rescan; - } - goto error; - } - int config; - r = libusb_get_configuration(Stlink.handle, &config); - if (r) { - DEBUG("libusb_get_configuration failed %d: %s", r, libusb_strerror(r)); - goto error_1; - } - DEBUG("Config %d\n", config); - if (config != 1) { - r = libusb_set_configuration(Stlink.handle, 0); - if (r) { - DEBUG("libusb_set_configuration failed %d: %s", - r, libusb_strerror(r)); - goto error_1; - } - } - r = libusb_claim_interface(Stlink.handle, 0); - if (r) - { - DEBUG("libusb_claim_interface failed %s\n", libusb_strerror(r)); - goto error_1; - } - if (hotplug) { /* Allow gracefully exit when stlink is unplugged*/ - libusb_hotplug_callback_handle hp; - int rc = libusb_hotplug_register_callback - (NULL, LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT, 0, Stlink.vid, Stlink.pid, - LIBUSB_HOTPLUG_MATCH_ANY, hotplug_callback_detach, NULL, &hp); - if (LIBUSB_SUCCESS != rc) { - DEBUG("Error registering detach callback\n"); - goto error; - } - } - Stlink.req_trans = libusb_alloc_transfer(0); - Stlink.rep_trans = libusb_alloc_transfer(0); - stlink_version(); - if ((Stlink.ver_stlink < 3 && Stlink.ver_jtag < 32) || - (Stlink.ver_stlink == 3 && Stlink.ver_jtag < 3)) { - /* Maybe the adapter is in some strange state. Try to reset */ - int result = libusb_reset_device(Stlink.handle); - DEBUG("Trying reset\n"); - if (result == LIBUSB_ERROR_BUSY) { /* Try again */ - platform_delay(50); - result = libusb_reset_device(Stlink.handle); - } - if (result != LIBUSB_SUCCESS) { - DEBUG("libusb_reset_device failed\n"); - goto error_1; - } - stlink_version(); - } - if ((Stlink.ver_stlink < 3 && Stlink.ver_jtag < 32) || - (Stlink.ver_stlink == 3 && Stlink.ver_jtag < 3)) { - DEBUG("Please update Firmware\n"); - goto error_1; - } - stlink_leave_state(); - stlink_resetsys(); - if (cl_opts.opt_mode != BMP_MODE_DEBUG) { - ret = cl_execute(&cl_opts); - } else { - assert(gdb_if_init() == 0); - return; - } - error_1: - libusb_close(Stlink.handle); - error: - libusb_exit(Stlink.libusb_ctx); - exit(ret); -} - -void stlink_srst_set_val(bool assert) -{ - uint8_t cmd[16] = {STLINK_DEBUG_COMMAND, - STLINK_DEBUG_APIV2_DRIVE_NRST, - (assert)? STLINK_DEBUG_APIV2_DRIVE_NRST_LOW - : STLINK_DEBUG_APIV2_DRIVE_NRST_HIGH}; - uint8_t data[2]; - send_recv(cmd, 16, data, 2); - stlink_usb_error_check(data, true); -} - -bool stlink_set_freq_divisor(uint16_t divisor) -{ - uint8_t cmd[16] = {STLINK_DEBUG_COMMAND, - STLINK_DEBUG_APIV2_SWD_SET_FREQ, - divisor & 0xff, divisor >> 8}; - uint8_t data[2]; - send_recv(cmd, 16, data, 2); - if (stlink_usb_error_check(data, false)) - return false; - return true; -} - -bool stlink3_set_freq_divisor(uint16_t divisor) -{ - uint8_t cmd[16] = {STLINK_DEBUG_COMMAND, - STLINK_APIV3_GET_COM_FREQ, - Stlink.transport_mode}; - uint8_t data[52]; - send_recv(cmd, 16, data, 52); - stlink_usb_error_check(data, true); - int size = data[8]; - if (divisor > size) - divisor = size; - uint8_t *p = data + 12 + divisor * sizeof(uint32_t); - uint32_t freq = p[0] | p[1] << 8 | p[2] << 16 | p[3] << 24; - DEBUG("Selected %" PRId32 " khz\n", freq); - cmd[1] = STLINK_APIV3_SET_COM_FREQ; - cmd[2] = Stlink.transport_mode; - cmd[3] = 0; - p = data + 12 + divisor * sizeof(uint32_t); - cmd[4] = p[0]; - cmd[5] = p[1]; - cmd[6] = p[2]; - cmd[7] = p[3]; - send_recv(cmd, 16, data, 8); - return true; -} - -int stlink_hwversion(void) -{ - return Stlink.ver_stlink; -} - -int stlink_enter_debug_swd(void) -{ - stlink_leave_state(); - Stlink.transport_mode = STLINK_MODE_SWD; - if (Stlink.ver_stlink == 3) - stlink3_set_freq_divisor(2); - else - stlink_set_freq_divisor(1); - uint8_t cmd[16] = {STLINK_DEBUG_COMMAND, - STLINK_DEBUG_APIV2_ENTER, - STLINK_DEBUG_ENTER_SWD_NO_RESET}; - uint8_t data[2]; - DEBUG("Enter SWD\n"); - send_recv_retry(cmd, 16, data, 2); - return stlink_usb_error_check(data, true); -} - -int stlink_enter_debug_jtag(void) -{ - stlink_leave_state(); - Stlink.transport_mode = STLINK_MODE_JTAG; - if (Stlink.ver_stlink == 3) - stlink3_set_freq_divisor(4); - else - stlink_set_freq_divisor(1); - uint8_t cmd[16] = {STLINK_DEBUG_COMMAND, - STLINK_DEBUG_APIV2_ENTER, - STLINK_DEBUG_ENTER_JTAG_NO_RESET}; - uint8_t data[2]; - DEBUG("Enter JTAG\n"); - send_recv(cmd, 16, data, 2); - return stlink_usb_error_check(data, true); -} - -uint32_t stlink_read_coreid(void) -{ - uint8_t cmd[16] = {STLINK_DEBUG_COMMAND, - STLINK_DEBUG_READCOREID}; - uint8_t data[4]; - send_recv(cmd, 16, data, 4); - uint32_t id = data[0] | data[1] << 8 | data[2] << 16 | data[3] << 24; - DEBUG("Read Core ID: 0x%08" PRIx32 "\n", id); - return id; -} - -int stlink_read_idcodes(uint32_t *idcodes) -{ - uint8_t cmd[16] = {STLINK_DEBUG_COMMAND, - STLINK_DEBUG_APIV2_READ_IDCODES}; - uint8_t data[12]; - send_recv(cmd, 16, data, 12); - if (stlink_usb_error_check(data, true)) - return 0; - uint8_t *p = data + 4; - idcodes[0] = p[0] | p[1] << 8 | p[2] << 16 | p[3] << 24; - p += 4; - idcodes[1] = p[0] | p[1] << 8 | p[2] << 16 | p[3] << 24; - return 2; -} - -uint32_t stlink_dp_read(ADIv5_DP_t *dp, uint16_t addr) -{ - if (addr & ADIV5_APnDP) { - DEBUG_STLINK("AP read addr 0x%04" PRIx16 "\n", addr); - stlink_dp_low_access(dp, ADIV5_LOW_READ, addr, 0); - return stlink_dp_low_access(dp, ADIV5_LOW_READ, - ADIV5_DP_RDBUFF, 0); - } else { - DEBUG_STLINK("DP read addr 0x%04" PRIx16 "\n", addr); - return stlink_dp_low_access(dp, ADIV5_LOW_READ, addr, 0); - } -} - -uint32_t stlink_dp_error(ADIv5_DP_t *dp) -{ - uint32_t err, clr = 0; - - err = stlink_dp_read(dp, ADIV5_DP_CTRLSTAT) & - (ADIV5_DP_CTRLSTAT_STICKYORUN | ADIV5_DP_CTRLSTAT_STICKYCMP | - ADIV5_DP_CTRLSTAT_STICKYERR | ADIV5_DP_CTRLSTAT_WDATAERR); - - if(err & ADIV5_DP_CTRLSTAT_STICKYORUN) - clr |= ADIV5_DP_ABORT_ORUNERRCLR; - if(err & ADIV5_DP_CTRLSTAT_STICKYCMP) - clr |= ADIV5_DP_ABORT_STKCMPCLR; - if(err & ADIV5_DP_CTRLSTAT_STICKYERR) - clr |= ADIV5_DP_ABORT_STKERRCLR; - if(err & ADIV5_DP_CTRLSTAT_WDATAERR) - clr |= ADIV5_DP_ABORT_WDERRCLR; - - adiv5_dp_write(dp, ADIV5_DP_ABORT, clr); - dp->fault = 0; - if (err) - DEBUG("stlink_dp_error %d\n", err); - err |= Stlink.ap_error; - Stlink.ap_error = false; - return err; -} - -void stlink_dp_abort(ADIv5_DP_t *dp, uint32_t abort) -{ - adiv5_dp_write(dp, ADIV5_DP_ABORT, abort); -} - -int stlink_read_dp_register(uint16_t port, uint16_t addr, uint32_t *reg) -{ - uint8_t cmd[16] = {STLINK_DEBUG_COMMAND, - STLINK_DEBUG_APIV2_READ_DAP_REG, - port & 0xff, port >> 8, - addr & 0xff, addr >> 8}; - if (port == STLINK_DEBUG_PORT_ACCESS && Stlink.dap_select) - cmd[4] = ((Stlink.dap_select & 0xf) << 4) | (addr & 0xf); - else - cmd[4] = addr & 0xff; - DEBUG_STLINK("Read DP, Addr 0x%04" PRIx16 ": \n", addr); - uint8_t data[8]; - int res = send_recv_retry(cmd, 16, data, 8); - if (res == STLINK_ERROR_OK) { - uint32_t ret = data[4] | data[5] << 8 | data[6] << 16 | data[7] << 24; - DEBUG_STLINK("0x%08" PRIx32" \n", ret); - *reg = ret; - } else { - DEBUG_STLINK("failed, res %d\n", res); - } - return res; -} - -int stlink_write_dp_register(uint16_t port, uint16_t addr, uint32_t val) -{ - if (port == STLINK_DEBUG_PORT_ACCESS && addr == 8) { - Stlink.dap_select = val; - DEBUG_STLINK("Caching SELECT 0x%02" PRIx32 "\n", val); - return STLINK_ERROR_OK; - } else { - uint8_t cmd[16] = { - STLINK_DEBUG_COMMAND, STLINK_DEBUG_APIV2_WRITE_DAP_REG, - port & 0xff, port >> 8, - addr & 0xff, addr >> 8, - val & 0xff, (val >> 8) & 0xff, (val >> 16) & 0xff, - (val >> 24) & 0xff}; - uint8_t data[2]; - send_recv_retry(cmd, 16, data, 2); - DEBUG_STLINK("Write DP, Addr 0x%04" PRIx16 ": 0x%08" PRIx32 - " \n", addr, val); - return stlink_usb_error_check(data, true); - } -} - -uint32_t stlink_dp_low_access(ADIv5_DP_t *dp, uint8_t RnW, - uint16_t addr, uint32_t value) -{ - uint32_t response = 0; - int res; - if (RnW) { - res = stlink_read_dp_register( - STLINK_DEBUG_PORT_ACCESS, addr, &response); - DEBUG_STLINK("SWD read addr %04" PRIx16 ": %08" PRIx32 "\n", - addr, response); - } else { - DEBUG_STLINK("SWD write addr %04" PRIx16 ": %08" PRIx32 "\n", - addr, value); - res = stlink_write_dp_register(STLINK_DEBUG_PORT_ACCESS, addr, value); - } - if (res == STLINK_ERROR_WAIT) - raise_exception(EXCEPTION_TIMEOUT, "DP ACK timeout"); - - if(res == STLINK_ERROR_DP_FAULT) { - dp->fault = 1; - return 0; - } - if(res == STLINK_ERROR_FAIL) - raise_exception(EXCEPTION_ERROR, "SWDP invalid ACK"); - - return response; -} - -static bool stlink_ap_setup(int ap) -{ - if (ap > 7) - return false; - uint8_t cmd[16] = { - STLINK_DEBUG_COMMAND, - STLINK_DEBUG_APIV2_INIT_AP, - ap, - }; - uint8_t data[2]; - send_recv_retry(cmd, 16, data, 2); - DEBUG_STLINK("Open AP %d\n", ap); - int res = stlink_usb_error_check(data, true); - if (res) { - if (Stlink.ver_hw == 30) { - DEBUG("STLINKV3 only connects to STM8/32!\n"); - } - return false; - } - return true; -} - -static void stlink_ap_cleanup(int ap) -{ - uint8_t cmd[16] = { - STLINK_DEBUG_COMMAND, - STLINK_DEBUG_APIV2_CLOSE_AP_DBG, - ap, - }; - uint8_t data[2]; - send_recv(cmd, 16, data, 2); - DEBUG_STLINK("Close AP %d\n", ap); - stlink_usb_error_check(data, true); -} -static int stlink_usb_get_rw_status(bool verbose) -{ - uint8_t cmd[16] = { - STLINK_DEBUG_COMMAND, - STLINK_DEBUG_APIV2_GETLASTRWSTATUS2 - }; - uint8_t data[12]; - send_recv(cmd, 16, data, 12); - return stlink_usb_error_check(data, verbose); -} - -static void stlink_readmem(ADIv5_AP_t *ap, void *dest, uint32_t src, size_t len) -{ - if (len == 0) - return; - size_t read_len = len; - uint8_t type; - char *CMD; - if (src & 1 || len & 1) { - CMD = "READMEM_8BIT"; - type = STLINK_DEBUG_READMEM_8BIT; - if (len > Stlink.block_size) { - DEBUG(" Too large!\n"); - return; - } - if (len == 1) - read_len ++; /* Fix read length as in openocd*/ - } else if (src & 3 || len & 3) { - CMD = "READMEM_16BIT"; - type = STLINK_DEBUG_APIV2_READMEM_16BIT; - } else { - CMD = "READMEM_32BIT"; - type = STLINK_DEBUG_READMEM_32BIT; - - } - DEBUG_STLINK("%s len %zu addr 0x%08" PRIx32 " AP %d : ", - CMD, len, src, ap->apsel); - uint8_t cmd[16] = { - STLINK_DEBUG_COMMAND, - type, - src & 0xff, (src >> 8) & 0xff, (src >> 16) & 0xff, - (src >> 24) & 0xff, - len & 0xff, len >> 8, ap->apsel}; - int res = read_retry(cmd, 16, dest, read_len); - if (res == STLINK_ERROR_OK) { - uint8_t *p = (uint8_t*)dest; - for (size_t i = 0; i < len ; i++) { - DEBUG_STLINK("%02x", *p++); - } - } else { - /* FIXME: What is the right measure when failing? - * - * E.g. TM4C129 gets here when NRF probe reads 0x10000010 - * Approach taken: - * Fill the memory with some fixed pattern so hopefully - * the caller notices the error*/ - DEBUG("stlink_readmem failed\n"); - memset(dest, 0xff, len); - } - DEBUG_STLINK("\n"); -} - -static void stlink_writemem8(ADIv5_AP_t *ap, uint32_t addr, size_t len, - uint8_t *buffer) -{ - DEBUG_STLINK("Mem Write8 AP %d len %zu addr 0x%08" PRIx32 ": ", - ap->apsel, len, addr); - for (size_t t = 0; t < len; t++) { - DEBUG_STLINK("%02x", buffer[t]); - } - DEBUG_STLINK("\n"); - while (len) { - size_t length; - if (len > Stlink.block_size) - length = Stlink.block_size; - else - length = len; - uint8_t cmd[16] = { - STLINK_DEBUG_COMMAND, - STLINK_DEBUG_WRITEMEM_8BIT, - addr & 0xff, (addr >> 8) & 0xff, (addr >> 16) & 0xff, - (addr >> 24) & 0xff, - length & 0xff, length >> 8, ap->apsel}; - send_recv(cmd, 16, NULL, 0); - send_recv((void*)buffer, length, NULL, 0); - stlink_usb_get_rw_status(true); - len -= length; - addr += length; - } -} - -static void stlink_writemem16(ADIv5_AP_t *ap, uint32_t addr, size_t len, - uint16_t *buffer) -{ - DEBUG_STLINK("Mem Write16 AP %d len %zu addr 0x%08" PRIx32 ": ", - ap->apsel, len, addr); - for (size_t t = 0; t < len; t+=2) { - DEBUG_STLINK("%04x", buffer[t]); - } - DEBUG_STLINK("\n"); - uint8_t cmd[16] = { - STLINK_DEBUG_COMMAND, - STLINK_DEBUG_APIV2_WRITEMEM_16BIT, - addr & 0xff, (addr >> 8) & 0xff, (addr >> 16) & 0xff, - (addr >> 24) & 0xff, - len & 0xff, len >> 8, ap->apsel}; - send_recv(cmd, 16, NULL, 0); - send_recv((void*)buffer, len, NULL, 0); - stlink_usb_get_rw_status(true); -} - -static void stlink_writemem32(ADIv5_AP_t *ap, uint32_t addr, size_t len, - uint32_t *buffer) -{ - DEBUG_STLINK("Mem Write32 AP %d len %zu addr 0x%08" PRIx32 ": ", - ap->apsel, len, addr); - for (size_t t = 0; t < len; t+=4) { - DEBUG_STLINK("%04x", buffer[t]); - } - DEBUG_STLINK("\n"); - uint8_t cmd[16] = { - STLINK_DEBUG_COMMAND, - STLINK_DEBUG_WRITEMEM_32BIT, - addr & 0xff, (addr >> 8) & 0xff, (addr >> 16) & 0xff, - (addr >> 24) & 0xff, - len & 0xff, len >> 8, ap->apsel}; - write_retry(cmd, 16, (void*)buffer, len); -} - -void stlink_regs_read(ADIv5_AP_t *ap, void *data) -{ - uint8_t cmd[16] = {STLINK_DEBUG_COMMAND, STLINK_DEBUG_APIV2_READALLREGS, - ap->apsel}; - uint8_t res[88]; - DEBUG_STLINK("AP %d: Read all core registers\n", ap->apsel); - send_recv(cmd, 16, res, 88); - stlink_usb_error_check(res, true); - memcpy(data, res + 4, 84); -} - -uint32_t stlink_reg_read(ADIv5_AP_t *ap, int num) -{ - uint8_t cmd[16] = {STLINK_DEBUG_COMMAND, STLINK_DEBUG_APIV2_READREG, num, - ap->apsel}; - uint8_t res[8]; - send_recv(cmd, 16, res, 8); - stlink_usb_error_check(res, true); - uint32_t ret = res[0] | res[1] << 8 | res[2] << 16 | res[3] << 24; - DEBUG_STLINK("AP %d: Read reg %02" PRId32 " val 0x%08" PRIx32 "\n", - ap->apsel, num, ret); - return ret; -} - -void stlink_reg_write(ADIv5_AP_t *ap, int num, uint32_t val) -{ - uint8_t cmd[16] = { - STLINK_DEBUG_COMMAND, STLINK_DEBUG_APIV2_WRITEREG, num, - val & 0xff, (val >> 8) & 0xff, (val >> 16) & 0xff, - (val >> 24) & 0xff, ap->apsel}; - uint8_t res[2]; - send_recv(cmd, 16, res, 2); - DEBUG_STLINK("AP %d: Write reg %02" PRId32 " val 0x%08" PRIx32 "\n", - ap->apsel, num, val); - stlink_usb_error_check(res, true); -} - -static void stlink_mem_write_sized( ADIv5_AP_t *ap, uint32_t dest, - const void *src, size_t len, - enum align align) -{ - if (len == 0) - return; - switch(align) { - case ALIGN_BYTE: stlink_writemem8(ap, dest, len, (uint8_t *) src); - break; - case ALIGN_HALFWORD: stlink_writemem16(ap, dest, len, (uint16_t *) src); - break; - case ALIGN_WORD: stlink_writemem32(ap, dest, len, (uint32_t *) src); - break; - case ALIGN_DWORD: stlink_writemem32(ap, dest, len, (uint32_t *) src); - break; - } -} - -static void stlink_ap_write(ADIv5_AP_t *ap, uint16_t addr, uint32_t value) -{ - stlink_write_dp_register(ap->apsel, addr, value); -} - -static uint32_t stlink_ap_read(ADIv5_AP_t *ap, uint16_t addr) -{ - uint32_t ret; - stlink_read_dp_register(ap->apsel, addr, &ret); - return ret; -} - -struct jtag_dev_s jtag_devs[JTAG_MAX_DEVS+1]; -int jtag_dev_count; -jtag_proc_t jtag_proc; - -int jtag_scan_stlinkv2(const uint8_t *irlens) -{ - uint32_t idcodes[JTAG_MAX_DEVS+1]; - (void) *irlens; - target_list_free(); - - jtag_dev_count = 0; - memset(&jtag_devs, 0, sizeof(jtag_devs)); - if (stlink_enter_debug_jtag()) - return 0; - jtag_dev_count = stlink_read_idcodes(idcodes); - /* Check for known devices and handle accordingly */ - for(int i = 0; i < jtag_dev_count; i++) - jtag_devs[i].idcode = idcodes[i]; - for(int i = 0; i < jtag_dev_count; i++) - for(int j = 0; dev_descr[j].idcode; j++) - if((jtag_devs[i].idcode & dev_descr[j].idmask) == - dev_descr[j].idcode) { - if(dev_descr[j].handler) - dev_descr[j].handler(&jtag_devs[i]); - break; - } - - return jtag_dev_count; -} - -int platform_jtag_dp_init(ADIv5_DP_t *dp) -{ - dp->dp_read = stlink_dp_read; - dp->error = stlink_dp_error; - dp->low_access = stlink_dp_low_access; - dp->abort = stlink_dp_abort; - - return true; - -} - -void platform_adiv5_dp_defaults(ADIv5_DP_t *dp) -{ - dp->ap_regs_read = stlink_regs_read; - dp->ap_reg_read = stlink_reg_read; - dp->ap_reg_write = stlink_reg_write; - dp->ap_setup = stlink_ap_setup; - dp->ap_cleanup = stlink_ap_cleanup; - dp->ap_write = stlink_ap_write; - dp->ap_read = stlink_ap_read; - dp->mem_read = stlink_readmem; - dp->mem_write_sized = stlink_mem_write_sized; -} diff --git a/src/platforms/pc-stlinkv2/stlinkv2.h b/src/platforms/pc-stlinkv2/stlinkv2.h deleted file mode 100644 index dea9a8b7..00000000 --- a/src/platforms/pc-stlinkv2/stlinkv2.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * This file is part of the Black Magic Debug project. - * - * Copyright (C) 2019 Uwe Bonnes - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -#if !defined(__STLINKV2_H_) - -#define STLINK_ERROR_FAIL -1 -#define STLINK_ERROR_OK 0 -#define STLINK_ERROR_WAIT 1 - -#define STLINK_DEBUG_PORT_ACCESS 0xffff - -void stlink_init(int argc, char **argv); -int stlink_hwversion(void); -void stlink_leave_state(void); -const char *stlink_target_voltage(void); -void stlink_srst_set_val(bool assert); -int stlink_enter_debug_swd(void); -int stlink_enter_debug_jtag(void); -int stlink_read_idcodes(uint32_t *); -uint32_t stlink_read_coreid(void); -int stlink_read_dp_register(uint16_t port, uint16_t addr, uint32_t *res); -int stlink_write_dp_register(uint16_t port, uint16_t addr, uint32_t val); - -uint32_t stlink_dp_low_access(ADIv5_DP_t *dp, uint8_t RnW, - uint16_t addr, uint32_t value); -uint32_t stlink_dp_read(ADIv5_DP_t *dp, uint16_t addr); -uint32_t stlink_dp_error(ADIv5_DP_t *dp); -void stlink_dp_abort(ADIv5_DP_t *dp, uint32_t abort); -int stlink_open_ap(uint8_t ap); -void stlink_close_ap(uint8_t ap); -void stlink_regs_read(ADIv5_AP_t *ap, void *data); -uint32_t stlink_reg_read(ADIv5_AP_t *ap, int idx); -void stlink_reg_write(ADIv5_AP_t *ap, int num, uint32_t val); -extern int debug_level; -# define DEBUG_STLINK if (debug_level > 0) printf -# define DEBUG_USB if (debug_level > 1) printf -#endif diff --git a/src/platforms/pc-stlinkv2/swdptap.c b/src/platforms/pc-stlinkv2/swdptap.c deleted file mode 100644 index e69de29b..00000000 diff --git a/src/platforms/pc/cl_utils.c b/src/platforms/pc/cl_utils.c index d68dc78c..6fd4fe9c 100644 --- a/src/platforms/pc/cl_utils.c +++ b/src/platforms/pc/cl_utils.c @@ -120,27 +120,29 @@ static void cl_help(char **argv, BMP_CL_OPTIONS_t *opt) printf("\t-h\t\t: This help.\n"); printf("\t-v[1|2]\t\t: Increasing verbosity\n"); printf("\t-d \"path\"\t: Use serial device at \"path\"\n"); - printf("\t-P \t: Use device found as "); + printf("\t-P \t: Use debugger found at position \n"); + printf("\t-n \t: Use target device found at position \n"); printf("\t-s \"string\"\t: Use dongle with (partial) " "serial number \"string\"\n"); printf("\t-c \"string\"\t: Use ftdi dongle with type \"string\"\n"); - printf("\t-n\t\t: Exit immediate if no device found\n"); printf("\tRun mode related options:\n"); + printf("\tDefault mode is to start the debug server at :2000\n"); + printf("\t-j\t\t: Use JTAG. SWD is default.\n"); printf("\t-C\t\t: Connect under reset\n"); - printf("\t-t\t\t: Scan SWD, with no target found scan jtag and exit\n"); + printf("\t-t\t\t: Scan SWD and display information about connected" + "devices\n"); printf("\t-E\t\t: Erase flash until flash end or for given size\n"); printf("\t-V\t\t: Verify flash against binary file\n"); printf("\t-r\t\t: Read flash and write to binary file\n"); printf("\t-p\t\t: Supplies power to the target (where applicable)\n"); printf("\t-R\t\t: Reset device\n"); - printf("\t\tDefault mode is starting the debug server\n"); printf("\tFlash operation modifiers options:\n"); printf("\t-a \t: Start flash operation at flash address \n" - "\t\t\tDefault start is 0x08000000\n"); + "\t\t\t Default start is 0x08000000\n"); printf("\t-S \t: Read bytes. Default is until read fails.\n"); - printf("\t-j\t\t: Use JTAG. SWD is default.\n"); printf("\t \t\t: Use (binary) file for flash operation\n" - "\t\t\tGiven writes to flash if neither -r or -V is given\n"); + "\t\t\t Given writes to flash if neither -r or -V is " + "given\n"); exit(0); } @@ -150,7 +152,7 @@ void cl_init(BMP_CL_OPTIONS_t *opt, int argc, char **argv) opt->opt_target_dev = 1; opt->opt_flash_start = 0x08000000; opt->opt_flash_size = 16 * 1024 *1024; - while((c = getopt(argc, argv, "Ehv::d:s:I:c:CnN:tVta:S:jpP:rR")) != -1) { + while((c = getopt(argc, argv, "Ehv::d:s:I:c:Cn:tVta:S:jpP:rR")) != -1) { switch(c) { case 'c': if (optarg) @@ -171,9 +173,6 @@ void cl_init(BMP_CL_OPTIONS_t *opt, int argc, char **argv) case 'C': opt->opt_connect_under_reset = true; break; - case 'n': - opt->opt_no_wait = true; - break; case 'd': if (optarg) opt->opt_device = optarg; @@ -208,7 +207,7 @@ void cl_init(BMP_CL_OPTIONS_t *opt, int argc, char **argv) if (optarg) opt->opt_flash_start = strtol(optarg, NULL, 0); break; - case 'N': + case 'n': if (optarg) opt->opt_target_dev = strtol(optarg, NULL, 0); break; diff --git a/src/platforms/pc/cl_utils.h b/src/platforms/pc/cl_utils.h index 5c485b78..88bff7ed 100644 --- a/src/platforms/pc/cl_utils.h +++ b/src/platforms/pc/cl_utils.h @@ -39,7 +39,6 @@ enum bmp_cl_mode { typedef struct BMP_CL_OPTIONS_s { enum bmp_cl_mode opt_mode; bool opt_usejtag; - bool opt_no_wait; bool opt_tpwr; bool opt_connect_under_reset; char *opt_flash_file; diff --git a/src/platforms/pc/libusb_utils.c b/src/platforms/pc/libusb_utils.c index 26c95a02..26724904 100644 --- a/src/platforms/pc/libusb_utils.c +++ b/src/platforms/pc/libusb_utils.c @@ -18,7 +18,6 @@ */ #include "general.h" #include "cl_utils.h" -#include static void LIBUSB_CALL on_trans_done(struct libusb_transfer *trans) { From ab7991c3a6917f8aa82d6832b28f440aec432f52 Mon Sep 17 00:00:00 2001 From: Uwe Bonnes Date: Sun, 19 Apr 2020 18:22:06 +0200 Subject: [PATCH 12/13] hosted: Add bmp_remote, remove old pc-hosted platform. --- src/platforms/hosted/Makefile.inc | 5 + src/platforms/hosted/bmp_remote.c | 147 ++++++++++++++++++++ src/platforms/hosted/bmp_remote.h | 39 ++++++ src/platforms/hosted/platform.c | 34 ++++- src/platforms/hosted/platform.h | 2 + src/platforms/hosted/remote_jtagtap.c | 165 ++++++++++++++++++++++ src/platforms/hosted/remote_swdptap.c | 128 ++++++++++++++++++ src/platforms/pc-hosted/Makefile.inc | 16 --- src/platforms/pc-hosted/README.md | 40 ------ src/platforms/pc-hosted/jtagtap.c | 161 ---------------------- src/platforms/pc-hosted/platform.c | 188 -------------------------- src/platforms/pc-hosted/platform.h | 54 -------- src/platforms/pc-hosted/swdptap.c | 133 ------------------ 13 files changed, 516 insertions(+), 596 deletions(-) create mode 100644 src/platforms/hosted/bmp_remote.c create mode 100644 src/platforms/hosted/bmp_remote.h create mode 100644 src/platforms/hosted/remote_jtagtap.c create mode 100644 src/platforms/hosted/remote_swdptap.c delete mode 100644 src/platforms/pc-hosted/Makefile.inc delete mode 100644 src/platforms/pc-hosted/README.md delete mode 100644 src/platforms/pc-hosted/jtagtap.c delete mode 100644 src/platforms/pc-hosted/platform.c delete mode 100644 src/platforms/pc-hosted/platform.h delete mode 100644 src/platforms/pc-hosted/swdptap.c diff --git a/src/platforms/hosted/Makefile.inc b/src/platforms/hosted/Makefile.inc index 94ed44bf..7fb94dc3 100644 --- a/src/platforms/hosted/Makefile.inc +++ b/src/platforms/hosted/Makefile.inc @@ -3,11 +3,16 @@ CFLAGS += -DENABLE_DEBUG -DPLATFORM_HAS_DEBUG CFLAGS +=-I ./target -I./platforms/pc LDFLAGS += -lusb-1.0 ifneq (, $(findstring mingw, $(SYS))) +SRC += serial_win.c LDFLAGS += -lws2_32 else ifneq (, $(findstring cygwin, $(SYS))) +SRC += serial_win.c LDFLAGS += -lws2_32 +else +SRC += serial_unix.c endif VPATH += platforms/pc SRC += timing.c cl_utils.c utils.c libusb_utils.c SRC += stlinkv2.c +SRC += bmp_remote.c remote_swdptap.c remote_jtagtap.c PC_HOSTED = 1 diff --git a/src/platforms/hosted/bmp_remote.c b/src/platforms/hosted/bmp_remote.c new file mode 100644 index 00000000..06e828a3 --- /dev/null +++ b/src/platforms/hosted/bmp_remote.c @@ -0,0 +1,147 @@ +/* + * This file is part of the Black Magic Debug project. + * + * Copyright (C) 2011 Black Sphere Technologies Ltd. + * Written by Gareth McMullin + * Additions by Dave Marples + * Additions by Uwe Bonnes (bon@elektron.ikp.physik.tu-darmstadt.de) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include "general.h" +#include "gdb_if.h" +#include "version.h" +#include "platform.h" +#include "remote.h" +#include "target.h" +#include "bmp_remote.h" + +#include +#include +#include +#include +#include + +#include "adiv5.h" + +int remote_init(void) +{ + char construct[REMOTE_MAX_MSG_SIZE]; + int c = snprintf(construct, REMOTE_MAX_MSG_SIZE, "%s", REMOTE_START_STR); + platform_buffer_write((uint8_t *)construct, c); + c = platform_buffer_read((uint8_t *)construct, REMOTE_MAX_MSG_SIZE); + + if ((!c) || (construct[0] == REMOTE_RESP_ERR)) { + fprintf(stderr,"Remote Start failed, error %s\n", + c ? (char *)&(construct[1]) : "unknown"); + return -1; + } + + printf("Remote is %s\n", &construct[1]); + return 0; +} + +bool remote_target_get_power(void) +{ + uint8_t construct[REMOTE_MAX_MSG_SIZE]; + int s; + + s=snprintf((char *)construct, REMOTE_MAX_MSG_SIZE, "%s", + REMOTE_PWR_GET_STR); + platform_buffer_write(construct, s); + + s = platform_buffer_read(construct, REMOTE_MAX_MSG_SIZE); + + if ((!s) || (construct[0] == REMOTE_RESP_ERR)) { + fprintf(stderr," platform_target_get_power failed, error %s\n", + s ? (char *)&(construct[1]) : "unknown"); + exit (-1); + } + + return (construct[1] == '1'); +} + +void remote_target_set_power(bool power) +{ + uint8_t construct[REMOTE_MAX_MSG_SIZE]; + int s; + + s = snprintf((char *)construct, REMOTE_MAX_MSG_SIZE,REMOTE_PWR_SET_STR, + power ? '1' : '0'); + platform_buffer_write(construct, s); + + s = platform_buffer_read(construct, REMOTE_MAX_MSG_SIZE); + + if ((!s) || (construct[0] == REMOTE_RESP_ERR)) { + fprintf(stderr, "platform_target_set_power failed, error %s\n", + s ? (char *)&(construct[1]) : "unknown"); + exit(-1); + } +} + +void remote_srst_set_val(bool assert) +{ + uint8_t construct[REMOTE_MAX_MSG_SIZE]; + int s; + + s = snprintf((char *)construct, REMOTE_MAX_MSG_SIZE, REMOTE_SRST_SET_STR, + assert ? '1' : '0'); + platform_buffer_write(construct, s); + + s = platform_buffer_read(construct, REMOTE_MAX_MSG_SIZE); + + if ((!s) || (construct[0] == REMOTE_RESP_ERR)) { + fprintf(stderr, "platform_srst_set_val failed, error %s\n", + s ? (char *)&(construct[1]) : "unknown"); + exit(-1); + } +} + +bool remote_srst_get_val(void) +{ + uint8_t construct[REMOTE_MAX_MSG_SIZE]; + int s; + + s = snprintf((char *)construct, REMOTE_MAX_MSG_SIZE,"%s", + REMOTE_SRST_GET_STR); + platform_buffer_write(construct, s); + + s = platform_buffer_read(construct, REMOTE_MAX_MSG_SIZE); + + if ((!s) || (construct[0] == REMOTE_RESP_ERR)) { + fprintf(stderr, "platform_srst_set_val failed, error %s\n", + s ? (char *)&(construct[1]) : "unknown"); + exit(-1); + } + return (construct[1] == '1'); +} + +const char *remote_target_voltage(void) +{ + static uint8_t construct[REMOTE_MAX_MSG_SIZE]; + int s; + + s = snprintf((char *)construct, REMOTE_MAX_MSG_SIZE," %s", + REMOTE_VOLTAGE_STR); + platform_buffer_write(construct, s); + + s = platform_buffer_read(construct, REMOTE_MAX_MSG_SIZE); + + if ((!s) || (construct[0] == REMOTE_RESP_ERR)) { + fprintf(stderr, "platform_target_voltage failed, error %s\n", + s ? (char *)&(construct[1]) : "unknown"); + exit(- 1); + } + return (char *)&construct[1]; +} diff --git a/src/platforms/hosted/bmp_remote.h b/src/platforms/hosted/bmp_remote.h new file mode 100644 index 00000000..1b9ac412 --- /dev/null +++ b/src/platforms/hosted/bmp_remote.h @@ -0,0 +1,39 @@ +/* + * This file is part of the Black Magic Debug project. + * + * Copyright (C) 2020 Uwe Bonnes + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#if !defined(__BMP_REMOTE_H_) +#define __BMP_REMOTE_H_ +#include "swdptap.h" +#include "jtagtap.h" + +#define REMOTE_MAX_MSG_SIZE (256) + +int platform_buffer_write(const uint8_t *data, int size); +int platform_buffer_read(uint8_t *data, int size); + +int remote_init(void); +int remote_swdptap_init(swd_proc_t *swd_proc); +int remote_jtagtap_init(jtag_proc_t *jtag_proc); +bool remote_target_get_power(void); +const char *remote_target_voltage(void); +void remote_target_set_power(bool power); +void remote_srst_set_val(bool assert); +bool remote_srst_get_val(void); +const char *platform_target_voltage(void); +#define __BMP_REMOTE_H_ +#endif diff --git a/src/platforms/hosted/platform.c b/src/platforms/hosted/platform.c index 69f340b3..55f8a52d 100644 --- a/src/platforms/hosted/platform.c +++ b/src/platforms/hosted/platform.c @@ -31,6 +31,8 @@ #include "cl_utils.h" #include "gdb_if.h" #include + +#include "bmp_remote.h" #include "stlinkv2.h" #define VENDOR_ID_BMP 0x1d50 @@ -220,6 +222,11 @@ void platform_init(int argc, char **argv) info.manufacturer, info.product); switch (info.bmp_type) { + case BMP_TYPE_BMP: + if (serial_open(&cl_opts, info.serial)) + exit(-1); + remote_init(); + break; case BMP_TYPE_STLINKV2: if (stlink_init( &info)) exit(-1); @@ -240,6 +247,7 @@ void platform_init(int argc, char **argv) int platform_adiv5_swdp_scan(void) { switch (info.bmp_type) { + case BMP_TYPE_BMP: case BMP_TYPE_STLINKV2: { target_list_free(); @@ -261,6 +269,8 @@ int platform_adiv5_swdp_scan(void) int platform_swdptap_init(void) { switch (info.bmp_type) { + case BMP_TYPE_BMP: + return remote_swdptap_init(&swd_proc); case BMP_TYPE_STLINKV2: return 0; break; @@ -273,6 +283,7 @@ int platform_swdptap_init(void) int platform_jtag_scan(const uint8_t *lrlens) { switch (info.bmp_type) { + case BMP_TYPE_BMP: case BMP_TYPE_STLINKV2: return jtag_scan_stlinkv2(&info, lrlens); default: @@ -284,6 +295,8 @@ int platform_jtag_scan(const uint8_t *lrlens) int platform_jtagtap_init(void) { switch (info.bmp_type) { + case BMP_TYPE_BMP: + return remote_jtagtap_init(&jtag_proc); case BMP_TYPE_STLINKV2: return 0; default: @@ -305,10 +318,11 @@ void platform_adiv5_dp_defaults(ADIv5_DP_t *dp) int platform_jtag_dp_init(ADIv5_DP_t *dp) { switch (info.bmp_type) { + case BMP_TYPE_BMP: case BMP_TYPE_STLINKV2: return stlink_jtag_dp_init(dp); default: - return -1; + return 0; } return 0; } @@ -322,7 +336,7 @@ char *platform_ident(void) return "BMP"; case BMP_TYPE_STLINKV2: return "STLINKV2"; - case BMP_TYPE_LIBFTDI: + case BMP_TYPE_LIBFTDI: return "LIBFTDI"; case BMP_TYPE_CMSIS_DAP: return "CMSIS_DAP"; @@ -335,10 +349,12 @@ char *platform_ident(void) const char *platform_target_voltage(void) { switch (info.bmp_type) { + case BMP_TYPE_BMP: + return remote_target_voltage(); case BMP_TYPE_STLINKV2: return stlink_target_voltage(&info); default: - break;; + break; } return NULL; } @@ -348,6 +364,8 @@ void platform_srst_set_val(bool assert) switch (info.bmp_type) { case BMP_TYPE_STLINKV2: return stlink_srst_set_val(&info, assert); + case BMP_TYPE_BMP: + return remote_srst_set_val(assert); default: break; } @@ -356,6 +374,8 @@ void platform_srst_set_val(bool assert) bool platform_srst_get_val(void) { switch (info.bmp_type) { + case BMP_TYPE_BMP: + return remote_srst_get_val(); case BMP_TYPE_STLINKV2: return stlink_srst_get_val(); default: @@ -364,4 +384,10 @@ bool platform_srst_get_val(void) return false; } -void platform_buffer_flush(void) {} +void platform_buffer_flush(void) +{ + switch (info.bmp_type) { + default: + break; + } +} diff --git a/src/platforms/hosted/platform.h b/src/platforms/hosted/platform.h index 5a9cea27..b0e50432 100644 --- a/src/platforms/hosted/platform.h +++ b/src/platforms/hosted/platform.h @@ -1,7 +1,9 @@ #ifndef __PLATFORM_H #define __PLATFORM_H + #include #include "libusb_utils.h" +#include #include "timing.h" diff --git a/src/platforms/hosted/remote_jtagtap.c b/src/platforms/hosted/remote_jtagtap.c new file mode 100644 index 00000000..7f64eee6 --- /dev/null +++ b/src/platforms/hosted/remote_jtagtap.c @@ -0,0 +1,165 @@ +/* + * This file is part of the Black Magic Debug project. + * + * Copyright (C) 2008 Black Sphere Technologies Ltd. + * Written by Gareth McMullin + * Modified by Dave Marples + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* Low level JTAG implementation using FT2232 with libftdi. + * + * Issues: + * Should share interface with swdptap.c or at least clean up... + */ + +#include +#include +#include + +#include + +#include "general.h" +#include "remote.h" +#include "jtagtap.h" +#include "bmp_remote.h" + +static void jtagtap_reset(void); +static void jtagtap_tms_seq(uint32_t MS, int ticks); +static void jtagtap_tdi_tdo_seq( + uint8_t *DO, const uint8_t final_tms, const uint8_t *DI, int ticks); +static void jtagtap_tdi_seq( + const uint8_t final_tms, const uint8_t *DI, int ticks); +static uint8_t jtagtap_next(uint8_t dTMS, uint8_t dTDI); + +int remote_jtagtap_init(jtag_proc_t *jtag_proc) +{ + uint8_t construct[REMOTE_MAX_MSG_SIZE]; + int s; + + s = snprintf((char *)construct, REMOTE_MAX_MSG_SIZE, "%s", + REMOTE_JTAG_INIT_STR); + platform_buffer_write(construct, s); + + s = platform_buffer_read(construct, REMOTE_MAX_MSG_SIZE); + if ((!s) || (construct[0] == REMOTE_RESP_ERR)) { + fprintf(stderr, "jtagtap_init failed, error %s\n", + s ? (char *)&(construct[1]) : "unknown"); + exit(-1); + } + + jtag_proc->jtagtap_reset = jtagtap_reset; + jtag_proc->jtagtap_next =jtagtap_next; + jtag_proc->jtagtap_tms_seq = jtagtap_tms_seq; + jtag_proc->jtagtap_tdi_tdo_seq = jtagtap_tdi_tdo_seq; + jtag_proc->jtagtap_tdi_seq = jtagtap_tdi_seq; + + return 0; +} + +/* See remote.c/.h for protocol information */ + +static void jtagtap_reset(void) +{ + uint8_t construct[REMOTE_MAX_MSG_SIZE]; + int s; + + s = snprintf((char *)construct, REMOTE_MAX_MSG_SIZE, "%s", + REMOTE_JTAG_RESET_STR); + platform_buffer_write(construct, s); + + s = platform_buffer_read(construct, REMOTE_MAX_MSG_SIZE); + if ((!s) || (construct[0] == REMOTE_RESP_ERR)) { + fprintf(stderr, "jtagtap_reset failed, error %s\n", + s ? (char *)&(construct[1]) : "unknown"); + exit(-1); + } +} + +static void jtagtap_tms_seq(uint32_t MS, int ticks) +{ + uint8_t construct[REMOTE_MAX_MSG_SIZE]; + int s; + + s = snprintf((char *)construct, REMOTE_MAX_MSG_SIZE, + REMOTE_JTAG_TMS_STR, ticks, MS); + platform_buffer_write(construct, s); + + s = platform_buffer_read(construct, REMOTE_MAX_MSG_SIZE); + if ((!s) || (construct[0] == REMOTE_RESP_ERR)) { + fprintf(stderr, "jtagtap_tms_seq failed, error %s\n", + s ? (char *)&(construct[1]) : "unknown"); + exit(-1); + } +} + +static void jtagtap_tdi_tdo_seq( + uint8_t *DO, const uint8_t final_tms, const uint8_t *DI, int ticks) +{ + uint8_t construct[REMOTE_MAX_MSG_SIZE]; + int s; + + uint64_t DIl=*(uint64_t *)DI; + + if(!ticks || !DI) return; + + /* Reduce the length of DI according to the bits we're transmitting */ + DIl &= (1LL << (ticks + 1))-1; + + s = snprintf((char *)construct, REMOTE_MAX_MSG_SIZE, + REMOTE_JTAG_TDIDO_STR, + final_tms ? REMOTE_TDITDO_TMS : REMOTE_TDITDO_NOTMS, + ticks, DIl); + platform_buffer_write(construct,s); + + s = platform_buffer_read(construct, REMOTE_MAX_MSG_SIZE); + if ((!s) || (construct[0] == REMOTE_RESP_ERR)) { + fprintf(stderr, "jtagtap_tms_seq failed, error %s\n", + s ? (char *)&(construct[1]) : "unknown"); + exit(-1); + } + + if (DO) { + uint64_t DOl = remotehston(-1, (char *)&construct[1]); + *(uint64_t *)DO = DOl; + } +} + +static void jtagtap_tdi_seq( + const uint8_t final_tms, const uint8_t *DI, int ticks) +{ + return jtagtap_tdi_tdo_seq(NULL, final_tms, DI, ticks); +} + + +static uint8_t jtagtap_next(uint8_t dTMS, uint8_t dTDI) +{ + uint8_t construct[REMOTE_MAX_MSG_SIZE]; + int s; + + s = snprintf((char *)construct, REMOTE_MAX_MSG_SIZE, REMOTE_JTAG_NEXT, + dTMS ? '1' : '0', dTDI ? '1' : '0'); + + platform_buffer_write(construct, s); + + s = platform_buffer_read(construct, REMOTE_MAX_MSG_SIZE); + if ((!s) || (construct[0] == REMOTE_RESP_ERR)) { + fprintf(stderr, "jtagtap_next failed, error %s\n", + s ? (char *)&(construct[1]) : "unknown"); + exit(-1); + } + + return remotehston(-1, (char *)&construct[1]); +} diff --git a/src/platforms/hosted/remote_swdptap.c b/src/platforms/hosted/remote_swdptap.c new file mode 100644 index 00000000..5b2af4d4 --- /dev/null +++ b/src/platforms/hosted/remote_swdptap.c @@ -0,0 +1,128 @@ +/* + * This file is part of the Black Magic Debug project. + * + * Copyright (C) 2018 Uwe Bonnes (bon@elektron.ikp.physik.tu-darmstadt.de) + * Written by Gareth McMullin + * Modified by Dave Marples + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* MPSSE bit-banging SW-DP interface over FTDI with loop unrolled. + * Speed is sensible. + */ + +#include +#include + +#include "general.h" +#include "remote.h" +#include "bmp_remote.h" + +static bool swdptap_seq_in_parity(uint32_t *res, int ticks); +static uint32_t swdptap_seq_in(int ticks); +static void swdptap_seq_out(uint32_t MS, int ticks); +static void swdptap_seq_out_parity(uint32_t MS, int ticks); + +int remote_swdptap_init(swd_proc_t *swd_proc) +{ + uint8_t construct[REMOTE_MAX_MSG_SIZE]; + int s; + + s = sprintf((char *)construct,"%s", REMOTE_SWDP_INIT_STR); + platform_buffer_write(construct, s); + + s = platform_buffer_read(construct, REMOTE_MAX_MSG_SIZE); + if ((!s) || (construct[0] == REMOTE_RESP_ERR)) { + fprintf(stderr, "swdptap_init failed, error %s\n", + s ? (char *)&(construct[1]) : "unknown"); + exit(-1); + } + + swd_proc->swdptap_seq_in = swdptap_seq_in; + swd_proc->swdptap_seq_in_parity = swdptap_seq_in_parity; + swd_proc->swdptap_seq_out = swdptap_seq_out; + swd_proc->swdptap_seq_out_parity = swdptap_seq_out_parity; + + return 0; +} + +static bool swdptap_seq_in_parity(uint32_t *res, int ticks) +{ + uint8_t construct[REMOTE_MAX_MSG_SIZE]; + int s; + + s = sprintf((char *)construct, REMOTE_SWDP_IN_PAR_STR, ticks); + platform_buffer_write(construct, s); + + s = platform_buffer_read(construct, REMOTE_MAX_MSG_SIZE); + if ((s<2) || (construct[0] == REMOTE_RESP_ERR)) { + fprintf(stderr, "swdptap_seq_in_parity failed, error %s\n", + s ? (char *)&(construct[1]) : "short response"); + exit(-1); + } + + *res=remotehston(-1, (char *)&construct[1]); + return (construct[0] != REMOTE_RESP_OK); +} + +static uint32_t swdptap_seq_in(int ticks) +{ + uint8_t construct[REMOTE_MAX_MSG_SIZE]; + int s; + + s = sprintf((char *)construct, REMOTE_SWDP_IN_STR, ticks); + platform_buffer_write(construct,s); + + s = platform_buffer_read(construct, REMOTE_MAX_MSG_SIZE); + if ((s<2) || (construct[0] == REMOTE_RESP_ERR)) { + fprintf(stderr, "swdptap_seq_in failed, error %s\n", + s ? (char *)&(construct[1]) : "short response"); + exit(-1); + } + + return remotehston(-1,(char *)&construct[1]); +} + +static void swdptap_seq_out(uint32_t MS, int ticks) +{ + uint8_t construct[REMOTE_MAX_MSG_SIZE]; + int s; + + s = sprintf((char *)construct,REMOTE_SWDP_OUT_STR, ticks, MS); + platform_buffer_write(construct, s); + + s=platform_buffer_read(construct, REMOTE_MAX_MSG_SIZE); + if ((s < 1) || (construct[0] == REMOTE_RESP_ERR)) { + fprintf(stderr, "swdptap_seq_out failed, error %s\n", + s ? (char *)&(construct[1]) : "short response"); + exit(-1); + } +} + +static void swdptap_seq_out_parity(uint32_t MS, int ticks) +{ + uint8_t construct[REMOTE_MAX_MSG_SIZE]; + int s; + + s = sprintf((char *)construct, REMOTE_SWDP_OUT_PAR_STR, ticks, MS); + platform_buffer_write(construct, s); + + s = platform_buffer_read(construct, REMOTE_MAX_MSG_SIZE); + if ((s < 1) || (construct[1] == REMOTE_RESP_ERR)){ + fprintf(stderr, "swdptap_seq_out_parity failed, error %s\n", + s ? (char *)&(construct[2]) : "short response"); + exit(-1); + } +} diff --git a/src/platforms/pc-hosted/Makefile.inc b/src/platforms/pc-hosted/Makefile.inc deleted file mode 100644 index 3d10dc19..00000000 --- a/src/platforms/pc-hosted/Makefile.inc +++ /dev/null @@ -1,16 +0,0 @@ -TARGET=blackmagic_hosted -SYS = $(shell $(CC) -dumpmachine) -CFLAGS += -DENABLE_DEBUG -CFLAGS +=-I ./target -I./platforms/pc -ifneq (, $(findstring mingw, $(SYS))) -SRC += serial_win.c -LDFLAGS += -lws2_32 -else ifneq (, $(findstring cygwin, $(SYS))) -SRC += serial_win.c -LDFLAGS += -lws2_32 -else -SRC += serial_unix.c -endif -VPATH += platforms/pc -SRC += cl_utils.c timing.c utils.c -PC_HOSTED = 1 diff --git a/src/platforms/pc-hosted/README.md b/src/platforms/pc-hosted/README.md deleted file mode 100644 index cca59d11..00000000 --- a/src/platforms/pc-hosted/README.md +++ /dev/null @@ -1,40 +0,0 @@ -PC Hosted variant - -THIS IS INCOMPLETE - ONLY SUPPORTS SWD AT THE MOMENT - -This variant will use any BMP probe with recent firmware as a remote -actuator, with the actual probe code running on the PC. The BMP itself -is 'dumb' and doesn't do anything (although any secondary serial port -remains available). - -To use it, compile for the pc-hosted target and then connect to your normal -BMP GDB port; - -src/blackmagic -s /dev/ttyACM0 - -...you can then connect your gdb session to localhost:2000 for all your -debugging goodness; - -$arm-eabi-none-gdb -(gdb) monitor swdp_scan -Target voltage: not supported -Available Targets: -No. Att Driver - 1 STM32F1 medium density M3/M4 -(gdb) attach 1 -Attaching to program: Builds/blackmagic/src/blackmagic, Remote target -0x08001978 in ?? () -(gdb) file src/blackmagic -A program is being debugged already. -Are you sure you want to change the file? (y or n) y -Load new symbol table from "src/blackmagic"? (y or n) y -Reading symbols from src/blackmagic... -(gdb) load -Loading section .text, size 0x1201c lma 0x8002000 -Loading section .data, size 0xd8 lma 0x801401c -Start address 0x800d9fc, load size 73972 -Transfer rate: 2 KB/sec, 960 bytes/write. -(gdb) - -...note that the speed of the probe in this way is about 10 times less than -running native. This build is intended for debug and development only. \ No newline at end of file diff --git a/src/platforms/pc-hosted/jtagtap.c b/src/platforms/pc-hosted/jtagtap.c deleted file mode 100644 index bc5a8160..00000000 --- a/src/platforms/pc-hosted/jtagtap.c +++ /dev/null @@ -1,161 +0,0 @@ -/* - * This file is part of the Black Magic Debug project. - * - * Copyright (C) 2008 Black Sphere Technologies Ltd. - * Written by Gareth McMullin - * Modified by Dave Marples - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -/* Low level JTAG implementation using FT2232 with libftdi. - * - * Issues: - * Should share interface with swdptap.c or at least clean up... - */ - -#include -#include -#include - -#include - -#include "general.h" -#include "remote.h" -#include "jtagtap.h" - -jtag_proc_t jtag_proc; - -static void jtagtap_reset(void); -static void jtagtap_tms_seq(uint32_t MS, int ticks); -static void jtagtap_tdi_tdo_seq( - uint8_t *DO, const uint8_t final_tms, const uint8_t *DI, int ticks); -static void jtagtap_tdi_seq( - const uint8_t final_tms, const uint8_t *DI, int ticks); -static uint8_t jtagtap_next(uint8_t dTMS, uint8_t dTDI); - -int platform_jtagtap_init(void) -{ - uint8_t construct[PLATFORM_MAX_MSG_SIZE]; - int s; - - s=snprintf((char *)construct,PLATFORM_MAX_MSG_SIZE,"%s",REMOTE_JTAG_INIT_STR); - platform_buffer_write(construct,s); - - s=platform_buffer_read(construct, PLATFORM_MAX_MSG_SIZE); - if ((!s) || (construct[0]==REMOTE_RESP_ERR)) - { - fprintf(stderr,"jtagtap_init failed, error %s\n",s?(char *)&(construct[1]):"unknown"); - exit(-1); - } - - jtag_proc.jtagtap_reset = jtagtap_reset; - jtag_proc.jtagtap_next =jtagtap_next; - jtag_proc.jtagtap_tms_seq = jtagtap_tms_seq; - jtag_proc.jtagtap_tdi_tdo_seq = jtagtap_tdi_tdo_seq; - jtag_proc.jtagtap_tdi_seq = jtagtap_tdi_seq; - - return 0; -} - -/* See remote.c/.h for protocol information */ - -static void jtagtap_reset(void) -{ - uint8_t construct[PLATFORM_MAX_MSG_SIZE]; - int s; - - s=snprintf((char *)construct,PLATFORM_MAX_MSG_SIZE,"%s",REMOTE_JTAG_RESET_STR); - platform_buffer_write(construct,s); - - s=platform_buffer_read(construct, PLATFORM_MAX_MSG_SIZE); - if ((!s) || (construct[0]==REMOTE_RESP_ERR)) - { - fprintf(stderr,"jtagtap_reset failed, error %s\n",s?(char *)&(construct[1]):"unknown"); - exit(-1); - } -} - -static void jtagtap_tms_seq(uint32_t MS, int ticks) - -{ - uint8_t construct[PLATFORM_MAX_MSG_SIZE]; - int s; - - s=snprintf((char *)construct,PLATFORM_MAX_MSG_SIZE,REMOTE_JTAG_TMS_STR,ticks,MS); - platform_buffer_write(construct,s); - - s=platform_buffer_read(construct, PLATFORM_MAX_MSG_SIZE); - if ((!s) || (construct[0]==REMOTE_RESP_ERR)) - { - fprintf(stderr,"jtagtap_tms_seq failed, error %s\n",s?(char *)&(construct[1]):"unknown"); - exit(-1); - } -} - -static void jtagtap_tdi_tdo_seq( - uint8_t *DO, const uint8_t final_tms, const uint8_t *DI, int ticks) -{ - uint8_t construct[PLATFORM_MAX_MSG_SIZE]; - int s; - - uint64_t DIl=*(uint64_t *)DI; - - if(!ticks || !DI) return; - - /* Reduce the length of DI according to the bits we're transmitting */ - DIl &= (1LL << (ticks + 1)) - 1; - - s=snprintf((char *)construct,PLATFORM_MAX_MSG_SIZE,REMOTE_JTAG_TDIDO_STR,final_tms?REMOTE_TDITDO_TMS:REMOTE_TDITDO_NOTMS,ticks,DIl); - platform_buffer_write(construct,s); - - s=platform_buffer_read(construct, PLATFORM_MAX_MSG_SIZE); - if ((!s) || (construct[0]==REMOTE_RESP_ERR)) - { - fprintf(stderr,"jtagtap_tms_seq failed, error %s\n",s?(char *)&(construct[1]):"unknown"); - exit(-1); - } - - if (DO) { - uint64_t DOl = remotehston(-1, (char *)&construct[1]); - *(uint64_t *)DO = DOl; - } -} - -static void jtagtap_tdi_seq( - const uint8_t final_tms, const uint8_t *DI, int ticks) -{ - return jtagtap_tdi_tdo_seq(NULL, final_tms, DI, ticks); -} - - -static uint8_t jtagtap_next(uint8_t dTMS, uint8_t dTDI) - -{ - uint8_t construct[PLATFORM_MAX_MSG_SIZE]; - int s; - - s=snprintf((char *)construct,PLATFORM_MAX_MSG_SIZE,REMOTE_JTAG_NEXT,dTMS?'1':'0',dTDI?'1':'0'); - - platform_buffer_write(construct,s); - - s=platform_buffer_read(construct, PLATFORM_MAX_MSG_SIZE); - if ((!s) || (construct[0]==REMOTE_RESP_ERR)) - { - fprintf(stderr,"jtagtap_next failed, error %s\n",s?(char *)&(construct[1]):"unknown"); - exit(-1); - } - - return remotehston(-1,(char *)&construct[1]); -} diff --git a/src/platforms/pc-hosted/platform.c b/src/platforms/pc-hosted/platform.c deleted file mode 100644 index 849b926a..00000000 --- a/src/platforms/pc-hosted/platform.c +++ /dev/null @@ -1,188 +0,0 @@ -/* - * This file is part of the Black Magic Debug project. - * - * Copyright (C) 2011 Black Sphere Technologies Ltd. - * Written by Gareth McMullin - * Additions by Dave Marples - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -#include "general.h" -#include "gdb_if.h" -#include "version.h" -#include "platform.h" -#include "remote.h" -#include "target.h" - -#include -#include -#include -#include -#include - -#include "cl_utils.h" -static BMP_CL_OPTIONS_t cl_opts; /* Portable way to nullify the struct*/ - -int platform_adiv5_swdp_scan(void) -{ - return adiv5_swdp_scan(); -} - -int platform_jtag_scan(const uint8_t *lrlens) -{ - return jtag_scan(lrlens); -} - -int platform_jtag_dp_init() -{ - return 0; -} - -void platform_init(int argc, char **argv) -{ - cl_opts.opt_idstring = "Blackmagic Debug Probe Remote"; - cl_init(&cl_opts, argc, argv); - char construct[PLATFORM_MAX_MSG_SIZE]; - - printf("\nBlack Magic Probe (" FIRMWARE_VERSION ")\n"); - printf("Copyright (C) 2019 Black Sphere Technologies Ltd.\n"); - printf("License GPLv3+: GNU GPL version 3 or later " - "\n\n"); - - if (serial_open(cl_opts.opt_device, cl_opts.opt_serial)) - exit(-1); - int c=snprintf(construct,PLATFORM_MAX_MSG_SIZE,"%s",REMOTE_START_STR); - platform_buffer_write((uint8_t *)construct,c); - c=platform_buffer_read((uint8_t *)construct, PLATFORM_MAX_MSG_SIZE); - - if ((!c) || (construct[0]==REMOTE_RESP_ERR)) - { - fprintf(stderr,"Remote Start failed, error %s\n",c?(char *)&(construct[1]):"unknown"); - exit(-1); - } - - printf("Remote is %s\n",&construct[1]); - if (cl_opts.opt_mode != BMP_MODE_DEBUG) { - int ret = cl_execute(&cl_opts); - if (cl_opts.opt_tpwr) - platform_target_set_power(0); - serial_close(); - exit(ret); - } else { - assert(gdb_if_init() == 0); - } -} - -bool platform_target_get_power(void) -{ - uint8_t construct[PLATFORM_MAX_MSG_SIZE]; - int s; - - s=snprintf((char *)construct,PLATFORM_MAX_MSG_SIZE,"%s",REMOTE_PWR_GET_STR); - platform_buffer_write(construct,s); - - s=platform_buffer_read(construct, PLATFORM_MAX_MSG_SIZE); - - if ((!s) || (construct[0]==REMOTE_RESP_ERR)) - { - fprintf(stderr,"platform_target_get_power failed, error %s\n",s?(char *)&(construct[1]):"unknown"); - exit(-1); - } - - return (construct[1]=='1'); -} - -void platform_target_set_power(bool power) -{ - uint8_t construct[PLATFORM_MAX_MSG_SIZE]; - int s; - - s=snprintf((char *)construct,PLATFORM_MAX_MSG_SIZE,REMOTE_PWR_SET_STR,power?'1':'0'); - platform_buffer_write(construct,s); - - s=platform_buffer_read(construct, PLATFORM_MAX_MSG_SIZE); - - if ((!s) || (construct[0]==REMOTE_RESP_ERR)) - { - fprintf(stderr,"platform_target_set_power failed, error %s\n",s?(char *)&(construct[1]):"unknown"); - exit(-1); - } -} - -void platform_srst_set_val(bool assert) -{ - uint8_t construct[PLATFORM_MAX_MSG_SIZE]; - int s; - - s=snprintf((char *)construct,PLATFORM_MAX_MSG_SIZE,REMOTE_SRST_SET_STR,assert?'1':'0'); - platform_buffer_write(construct,s); - - s=platform_buffer_read(construct, PLATFORM_MAX_MSG_SIZE); - - if ((!s) || (construct[0]==REMOTE_RESP_ERR)) - { - fprintf(stderr,"platform_srst_set_val failed, error %s\n",s?(char *)&(construct[1]):"unknown"); - exit(-1); - } -} - -bool platform_srst_get_val(void) - -{ - uint8_t construct[PLATFORM_MAX_MSG_SIZE]; - int s; - - s=snprintf((char *)construct,PLATFORM_MAX_MSG_SIZE,"%s",REMOTE_SRST_GET_STR); - platform_buffer_write(construct,s); - - s=platform_buffer_read(construct, PLATFORM_MAX_MSG_SIZE); - - if ((!s) || (construct[0]==REMOTE_RESP_ERR)) - { - fprintf(stderr,"platform_srst_set_val failed, error %s\n",s?(char *)&(construct[1]):"unknown"); - exit(-1); - } - - return (construct[1]=='1'); -} - -void platform_buffer_flush(void) -{ - -} - -const char *platform_target_voltage(void) - -{ - static uint8_t construct[PLATFORM_MAX_MSG_SIZE]; - int s; - - s=snprintf((char *)construct,PLATFORM_MAX_MSG_SIZE,"%s",REMOTE_VOLTAGE_STR); - platform_buffer_write(construct,s); - - s=platform_buffer_read(construct, PLATFORM_MAX_MSG_SIZE); - - if ((!s) || (construct[0]==REMOTE_RESP_ERR)) - { - fprintf(stderr,"platform_target_voltage failed, error %s\n",s?(char *)&(construct[1]):"unknown"); - exit(-1); - } - - return (char *)&construct[1]; -} - -void platform_adiv5_dp_defaults(void *arg) -{ - (void) arg; -} diff --git a/src/platforms/pc-hosted/platform.h b/src/platforms/pc-hosted/platform.h deleted file mode 100644 index 696639bb..00000000 --- a/src/platforms/pc-hosted/platform.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * This file is part of the Black Magic Debug project. - * - * Copyright (C) 2011 Black Sphere Technologies Ltd. - * Written by Gareth McMullin - * Additions by Dave Marples - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef __PLATFORM_H -#define __PLATFORM_H - -#include "timing.h" - -#ifndef _WIN32 -# include -#else -# ifndef alloca -# define alloca __builtin_alloca -# endif -#endif - -#define PLATFORM_HAS_POWER_SWITCH -#define PLATFORM_MAX_MSG_SIZE (256) -#define PLATFORM_IDENT() "PC-HOSTED" -#define BOARD_IDENT PLATFORM_IDENT -#define SET_RUN_STATE(state) -#define SET_IDLE_STATE(state) -#define SET_ERROR_STATE(state) - -/* Allow 100mS for responses to reach us */ -#define RESP_TIMEOUT (100) - -void platform_buffer_flush(void); -int platform_buffer_write(const uint8_t *data, int size); -int platform_buffer_read(uint8_t *data, int size); -static inline int platform_hwversion(void) -{ - return 0; -} - -#endif diff --git a/src/platforms/pc-hosted/swdptap.c b/src/platforms/pc-hosted/swdptap.c deleted file mode 100644 index c62a1f99..00000000 --- a/src/platforms/pc-hosted/swdptap.c +++ /dev/null @@ -1,133 +0,0 @@ -/* - * This file is part of the Black Magic Debug project. - * - * Copyright (C) 2018 Uwe Bonnes (bon@elektron.ikp.physik.tu-darmstadt.de) - * Written by Gareth McMullin - * Modified by Dave Marples - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -/* MPSSE bit-banging SW-DP interface over FTDI with loop unrolled. - * Speed is sensible. - */ - -#include -#include - -#include "general.h" -#include "swdptap.h" -#include "remote.h" - -static bool swdptap_seq_in_parity(uint32_t *res, int ticks); -static uint32_t swdptap_seq_in(int ticks); -static void swdptap_seq_out(uint32_t MS, int ticks); -static void swdptap_seq_out_parity(uint32_t MS, int ticks); - -swd_proc_t swd_proc; - -int platform_swdptap_init(void) - -{ - uint8_t construct[PLATFORM_MAX_MSG_SIZE]; - int s; - - s=sprintf((char *)construct,"%s",REMOTE_SWDP_INIT_STR); - platform_buffer_write(construct,s); - - s=platform_buffer_read(construct, PLATFORM_MAX_MSG_SIZE); - if ((!s) || (construct[0]==REMOTE_RESP_ERR)) - { - fprintf(stderr,"swdptap_init failed, error %s\n",s?(char *)&(construct[1]):"unknown"); - exit(-1); - } - - swd_proc.swdptap_seq_in = swdptap_seq_in; - swd_proc.swdptap_seq_in_parity = swdptap_seq_in_parity; - swd_proc.swdptap_seq_out = swdptap_seq_out; - swd_proc.swdptap_seq_out_parity = swdptap_seq_out_parity; - - return 0; -} - -static bool swdptap_seq_in_parity(uint32_t *res, int ticks) - -{ - uint8_t construct[PLATFORM_MAX_MSG_SIZE]; - int s; - - s=sprintf((char *)construct,REMOTE_SWDP_IN_PAR_STR,ticks); - platform_buffer_write(construct,s); - - s=platform_buffer_read(construct, PLATFORM_MAX_MSG_SIZE); - if ((s<2) || (construct[0]==REMOTE_RESP_ERR)) - { - fprintf(stderr,"swdptap_seq_in_parity failed, error %s\n",s?(char *)&(construct[1]):"short response"); - exit(-1); - } - - *res=remotehston(-1,(char *)&construct[1]); - return (construct[0]!=REMOTE_RESP_OK); -} - -static uint32_t swdptap_seq_in(int ticks) -{ - uint8_t construct[PLATFORM_MAX_MSG_SIZE]; - int s; - - s=sprintf((char *)construct,REMOTE_SWDP_IN_STR,ticks); - platform_buffer_write(construct,s); - - s=platform_buffer_read(construct, PLATFORM_MAX_MSG_SIZE); - if ((s<2) || (construct[0]==REMOTE_RESP_ERR)) - { - fprintf(stderr,"swdptap_seq_in failed, error %s\n",s?(char *)&(construct[1]):"short response"); - exit(-1); - } - - return remotehston(-1,(char *)&construct[1]); -} - -static void swdptap_seq_out(uint32_t MS, int ticks) -{ - uint8_t construct[PLATFORM_MAX_MSG_SIZE]; - int s; - - s=sprintf((char *)construct,REMOTE_SWDP_OUT_STR,ticks,MS); - platform_buffer_write(construct,s); - - s=platform_buffer_read(construct, PLATFORM_MAX_MSG_SIZE); - if ((s<1) || (construct[0]==REMOTE_RESP_ERR)) - { - fprintf(stderr,"swdptap_seq_out failed, error %s\n",s?(char *)&(construct[1]):"short response"); - exit(-1); - } -} - - -static void swdptap_seq_out_parity(uint32_t MS, int ticks) -{ - uint8_t construct[PLATFORM_MAX_MSG_SIZE]; - int s; - - s=sprintf((char *)construct,REMOTE_SWDP_OUT_PAR_STR,ticks,MS); - platform_buffer_write(construct,s); - - s=platform_buffer_read(construct, PLATFORM_MAX_MSG_SIZE); - if ((s<1) || (construct[1]==REMOTE_RESP_ERR)) - { - fprintf(stderr,"swdptap_seq_out_parity failed, error %s\n",s?(char *)&(construct[2]):"short response"); - exit(-1); - } -} From ef816e318391c64014554140be65a5cafc6c8be2 Mon Sep 17 00:00:00 2001 From: Uwe Bonnes Date: Tue, 28 Apr 2020 16:54:56 +0200 Subject: [PATCH 13/13] hosted: add libftdi implementation, remove old implementation. --- src/platforms/hosted/Makefile.inc | 3 + .../{libftdi/platform.c => hosted/ftdi_bmp.c} | 70 ++++++------------- .../{libftdi/platform.h => hosted/ftdi_bmp.h} | 46 ++++-------- .../jtagtap.c => hosted/libftdi_jtagtap.c} | 62 ++++++++-------- .../swdptap.c => hosted/libftdi_swdptap.c} | 38 +++++----- src/platforms/hosted/platform.c | 27 ++++++- src/platforms/libftdi/Makefile.inc | 13 ---- src/platforms/libftdi/README.md | 14 ---- 8 files changed, 111 insertions(+), 162 deletions(-) rename src/platforms/{libftdi/platform.c => hosted/ftdi_bmp.c} (84%) rename src/platforms/{libftdi/platform.h => hosted/ftdi_bmp.h} (69%) rename src/platforms/{libftdi/jtagtap.c => hosted/libftdi_jtagtap.c} (76%) rename src/platforms/{libftdi/swdptap.c => hosted/libftdi_swdptap.c} (88%) delete mode 100644 src/platforms/libftdi/Makefile.inc delete mode 100644 src/platforms/libftdi/README.md diff --git a/src/platforms/hosted/Makefile.inc b/src/platforms/hosted/Makefile.inc index 7fb94dc3..139c9cf8 100644 --- a/src/platforms/hosted/Makefile.inc +++ b/src/platforms/hosted/Makefile.inc @@ -2,6 +2,8 @@ SYS = $(shell $(CC) -dumpmachine) CFLAGS += -DENABLE_DEBUG -DPLATFORM_HAS_DEBUG CFLAGS +=-I ./target -I./platforms/pc LDFLAGS += -lusb-1.0 +CFLAGS += $(shell pkg-config --cflags libftdi1) +LDFLAGS += $(shell pkg-config --libs libftdi1) ifneq (, $(findstring mingw, $(SYS))) SRC += serial_win.c LDFLAGS += -lws2_32 @@ -15,4 +17,5 @@ VPATH += platforms/pc SRC += timing.c cl_utils.c utils.c libusb_utils.c SRC += stlinkv2.c SRC += bmp_remote.c remote_swdptap.c remote_jtagtap.c +SRC += ftdi_bmp.c libftdi_swdptap.c libftdi_jtagtap.c PC_HOSTED = 1 diff --git a/src/platforms/libftdi/platform.c b/src/platforms/hosted/ftdi_bmp.c similarity index 84% rename from src/platforms/libftdi/platform.c rename to src/platforms/hosted/ftdi_bmp.c index e2ceb59a..1c65e238 100644 --- a/src/platforms/libftdi/platform.c +++ b/src/platforms/hosted/ftdi_bmp.c @@ -27,9 +27,9 @@ #include #include -struct ftdi_context *ftdic; +#include "ftdi_bmp.h" -#include "cl_utils.h" +struct ftdi_context *ftdic; #define BUF_SIZE 4096 static uint8_t outbuf[BUF_SIZE]; @@ -181,39 +181,18 @@ cable_desc_t cable_desc[] = { }, }; -int platform_adiv5_swdp_scan(void) +int ftdi_bmp_init(BMP_CL_OPTIONS_t *cl_opts, bmp_info_t *info) { - return adiv5_swdp_scan(); -} - -int platform_jtag_scan(const uint8_t *lrlens) -{ - return jtag_scan(lrlens); -} - -int platform_jtag_dp_init() -{ - return 0; -} - -void platform_init(int argc, char **argv) -{ - BMP_CL_OPTIONS_t cl_opts = {0}; - cl_opts.opt_idstring = "Blackmagic Debug Probe for FTDI/MPSSE"; - cl_opts.opt_cable = "ftdi"; - cl_init(&cl_opts, argc, argv); - int err; unsigned index = 0; - int ret = -1; for(index = 0; index < sizeof(cable_desc)/sizeof(cable_desc[0]); index++) - if (strcmp(cable_desc[index].name, cl_opts.opt_cable) == 0) + if (strcmp(cable_desc[index].name, cl_opts->opt_cable) == 0) break; if (index == sizeof(cable_desc)/sizeof(cable_desc[0])){ - fprintf(stderr, "No cable matching %s found\n", cl_opts.opt_cable); - exit(-1); + fprintf(stderr, "No cable matching %s found\n", cl_opts->opt_cable); + return -1; } active_cable = &cable_desc[index]; @@ -233,6 +212,7 @@ void platform_init(int argc, char **argv) ftdi_get_error_string(ftdic)); abort(); } + info->ftdic = ftdic; if((err = ftdi_set_interface(ftdic, active_cable->interface)) != 0) { fprintf(stderr, "ftdi_set_interface: %d: %s\n", err, ftdi_get_error_string(ftdic)); @@ -240,7 +220,7 @@ void platform_init(int argc, char **argv) } if((err = ftdi_usb_open_desc( ftdic, active_cable->vendor, active_cable->product, - active_cable->description, cl_opts.opt_serial)) != 0) { + active_cable->description, cl_opts->opt_serial)) != 0) { fprintf(stderr, "unable to open ftdi device: %d (%s)\n", err, ftdi_get_error_string(ftdic)); goto error_1; @@ -261,57 +241,47 @@ void platform_init(int argc, char **argv) err, ftdi_get_error_string(ftdic)); goto error_2; } - if (cl_opts.opt_mode != BMP_MODE_DEBUG) { - ret = cl_execute(&cl_opts); - } else { - assert(gdb_if_init() == 0); - return; - } + return 0; error_2: ftdi_usb_close(ftdic); error_1: ftdi_free(ftdic); - exit(ret); + return -1; } -void platform_srst_set_val(bool assert) +void libftdi_srst_set_val(bool assert) { (void)assert; - platform_buffer_flush(); + libftdi_buffer_flush(); } -bool platform_srst_get_val(void) { return false; } +bool libftdi_srst_get_val(void) { return false; } -void platform_buffer_flush(void) +void libftdi_buffer_flush(void) { assert(ftdi_write_data(ftdic, outbuf, bufptr) == bufptr); -// printf("FT2232 platform_buffer flush: %d bytes\n", bufptr); +// printf("FT2232 libftdi_buffer flush: %d bytes\n", bufptr); bufptr = 0; } -int platform_buffer_write(const uint8_t *data, int size) +int libftdi_buffer_write(const uint8_t *data, int size) { - if((bufptr + size) / BUF_SIZE > 0) platform_buffer_flush(); + if((bufptr + size) / BUF_SIZE > 0) libftdi_buffer_flush(); memcpy(outbuf + bufptr, data, size); bufptr += size; return size; } -int platform_buffer_read(uint8_t *data, int size) +int libftdi_buffer_read(uint8_t *data, int size) { int index = 0; outbuf[bufptr++] = SEND_IMMEDIATE; - platform_buffer_flush(); + libftdi_buffer_flush(); while((index += ftdi_read_data(ftdic, data + index, size-index)) != size); return size; } -const char *platform_target_voltage(void) +const char *libftdi_target_voltage(void) { return "not supported"; } - -void platform_adiv5_dp_defaults(void *arg) -{ - (void) arg; -} diff --git a/src/platforms/libftdi/platform.h b/src/platforms/hosted/ftdi_bmp.h similarity index 69% rename from src/platforms/libftdi/platform.h rename to src/platforms/hosted/ftdi_bmp.h index d4368baf..c44607b4 100644 --- a/src/platforms/libftdi/platform.h +++ b/src/platforms/hosted/ftdi_bmp.h @@ -18,34 +18,12 @@ * along with this program. If not, see . */ -#ifndef __PLATFORM_H -#define __PLATFORM_H +#ifndef __FTDI_BMP_H +#define __FTDI_BMP_H -#include - -#include "timing.h" - -#ifndef _WIN32 -# include -#else -# ifndef alloca -# define alloca __builtin_alloca -# endif -#endif - -#define FT2232_VID 0x0403 -#define FT2232_PID 0x6010 - -#define PLATFORM_IDENT() "FTDI/MPSSE" -#define SET_RUN_STATE(state) -#define SET_IDLE_STATE(state) -#define SET_ERROR_STATE(state) - -extern struct ftdi_context *ftdic; - -void platform_buffer_flush(void); -int platform_buffer_write(const uint8_t *data, int size); -int platform_buffer_read(uint8_t *data, int size); +#include "cl_utils.h" +#include "swdptap.h" +#include "jtagtap.h" typedef struct cable_desc_s { int vendor; @@ -65,15 +43,19 @@ typedef struct cable_desc_s { }cable_desc_t; extern cable_desc_t *active_cable; +extern struct ftdi_context *ftdic; -static inline int platform_hwversion(void) -{ - return 0; -} +int ftdi_bmp_init(BMP_CL_OPTIONS_t *cl_opts, bmp_info_t *info); + +int libftdi_swdptap_init(swd_proc_t *swd_proc); +int libftdi_jtagtap_init(jtag_proc_t *jtag_proc); +void libftdi_buffer_flush(void); +int libftdi_buffer_write(const uint8_t *data, int size); +int libftdi_buffer_read(uint8_t *data, int size); +const char *libftdi_target_voltage(void); #define MPSSE_TDI 2 #define MPSSE_TDO 4 #define MPSSE_TMS 8 #endif - diff --git a/src/platforms/libftdi/jtagtap.c b/src/platforms/hosted/libftdi_jtagtap.c similarity index 76% rename from src/platforms/libftdi/jtagtap.c rename to src/platforms/hosted/libftdi_jtagtap.c index a928d190..1724d3f9 100644 --- a/src/platforms/libftdi/jtagtap.c +++ b/src/platforms/hosted/libftdi_jtagtap.c @@ -31,9 +31,10 @@ #include #include "general.h" -#include "jtagtap.h" +#include "ftdi_bmp.h" -jtag_proc_t jtag_proc; +extern cable_desc_t *active_cable; +extern struct ftdi_context *ftdic; static void jtagtap_reset(void); static void jtagtap_tms_seq(uint32_t MS, int ticks); @@ -43,7 +44,7 @@ static void jtagtap_tdi_seq( const uint8_t final_tms, const uint8_t *DI, int ticks); static uint8_t jtagtap_next(uint8_t dTMS, uint8_t dTDI); -int platform_jtagtap_init(void) +int libftdi_jtagtap_init(jtag_proc_t *jtag_proc) { assert(ftdic != NULL); int err = ftdi_usb_purge_buffers(ftdic); @@ -57,14 +58,14 @@ int platform_jtagtap_init(void) if (err != 0) { fprintf(stderr, "ftdi_set_bitmode: %d: %s\n", err, ftdi_get_error_string(ftdic)); - return -1;; + return -1; } /* Enable MPSSE controller. Pin directions are set later.*/ err = ftdi_set_bitmode(ftdic, 0, BITMODE_MPSSE); if (err != 0) { fprintf(stderr, "ftdi_set_bitmode: %d: %s\n", err, ftdi_get_error_string(ftdic)); - return -1;; + return -1; } uint8_t ftdi_init[9] = {TCK_DIVISOR, 0x00, 0x00, SET_BITS_LOW, 0,0, SET_BITS_HIGH, 0,0}; @@ -72,37 +73,32 @@ int platform_jtagtap_init(void) ftdi_init[5]= active_cable->dbus_ddr; ftdi_init[7]= active_cable->cbus_data; ftdi_init[8]= active_cable->cbus_ddr; - platform_buffer_write(ftdi_init, 9); - platform_buffer_flush(); + libftdi_buffer_write(ftdi_init, 9); + libftdi_buffer_flush(); - jtag_proc.jtagtap_reset = jtagtap_reset; - jtag_proc.jtagtap_next =jtagtap_next; - jtag_proc.jtagtap_tms_seq = jtagtap_tms_seq; - jtag_proc.jtagtap_tdi_tdo_seq = jtagtap_tdi_tdo_seq; - jtag_proc.jtagtap_tdi_seq = jtagtap_tdi_seq; - - /* Go to JTAG mode for SWJ-DP */ - for (int i = 0; i <= 50; i++) - jtagtap_next(1, 0); /* Reset SW-DP */ - jtagtap_tms_seq(0xE73C, 16); /* SWD to JTAG sequence */ - jtagtap_soft_reset(); + jtag_proc->jtagtap_reset = jtagtap_reset; + jtag_proc->jtagtap_next =jtagtap_next; + jtag_proc->jtagtap_tms_seq = jtagtap_tms_seq; + jtag_proc->jtagtap_tdi_tdo_seq = jtagtap_tdi_tdo_seq; + jtag_proc->jtagtap_tdi_seq = jtagtap_tdi_seq; return 0; } -void jtagtap_reset(void) +static void jtagtap_reset(void) { jtagtap_soft_reset(); } static void jtagtap_tms_seq(uint32_t MS, int ticks) { - uint8_t tmp[3] = {MPSSE_WRITE_TMS | MPSSE_LSB | MPSSE_BITMODE| MPSSE_READ_NEG, 0, 0}; + uint8_t tmp[3] = { + MPSSE_WRITE_TMS | MPSSE_LSB | MPSSE_BITMODE| MPSSE_READ_NEG, 0, 0}; while(ticks >= 0) { tmp[1] = ticks<7?ticks-1:6; tmp[2] = 0x80 | (MS & 0x7F); - platform_buffer_write(tmp, 3); + libftdi_buffer_write(tmp, 3); MS >>= 7; ticks -= 7; } } @@ -120,15 +116,16 @@ static void jtagtap_tdi_tdo_seq( rticks = ticks & 7; ticks >>= 3; uint8_t data[3]; - uint8_t cmd = ((DO)? MPSSE_DO_READ : 0) | ((DI)? (MPSSE_DO_WRITE | MPSSE_WRITE_NEG) : 0) | MPSSE_LSB; + uint8_t cmd = ((DO)? MPSSE_DO_READ : 0) | + ((DI)? (MPSSE_DO_WRITE | MPSSE_WRITE_NEG) : 0) | MPSSE_LSB; rsize = ticks; if(ticks) { data[0] = cmd; data[1] = ticks - 1; data[2] = 0; - platform_buffer_write(data, 3); + libftdi_buffer_write(data, 3); if (DI) - platform_buffer_write(DI, ticks); + libftdi_buffer_write(DI, ticks); } if(rticks) { int index = 0; @@ -137,21 +134,22 @@ static void jtagtap_tdi_tdo_seq( data[index++] = rticks - 1; if (DI) data[index++] = DI[ticks]; - platform_buffer_write(data, index); + libftdi_buffer_write(data, index); } if(final_tms) { int index = 0; rsize++; - data[index++] = MPSSE_WRITE_TMS | ((DO)? MPSSE_DO_READ : 0) | MPSSE_LSB | MPSSE_BITMODE | MPSSE_WRITE_NEG; + data[index++] = MPSSE_WRITE_TMS | ((DO)? MPSSE_DO_READ : 0) | + MPSSE_LSB | MPSSE_BITMODE | MPSSE_WRITE_NEG; data[index++] = 0; if (DI) data[index++] = (DI[ticks]) >> rticks?0x81 : 0x01; - platform_buffer_write(data, index); + libftdi_buffer_write(data, index); } if (DO) { int index = 0; uint8_t *tmp = alloca(ticks); - platform_buffer_read(tmp, rsize); + libftdi_buffer_read(tmp, rsize); if(final_tms) rsize--; while(rsize--) { @@ -181,10 +179,11 @@ static void jtagtap_tdi_seq( static uint8_t jtagtap_next(uint8_t dTMS, uint8_t dTDI) { uint8_t ret; - uint8_t tmp[3] = {MPSSE_WRITE_TMS | MPSSE_DO_READ | MPSSE_LSB | MPSSE_BITMODE | MPSSE_WRITE_NEG, 0, 0}; + uint8_t tmp[3] = {MPSSE_WRITE_TMS | MPSSE_DO_READ | MPSSE_LSB | + MPSSE_BITMODE | MPSSE_WRITE_NEG, 0, 0}; tmp[2] = (dTDI?0x80:0) | (dTMS?0x01:0); - platform_buffer_write(tmp, 3); - platform_buffer_read(&ret, 1); + libftdi_buffer_write(tmp, 3); + libftdi_buffer_read(&ret, 1); ret &= 0x80; @@ -192,4 +191,3 @@ static uint8_t jtagtap_next(uint8_t dTMS, uint8_t dTDI) return ret; } - diff --git a/src/platforms/libftdi/swdptap.c b/src/platforms/hosted/libftdi_swdptap.c similarity index 88% rename from src/platforms/libftdi/swdptap.c rename to src/platforms/hosted/libftdi_swdptap.c index d710d453..07989018 100644 --- a/src/platforms/libftdi/swdptap.c +++ b/src/platforms/hosted/libftdi_swdptap.c @@ -26,7 +26,7 @@ #include #include "general.h" -#include "swdptap.h" +#include "ftdi_bmp.h" static uint8_t olddir = 0; @@ -40,9 +40,7 @@ static uint32_t swdptap_seq_in(int ticks); static void swdptap_seq_out(uint32_t MS, int ticks); static void swdptap_seq_out_parity(uint32_t MS, int ticks); -swd_proc_t swd_proc; - -int platform_swdptap_init(void) +int libftdi_swdptap_init(swd_proc_t *swd_proc) { if (!active_cable->bitbang_tms_in_pin) { DEBUG("SWD not possible or missing item in cable description.\n"); @@ -52,21 +50,21 @@ int platform_swdptap_init(void) if (err != 0) { fprintf(stderr, "ftdi_usb_purge_buffer: %d: %s\n", err, ftdi_get_error_string(ftdic)); - abort(); + return -1; } /* Reset MPSSE controller. */ err = ftdi_set_bitmode(ftdic, 0, BITMODE_RESET); if (err != 0) { fprintf(stderr, "ftdi_set_bitmode: %d: %s\n", err, ftdi_get_error_string(ftdic)); - return -1;; + return -1; } /* Enable MPSSE controller. Pin directions are set later.*/ err = ftdi_set_bitmode(ftdic, 0, BITMODE_MPSSE); if (err != 0) { fprintf(stderr, "ftdi_set_bitmode: %d: %s\n", err, ftdi_get_error_string(ftdic)); - return -1;; + return -1; } uint8_t ftdi_init[9] = {TCK_DIVISOR, 0x01, 0x00, SET_BITS_LOW, 0,0, SET_BITS_HIGH, 0,0}; @@ -74,13 +72,13 @@ int platform_swdptap_init(void) ftdi_init[5]= active_cable->dbus_ddr & ~MPSSE_TD_MASK; ftdi_init[7]= active_cable->cbus_data; ftdi_init[8]= active_cable->cbus_ddr; - platform_buffer_write(ftdi_init, 9); - platform_buffer_flush(); + libftdi_buffer_write(ftdi_init, 9); + libftdi_buffer_flush(); - swd_proc.swdptap_seq_in = swdptap_seq_in; - swd_proc.swdptap_seq_in_parity = swdptap_seq_in_parity; - swd_proc.swdptap_seq_out = swdptap_seq_out; - swd_proc.swdptap_seq_out_parity = swdptap_seq_out_parity; + swd_proc->swdptap_seq_in = swdptap_seq_in; + swd_proc->swdptap_seq_in_parity = swdptap_seq_in_parity; + swd_proc->swdptap_seq_out = swdptap_seq_out; + swd_proc->swdptap_seq_out_parity = swdptap_seq_out_parity; return 0; } @@ -111,7 +109,7 @@ static void swdptap_turnaround(uint8_t dir) cmd[index++] = active_cable->dbus_data | MPSSE_MASK; cmd[index++] = active_cable->dbus_ddr & ~MPSSE_TD_MASK; } - platform_buffer_write(cmd, index); + libftdi_buffer_write(cmd, index); } static bool swdptap_seq_in_parity(uint32_t *res, int ticks) @@ -126,11 +124,11 @@ static bool swdptap_seq_in_parity(uint32_t *res, int ticks) cmd[3] = 0; swdptap_turnaround(1); while (index--) { - platform_buffer_write(cmd, 4); + libftdi_buffer_write(cmd, 4); } uint8_t data[33]; unsigned int ret = 0; - platform_buffer_read(data, ticks + 1); + libftdi_buffer_read(data, ticks + 1); if (data[ticks] & active_cable->bitbang_tms_in_pin) parity ^= 1; while (ticks--) { @@ -155,11 +153,11 @@ static uint32_t swdptap_seq_in(int ticks) swdptap_turnaround(1); while (index--) { - platform_buffer_write(cmd, 4); + libftdi_buffer_write(cmd, 4); } uint8_t data[32]; uint32_t ret = 0; - platform_buffer_read(data, ticks); + libftdi_buffer_read(data, ticks); while (ticks--) { if (data[ticks] & active_cable->bitbang_tms_in_pin) ret |= (1 << ticks); @@ -185,7 +183,7 @@ static void swdptap_seq_out(uint32_t MS, int ticks) ticks = 0; } } - platform_buffer_write(cmd, index); + libftdi_buffer_write(cmd, index); } static void swdptap_seq_out_parity(uint32_t MS, int ticks) @@ -216,5 +214,5 @@ static void swdptap_seq_out_parity(uint32_t MS, int ticks) cmd[index++] = MPSSE_TMS_SHIFT; cmd[index++] = 0; cmd[index++] = parity; - platform_buffer_write(cmd, index); + libftdi_buffer_write(cmd, index); } diff --git a/src/platforms/hosted/platform.c b/src/platforms/hosted/platform.c index 55f8a52d..c061e738 100644 --- a/src/platforms/hosted/platform.c +++ b/src/platforms/hosted/platform.c @@ -34,6 +34,7 @@ #include "bmp_remote.h" #include "stlinkv2.h" +#include "ftdi_bmp.h" #define VENDOR_ID_BMP 0x1d50 #define PRODUCT_ID_BMP 0x6018 @@ -215,6 +216,13 @@ void platform_init(int argc, char **argv) } if (cl_opts.opt_device) { info.bmp_type = BMP_TYPE_BMP; + } else if (cl_opts.opt_cable) { + /* check for libftdi devices*/ + res = ftdi_bmp_init(&cl_opts, &info); + if (res) + exit(-1); + else + info.bmp_type = BMP_TYPE_LIBFTDI; } else if (find_debuggers(&cl_opts, &info)) { exit(-1); } @@ -231,6 +239,8 @@ void platform_init(int argc, char **argv) if (stlink_init( &info)) exit(-1); break; + case BMP_TYPE_LIBFTDI: + break; default: exit(-1); } @@ -248,6 +258,9 @@ int platform_adiv5_swdp_scan(void) { switch (info.bmp_type) { case BMP_TYPE_BMP: + case BMP_TYPE_LIBFTDI: + return adiv5_swdp_scan(); + break; case BMP_TYPE_STLINKV2: { target_list_free(); @@ -274,6 +287,8 @@ int platform_swdptap_init(void) case BMP_TYPE_STLINKV2: return 0; break; + case BMP_TYPE_LIBFTDI: + return libftdi_swdptap_init(&swd_proc); default: return -1; } @@ -284,6 +299,8 @@ int platform_jtag_scan(const uint8_t *lrlens) { switch (info.bmp_type) { case BMP_TYPE_BMP: + case BMP_TYPE_LIBFTDI: + return jtag_scan(lrlens); case BMP_TYPE_STLINKV2: return jtag_scan_stlinkv2(&info, lrlens); default: @@ -299,6 +316,8 @@ int platform_jtagtap_init(void) return remote_jtagtap_init(&jtag_proc); case BMP_TYPE_STLINKV2: return 0; + case BMP_TYPE_LIBFTDI: + return libftdi_jtagtap_init(&jtag_proc); default: return -1; } @@ -319,6 +338,8 @@ int platform_jtag_dp_init(ADIv5_DP_t *dp) { switch (info.bmp_type) { case BMP_TYPE_BMP: + case BMP_TYPE_LIBFTDI: + return 0; case BMP_TYPE_STLINKV2: return stlink_jtag_dp_init(dp); default: @@ -336,7 +357,7 @@ char *platform_ident(void) return "BMP"; case BMP_TYPE_STLINKV2: return "STLINKV2"; - case BMP_TYPE_LIBFTDI: + case BMP_TYPE_LIBFTDI: return "LIBFTDI"; case BMP_TYPE_CMSIS_DAP: return "CMSIS_DAP"; @@ -353,6 +374,8 @@ const char *platform_target_voltage(void) return remote_target_voltage(); case BMP_TYPE_STLINKV2: return stlink_target_voltage(&info); + case BMP_TYPE_LIBFTDI: + return libftdi_target_voltage(); default: break; } @@ -387,6 +410,8 @@ bool platform_srst_get_val(void) void platform_buffer_flush(void) { switch (info.bmp_type) { + case BMP_TYPE_LIBFTDI: + return libftdi_buffer_flush(); default: break; } diff --git a/src/platforms/libftdi/Makefile.inc b/src/platforms/libftdi/Makefile.inc deleted file mode 100644 index fab3b064..00000000 --- a/src/platforms/libftdi/Makefile.inc +++ /dev/null @@ -1,13 +0,0 @@ -SYS = $(shell $(CC) -dumpmachine) -CFLAGS += -DENABLE_DEBUG -CFLAGS += $(shell pkg-config --cflags libftdi1) -LDFLAGS += $(shell pkg-config --libs libftdi1) -ifneq (, $(findstring mingw, $(SYS))) -LDFLAGS += -lusb-1.0 -lws2_32 -else ifneq (, $(findstring cygwin, $(SYS))) -LDFLAGS += -lusb-1.0 -lws2_32 -endif -VPATH += platforms/pc -SRC += timing.c cl_utils.c utils.c -CFLAGS +=-I ./target -I./platforms/pc -PC_HOSTED = 1 \ No newline at end of file diff --git a/src/platforms/libftdi/README.md b/src/platforms/libftdi/README.md deleted file mode 100644 index 51676cac..00000000 --- a/src/platforms/libftdi/README.md +++ /dev/null @@ -1,14 +0,0 @@ -Compiling on windows - -You can crosscompile blackmagic for windows with mingw or on windows -with cygwin. For compilation, headers for libftdi1 and libusb-1.0 are -needed. For running, libftdi1.dll and libusb-1.0.dll are needed and -the executable must be able to find them. Mingw on cygwin does not provide -a libftdi package yet. - -To prepare libusb access to the ftdi device, run zadig https://zadig.akeo.ie/. -Choose WinUSB(libusb-1.0) for the BMP Ftdi device. - -Running cygwin/blackmagic in a cygwin console, the program does not react -on ^C. In another console, run "ps ax" to find the WINPID of the process -and then "taskkill /F ?PID (WINPID)".