From 7309e7ba7c3013241582f2c778ce180ff12fe2b3 Mon Sep 17 00:00:00 2001 From: Victor Rajewski Date: Wed, 4 Dec 2024 10:48:29 +1100 Subject: [PATCH] stm32/mboot: Add mboot version string. Adds a configurable version string to a known location at the end of mboot flash section. Also stores options mboot was built with. Signed-off-by: Victor Rajewski --- ports/stm32/mboot/Makefile | 21 ++++++++-- ports/stm32/mboot/README.md | 16 ++++++++ ports/stm32/mboot/fwupdate.py | 22 ++++++++++ ports/stm32/mboot/stm32_sections.ld | 6 +++ ports/stm32/mboot/version.c | 62 +++++++++++++++++++++++++++++ 5 files changed, 124 insertions(+), 3 deletions(-) create mode 100644 ports/stm32/mboot/version.c diff --git a/ports/stm32/mboot/Makefile b/ports/stm32/mboot/Makefile index 07053b3293907..2d854e3b6de40 100755 --- a/ports/stm32/mboot/Makefile +++ b/ports/stm32/mboot/Makefile @@ -36,6 +36,12 @@ include $(BOARD_DIR)/mpconfigboard.mk # A board can set MBOOT_TEXT0_ADDR to a custom location where mboot should reside. MBOOT_TEXT0_ADDR ?= 0x08000000 +# The string in MBOOT_VERSION (default defined in version.c if not defined by a +# board) will be stored in the final MBOOT_VERSION_ALLOCATED_BYTES bytes of mboot flash. +# A board can change the size of this region by defining MBOOT_VERSION_ALLOCATED_BYTES. +MBOOT_VERSION_ALLOCATED_BYTES ?= 64 +MBOOT_VERSION_INCLUDE_OPTIONS ?= 1 # if set to 1, this will append build options to version string (see version.c) + USBDEV_DIR=usbdev DFU=$(TOP)/tools/dfu.py PYDFU ?= $(TOP)/tools/pydfu.py @@ -78,6 +84,10 @@ CFLAGS += -DBUILDING_MBOOT=$(BUILDING_MBOOT) CFLAGS += -DMICROPY_HW_STM32WB_FLASH_SYNCRONISATION=0 CFLAGS += -DUSBD_ENABLE_VENDOR_DEVICE_REQUESTS=1 CFLAGS += -DBOOTLOADER_DFU_USB_VID=$(BOOTLOADER_DFU_USB_VID) -DBOOTLOADER_DFU_USB_PID=$(BOOTLOADER_DFU_USB_PID) +ifdef MBOOT_VERSION +CFLAGS += -DMBOOT_VERSION=\"$(MBOOT_VERSION)\" +endif +CFLAGS += -DMBOOT_VERSION_ALLOCATED_BYTES=$(MBOOT_VERSION_ALLOCATED_BYTES) -DMBOOT_VERSION_INCLUDE_OPTIONS=$(MBOOT_VERSION_INCLUDE_OPTIONS) MBOOT_LD_FILES ?= stm32_memory.ld stm32_sections.ld LDFLAGS += -nostdlib -L . $(addprefix -T,$(MBOOT_LD_FILES)) -Map=$(@:.elf=.map) --cref @@ -121,6 +131,7 @@ SRC_C += \ vfs_fat.c \ vfs_lfs.c \ vfs_raw.c \ + version.c \ drivers/bus/softspi.c \ drivers/bus/softqspi.c \ drivers/memory/spiflash.c \ @@ -206,7 +217,7 @@ deploy-stlink: $(BUILD)/firmware.dfu $(BUILD)/firmware.dfu: $(BUILD)/firmware.elf $(ECHO) "Create $@" - $(Q)$(OBJCOPY) -O binary -j .isr_vector -j .text -j .data $^ $(BUILD)/firmware.bin + $(Q)$(OBJCOPY) -O binary -j .isr_vector -j .text -j .data -j .mboot_version_text $^ $(BUILD)/firmware.bin $(Q)$(PYTHON) $(DFU) -b $(MBOOT_TEXT0_ADDR):$(BUILD)/firmware.bin $@ $(BUILD)/firmware.hex: $(BUILD)/firmware.elf @@ -215,7 +226,7 @@ $(BUILD)/firmware.hex: $(BUILD)/firmware.elf $(BUILD)/firmware.elf: $(OBJ) $(ECHO) "LINK $@" - $(Q)$(LD) $(LDFLAGS) -o $@ $^ $(LIBS) + $(Q)$(LD) $(LDFLAGS) --defsym mboot_version_len=$(MBOOT_VERSION_ALLOCATED_BYTES) -o $@ $^ $(LIBS) $(Q)$(SIZE) $@ ######################################### @@ -231,8 +242,9 @@ GEN_PINS_SRC = $(BUILD)/pins_$(BOARD).c GEN_PINS_HDR = $(HEADER_BUILD)/pins.h GEN_PINS_AF_CONST = $(HEADER_BUILD)/pins_af_const.h GEN_PINS_AF_DEFS = $(HEADER_BUILD)/pins_af_defs.h +GEN_MPVERSION = $(HEADER_BUILD)/mpversion.h -$(OBJ): $(GEN_QSTRDEFS_GENERATED) $(GEN_ROOT_POINTERS) $(GEN_PINS_AF_DEFS) +$(OBJ): $(GEN_QSTRDEFS_GENERATED) $(GEN_ROOT_POINTERS) $(GEN_PINS_AF_DEFS) $(GEN_MPVERSION) $(HEADER_BUILD): $(MKDIR) -p $(BUILD)/genhdr @@ -250,6 +262,9 @@ $(GEN_PINS_AF_DEFS): $(BOARD_PINS) $(MAKE_PINS) ../$(AF_FILE) $(PREFIX_FILE) | $ --output-af-const $(GEN_PINS_AF_CONST) --output-af-defs $(GEN_PINS_AF_DEFS) \ --mboot-mode +$(GEN_MPVERSION): | $(HEADER_BUILD) + $(PYTHON) ../../../py/makeversionhdr.py $@ + ######################################### vpath %.S . $(TOP) diff --git a/ports/stm32/mboot/README.md b/ports/stm32/mboot/README.md index 221e3a7c3acad..b17fbe3f5cf86 100644 --- a/ports/stm32/mboot/README.md +++ b/ports/stm32/mboot/README.md @@ -89,6 +89,17 @@ How to use the beginning of the chunk when the end is reached. Then use a split raw filesystem to inform mboot of this wrapping. + The version and config options that mboot was built with are stored in a + small, fixed section of bytes at the end of the flash region allocated + for mboot. The length of the fixed section defaults to 64 bytes, but can + be overridden by setting MBOOT_VERSION_ALLOCATED_BYTES. If running + low on flash for the mboot build, this can be reduced or even set to 0. + The version string stored defaults to the micropython git version as + generated by makeversionhdr.py. The default version string can be + overridden by setting MBOOT_VERSION in a board's build files. The version + string is appended with options mboot was built with - see version.c for + details. This can be prevented by setting MBOOT_VERSION_INCLUDE_OPTIONS to 0. + 2. Build the board's main application firmware as usual. 3. Build mboot via: @@ -209,6 +220,11 @@ and signed firmware, and can be deployed via USB DFU, or by copying it to the de internal filesystem (if `MBOOT_FSLOAD` is enabled). `firmware.dfu` is still unencrypted and can be directly flashed with jtag etc. +Retrieving the mboot version in micropython +------------------------------------------- +The function `get_mboot_version` in `fwupdate.py` returns the version mboot was built with, +optionally with build options. + Example: Mboot on PYBv1.x ------------------------- diff --git a/ports/stm32/mboot/fwupdate.py b/ports/stm32/mboot/fwupdate.py index 8578ff4fc9032..15f7ab5096b51 100644 --- a/ports/stm32/mboot/fwupdate.py +++ b/ports/stm32/mboot/fwupdate.py @@ -281,3 +281,25 @@ def update_mpy(*args, **kwargs): elems = update_app_elements(*args, **kwargs) if elems: machine.bootloader(elems) + + +def get_mboot_version( + mboot_base=0x0800_0000, # address of start of mboot flash section + mboot_len=0x8000, # length of mboot flash section + mboot_ver_len=64, # length of mboot version section (defined in mboot/Makefile or in board dir) + valid_prefix="mboot-", # prefix that the version string was defined with + include_opts=True, # return the options mboot was built with (set False for just the version) +): + s = "" + for i in range(mboot_ver_len): + c = stm.mem8[mboot_base + mboot_len - mboot_ver_len + i] + if c == 0xFF: # have hit empty flash + break + s += chr(c) + if s.startswith(valid_prefix): + if include_opts: + return s + else: + return s.split("+")[0] # optional mboot config info stored after "+" + else: # version hasn't been set, so on the original mboot (i.e. mboot-v1.0.0) + return None \ No newline at end of file diff --git a/ports/stm32/mboot/stm32_sections.ld b/ports/stm32/mboot/stm32_sections.ld index 3302c5f97291d..07321e0a333f6 100644 --- a/ports/stm32/mboot/stm32_sections.ld +++ b/ports/stm32/mboot/stm32_sections.ld @@ -47,6 +47,12 @@ SECTIONS _edata = .; } >RAM AT> FLASH_BL + /* Final section of mboot flash reserved for mboot version */ + .mboot_version_text (ORIGIN(FLASH_BL) + LENGTH(FLASH_BL) - mboot_version_len) : + { + KEEP(*(.mboot_version)) ; + } >FLASH_BL + /* Zeroed-out data section */ .bss : { diff --git a/ports/stm32/mboot/version.c b/ports/stm32/mboot/version.c new file mode 100644 index 0000000000000..624f746e574ad --- /dev/null +++ b/ports/stm32/mboot/version.c @@ -0,0 +1,62 @@ +#include "mboot.h" +#include "genhdr/mpversion.h" + +#ifdef MBOOT_VERSION_ALLOCATED_BYTES + +#ifndef MBOOT_VERSION +#define MBOOT_VERSION "mboot-" MICROPY_GIT_TAG +#endif + +#if MBOOT_VERSION_INCLUDE_OPTIONS // if this is defined, append a list of build options e.g. fat.lfs2 +#define MBOOT_VERSION_USB MBOOT_VERSION "+usb" // USB is always included + +#if defined(MBOOT_I2C_SCL) +#define MBOOT_VERSION_I2C MBOOT_VERSION_USB ".i2c" +#else +#define MBOOT_VERSION_I2C MBOOT_VERSION_USB +#endif + +#if MBOOT_ADDRESS_SPACE_64BIT +#define MBOOT_VERSION_64BIT MBOOT_VERSION_I2C ".64" +#else +#define MBOOT_VERSION_64BIT MBOOT_VERSION_I2C +#endif + +#if MBOOT_VFS_FAT +#define MBOOT_VERSION_FAT MBOOT_VERSION_64BIT ".fat" +#else +#define MBOOT_VERSION_FAT MBOOT_VERSION_64BIT +#endif + +#if MBOOT_VFS_LFS1 +#define MBOOT_VERSION_LFS1 MBOOT_VERSION_FAT ".lfs1" +#else +#define MBOOT_VERSION_LFS1 MBOOT_VERSION_FAT +#endif + +#if MBOOT_VFS_LFS2 +#define MBOOT_VERSION_LFS2 MBOOT_VERSION_LFS1 ".lfs2" +#else +#define MBOOT_VERSION_LFS2 MBOOT_VERSION_LFS1 +#endif + +#if MBOOT_VFS_RAW +#define MBOOT_VERSION_RAW MBOOT_VERSION_LFS2 ".raw" +#else +#define MBOOT_VERSION_RAW MBOOT_VERSION_LFS2 +#endif + +#define MBOOT_VERSION_FINAL MBOOT_VERSION_RAW + +#else // MBOOT_VERSION_INCLUDE_OPTIONS + +#define MBOOT_VERSION_FINAL MBOOT_VERSION + +#endif // MBOOT_VERSION_INCLUDE_OPTIONS + +// Ensure we don't overrun the allocated space +_Static_assert(sizeof(MBOOT_VERSION_FINAL) <= MBOOT_VERSION_ALLOCATED_BYTES + 1, "mboot version string is too long"); +// Cuts off the null terminator +const char mboot_version[sizeof(MBOOT_VERSION_FINAL) - 1] __attribute__((section(".mboot_version"))) __attribute__ ((__used__)) = MBOOT_VERSION_FINAL; + +#endif // MBOOT_VERSION