mirror of
https://gitea.osmocom.org/sim-card/simtrace2.git
synced 2026-03-23 16:58:33 +03:00
DFU: Introduce board/app-specific override for booting in DFU mode
Using the USBDFU_OverrideEnterDFU() function, a board/application can define extra conditions when the system should boot in DFU mode, even if it was not explicitly switched to DFU mode from the application. The app/dfu/main.c uses this mechanism to boot into DFU mode if the stack + reset vector addresses are not plausible (i.e. some random junk appears to be flashed in the application partition) or if the user places a jumper accross the RxD+TxD lines of the debug UART. The idea is that the system can be recovered by placing this jumper and then re-installing the application from DFU.
This commit is contained in:
@@ -103,6 +103,57 @@ int USBDFU_handle_upload(uint8_t altif, unsigned int offset,
|
|||||||
return req_len;
|
return req_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int uart_has_loopback_jumper(void)
|
||||||
|
{
|
||||||
|
unsigned int i;
|
||||||
|
const Pin uart_loopback_pins[] = {
|
||||||
|
{PIO_PA9A_URXD0, PIOA, ID_PIOA, PIO_INPUT, PIO_DEFAULT},
|
||||||
|
{PIO_PA10A_UTXD0, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT}
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Configure UART pins as I/O */
|
||||||
|
PIO_Configure(uart_loopback_pins, PIO_LISTSIZE(uart_loopback_pins));
|
||||||
|
|
||||||
|
for (i = 0; i < 10; i++) {
|
||||||
|
/* Set TxD high; abort if RxD doesn't go high either */
|
||||||
|
PIO_Set(&uart_loopback_pins[1]);
|
||||||
|
if (!PIO_Get(&uart_loopback_pins[0]))
|
||||||
|
return 0;
|
||||||
|
/* Set TxD low, abort if RxD doesn't go low either */
|
||||||
|
PIO_Clear(&uart_loopback_pins[1]);
|
||||||
|
if (PIO_Get(&uart_loopback_pins[0]))
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/* if we reached here, RxD always follows TxD and thus a
|
||||||
|
* loopback jumper has been placed on RxD/TxD, and we will boot
|
||||||
|
* into DFU unconditionally */
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* using this function we can determine if we should enter DFU mode
|
||||||
|
* during boot, or if we should proceed towards the application/runtime */
|
||||||
|
int USBDFU_OverrideEnterDFU(void)
|
||||||
|
{
|
||||||
|
uint32_t *app_part = (uint32_t *)FLASH_ADDR(0);
|
||||||
|
|
||||||
|
/* If the loopback jumper is set, we enter DFU mode */
|
||||||
|
if (uart_has_loopback_jumper())
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
/* if the first word of the application partition doesn't look
|
||||||
|
* like a stack pointer (i.e. point to RAM), enter DFU mode */
|
||||||
|
if ((app_part[0] < IRAM_ADDR) ||
|
||||||
|
((uint8_t *)app_part[0] > IRAM_END))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
/* if the second word of the application partition doesn't look
|
||||||
|
* like a function from flash (reset vector), enter DFU mode */
|
||||||
|
if (((uint32_t *)app_part[1] < app_part) ||
|
||||||
|
((uint8_t *)app_part[1] > IFLASH_END))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* returns '1' in case we should break any endless loop */
|
/* returns '1' in case we should break any endless loop */
|
||||||
static void check_exec_dbg_cmd(void)
|
static void check_exec_dbg_cmd(void)
|
||||||
|
|||||||
@@ -110,6 +110,7 @@ extern int USBDFU_handle_dnload(uint8_t altif, unsigned int offset,
|
|||||||
uint8_t *data, unsigned int len);
|
uint8_t *data, unsigned int len);
|
||||||
extern int USBDFU_handle_upload(uint8_t altif, unsigned int offset,
|
extern int USBDFU_handle_upload(uint8_t altif, unsigned int offset,
|
||||||
uint8_t *data, unsigned int req_len);
|
uint8_t *data, unsigned int req_len);
|
||||||
|
extern int USBDFU_OverrideEnterDFU(void);
|
||||||
|
|
||||||
/* function to be called at end of EP0 handler during runtime */
|
/* function to be called at end of EP0 handler during runtime */
|
||||||
void USBDFU_Runtime_RequestHandler(const USBGenericRequest *request);
|
void USBDFU_Runtime_RequestHandler(const USBGenericRequest *request);
|
||||||
|
|||||||
@@ -472,6 +472,14 @@ void USBDFU_SwitchToApp(void)
|
|||||||
NVIC_SystemReset();
|
NVIC_SystemReset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* A board can provide a function overriding this, enabling a
|
||||||
|
* board-specific 'boot into DFU' override, like a specific GPIO that
|
||||||
|
* needs to be pulled a certain way. */
|
||||||
|
WEAK int USBDFU_OverrideEnterDFU(void)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
void USBDCallbacks_RequestReceived(const USBGenericRequest *request)
|
void USBDCallbacks_RequestReceived(const USBGenericRequest *request)
|
||||||
{
|
{
|
||||||
USBDFU_DFU_RequestHandler(request);
|
USBDFU_DFU_RequestHandler(request);
|
||||||
|
|||||||
@@ -157,7 +157,7 @@ void ResetException( void )
|
|||||||
/* we are before the text segment has been relocated, so g_dfu is
|
/* we are before the text segment has been relocated, so g_dfu is
|
||||||
* not initialized yet */
|
* not initialized yet */
|
||||||
g_dfu = &_g_dfu;
|
g_dfu = &_g_dfu;
|
||||||
if (g_dfu->magic != USB_DFU_MAGIC) {
|
if ((g_dfu->magic != USB_DFU_MAGIC) && !USBDFU_OverrideEnterDFU()) {
|
||||||
BootIntoApp();
|
BootIntoApp();
|
||||||
/* Infinite loop */
|
/* Infinite loop */
|
||||||
while ( 1 ) ;
|
while ( 1 ) ;
|
||||||
|
|||||||
Reference in New Issue
Block a user