diff options
9 files changed, 328 insertions, 44 deletions
@@ -47,6 +47,7 @@ export LIBS = $(MBED_DIR)/libstmf4.a $(RTOS_DIR)/librtos.a # linker script export LDSCRIPT = $(BOARD_DIR)/TOOLCHAIN_GCC_ARM/STM32F429BI.ld +export BOOTLOADER_LDSCRIPT = $(BOARD_DIR)/TOOLCHAIN_GCC_ARM/STM32F429BI_bootloader.ld # board-specific objects, to link into every project export BOARD_OBJS = \ @@ -133,6 +134,9 @@ libhal-test: $(BOARD_OBJS) $(LIBS) $(LIBHAL_DIR)/libhal.a hsm: $(BOARD_OBJS) $(LIBS) $(LIBHAL_DIR)/libhal.a $(MAKE) -C projects/hsm +bootloader: $(BOARD_OBJS) $(LIBS) + $(MAKE) -C projects/bootloader + # don't automatically delete objects, to avoid a lot of unnecessary rebuilding .SECONDARY: $(BOARD_OBJS) @@ -1,9 +1,12 @@ -STM32 software for dev-bridge board -=================================== +STM32 software for dev-bridge/Alpha board +========================================= The dev-bridge board is a daughterboard for the Novena, which talks to the Novena's FPGA through the high-speed expansion connector. +The Alpha board is a stand-alone board with an Artix-7 FPGA, a STM32 Cortex-M4 +microcontroller, two USB interfaces etc. + See user/ft/stm32-dev-bridge/hardware/rev01 for schematics of the bridge board. There will be more information on the wiki shortly. @@ -50,33 +53,51 @@ Do "bin/flash-target" from the top level directory (where this file is) to flash a built image into the microcontroller. See the section ST-LINK below for information about the actual hardware programming device needed. +Example loading the bootloader and the led-test firmware to get some LEDs +flashing: + + $ make bootloader board-test + $ ./bin/flash-target projects/board-test/led-test + $ ./bin/flash-target projects/bootloader/bootloader + +At this point, the STM32 will reset into the bootloader which flashes the +blue LED five times in one second, and then execution of the LED test +firmware will begin. The LED test firmware will flash the green, yellow, +red and blue LEDs in order until the end of time. + ST-LINK ======= To program the MCU, an ST-LINK adapter is used. The cheapest way to get one is to buy an evaluation board with an ST-LINK integrated, and pinouts to program external chips. This should work with any evaluation board from -STM; we have tested with STM32F4DISCOVERY (with ST-LINK v2.0) and +STM; we have tested with STM32F4DISCOVERY (with ST-LINK v2.0) and NUCLEO-F411RE (with ST-LINK v2.1). -The ST-LINK programming pins are the 1+4 throughole pads above the ARM -on the circuit board. See the schematics for details, but the pinout -from left to right (1, space, 4) of rev01 is +The ST-LINK programming pins is called J1 and is near the CrypTech logo +printed on the circuit board. The pin-outs is shown on the circuit board +(follow the thin white line from J1 to the white box with STM32_SWD +written in it). From left to right, the pins are + + 3V3, CLK, GND, I/O, NRST and N/C - NRST, space, CLK, IO, GND, VCC +This matches the pin-out on the DISCO and NUCLEO boards we have tried. First remove the pair of ST-LINK jumpers (CN4 on the DISCO, CN2 on the NUCLEO). Then find the 6-pin SWD header on the left of the STM board (CN2 -on the DISCO, CN4 on the NUCLEO), and connect them to the dev-bridge -board: +on the DISCO, CN4 on the NUCLEO), and connect them to the Alpha board: -* 5 T_NRST <-> NRST -* 2 T_JTCK <-> CLK -* 4 T_JTMS <-> IO -* 3 GND <-> GND + NUCLEO / DISCO CRYPTECH ALPHA + -------------- -------------- +* 1 VDD_TARGET <-> 3V3 +* 2 SWCLK / T_JTCK <-> CLK +* 3 GND <-> GND +* 4 SWDIO / T_JTMS <-> IO +* 5 T_NRST / NRST <-> NRST -The dev-bridge board should be connected to the Novena and powered on -before attempting to flash it. +N/C (pin 6) means Not Connected. + +The Alpha board should be powered on before attempting to flash it. Debugging the firmware @@ -87,24 +108,13 @@ firmware in an STM32: http://fun-tech.se/stm32/OpenOCD/gdb.php -I've only managed to get the most basic text line gdb to work, -something along these lines: - -1) Start OpenOCD server (with a configuration file for your type of ST-LINK - adapter) - - $ openocd -f /usr/share/openocd/scripts/board/stm32f4discovery.cfg - -2) Connect to the OpenOCD server and re-flash already compiled firmware: - - $ telnet localhost 4444 - reset halt - flash probe 0 - stm32f2x mass_erase 0 - flash write_bank 0 /path/to/main.bin 0 - reset halt +There is a shell script called 'bin/debug' that starts an OpenOCD server +and GDB. Example: -3) Start GDB and have it connect to the OpenOCD server: + $ ./bin/debug projects/board-test/led-test - $ arm-none-eabi-gdb --eval-command="target remote localhost:3333" main.elf +Once in GDB, issue "monitor reset halt" to reset the STM32 before debugging. +Remember that the first code to run will be the bootloader, but if you do +e.g. "break main" and "continue" you will end up in led-test main() after +the bootloader has jumped there. diff --git a/libraries/mbed/targets/cmsis/TARGET_STM/TARGET_STM32F4/TARGET_CRYPTECH_ALPHA/TOOLCHAIN_GCC_ARM/STM32F429BI.ld b/libraries/mbed/targets/cmsis/TARGET_STM/TARGET_STM32F4/TARGET_CRYPTECH_ALPHA/TOOLCHAIN_GCC_ARM/STM32F429BI.ld index c78e619..ad7ddaf 100644 --- a/libraries/mbed/targets/cmsis/TARGET_STM/TARGET_STM32F4/TARGET_CRYPTECH_ALPHA/TOOLCHAIN_GCC_ARM/STM32F429BI.ld +++ b/libraries/mbed/targets/cmsis/TARGET_STM/TARGET_STM32F4/TARGET_CRYPTECH_ALPHA/TOOLCHAIN_GCC_ARM/STM32F429BI.ld @@ -1,12 +1,18 @@ -/* Linker script to configure memory regions. */ +/* Linker script to configure memory regions. + * + * This is the script for the firmware (meaning any application except the bootloader). + * It should be placed 128 KB from the start of the STM32 internal flash. + * + */ MEMORY { /* FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 2048k */ BOOTLOADER (rx) : ORIGIN = 0x08000000, LENGTH = 128K FIRMWARE (rx) : ORIGIN = 0x08000000 + 128K, LENGTH = 2048K - 128K - FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 2048K + FLASH (rx) : ORIGIN = 0x08000000 + 128K, LENGTH = 2048K - 128K RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 192K - 4 } +/* original: FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 2048K */ /* Linker script to place sections and symbol values. Should be used together * with other linker script that defines memory regions FLASH and RAM. diff --git a/libraries/mbed/targets/cmsis/TARGET_STM/TARGET_STM32F4/TARGET_CRYPTECH_ALPHA/TOOLCHAIN_GCC_ARM/STM32F429BI_bootloader.ld b/libraries/mbed/targets/cmsis/TARGET_STM/TARGET_STM32F4/TARGET_CRYPTECH_ALPHA/TOOLCHAIN_GCC_ARM/STM32F429BI_bootloader.ld new file mode 100644 index 0000000..2a5de56 --- /dev/null +++ b/libraries/mbed/targets/cmsis/TARGET_STM/TARGET_STM32F4/TARGET_CRYPTECH_ALPHA/TOOLCHAIN_GCC_ARM/STM32F429BI_bootloader.ld @@ -0,0 +1,172 @@ +/* Linker script to configure memory regions. + * + * This one is for the bootloader, so FLASH points at the real beginning of the + * STM32 internal flash memory (0x08000000). + * + */ +MEMORY +{ + /* FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 2048k */ + BOOTLOADER (rx) : ORIGIN = 0x08000000, LENGTH = 128K + FIRMWARE (rx) : ORIGIN = 0x08000000 + 128K, LENGTH = 2048K - 128K + FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 2048K + RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 192K - 4 +} + +/* Linker script to place sections and symbol values. Should be used together + * with other linker script that defines memory regions FLASH and RAM. + * It references following symbols, which must be defined in code: + * Reset_Handler : Entry of reset handler + * + * It defines following symbols, which code can use without definition: + * __exidx_start + * __exidx_end + * __etext + * __data_start__ + * __preinit_array_start + * __preinit_array_end + * __init_array_start + * __init_array_end + * __fini_array_start + * __fini_array_end + * __data_end__ + * __bss_start__ + * __bss_end__ + * __end__ + * end + * __HeapLimit + * __StackLimit + * __StackTop + * __stack + * _estack + */ +ENTRY(Reset_Handler) + +SECTIONS +{ + .text : + { + KEEP(*(.isr_vector)) + *(.text*) + KEEP(*(.init)) + KEEP(*(.fini)) + + /* .ctors */ + *crtbegin.o(.ctors) + *crtbegin?.o(.ctors) + *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors) + *(SORT(.ctors.*)) + *(.ctors) + + /* .dtors */ + *crtbegin.o(.dtors) + *crtbegin?.o(.dtors) + *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors) + *(SORT(.dtors.*)) + *(.dtors) + + *(.rodata*) + + KEEP(*(.eh_frame*)) + } > FLASH + + .ARM.extab : + { + *(.ARM.extab* .gnu.linkonce.armextab.*) + } > FLASH + + __exidx_start = .; + .ARM.exidx : + { + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + } > FLASH + __exidx_end = .; + + __etext = .; + _sidata = .; + + .data : AT (__etext) + { + __data_start__ = .; + _sdata = .; + *(vtable) + *(.data*) + + . = ALIGN(4); + /* preinit data */ + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP(*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + + . = ALIGN(4); + /* init data */ + PROVIDE_HIDDEN (__init_array_start = .); + KEEP(*(SORT(.init_array.*))) + KEEP(*(.init_array)) + PROVIDE_HIDDEN (__init_array_end = .); + + + . = ALIGN(4); + /* finit data */ + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP(*(SORT(.fini_array.*))) + KEEP(*(.fini_array)) + PROVIDE_HIDDEN (__fini_array_end = .); + + KEEP(*(.jcr*)) + . = ALIGN(4); + /* All data end */ + __data_end__ = .; + _edata = .; + + } > RAM + + .bss : + { + . = ALIGN(4); + __bss_start__ = .; + _sbss = .; + *(.bss*) + *(COMMON) + . = ALIGN(4); + __bss_end__ = .; + _ebss = .; + } > RAM + + .heap (COPY): + { + __end__ = .; + end = __end__; + *(.heap*) + __HeapLimit = .; + } > RAM + + /* .stack_dummy section doesn't contains any symbols. It is only + * used for linker to calculate size of stack sections, and assign + * values to stack symbols later */ + .stack_dummy (COPY): + { + *(.stack*) + } > RAM + + /* Set stack top to end of RAM, and stack limit move down by + * size of stack_dummy section */ + __StackTop = ORIGIN(RAM) + LENGTH(RAM); + _estack = __StackTop; + __StackLimit = __StackTop - SIZEOF(.stack_dummy); + PROVIDE(__stack = __StackTop); + + /* The DFU code needs to know where the firmware lives */ + CRYPTECH_BOOTLOADER_START = ORIGIN(BOOTLOADER); + CRYPTECH_BOOTLOADER_END = ORIGIN(BOOTLOADER) + LENGTH(BOOTLOADER) - 1; + CRYPTECH_FIRMWARE_START = ORIGIN(FIRMWARE); + CRYPTECH_FIRMWARE_END = ORIGIN(FIRMWARE) + LENGTH(FIRMWARE) - 1; + /* The last 4 bytes of RAM is used to control the DFU reset+jumping. + * Have to be reserved in here to not get overwritten by the Reset_Handler + * that zeros memory. Maybe there is a better way? + */ + CRYPTECH_DFU_CONTROL = ORIGIN(RAM) + LENGTH(RAM); + + /* Check if data + heap + stack exceeds RAM limit */ + ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed with stack") +} diff --git a/libraries/mbed/targets/cmsis/TARGET_STM/TARGET_STM32F4/TARGET_CRYPTECH_ALPHA/system_stm32f4xx.c b/libraries/mbed/targets/cmsis/TARGET_STM/TARGET_STM32F4/TARGET_CRYPTECH_ALPHA/system_stm32f4xx.c index cc527ae..2824fd6 100644 --- a/libraries/mbed/targets/cmsis/TARGET_STM/TARGET_STM32F4/TARGET_CRYPTECH_ALPHA/system_stm32f4xx.c +++ b/libraries/mbed/targets/cmsis/TARGET_STM/TARGET_STM32F4/TARGET_CRYPTECH_ALPHA/system_stm32f4xx.c @@ -75,8 +75,6 @@ #define HSI_VALUE ((uint32_t)16000000) /*!< Value of the Internal oscillator in Hz*/ #endif /* HSI_VALUE */ -extern uint32_t CRYPTECH_FIRMWARE_START; /* defined in the linker script (STM32F429BI.ld) */ - /** * @} */ @@ -200,13 +198,14 @@ void SystemInit(void) /* Configure the Vector Table location add offset address ------------------*/ /* cryptech: Don't change VTOR if it is already set up by the bootloader */ - if (SCB->VTOR != CRYPTECH_FIRMWARE_START) { #ifdef VECT_TAB_SRAM - SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM */ + SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM */ #else + /* Set up VTOR unless it has already been set by the bootloader. */ + if (! SCB->VTOR) { SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH */ -#endif } +#endif /* Configure the Cube driver */ SystemCoreClock = 16000000; // At this stage the HSI is used as system clock diff --git a/projects/bootloader/Makefile b/projects/bootloader/Makefile new file mode 100644 index 0000000..7cef633 --- /dev/null +++ b/projects/bootloader/Makefile @@ -0,0 +1,18 @@ +PROG = bootloader + +all: $(PROG:=.elf) + +%.elf: %.o $(BOARD_OBJS) $(LIBS) + $(CC) $(CFLAGS) $^ -o $@ -T$(BOOTLOADER_LDSCRIPT) -g -Wl,-Map=$*.map + $(OBJCOPY) -O ihex $*.elf $*.hex + $(OBJCOPY) -O binary $*.elf $*.bin + $(OBJDUMP) -St $*.elf >$*.lst + $(SIZE) $*.elf + +clean: + rm -f *.o + rm -f *.elf + rm -f *.hex + rm -f *.bin + rm -f *.map + rm -f *.lst diff --git a/projects/bootloader/bootloader.c b/projects/bootloader/bootloader.c new file mode 100644 index 0000000..1450c1a --- /dev/null +++ b/projects/bootloader/bootloader.c @@ -0,0 +1,78 @@ +/* + * Bootloader to either install new firmware received from the MGMT UART, + * or jump to previously installed firmware. + * + */ +#include "stm32f4xx_hal.h" +#include "stm-init.h" +#include "stm-led.h" +#include "stm-uart.h" + +/* Magic bytes to signal the bootloader it should jump to the firmware + * instead of trying to receive a new firmware using the MGMT UART. + */ +#define HARDWARE_EARLY_DFU_JUMP 0xBADABADA + +/* symbols defined in the linker script (STM32F429BI.ld) */ +extern uint32_t CRYPTECH_FIRMWARE_START; +extern uint32_t CRYPTECH_FIRMWARE_END; +extern uint32_t CRYPTECH_DFU_CONTROL; + +/* 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 +main() +{ + int i; + + /* 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 *) "This is the bootloader speaking..."); + + /* This is where uploading of new firmware over UART could happen */ + + led_on(LED_BLUE); + for (i = 0; i < 10; i++) { + HAL_Delay(100); + led_toggle(LED_BLUE); + } + + /* 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"); + + /* De-initialize hardware by rebooting */ + HAL_NVIC_SystemReset(); + while (1) {}; +} diff --git a/projects/cli-test/cli-test.c b/projects/cli-test/cli-test.c index 1a8c6b7..30623a4 100644 --- a/projects/cli-test/cli-test.c +++ b/projects/cli-test/cli-test.c @@ -410,9 +410,6 @@ main() { static struct cli_def cli; - /* This is simulating the bootloader from the cli-test. */ - check_early_dfu_jump(); - stm_init(); led_on(LED_RED); diff --git a/projects/cli-test/mgmt-dfu.c b/projects/cli-test/mgmt-dfu.c index 1c7e052..33c6e2e 100644 --- a/projects/cli-test/mgmt-dfu.c +++ b/projects/cli-test/mgmt-dfu.c @@ -54,7 +54,7 @@ extern uint32_t CRYPTECH_DFU_CONTROL; __IO uint32_t *dfu_control = &CRYPTECH_DFU_CONTROL; __IO uint32_t *dfu_new_msp = &CRYPTECH_FIRMWARE_START; -__IO uint32_t *dfu_firmware = &CRYPTECH_FIRMWARE_START + 4; +__IO uint32_t *dfu_firmware = &CRYPTECH_FIRMWARE_START + 1; /* Flash sector offsets from RM0090, Table 6. Flash module - 2 Mbyte dual bank organization */ #define FLASH_NUM_SECTORS 24 + 1 |