diff options
Diffstat (limited to 'projects/bootloader/bootloader.c')
-rw-r--r-- | projects/bootloader/bootloader.c | 126 |
1 files changed, 126 insertions, 0 deletions
diff --git a/projects/bootloader/bootloader.c b/projects/bootloader/bootloader.c new file mode 100644 index 0000000..ab3c1d9 --- /dev/null +++ b/projects/bootloader/bootloader.c @@ -0,0 +1,126 @@ +/* + * bootloader.c + * ------------ + * Bootloader to either install new firmware received from the MGMT UART, + * or jump to previously installed firmware. + * + * Copyright (c) 2016, NORDUnet A/S All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the NORDUnet nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "stm-init.h" +#include "stm-led.h" +#include "stm-uart.h" +#include "dfu.h" + +/* Linker symbols are strange in C. Make regular pointers for sanity. */ +__IO uint32_t *dfu_control = &CRYPTECH_DFU_CONTROL; +__IO uint32_t *dfu_firmware = &CRYPTECH_FIRMWARE_START; +/* The first word in the firmware is an address to the stack (msp) */ +__IO uint32_t *dfu_msp_ptr = &CRYPTECH_FIRMWARE_START; +/* The second word in the firmware is a pointer to the code + * (points at the Reset_Handler from the linker script). + */ +__IO uint32_t *dfu_code_ptr = &CRYPTECH_FIRMWARE_START + 1; + +typedef void (*pFunction)(void); + +/* This is it's own function to make it more convenient to set a breakpoint at it in gdb */ +void do_early_dfu_jump(void) +{ + pFunction loaded_app = (pFunction) *dfu_code_ptr; + /* Set the stack pointer to the correct one for the firmware */ + __set_MSP(*dfu_msp_ptr); + /* Set the Vector Table Offset Register */ + SCB->VTOR = (uint32_t) dfu_firmware; + loaded_app(); + while (1); +} + +int should_dfu() +{ + int i; + uint8_t rx = 0; + + /* While blinking the blue LED for one second, see if we receive a CR on the MGMT UART. + * We've discussed also requiring one or both of the FPGA config jumpers installed + * before allowing DFU of the STM32 - that check could be done here. + */ + led_on(LED_BLUE); + for (i = 0; i < 10; i++) { + HAL_Delay(100); + led_toggle(LED_BLUE); + if (uart_recv_char2(STM_UART_MGMT, &rx, 0) == HAL_OK) { + if (rx == 13) return 1; + } + } + return 0; +} + +int +main() +{ + int status; + + /* Check if we've just rebooted in order to jump to the firmware. */ + if (*dfu_control == HARDWARE_EARLY_DFU_JUMP) { + *dfu_control = 0; + do_early_dfu_jump(); + } + + stm_init(); + + uart_send_string2(STM_UART_MGMT, (char *) "\r\n\r\nThis is the bootloader speaking..."); + + if (should_dfu()) { + led_off(LED_BLUE); + if ((status = dfu_receive_firmware()) != 0) { + /* Upload of new firmware failed, reboot after lighting the red LED + * for three seconds. + */ + led_off(LED_BLUE); + led_on(LED_RED); + uart_send_string2(STM_UART_MGMT, (char *) "dfu_receive_firmware failed: "); + uart_send_number2(STM_UART_MGMT, status, 3, 16); + uart_send_string2(STM_UART_MGMT, (char *) "\r\n\r\nRebooting in three seconds\r\n"); + HAL_Delay(3000); + HAL_NVIC_SystemReset(); + while (1) {}; + } + } + + /* Set dfu_control to the magic value that will cause the us to call do_early_dfu_jump + * after rebooting back into this main() function. + */ + *dfu_control = HARDWARE_EARLY_DFU_JUMP; + + uart_send_string2(STM_UART_MGMT, (char *) "loading firmware\r\n\r\n"); + + /* De-initialize hardware by rebooting */ + HAL_NVIC_SystemReset(); + while (1) {}; +} |