From d1e963479ee109dba6de1121dc91393f678e5607 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Fri, 3 Mar 2017 00:34:17 +0100 Subject: [PATCH] DFU: fix transitions between runtime and DFU mode we now always go through a processor reset to avoid any state that might be persistent/left-over during the switch. --- .../libchip_sam3s/source/USBD_HAL.c | 14 ++++++++++++-- .../atmel_softpack_libraries/usb/device/dfu/dfu.h | 3 +-- .../usb/device/dfu/dfu_driver.c | 3 +-- .../usb/device/dfu/dfu_runtime.c | 12 +++++++----- .../libboard/common/source/board_cstartup_gnu.c | 8 ++++++-- 5 files changed, 27 insertions(+), 13 deletions(-) diff --git a/firmware/atmel_softpack_libraries/libchip_sam3s/source/USBD_HAL.c b/firmware/atmel_softpack_libraries/libchip_sam3s/source/USBD_HAL.c index 7214f4e7..3fa4c64b 100644 --- a/firmware/atmel_softpack_libraries/libchip_sam3s/source/USBD_HAL.c +++ b/firmware/atmel_softpack_libraries/libchip_sam3s/source/USBD_HAL.c @@ -1163,10 +1163,20 @@ void USBD_IrqHandler(void) TRACE_INFO_WP("EoBRes "); -#if defined(BOARD_USB_DFU) && defined(APPLICATION_dfu) +#if defined(BOARD_USB_DFU) +#if defined(APPLICATION_dfu) + /* if we are currently in the DFU bootloader, and we are beyond + * the MANIFEST stage, we shall switch to the normal + * application */ if (g_dfu->past_manifest) USBDFU_SwitchToApp(); -#endif +#else + /* if we are currently in the main application, and we are in + * appDETACH state, switch into the DFU bootloader */ + if (g_dfu->state == DFU_STATE_appDETACH) + DFURT_SwitchToDFU(); +#endif /* APPLICATION_dfu */ +#endif /* BOARD_USB_DFU */ /* Flush and enable the Suspend interrupt */ UDP->UDP_ICR = UDP_ICR_WAKEUP | UDP_ICR_RXRSM | UDP_ICR_RXSUSP; diff --git a/firmware/atmel_softpack_libraries/usb/device/dfu/dfu.h b/firmware/atmel_softpack_libraries/usb/device/dfu/dfu.h index b49cce08..dd0e5e2c 100644 --- a/firmware/atmel_softpack_libraries/usb/device/dfu/dfu.h +++ b/firmware/atmel_softpack_libraries/usb/device/dfu/dfu.h @@ -86,12 +86,11 @@ extern const USBDDriverDescriptors dfu_descriptors; /* magic value we use during boot to detect if we should start in DFU * mode or runtime mode */ #define USB_DFU_MAGIC 0xDFDFDFDF -/* RAM address for this magic value above */ -#define USB_DFU_MAGIC_ADDR IRAM_ADDR /* The API between the core DFU handler and the board/soc specific code */ struct dfudata { + uint32_t magic; uint8_t status; uint32_t state; int past_manifest; diff --git a/firmware/atmel_softpack_libraries/usb/device/dfu/dfu_driver.c b/firmware/atmel_softpack_libraries/usb/device/dfu/dfu_driver.c index f5e7c828..16e07d3a 100644 --- a/firmware/atmel_softpack_libraries/usb/device/dfu/dfu_driver.c +++ b/firmware/atmel_softpack_libraries/usb/device/dfu/dfu_driver.c @@ -457,7 +457,7 @@ void USBDFU_Initialize(const USBDDriverDescriptors *pDescriptors) void USBDFU_SwitchToApp(void) { /* make sure the MAGIC is not set to enter DFU again */ - *(unsigned int *)USB_DFU_MAGIC_ADDR = 0; + g_dfu->magic = 0; printf("switching to app\r\n"); @@ -468,7 +468,6 @@ void USBDFU_SwitchToApp(void) __disable_irq(); /* Tell the hybrid to execute FTL JUMP! */ - //BootIntoApp(); NVIC_SystemReset(); } diff --git a/firmware/atmel_softpack_libraries/usb/device/dfu/dfu_runtime.c b/firmware/atmel_softpack_libraries/usb/device/dfu/dfu_runtime.c index ba9665ee..b71a572d 100644 --- a/firmware/atmel_softpack_libraries/usb/device/dfu/dfu_runtime.c +++ b/firmware/atmel_softpack_libraries/usb/device/dfu/dfu_runtime.c @@ -178,15 +178,17 @@ out: void DFURT_SwitchToDFU(void) { - unsigned int *dfu_except_tbl = (unsigned int *)IFLASH_ADDR; - void (*toDFU)(void) = (void *)dfu_except_tbl[1]; - - *(unsigned int *)USB_DFU_MAGIC_ADDR = USB_DFU_MAGIC; + /* store the magic value that the DFU loader can detect and + * activate itself, rather than boot into the application */ + g_dfu->magic = USB_DFU_MAGIC; + /* Disconnect the USB by remoting the pull-up */ USBD_Disconnect(); __disable_irq(); - toDFU(); + /* reset the processor, we will start execution with the + * ResetVector of the bootloader */ + NVIC_SystemReset(); } void USBDCallbacks_RequestReceived(const USBGenericRequest *request) diff --git a/firmware/libboard/common/source/board_cstartup_gnu.c b/firmware/libboard/common/source/board_cstartup_gnu.c index f4792f58..bc89b1b8 100644 --- a/firmware/libboard/common/source/board_cstartup_gnu.c +++ b/firmware/libboard/common/source/board_cstartup_gnu.c @@ -125,6 +125,7 @@ IntFunc exception_table[] = { }; #if defined(BOARD_USB_DFU) && defined(APPLICATION_dfu) +#include "usb/device/dfu/dfu.h" static void BootIntoApp(void) { unsigned int *pSrc; @@ -134,7 +135,7 @@ static void BootIntoApp(void) SCB->VTOR = ((unsigned int)(pSrc)) | (0x0 << 7); appReset = pSrc[1]; - printf("Booting into App from %p, PC=%p\r\n", pSrc, appReset); + g_dfu->state = DFU_STATE_appIDLE; appReset(); } @@ -153,8 +154,11 @@ void ResetException( void ) #if defined(BOARD_USB_DFU) && defined(APPLICATION_dfu) - if (*(unsigned long *)IRAM_ADDR != 0xDFDFDFDF) + if (g_dfu->magic != USB_DFU_MAGIC) { BootIntoApp(); + /* Infinite loop */ + while ( 1 ) ; + } #endif /* Initialize the relocate segment */