From 443b3e5196248f713d2078ae310208b101581e6e Mon Sep 17 00:00:00 2001 From: Martin Mares Date: Tue, 25 Feb 2020 18:32:39 +0100 Subject: [PATCH] Bootloader: Checksum after flashing --- lib/dfu-bootloader.c | 107 ++++++++++++++++++++++++++++--------------- 1 file changed, 70 insertions(+), 37 deletions(-) diff --git a/lib/dfu-bootloader.c b/lib/dfu-bootloader.c index 1ef4806..1d7e02e 100644 --- a/lib/dfu-bootloader.c +++ b/lib/dfu-bootloader.c @@ -41,6 +41,9 @@ byte usbd_control_buffer[BLOCK_SIZE]; static enum dfu_state dfu_state = STATE_DFU_IDLE; +static uint timeout; +#define DEFAULT_TIMEOUT 5000 // ms +#define DFU_TIMEOUT 2000 static struct { byte buf[sizeof(usbd_control_buffer)]; @@ -118,6 +121,35 @@ const struct usb_config_descriptor config = { .interface = ifaces, }; +static inline u32 get_u32(u32 addr) +{ + return *(u32*)addr; +} + +static inline u16 get_u16(u32 addr) +{ + return *(u16*)addr; +} + +static bool verify_firmware(void) +{ + u32 len = get_u32(BOOTLOADER_APP_START + HDR_LENGTH); + u16 flash_in_progress = get_u16(BOOTLOADER_APP_START + HDR_FLASH_IN_PROGRESS); + + // FIXME: Should check if len is reasonable + + crc_reset(); + u32 crc = crc_calculate_block((u32 *)BOOTLOADER_APP_START, len/4); + u32 want_crc = get_u32(BOOTLOADER_APP_START + len); + DEBUG("DFU: fip=%04x crc=%08x/%08x len=%u\n", (uint) flash_in_progress, (uint) crc, (uint) want_crc, (uint) len); + if (flash_in_progress || crc != want_crc) { + DEBUG("DFU: Bad firmware\n"); + return 0; + } + + return 1; +} + static byte dfu_getstatus(usbd_device *usbd_dev UNUSED, u32 *bwPollTimeout) { switch (dfu_state) { @@ -148,10 +180,8 @@ static void dfu_getstatus_complete(usbd_device *usbd_dev UNUSED, struct usb_setu DEBUG("DFU: Block %u -> %08x + %u\n", prog.blocknum, (uint) baseaddr, prog.len); flash_unlock(); 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); - } + for (uint i = 0; i < prog.len; i += 2) + flash_program_half_word(baseaddr + i, *(u16*)(prog.buf + i)); flash_lock(); for (uint i = 0; i < prog.len; i++) { if (*(byte *)(baseaddr + i) != prog.buf[i]) { @@ -166,7 +196,10 @@ static void dfu_getstatus_complete(usbd_device *usbd_dev UNUSED, struct usb_setu flash_unlock(); flash_program_half_word(BOOTLOADER_APP_START + 0x20, 0); flash_lock(); - dfu_state = STATE_DFU_MANIFEST_WAIT_RESET; + if (verify_firmware()) + dfu_state = STATE_DFU_MANIFEST_WAIT_RESET; + else + dfu_state = STATE_DFU_ERROR; return; default: return; @@ -183,6 +216,7 @@ static enum usbd_request_return_codes dfu_control_request(usbd_device *usbd_dev, return USBD_REQ_NOTSUPP; /* Only accept class request. */ DEBUG("DFU: Request %02x in state %d\n", req->bRequest, dfu_state); + timeout = DFU_TIMEOUT; switch (req->bRequest) { case DFU_DNLOAD: @@ -233,10 +267,10 @@ static enum usbd_request_return_codes dfu_control_request(usbd_device *usbd_dev, static void dfu_set_config(usbd_device *usbd_dev, u16 wValue UNUSED) { usbd_register_control_callback( - usbd_dev, - USB_REQ_TYPE_CLASS | USB_REQ_TYPE_INTERFACE, - USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT, - dfu_control_request); + usbd_dev, + USB_REQ_TYPE_CLASS | USB_REQ_TYPE_INTERFACE, + USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT, + dfu_control_request); } static void dfu_reset(void) @@ -328,15 +362,8 @@ static void reset_peripherals(void) RCC_APB2RSTR = 0; } -int main(void) +static void configure_hardware(void) { - usbd_device *usbd_dev; - - reset_peripherals(); - - // Flash programming requires running on the internal oscillator - my_rcc_clock_setup_in_hsi_out_48mhz(); - rcc_periph_clock_enable(RCC_GPIOA); rcc_periph_clock_enable(RCC_GPIOC); rcc_periph_clock_enable(RCC_USB); @@ -368,18 +395,33 @@ int main(void) systick_set_frequency(1000, CPU_CLOCK_MHZ * 1000000); systick_clear(); systick_counter_enable(); +} - desig_get_unique_id_as_dfu(usb_serial_number); - - DEBUG("DFU: Entered boot-loader (SN %s)\n", usb_serial_number); - - // Simulate USB disconnect +static void usb_disconnect(void) +{ 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<100; i++) { while (!systick_get_countflag()) ; } +} + +int main(void) +{ + usbd_device *usbd_dev; + + reset_peripherals(); + + // Flash programming requires running on the internal oscillator + my_rcc_clock_setup_in_hsi_out_48mhz(); + + configure_hardware(); + desig_get_unique_id_as_dfu(usb_serial_number); + + DEBUG("DFU: Started (SN %s)\n", usb_serial_number); + + usb_disconnect(); DEBUG("DFU: Ready\n"); debug_led(0); @@ -390,32 +432,23 @@ int main(void) restart: ; - uint timeout = 5000; + timeout = DEFAULT_TIMEOUT; while (timeout || (dfu_state != STATE_DFU_IDLE && dfu_state != STATE_DFU_MANIFEST_WAIT_RESET)) { usbd_poll(usbd_dev); if (timeout && systick_get_countflag()) { timeout--; + // FIXME: Blink LED even after timeout if (!(timeout & 0x3f)) debug_led_toggle(); } } - u32 *app = (u32 *) BOOTLOADER_APP_START; - u32 sp = app[0]; - u32 pc = app[1]; - u32 len = app[HDR_LENGTH/4]; - u16 flash_in_progress = *(u16 *)(BOOTLOADER_APP_START + HDR_FLASH_IN_PROGRESS); - - crc_reset(); - u32 crc = crc_calculate_block(app, len/4); - u32 want_crc = *(u32 *)(BOOTLOADER_APP_START + len); - DEBUG("DFU: fip=%04x, crc=%08x, want=%08x, len=%u\n", (uint) flash_in_progress, (uint) crc, (uint) want_crc, (uint) len); - if (flash_in_progress || crc != want_crc) { - DEBUG("DFU: Bad firmware\n"); + if (!verify_firmware()) goto restart; - } - DEBUG("DFU: Starting application (sp=%08x, pc=%08x)\n", (uint) sp, (uint) pc); + u32 sp = get_u32(BOOTLOADER_APP_START); + u32 pc = get_u32(BOOTLOADER_APP_START + 4); + DEBUG("DFU: Boot (sp=%08x pc=%08x)\n", (uint) sp, (uint) pc); #ifdef DEBUG_USART while (!usart_get_flag(DEBUG_USART, USART_FLAG_TC)) -- 2.39.5