From bda583b94c67bda3b5342073fd180619d3e745ed Mon Sep 17 00:00:00 2001 From: Michael Ehrenreich Date: Thu, 28 Apr 2022 21:05:09 +0200 Subject: [PATCH] Add persist RAM area for passing data across resets; implement booting from a partition specified in the persist RAM area --- CMakeLists.txt | 7 ++++- ab_boot/ab_boot.c | 58 ++++++++++++++++++++++++++------------- ab_boot/ab_boot.h | 2 +- ld/STM32F103RCTx_FLASH.ld | 11 +++++++- main.cpp | 26 ++++++++++++++---- persist/persist.c | 10 +++++++ persist/persist.h | 39 ++++++++++++++++++++++++++ 7 files changed, 126 insertions(+), 27 deletions(-) create mode 100644 persist/persist.c create mode 100644 persist/persist.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 9964d79..288508b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -76,6 +76,7 @@ set(COMMON_SOURCES defines.h main.cpp system_stm32f1xx.c + persist/persist.c ) # @@ -216,7 +217,11 @@ add_custom_target(greyhash ALL SOURCES greyhash.hex greyhash.bin) add_custom_target(flash-greyhash COMMAND st-flash --reset write greyhash.bin ${A_FIRMWARE_APP_BASE} SOURCES greyhash.bin DEPENDS greyhash.bin) -add_executable(ab_boot.elf ab_boot/ab_boot.c system_stm32f1xx.c) +add_executable(ab_boot.elf + ab_boot/ab_boot.c + system_stm32f1xx.c + persist/persist.c +) target_link_options(ab_boot.elf PRIVATE ${COMMON_LINKER_FLAGS} ${AB_BOOT_FIRMWARE_LINKER_FLAGS}) target_link_libraries(ab_boot.elf stm32_hal) target_compile_options(ab_boot.elf PRIVATE ) diff --git a/ab_boot/ab_boot.c b/ab_boot/ab_boot.c index ec60d6e..bbe1d66 100644 --- a/ab_boot/ab_boot.c +++ b/ab_boot/ab_boot.c @@ -1,31 +1,51 @@ #include +#include #include "stm32f1xx_hal.h" #include "ab_boot.h" +#include "persist/persist.h" -int main() -{ - struct ab_boot_config *config = (struct ab_boot_config *)CONFIG_START; - - uint32_t *bootp; - if (config->boot_partition >= FLASH_START && - config->boot_partition < FLASH_END && - (config->boot_partition & 3) == 0) - { - bootp = (uint32_t *)config->boot_partition; - } - else - { - bootp = (uint32_t *)APP_A_START; - } - - uint32_t sp = bootp[0]; - uint32_t entry = bootp[1]; +static inline void __attribute__((noreturn)) boot_image(uint32_t sp, uint32_t entry) { asm volatile( " mov sp, %0 \n" - " bx %1 \n" + " blx %1 \n" "1: b 1b \n" : : "r" (sp), "r" (entry) ); + __builtin_unreachable(); +} + +static bool is_valid_boot_address(uint32_t *bootp) +{ + return (uint32_t)bootp >= FLASH_START && + (uint32_t)bootp < FLASH_END && + ((uint32_t)bootp & 3) == 0; +} + +int main() +{ + struct ab_boot_config *flash_config = (struct ab_boot_config *)CONFIG_START; + struct ab_boot_config *config = NULL; + if (is_persist_valid() && + is_valid_boot_address(persist.ab_boot_config.boot_partition)) + { + // Invalidate persist + persist.checksum = 0; + config = &persist.ab_boot_config; + } + else if (is_valid_boot_address(flash_config->boot_partition)) + { + config = flash_config; + } + + uint32_t *bootp; + if (config) + bootp = config->boot_partition; + else + bootp = (uint32_t *)APP_A_START; + + uint32_t sp = bootp[0]; + uint32_t entry = bootp[1]; + boot_image(sp, entry); } diff --git a/ab_boot/ab_boot.h b/ab_boot/ab_boot.h index 38d8fb0..7d2bd9b 100644 --- a/ab_boot/ab_boot.h +++ b/ab_boot/ab_boot.h @@ -17,5 +17,5 @@ struct ab_boot_config { - uint32_t boot_partition; + uint32_t *boot_partition; }; diff --git a/ld/STM32F103RCTx_FLASH.ld b/ld/STM32F103RCTx_FLASH.ld index 46c70d4..0801d36 100644 --- a/ld/STM32F103RCTx_FLASH.ld +++ b/ld/STM32F103RCTx_FLASH.ld @@ -39,7 +39,8 @@ _Min_Stack_Size = 0x400; /* required amount of stack */ /* Specify the memory areas */ MEMORY { -RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 48K +RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 47K +PERSIST (rw) : ORIGIN = 0x2000BC00, LENGTH = 1K FLASH (rx) : ORIGIN = _App_Base, LENGTH = _App_Length CONFIG(r) : ORIGIN = 0x0803f800, LENGTH = 2K } @@ -155,6 +156,14 @@ SECTIONS /* Highest address of the user mode stack */ _estack = ORIGIN(RAM) + LENGTH(RAM); /* end of RAM area */ + .persist : + { + . = ALIGN(4); + persist = .; + . += LENGTH(PERSIST); + _epersist = .; + } > PERSIST + /* Remove information from the standard libraries */ /DISCARD/ : { diff --git a/main.cpp b/main.cpp index daaef2d..4cdd03d 100644 --- a/main.cpp +++ b/main.cpp @@ -27,6 +27,8 @@ #include #include "stm32f1xx_hal.h" +#include "ab_boot/ab_boot.h" +#include "persist/persist.h" #include "defines.h" #include "config.h" @@ -1364,22 +1366,36 @@ void MX_ADC2_Init() __HAL_ADC_ENABLE(&hadc2); } -#ifdef FEATURE_BUTTON -void poweroff() +void shutdown() { -// if (abs(speed) < 20) { // wait for the speed to drop, then shut down -> this is commented out for SAFETY reasons buzzer.pattern = 0; left.enable = false; - right.enable = 0; + right.enable = false; for (int i = 0; i < 8; i++) { buzzer.freq = (uint8_t)i; HAL_Delay(50); } +} + +#ifdef FEATURE_BUTTON +void poweroff() +{ + shutdown(); + HAL_GPIO_WritePin(OFF_PORT, OFF_PIN, GPIO_PIN_RESET); for (int i = 0; i < 5; i++) HAL_Delay(1000); -// } +} +#endif + +#ifdef FEATURE_CAN +void reboot_new_image(uint32_t *bootp) +{ + shutdown(); + + request_boot_image(bootp); + HAL_NVIC_SystemReset(); } #endif diff --git a/persist/persist.c b/persist/persist.c new file mode 100644 index 0000000..097f1c4 --- /dev/null +++ b/persist/persist.c @@ -0,0 +1,10 @@ +#include + +#include "persist.h" +#include "ab_boot/ab_boot.h" + +// keep this in sync with the linker script +#define PERSIST_SIZE 1024 + +extern struct persist_data persist; +static_assert(sizeof(persist) < PERSIST_SIZE); diff --git a/persist/persist.h b/persist/persist.h new file mode 100644 index 0000000..a1a1d25 --- /dev/null +++ b/persist/persist.h @@ -0,0 +1,39 @@ +#pragma once + +#include +#include + +#include "ab_boot/ab_boot.h" + +struct persist_data { + struct ab_boot_config ab_boot_config; + uint32_t checksum; +}; + +extern struct persist_data persist; + +static inline uint32_t calculate_persist_checksum() { + uint32_t checksum = 0; + uint32_t *pd = (uint32_t *)&persist; + for (int i = 0; i < (sizeof(persist) - 4) / 4; i++) { + checksum += pd[i]; + checksum = (checksum >> 3) | (checksum << 29); + } + + checksum = ~checksum; + + return checksum; +} + +static inline void update_persist_checksum() { + persist.checksum = calculate_persist_checksum(); +} + +static inline bool is_persist_valid() { + return calculate_persist_checksum() == persist.checksum; +} + +static inline void request_boot_image(uint32_t *bootp) { + persist.ab_boot_config.boot_partition = bootp; + update_persist_checksum(); +}