aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKévin Redon <kredon@sysmocom.de>2019-12-11 17:04:21 +0100
committerlaforge <laforge@osmocom.org>2020-01-16 20:35:04 +0000
commitb6e2f0f8e72acba7501dffe32bd49fed19020533 (patch)
tree351ca3618bbc07765fe143009ef5538b9fb07576
parent34200e4676634b0c41b7ea59b16fe2f03254c098 (diff)
DFU: add DFU application
this adds the DFU as application, allowing to flash the bootloader. a USB DFU alternative is added to flash the bootloader partition. when the DFU is started as bootloader, the partition/alternative to flash the bootloader is marked as "not available", and ineffective. the same happens for the application partition when DFU is started as application. this distinction is make at compile time, not at runtime, because of size restrictions (the bootloader was already close to the 16 kB limit). *_dfu_flash.bin should not be mixed with *_dfu_dfu.bin. *_dfu_dfu.bin should be flashed as application using the already existing DFU bootloader. once this images is started (as application), the *_dfu_flash.bin should be flashed as bootloader using the DFU application. once the DFU bootloader has been flashed, soft resetting (not re-powering) will cause the bootloader to start, allowing to flash the application with a normal image (e.g. not DFU), replacing the DFU application. this switch to DFU only happens after downloading (e.g. flashing). it is planned to have the DFU application erase itself after flashing, but this is currently not implemented. Change-Id: Ic273bb593a7669111b0219fe301d7897419167c8
-rw-r--r--firmware/Makefile2
-rw-r--r--firmware/apps/dfu/main.c35
-rw-r--r--firmware/apps/dfu/usb_strings.txt1
-rw-r--r--firmware/atmel_softpack_libraries/libchip_sam3s/source/USBD_HAL.c13
-rw-r--r--firmware/atmel_softpack_libraries/usb/device/dfu/dfu.h3
-rw-r--r--firmware/atmel_softpack_libraries/usb/device/dfu/dfu_desc.c29
-rw-r--r--firmware/atmel_softpack_libraries/usb/device/dfu/dfu_driver.c17
-rw-r--r--firmware/libboard/common/include/board_common.h5
-rw-r--r--firmware/libboard/common/source/board_cstartup_gnu.c7
9 files changed, 92 insertions, 20 deletions
diff --git a/firmware/Makefile b/firmware/Makefile
index 5c7aa92..bdca6e5 100644
--- a/firmware/Makefile
+++ b/firmware/Makefile
@@ -41,7 +41,7 @@ APP ?= dfu
# Defines which are the available memory targets for the SAM3S-EK board.
ifeq ($(APP), dfu)
-MEMORIES ?= flash
+MEMORIES ?= flash dfu
else
MEMORIES ?= dfu
endif
diff --git a/firmware/apps/dfu/main.c b/firmware/apps/dfu/main.c
index 5aafc7c..2e80884 100644
--- a/firmware/apps/dfu/main.c
+++ b/firmware/apps/dfu/main.c
@@ -26,8 +26,15 @@
#include <osmocom/core/timer.h>
+/* USB alternate interface index used to identify which partition to flash */
+/** USB alternate interface index indicating RAM partition */
#define ALTIF_RAM 0
+/** USB alternate interface index indicating flash partition */
+#if defined(ENVIRONMENT_flash)
#define ALTIF_FLASH 1
+#elif defined(ENVIRONMENT_dfu)
+#define ALTIF_FLASH 2
+#endif
unsigned int g_unique_id[4];
/* remember if the watchdog has been configured in the main loop so we can kick it in the ISR */
@@ -44,10 +51,18 @@ static const Pin pinsLeds[] = { PINS_LEDS } ;
*----------------------------------------------------------------------------*/
#define RAM_ADDR(offset) (IRAM_ADDR + BOARD_DFU_RAM_SIZE + offset)
+#if defined(ENVIRONMENT_flash)
#define FLASH_ADDR(offset) (IFLASH_ADDR + BOARD_DFU_BOOT_SIZE + offset)
+#elif defined(ENVIRONMENT_dfu)
+#define FLASH_ADDR(offset) (IFLASH_ADDR + offset)
+#endif
-#define IFLASH_END ((uint8_t *)IFLASH_ADDR + IFLASH_SIZE)
-#define IRAM_END ((uint8_t *)IRAM_ADDR + IRAM_SIZE)
+#define IRAM_END ((uint8_t *)IRAM_ADDR + IRAM_SIZE)
+#if defined(ENVIRONMENT_flash)
+#define IFLASH_END ((uint8_t *)IFLASH_ADDR + IFLASH_SIZE)
+#elif defined(ENVIRONMENT_dfu)
+#define IFLASH_END ((uint8_t *)IFLASH_ADDR + BOARD_DFU_BOOT_SIZE)
+#endif
/* incoming call-back: Host has transferred 'len' bytes (stored at
* 'data'), which we shall write to 'offset' into the partition
@@ -90,7 +105,11 @@ int USBDFU_handle_dnload(uint8_t altif, unsigned int offset,
break;
case ALTIF_FLASH:
addr = FLASH_ADDR(offset);
+#if defined(ENVIRONMENT_flash)
if (addr < IFLASH_ADDR || addr + len >= IFLASH_ADDR + IFLASH_SIZE) {
+#elif defined(ENVIRONMENT_dfu)
+ if (addr < IFLASH_ADDR || addr + len >= IFLASH_ADDR + BOARD_DFU_BOOT_SIZE) {
+#endif
g_dfu->state = DFU_STATE_dfuERROR;
g_dfu->status = DFU_STATUS_errADDRESS;
rc = DFU_RET_STALL;
@@ -281,12 +300,12 @@ extern int main(void)
TRACE_INFO("DFU bootloader start reason: ");
switch (USBDFU_OverrideEnterDFU()) {
case 0:
- /* 0 normally means that there is no override, but we are in the bootloader,
- * thus the first check in board_cstartup_gnu did return something else than 0.
- * this can only be g_dfu->magic which is erased when the segment are
- * relocated, which happens in board_cstartup_gnu just after USBDFU_OverrideEnterDFU.
- * no static variable can be used to store this case since this will also be overwritten
- */
+ if (SCB->VTOR < IFLASH_ADDR + BOARD_DFU_BOOT_SIZE) {
+ TRACE_INFO_WP("unknown\n\r");
+ } else {
+ TRACE_INFO_WP("DFU is the main application\n\r");
+ }
+ break;
case 1:
TRACE_INFO_WP("DFU switch requested by main application\n\r");
break;
diff --git a/firmware/apps/dfu/usb_strings.txt b/firmware/apps/dfu/usb_strings.txt
index f1c79bc..4a58cb8 100644
--- a/firmware/apps/dfu/usb_strings.txt
+++ b/firmware/apps/dfu/usb_strings.txt
@@ -3,3 +3,4 @@ PRODUCT_STRING
DFU (Device Firmware Upgrade)
RAM
Flash (Application Partition)
+Flash (Bootloader Partition)
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 ac2595c..1ebab5b 100644
--- a/firmware/atmel_softpack_libraries/libchip_sam3s/source/USBD_HAL.c
+++ b/firmware/atmel_softpack_libraries/libchip_sam3s/source/USBD_HAL.c
@@ -1171,12 +1171,19 @@ void USBD_IrqHandler(void)
/* 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)
+ if (g_dfu->past_manifest) {
+#if defined(ENVIRONMENT_flash)
USBDFU_SwitchToApp();
+#elif defined(ENVIRONMENT_dfu)
+ USBDFU_SwitchToDFU();
+#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)
+ * appDETACH state or past downloading, switch into the DFU bootloader.
+ */
+ if (g_dfu->state == DFU_STATE_appDETACH || g_dfu->state == DFU_STATE_dfuMANIFEST)
DFURT_SwitchToDFU();
#endif /* APPLICATION_dfu */
#endif /* BOARD_USB_DFU */
diff --git a/firmware/atmel_softpack_libraries/usb/device/dfu/dfu.h b/firmware/atmel_softpack_libraries/usb/device/dfu/dfu.h
index 7354696..5bd8684 100644
--- a/firmware/atmel_softpack_libraries/usb/device/dfu/dfu.h
+++ b/firmware/atmel_softpack_libraries/usb/device/dfu/dfu.h
@@ -124,6 +124,9 @@ void USBDFU_Initialize(const USBDDriverDescriptors *pDescriptors);
/* USBD tells us to switch from DFU mode to application mode */
void USBDFU_SwitchToApp(void);
+/* USBD tells us to switch from to DFU mode */
+void USBDFU_SwitchToDFU(void);
+
/* Return values to be used by USBDFU_handle_{dn,up}load */
#define DFU_RET_NOTHING 0
#define DFU_RET_ZLP 1
diff --git a/firmware/atmel_softpack_libraries/usb/device/dfu/dfu_desc.c b/firmware/atmel_softpack_libraries/usb/device/dfu/dfu_desc.c
index ebbe070..faebc13 100644
--- a/firmware/atmel_softpack_libraries/usb/device/dfu/dfu_desc.c
+++ b/firmware/atmel_softpack_libraries/usb/device/dfu/dfu_desc.c
@@ -19,9 +19,10 @@ enum {
STR_MANUF = 1,
STR_PROD,
STR_CONFIG,
+ // strings for the first alternate interface (e.g. DFU)
_STR_FIRST_ALT,
// serial string
- STR_SERIAL = (_STR_FIRST_ALT+BOARD_DFU_NUM_IF),
+ STR_SERIAL = (_STR_FIRST_ALT + BOARD_DFU_NUM_IF),
// version string (on additional interface)
VERSION_CONF_STR,
VERSION_STR,
@@ -29,6 +30,25 @@ enum {
STRING_DESC_CNT,
};
+/* string used to replace one of both DFU flash partition atlsettings */
+static const unsigned char usb_string_notavailable[] = {
+ USBStringDescriptor_LENGTH(13),
+ USBGenericDescriptor_STRING,
+ USBStringDescriptor_UNICODE('n'),
+ USBStringDescriptor_UNICODE('o'),
+ USBStringDescriptor_UNICODE('t'),
+ USBStringDescriptor_UNICODE(' '),
+ USBStringDescriptor_UNICODE('a'),
+ USBStringDescriptor_UNICODE('v'),
+ USBStringDescriptor_UNICODE('a'),
+ USBStringDescriptor_UNICODE('i'),
+ USBStringDescriptor_UNICODE('l'),
+ USBStringDescriptor_UNICODE('a'),
+ USBStringDescriptor_UNICODE('b'),
+ USBStringDescriptor_UNICODE('l'),
+ USBStringDescriptor_UNICODE('e'),
+};
+
/* USB string for the serial (using 128-bit device ID) */
static unsigned char usb_string_serial[] = {
USBStringDescriptor_LENGTH(32),
@@ -121,7 +141,7 @@ static const USBDeviceDescriptor fsDevice = {
.bNumEndpoints = 0, \
.bInterfaceClass = 0xfe, \
.bInterfaceSubClass = 1, \
- .iInterface = (_STR_FIRST_ALT+ALT), \
+ .iInterface = (_STR_FIRST_ALT + ALT), \
.bInterfaceProtocol = 2, \
}
@@ -180,6 +200,11 @@ void set_usb_serial_str(void)
for (i = 0; i < ARRAY_SIZE(usb_strings) && i < ARRAY_SIZE(usb_strings_extended); i++) {
usb_strings_extended[i] = usb_strings[i];
}
+#if defined(ENVIRONMENT_dfu)
+ usb_strings_extended[_STR_FIRST_ALT + 1] = usb_string_notavailable;
+#elif defined(ENVIRONMENT_flash)
+ usb_strings_extended[_STR_FIRST_ALT + 2] = usb_string_notavailable;
+#endif
usb_strings_extended[STR_SERIAL] = usb_string_serial;
usb_strings_extended[VERSION_CONF_STR] = usb_string_version_conf;
usb_strings_extended[VERSION_STR] = usb_string_version;
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 1cca7ab..cfb9f63 100644
--- a/firmware/atmel_softpack_libraries/usb/device/dfu/dfu_driver.c
+++ b/firmware/atmel_softpack_libraries/usb/device/dfu/dfu_driver.c
@@ -43,7 +43,7 @@ static unsigned char if_altsettings[1];
/** structure containing the DFU state and magic value to know if DFU or application should be started */
__dfudata struct dfudata _g_dfu = {
- .state = DFU_STATE_appIDLE,
+ .state = DFU_STATE_dfuIDLE,
.past_manifest = 0,
.total_bytes = 0,
};
@@ -463,7 +463,20 @@ void USBDFU_SwitchToApp(void)
/* make sure the MAGIC is not set to enter DFU again */
g_dfu->magic = 0;
- printf("switching to app\r\n");
+ /* disconnect from USB to ensure re-enumeration */
+ USBD_Disconnect();
+
+ /* disable any interrupts during transition */
+ __disable_irq();
+
+ /* Tell the hybrid to execute FTL JUMP! */
+ NVIC_SystemReset();
+}
+
+void USBDFU_SwitchToDFU(void)
+{
+ /* make sure the MAGIC is not set to enter DFU again */
+ g_dfu->magic = USB_DFU_MAGIC;
/* disconnect from USB to ensure re-enumeration */
USBD_Disconnect();
diff --git a/firmware/libboard/common/include/board_common.h b/firmware/libboard/common/include/board_common.h
index dd21e4b..7c4b908 100644
--- a/firmware/libboard/common/include/board_common.h
+++ b/firmware/libboard/common/include/board_common.h
@@ -112,10 +112,13 @@
#define BOARD_USB_UDP
#define BOARD_USB_DFU
+
+
#define BOARD_DFU_BOOT_SIZE (16 * 1024)
#define BOARD_DFU_RAM_SIZE (2 * 1024)
#define BOARD_DFU_PAGE_SIZE 512
-#define BOARD_DFU_NUM_IF 2
+/** number of DFU interfaces (used to flash specific partitions) */
+#define BOARD_DFU_NUM_IF 3
extern void board_exec_dbg_cmd(int ch);
extern void board_main_top(void);
diff --git a/firmware/libboard/common/source/board_cstartup_gnu.c b/firmware/libboard/common/source/board_cstartup_gnu.c
index e82a2fb..d548a30 100644
--- a/firmware/libboard/common/source/board_cstartup_gnu.c
+++ b/firmware/libboard/common/source/board_cstartup_gnu.c
@@ -126,7 +126,7 @@ IntFunc exception_table[] = {
IrqHandlerNotUsed /* 35 not used */
};
-#if defined(BOARD_USB_DFU) && defined(APPLICATION_dfu)
+#if defined(BOARD_USB_DFU) && defined(APPLICATION_dfu) && defined(ENVIRONMENT_flash)
#include "usb/device/dfu/dfu.h"
static void BootIntoApp(void)
{
@@ -159,8 +159,9 @@ void ResetException( void )
LowLevelInit() ;
-#if defined(BOARD_USB_DFU) && defined(APPLICATION_dfu)
- if (!USBDFU_OverrideEnterDFU()) {
+#if defined(BOARD_USB_DFU) && defined(APPLICATION_dfu) && defined(ENVIRONMENT_flash)
+ // boot application if there is not DFU override
+ if (!USBDFU_OverrideEnterDFU() && SCB->VTOR < IFLASH_ADDR + BOARD_DFU_BOOT_SIZE) {
UART_Exit();
__disable_irq();
BootIntoApp();