From fbd3fa1ca9ff01dd7f67502b9549da62e5f8279f Mon Sep 17 00:00:00 2001 From: Martin Mares Date: Mon, 24 Feb 2020 15:58:22 +0100 Subject: [PATCH] DFU: Flash first page last --- bsb/bootloader/config.h | 6 ++-- lib/dfu-bootloader.c | 71 ++++++++++++++++++++++++++--------------- 2 files changed, 48 insertions(+), 29 deletions(-) diff --git a/bsb/bootloader/config.h b/bsb/bootloader/config.h index 232fd4a..6900748 100644 --- a/bsb/bootloader/config.h +++ b/bsb/bootloader/config.h @@ -18,7 +18,7 @@ #define BOOTLOADER_DEBUG #define BOOTLOADER_APP_START 0x08002000 #define BOOTLOADER_MFG_ID 0x4242 -#define BOOTLOADER_DEV_ID 0x0004 -#define BOOTLOADER_DEV_VERSION 0x0100 +#define BOOTLOADER_PROD_ID 0x0004 +#define BOOTLOADER_PROD_VERSION 0x0100 #define BOOTLOADER_MFG_NAME "United Computer Wizards" -#define BOOTLOADER_DEV_NAME "BSB Interface (boot-loader)" +#define BOOTLOADER_PROD_NAME "BSB Interface (boot-loader)" diff --git a/lib/dfu-bootloader.c b/lib/dfu-bootloader.c index 4f792ce..ce01a41 100644 --- a/lib/dfu-bootloader.c +++ b/lib/dfu-bootloader.c @@ -35,24 +35,29 @@ byte usbd_control_buffer[1024]; static enum dfu_state usbdfu_state = STATE_DFU_IDLE; -static struct { +struct prog_info { byte buf[sizeof(usbd_control_buffer)]; - u16 len; - u32 addr; u16 blocknum; -} prog; + u16 len; +}; + +static struct prog_info prog_page; + +// The first page of application code is programmed last, +// so that we are able to detect incompletely uploaded firmware. +static struct prog_info prog_header; static char usb_serial_number[13]; enum usb_string { STR_MANUFACTURER = 1, - STR_DEVICE, + STR_PRODUCT, STR_SERIAL, }; static const char *usb_strings[] = { BOOTLOADER_MFG_NAME, - BOOTLOADER_DEV_NAME, + BOOTLOADER_PROD_NAME, usb_serial_number, }; @@ -65,10 +70,10 @@ const struct usb_device_descriptor dev = { .bDeviceProtocol = 0, .bMaxPacketSize0 = 64, .idVendor = BOOTLOADER_MFG_ID, - .idProduct = BOOTLOADER_DEV_ID, - .bcdDevice = BOOTLOADER_DEV_VERSION, + .idProduct = BOOTLOADER_PROD_ID, + .bcdDevice = BOOTLOADER_PROD_VERSION, .iManufacturer = STR_MANUFACTURER, - .iProduct = STR_DEVICE, + .iProduct = STR_PRODUCT, .iSerialNumber = STR_SERIAL, .bNumConfigurations = 1, }; @@ -128,23 +133,37 @@ static byte usbdfu_getstatus(usbd_device *usbd_dev UNUSED, u32 *bwPollTimeout) } } +static void program_page(struct prog_info *prog, bool need_erase) +{ + flash_unlock(); + u32 baseaddr = BOOTLOADER_APP_START + prog->blocknum * dfu_function.wTransferSize; + DEBUG("DFU: Block %u -> %08x\n", prog->blocknum, (uint) baseaddr); + if (need_erase) + flash_erase_page(baseaddr); + for (uint i = 0; i < prog->len; i += 2) { + u16 data = *(u16 *)(prog->buf + i); + flash_program_half_word(baseaddr + i, data); + } + flash_lock(); +} + static void usbdfu_getstatus_complete(usbd_device *usbd_dev UNUSED, struct usb_setup_data *req UNUSED) { switch (usbdfu_state) { - case STATE_DFU_DNBUSY: { - flash_unlock(); - u32 baseaddr = BOOTLOADER_APP_START + prog.blocknum * dfu_function.wTransferSize; - DEBUG("DFU: Block %u -> %08x\n", prog.blocknum, (uint) baseaddr); - flash_erase_page(baseaddr); - for (uint i = 0; i < prog.len; i += 2) { - u16 *dat = (u16 *)(prog.buf + i); - flash_program_half_word(baseaddr + i, *dat); - } - flash_lock(); + case STATE_DFU_DNBUSY: + if (prog_page.blocknum == 0) { + // The first block will be programmed last + prog_header = prog_page; + flash_unlock(); + flash_erase_page(BOOTLOADER_APP_START); + flash_lock(); + } else + program_page(&prog_page, true); usbdfu_state = STATE_DFU_DNLOAD_IDLE; return; - } case STATE_DFU_MANIFEST: + // At the very end, program the first page + program_page(&prog_header, false); /* USB device must detach, we just reset... */ scb_reset_system(); return; /* Will never return. */ @@ -162,7 +181,7 @@ static enum usbd_request_return_codes usbdfu_control_request(usbd_device *usbd_d if ((req->bmRequestType & 0x7F) != 0x21) return USBD_REQ_NOTSUPP; /* Only accept class request. */ - DEBUG("DFU: req %02x in state %d\n", req->bRequest, usbdfu_state); + DEBUG("DFU: Request %02x in state %d\n", req->bRequest, usbdfu_state); switch (req->bRequest) { case DFU_DNLOAD: @@ -170,9 +189,9 @@ static enum usbd_request_return_codes usbdfu_control_request(usbd_device *usbd_d usbdfu_state = STATE_DFU_MANIFEST_SYNC; } else { /* Copy download data for use on GET_STATUS. */ - prog.blocknum = req->wValue; - prog.len = *len; - memcpy(prog.buf, *buf, *len); + prog_page.blocknum = req->wValue; + prog_page.len = *len; + memcpy(prog_page.buf, *buf, *len); usbdfu_state = STATE_DFU_DNLOAD_SYNC; } return USBD_REQ_HANDLED; @@ -273,7 +292,7 @@ int main(void) // Simulate USB disconnect gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_OPENDRAIN, GPIO11 | GPIO12); gpio_clear(GPIOA, GPIO11 | GPIO12); - for (uint i=0; i<1000; i++) { + for (uint i=0; i<100; i++) { while (!systick_get_countflag()) ; } @@ -302,7 +321,7 @@ restart: ; u32 pc = app[1]; DEBUG("DFU: Starting application (sp=%08x, pc=%08x)\n", (uint) sp, (uint) pc); - if (sp & 0x2ffe0000 != 0x20000000) { + if ((sp & 0x2ffe0000) != 0x20000000) { DEBUG("DFU: Suspicious SP, refusing to start\n"); goto restart; } -- 2.39.5