summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVictor Rajewski <victor@allumeenergy.com.au>2024-12-04 10:48:29 +1100
committerDamien George <damien@micropython.org>2025-01-02 12:59:14 +1100
commit61e2931f864129524e0707c7487f804cfe59e84e (patch)
tree1a1a438b7395e6c8f7bb26e309d349d5569f39ec
parent931a768f5529649c43a65e999ab28f2820002c38 (diff)
stm32/mboot: Add mboot version string.
Adds a configurable version string to a known location at the end of mboot flash section. Also stores the options mboot was built with, eg usb and which filesystems are supported. A board can override the defaults, or disable the version string entirely by setting MBOOT_VERSION_ALLOCATED_BYTES=0. Signed-off-by: Victor Rajewski <victor@allumeenergy.com.au>
-rwxr-xr-xports/stm32/mboot/Makefile20
-rw-r--r--ports/stm32/mboot/README.md16
-rw-r--r--ports/stm32/mboot/fwupdate.py22
-rw-r--r--ports/stm32/mboot/stm32_sections.ld6
-rw-r--r--ports/stm32/mboot/version.c62
5 files changed, 124 insertions, 2 deletions
diff --git a/ports/stm32/mboot/Makefile b/ports/stm32/mboot/Makefile
index 07053b329..87bced1ae 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,9 +84,14 @@ 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
+LDFLAGS += --defsym mboot_version_len=$(MBOOT_VERSION_ALLOCATED_BYTES)
LIBS += $(shell $(CC) $(CFLAGS) -print-libgcc-file-name)
# Remove uncalled code from the final image.
@@ -121,6 +132,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 +218,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
@@ -231,8 +243,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 +263,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 221e3a7c3..c294041a5 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 8578ff4fc..b28ba2a78 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 == 0x00 or c == 0xFF: # have hit padding or 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
diff --git a/ports/stm32/mboot/stm32_sections.ld b/ports/stm32/mboot/stm32_sections.ld
index 3302c5f97..43511f083 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 000000000..b9912f61f
--- /dev/null
+++ b/ports/stm32/mboot/version.c
@@ -0,0 +1,62 @@
+#include "mboot.h"
+#include "genhdr/mpversion.h"
+
+#if defined(MBOOT_VERSION_ALLOCATED_BYTES) && MBOOT_VERSION_ALLOCATED_BYTES > 0
+
+#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