From 1d8ebcd75f9191cdbb0f6ebde2cb80ff03f1d815 Mon Sep 17 00:00:00 2001 From: Uwe Bonnes Date: Fri, 3 Mar 2017 13:12:14 +0100 Subject: [PATCH 1/7] Handle SET_ADDRESS according to DFUSE specs. --- src/platforms/stm32/dfucore.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/src/platforms/stm32/dfucore.c b/src/platforms/stm32/dfucore.c index 7b733d71..38cb4218 100644 --- a/src/platforms/stm32/dfucore.c +++ b/src/platforms/stm32/dfucore.c @@ -48,6 +48,7 @@ static struct { uint32_t addr; uint16_t blocknum; } prog; +static uint8_t current_error; const struct usb_device_descriptor dev = { .bLength = USB_DT_DEVICE_SIZE, @@ -149,7 +150,8 @@ static uint8_t usbdfu_getstatus(uint32_t *bwPollTimeout) /* Device will reset when read is complete */ usbdfu_state = STATE_DFU_MANIFEST; return DFU_STATUS_OK; - + case STATE_DFU_ERROR: + return current_error; default: return DFU_STATUS_OK; } @@ -159,23 +161,17 @@ static void usbdfu_getstatus_complete(usbd_device *dev, struct usb_setup_data *req) { (void)req; + (void)dev; switch(usbdfu_state) { case STATE_DFU_DNBUSY: flash_unlock(); if(prog.blocknum == 0) { - uint32_t addr = get_le32(prog.buf + 1); - if ((addr < app_address) || (addr >= max_address)) { - flash_lock(); - usbd_ep_stall_set(dev, 0, 1); - return; - } + int32_t addr = get_le32(prog.buf + 1); switch(prog.buf[0]) { case CMD_ERASE: dfu_check_and_do_sector_erase(addr); - case CMD_SETADDR: - prog.addr = addr; } } else { uint32_t baseaddr = prog.addr + @@ -218,6 +214,15 @@ static int usbdfu_control_request(usbd_device *dev, prog.blocknum = req->wValue; prog.len = *len; memcpy(prog.buf, *buf, *len); + if ((req->wValue == 0) && (prog.buf[0] == CMD_SETADDR)) { + uint32_t addr = get_le32(prog.buf + 1); + if ((addr < app_address) || (addr >= max_address)) { + current_error = DFU_STATUS_ERR_TARGET; + usbdfu_state = STATE_DFU_ERROR; + return 1; + } else + prog.addr = addr; + } usbdfu_state = STATE_DFU_DNLOAD_SYNC; return 1; } From d7965714382b6492c53341039e44fa893691db4a Mon Sep 17 00:00:00 2001 From: Uwe Bonnes Date: Fri, 3 Mar 2017 15:34:22 +0100 Subject: [PATCH 2/7] Implement DFU_UPLOAD. --- src/platforms/stlink/Flashsize_F103 | 39 +++++++++++++++++++++++++++++ src/platforms/stm32/dfucore.c | 20 ++++++++++++--- 2 files changed, 56 insertions(+), 3 deletions(-) create mode 100644 src/platforms/stlink/Flashsize_F103 diff --git a/src/platforms/stlink/Flashsize_F103 b/src/platforms/stlink/Flashsize_F103 new file mode 100644 index 00000000..d4ece0f3 --- /dev/null +++ b/src/platforms/stlink/Flashsize_F103 @@ -0,0 +1,39 @@ +Announced versus available Flash size on F103 +============================================ +Up to Stlink V2, the CPU soldered on the board was a F103C8 with 64 kiByte +flash. Up to about version 280 of BMP, this limit was not hit when linked +against nanolib. + +StlinkV2-1 has a STM32F103CB, like a genuine BMP. + +However with more and more devices supported, BMP at about version 282 hit +this limit. There are two ways to work around: +- Branch STlink V2-1 as separate platform and and care for the original STlink + platform by restricting/ommitting features. +- Rely on uncertain upper flash on F103C8 + +The first option needs more care as an additional platform is introduced and +will restrict usage of older STlinks as BMPs. + +However F103C8 and F103CB have the same chip and upper flash exists on F103C8. +This flash may have been tested bad, or not have been tested at all, +or, in the best case, was tested good but market requirements made STM sell +it as F103C8. + +Ignoring the chip marking and using an F103C8 blindly as a F103Cb is done +already with few problems on many china boards (e.g. blue pill). Probably +this second approach will work for many of the older STLinks. + +Use at your own risk! + +With DFU upload available in the bootloader, you can verify by uploading the +binary from flash and comparing it against the binary downloaded. +- Download new BMP binary (if not already done) + dfu-util -s 0x08002000:leave:force -D blackmagic.bin +- Get length of binary + > ls -l blackmagic.bin + -rwxr-xr-x 1 bon users 57372 15. Apr 14:17 blackmagic.bin +- Upload binary from flash + > dfu-util -s 0x08002000:leave:force:57372 -U blackmagic.bin.1 +- Compare + > diff blackmagic.bin* diff --git a/src/platforms/stm32/dfucore.c b/src/platforms/stm32/dfucore.c index 38cb4218..bfe4f3af 100644 --- a/src/platforms/stm32/dfucore.c +++ b/src/platforms/stm32/dfucore.c @@ -70,7 +70,7 @@ const struct usb_device_descriptor dev = { const struct usb_dfu_descriptor dfu_function = { .bLength = sizeof(struct usb_dfu_descriptor), .bDescriptorType = DFU_FUNCTIONAL, - .bmAttributes = USB_DFU_CAN_DOWNLOAD | USB_DFU_WILL_DETACH, + .bmAttributes = USB_DFU_CAN_DOWNLOAD | USB_DFU_CAN_UPLOAD | USB_DFU_WILL_DETACH, .wDetachTimeout = 255, .wTransferSize = 1024, .bcdDFUVersion = 0x011A, @@ -236,8 +236,22 @@ static int usbdfu_control_request(usbd_device *dev, usbdfu_state = STATE_DFU_IDLE; return 1; case DFU_UPLOAD: - /* Upload not supported for now */ - return 0; + if ((usbdfu_state == STATE_DFU_IDLE) || + (usbdfu_state == STATE_DFU_DNLOAD_IDLE) || + (usbdfu_state == STATE_DFU_UPLOAD_IDLE)) { + prog.blocknum = req->wValue; + usbdfu_state = STATE_DFU_UPLOAD_IDLE; + if(prog.blocknum > 1) { + uint32_t baseaddr = prog.addr + + ((prog.blocknum - 2) * + dfu_function.wTransferSize); + memcpy(*buf, (void*)baseaddr, *len); + } + return 1; + } else { + usbd_ep_stall_set(dev, 0, 1); + return 0; + } case DFU_GETSTATUS: { uint32_t bwPollTimeout = 0; /* 24-bit integer in DFU class spec */ From 3c06396c8ee9d660b0bc70f526acef1b7218cbad Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Sat, 22 Apr 2017 13:50:04 -0700 Subject: [PATCH 3/7] Constify strings and constant structs --- src/target/cortexa.c | 2 +- src/target/cortexm.c | 2 +- src/target/jtag_scan.c | 10 +++++----- src/target/jtag_scan.h | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/target/cortexa.c b/src/target/cortexa.c index ba273754..9ef239c5 100644 --- a/src/target/cortexa.c +++ b/src/target/cortexa.c @@ -33,7 +33,7 @@ #include "target.h" #include "target_internal.h" -static char cortexa_driver_str[] = "ARM Cortex-A"; +static const char cortexa_driver_str[] = "ARM Cortex-A"; static bool cortexa_attach(target *t); static void cortexa_detach(target *t); diff --git a/src/target/cortexm.c b/src/target/cortexm.c index 80e1caf6..4e941060 100644 --- a/src/target/cortexm.c +++ b/src/target/cortexm.c @@ -34,7 +34,7 @@ #include -static char cortexm_driver_str[] = "ARM Cortex-M"; +static const char cortexm_driver_str[] = "ARM Cortex-M"; static bool cortexm_vector_catch(target *t, int argc, char *argv[]); diff --git a/src/target/jtag_scan.c b/src/target/jtag_scan.c index 4546be58..a30a8050 100644 --- a/src/target/jtag_scan.c +++ b/src/target/jtag_scan.c @@ -32,11 +32,11 @@ struct jtag_dev_s jtag_devs[JTAG_MAX_DEVS+1]; int jtag_dev_count; -static struct jtag_dev_descr_s { - uint32_t idcode; - uint32_t idmask; - char *descr; - void (*handler)(jtag_dev_t *dev); +static const struct jtag_dev_descr_s { + const uint32_t idcode; + const uint32_t idmask; + const char * const descr; + void (*const handler)(jtag_dev_t *dev); } dev_descr[] = { {.idcode = 0x0BA00477, .idmask = 0x0FFF0FFF, .descr = "ARM Limited: ADIv5 JTAG-DP port.", diff --git a/src/target/jtag_scan.h b/src/target/jtag_scan.h index e96f6e70..3c723f4a 100644 --- a/src/target/jtag_scan.h +++ b/src/target/jtag_scan.h @@ -36,7 +36,7 @@ typedef struct jtag_dev_s { uint8_t ir_postscan; uint32_t idcode; - char *descr; + const char *descr; uint32_t current_ir; From 01e3582525f2d4479d52189818923dfd8f15a6ef Mon Sep 17 00:00:00 2001 From: stoyan shopov Date: Fri, 28 Apr 2017 13:22:59 +0300 Subject: [PATCH 4/7] fixed a bug in the breakpoint removal code --- src/target/target.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/target/target.c b/src/target/target.c index fe11079c..54ab8bfc 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -355,7 +355,7 @@ int target_breakwatch_clear(target *t, { struct breakwatch *bwp = NULL, *bw; int ret = 1; - for (bw = t->bw_list; bw; bw = bw->next, bwp = bw) + for (bw = t->bw_list; bw; bwp = bw, bw = bw->next) if ((bw->type == type) && (bw->addr == addr) && (bw->size == len)) From 5af76a1b74e49d0f8e7639326d895f1e23c76411 Mon Sep 17 00:00:00 2001 From: Uwe Bonnes Date: Fri, 28 Apr 2017 17:39:23 +0200 Subject: [PATCH 5/7] dfu_f1/dfu_upgrade: Do not set read protection. As the first 4 pages of the bootloader will always keep write protection once read protection is applied, with the second update of the bootloader only the higher pages where updated effectivly. In most cases this resulted in an inaccessible device! --- src/platforms/stm32/dfu_f1.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/platforms/stm32/dfu_f1.c b/src/platforms/stm32/dfu_f1.c index a0955170..83e95ec1 100644 --- a/src/platforms/stm32/dfu_f1.c +++ b/src/platforms/stm32/dfu_f1.c @@ -77,11 +77,25 @@ void dfu_protect(dfu_mode_t mode) } #endif } - else if (mode == UPD_MODE) { + /* There is no way we can update the bootloader with a programm running + * on the same device when the bootloader pages are write + * protected or the device is read protected! + * + * Erasing option bytes to remove write protection will make the + * device read protected. Read protection means that the first pages + * get write protected again (PM0075, 2.4.1 Read protection.) + * + * Removing read protection after option erase results in device mass + * erase, crashing the update (PM0075, 2.4.2, Unprotection, Case 1). + */ +#if 0 + else if ((mode == UPD_MODE) && ((FLASH_WRPR & 0x03) != 0x03)) { flash_unlock(); FLASH_CR = 0; flash_erase_option_bytes(); + flash_program_option_bytes(FLASH_OBP_RDP, FLASH_OBP_RDP_KEY); } +#endif } void dfu_jump_app_if_valid(void) From b09a522f373585e1752aa39b2317ad0e0caca84f Mon Sep 17 00:00:00 2001 From: Uwe Bonnes Date: Thu, 27 Apr 2017 19:00:15 +0200 Subject: [PATCH 6/7] STM32F103: Use flash size from device for DFU string. Complements #204. STLinkV2-1 has F103CB on board! F103C8 on older Stlinks can use upper flash with hopefully acceptable error rate. For F103C8 devices, user has to give the force option to dfu-utils. --- src/platforms/f4discovery/platform.h | 2 -- src/platforms/hydrabus/platform.h | 1 - src/platforms/native/platform.h | 1 - src/platforms/stlink/platform.h | 1 - src/platforms/stm32/dfucore.c | 42 +++++++++++++++++++++++++--- src/platforms/swlink/platform.h | 1 - 6 files changed, 38 insertions(+), 10 deletions(-) diff --git a/src/platforms/f4discovery/platform.h b/src/platforms/f4discovery/platform.h index d1260dad..e274a38b 100644 --- a/src/platforms/f4discovery/platform.h +++ b/src/platforms/f4discovery/platform.h @@ -33,9 +33,7 @@ #define PLATFORM_HAS_TRACESWO #define BOARD_IDENT "Black Magic Probe (F4Discovery), (Firmware " FIRMWARE_VERSION ")" -#define BOARD_IDENT_DFU "Black Magic (Upgrade) for F4Discovery, (Firmware " FIRMWARE_VERSION ")" #define DFU_IDENT "Black Magic Firmware Upgrade (F4Discovery" -#define DFU_IFACE_STRING "@Internal Flash /0x08000000/1*016Ka,3*016Kg,1*064Kg,7*128Kg" /* Important pin mappings for STM32 implementation: * diff --git a/src/platforms/hydrabus/platform.h b/src/platforms/hydrabus/platform.h index b340f970..d0ba61aa 100644 --- a/src/platforms/hydrabus/platform.h +++ b/src/platforms/hydrabus/platform.h @@ -36,7 +36,6 @@ #define BOARD_IDENT "Black Magic Probe (HydraBus), (Firmware " FIRMWARE_VERSION ")" #define BOARD_IDENT_DFU "Black Magic (Upgrade) for HydraBus, (Firmware " FIRMWARE_VERSION ")" #define DFU_IDENT "Black Magic Firmware Upgrade (HydraBus)" -#define DFU_IFACE_STRING "@Internal Flash /0x08000000/1*016Ka,3*016Kg,1*064Kg,7*128Kg" /* Important pin mappings for STM32 implementation: * diff --git a/src/platforms/native/platform.h b/src/platforms/native/platform.h index 397dd8c1..c18a8c8f 100644 --- a/src/platforms/native/platform.h +++ b/src/platforms/native/platform.h @@ -38,7 +38,6 @@ #define BOARD_IDENT_DFU "Black Magic Probe (Upgrade)" #define BOARD_IDENT_UPD "Black Magic Probe (DFU Upgrade)" #define DFU_IDENT "Black Magic Firmware Upgrade" -#define DFU_IFACE_STRING "@Internal Flash /0x08000000/8*001Ka,120*001Kg" #define UPD_IFACE_STRING "@Internal Flash /0x08000000/8*001Kg" /* Important pin mappings for STM32 implementation: diff --git a/src/platforms/stlink/platform.h b/src/platforms/stlink/platform.h index ef030541..54125a9a 100644 --- a/src/platforms/stlink/platform.h +++ b/src/platforms/stlink/platform.h @@ -37,7 +37,6 @@ #define BOARD_IDENT_DFU "Black Magic (Upgrade) for STLink/Discovery, (Firmware " FIRMWARE_VERSION ")" #define BOARD_IDENT_UPD "Black Magic (DFU Upgrade) for STLink/Discovery, (Firmware " FIRMWARE_VERSION ")" #define DFU_IDENT "Black Magic Firmware Upgrade (STLINK)" -#define DFU_IFACE_STRING "@Internal Flash /0x08000000/8*001Ka,56*001Kg" #define UPD_IFACE_STRING "@Internal Flash /0x08000000/8*001Kg" /* Important pin mappings for STM32 implementation: diff --git a/src/platforms/stm32/dfucore.c b/src/platforms/stm32/dfucore.c index bfe4f3af..f020e610 100644 --- a/src/platforms/stm32/dfucore.c +++ b/src/platforms/stm32/dfucore.c @@ -22,10 +22,11 @@ #include #if defined(STM32F1) # include -#elif defined(STM32F2) -# include +# define DFU_IFACE_STRING "@Internal Flash /0x08000000/8*001Ka,000*001Kg" +# define DFU_IFACE_STRING_OFFSET 38 #elif defined(STM32F4) # include +# define DFU_IFACE_STRING "/0x08000000/1*016Ka,3*016Kg,1*064Kg,7*128Kg" #endif #include #include @@ -113,13 +114,14 @@ const struct usb_config_descriptor config = { }; static char serial_no[9]; +static char if_string[] = DFU_IFACE_STRING; static const char *usb_strings[] = { "Black Sphere Technologies", BOARD_IDENT_DFU, serial_no, /* This string is used by ST Microelectronics' DfuSe utility */ - DFU_IFACE_STRING, + if_string, }; static const char *usb_strings_upd[] = { @@ -297,6 +299,33 @@ void dfu_main(void) usbd_poll(usbdev); } +#if defined(DFU_IFACE_STRING_OFFSET) +static void set_dfu_iface_string(uint32_t size) +{ + uint32_t res; + char *p = if_string + DFU_IFACE_STRING_OFFSET; + /* We do not want the whole printf library in the bootloader. + * Fill the size digits by hand. + */ + res = size / 100; + if (res > 9) { + *p++ = '9'; + *p++ = '9'; + *p++ = '9'; + return; + } else { + *p++ = res + '0'; + size -= res * 100; + } + res = size / 10; + *p++ = res + '0'; + size -= res * 10; + *p++ = size + '0'; +} +#else +# define set_dfu_iface_string() +#endif + static char *get_dev_unique_id(char *s) { #if defined(STM32F4) || defined(STM32F2) @@ -317,10 +346,15 @@ static char *get_dev_unique_id(char *s) *(unique_id_p + 1) + *(unique_id_p + 2); int i; + uint32_t fuse_flash_size; /* Calculated the upper flash limit from the exported data in theparameter block*/ - max_address = (*(uint32_t *) FLASH_SIZE_R) <<10; + fuse_flash_size = *(uint32_t *) FLASH_SIZE_R & 0xfff; + set_dfu_iface_string(fuse_flash_size - 8); + if (fuse_flash_size == 0x40) /* Handle F103x8 as F103xC! */ + fuse_flash_size = 0x80; + max_address = FLASH_BASE + (fuse_flash_size << 10); /* Fetch serial number from chip's unique ID */ for(i = 0; i < 8; i++) { s[7-i] = ((unique_id >> (4*i)) & 0xF) + '0'; diff --git a/src/platforms/swlink/platform.h b/src/platforms/swlink/platform.h index 74bb7873..dbe42074 100644 --- a/src/platforms/swlink/platform.h +++ b/src/platforms/swlink/platform.h @@ -33,7 +33,6 @@ #define BOARD_IDENT_DFU "Black Magic (Upgrade), STM8S Discovery, (Firmware " FIRMWARE_VERSION ")" #define BOARD_IDENT_UPD "Black Magic (DFU Upgrade), STM8S Discovery, (Firmware " FIRMWARE_VERSION ")" #define DFU_IDENT "Black Magic Firmware Upgrade (SWLINK)" -#define DFU_IFACE_STRING "@Internal Flash /0x08000000/8*001Ka,56*001Kg" #define UPD_IFACE_STRING "@Internal Flash /0x08000000/8*001Kg" /* Pin mappings: From b7235da97fd5141ce1f0ea963237a8fb71e71930 Mon Sep 17 00:00:00 2001 From: Uwe Bonnes Date: Fri, 28 Apr 2017 20:18:20 +0200 Subject: [PATCH 7/7] dfucore.c: Announce no writable bootloader pages when device is read proteced or bootloader is write protected. Device read protection or write protection on first 4 bootloader pages can only be removed by mass erase. Triggering mass erase with a program running from flash is doomed for failure. User can force bootloader update, at their own risk to brick the device. --- src/platforms/stm32/dfucore.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/platforms/stm32/dfucore.c b/src/platforms/stm32/dfucore.c index f020e610..61cfd041 100644 --- a/src/platforms/stm32/dfucore.c +++ b/src/platforms/stm32/dfucore.c @@ -124,12 +124,13 @@ static const char *usb_strings[] = { if_string, }; +static char upd_if_string[] = UPD_IFACE_STRING; static const char *usb_strings_upd[] = { "Black Sphere Technologies", BOARD_IDENT_UPD, serial_no, /* This string is used by ST Microelectronics' DfuSe utility */ - UPD_IFACE_STRING, + upd_if_string, }; static uint32_t get_le32(const void *vp) @@ -355,6 +356,12 @@ static char *get_dev_unique_id(char *s) if (fuse_flash_size == 0x40) /* Handle F103x8 as F103xC! */ fuse_flash_size = 0x80; max_address = FLASH_BASE + (fuse_flash_size << 10); + /* If bootloader pages are write protected or device is read + * protected, deny bootloader update. + * User can still force updates, at his own risk! + */ + if (((FLASH_WRPR & 0x03) != 0x03) || (FLASH_OBR & FLASH_OBR_RDPRT_EN)) + upd_if_string[30] = '0'; /* Fetch serial number from chip's unique ID */ for(i = 0; i < 8; i++) { s[7-i] = ((unique_id >> (4*i)) & 0xF) + '0';