mirror of https://github.com/wolfSSL/wolfBoot.git
195 lines
8.6 KiB
Bash
Executable File
195 lines
8.6 KiB
Bash
Executable File
#!/bin/bash
|
|
#
|
|
# STM32N6 Flash Script for NUCLEO-N657X0-Q
|
|
# Programs NOR flash (MX25UM51245G on XSPI2) and loads wolfBoot to SRAM.
|
|
#
|
|
# Usage:
|
|
# ./tools/scripts/stm32n6_flash.sh # Build and flash all
|
|
# ./tools/scripts/stm32n6_flash.sh --skip-build # Flash only
|
|
# ./tools/scripts/stm32n6_flash.sh --app-only # Flash app to NOR only
|
|
# ./tools/scripts/stm32n6_flash.sh --test-update # Flash v1 + v2 update
|
|
# ./tools/scripts/stm32n6_flash.sh --halt # Leave OpenOCD running
|
|
|
|
set -e
|
|
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
CYAN='\033[0;36m'
|
|
NC='\033[0m'
|
|
|
|
SKIP_BUILD=0
|
|
APP_ONLY=0
|
|
TEST_UPDATE=0
|
|
LEAVE_RUNNING=0
|
|
|
|
while [[ $# -gt 0 ]]; do
|
|
case $1 in
|
|
--skip-build) SKIP_BUILD=1; shift ;;
|
|
--app-only) APP_ONLY=1; shift ;;
|
|
--test-update) TEST_UPDATE=1; shift ;;
|
|
--halt) LEAVE_RUNNING=1; shift ;;
|
|
-h|--help)
|
|
sed -n '2,/^$/p' "$0" | sed 's/^# \?//'
|
|
exit 0 ;;
|
|
*) echo -e "${RED}Unknown option: $1${NC}"; exit 1 ;;
|
|
esac
|
|
done
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
WOLFBOOT_ROOT="$(cd "${SCRIPT_DIR}/../.." && pwd)"
|
|
cd "${WOLFBOOT_ROOT}"
|
|
|
|
OPENOCD_CFG="${WOLFBOOT_ROOT}/config/openocd/openocd_stm32n6.cfg"
|
|
# OpenOCD's stmqspi driver addresses XSPI2 NOR via its physical/secure
|
|
# alias 0x70000000. Boot and update partition addresses are read from
|
|
# .config so this script tracks whatever partition layout the build is
|
|
# using (non-TZ: boot 0x70020000; TZ: boot 0x70180000).
|
|
BOOT_ADDR=$(grep -E '^WOLFBOOT_PARTITION_BOOT_ADDRESS\?*=' "${WOLFBOOT_ROOT}/.config" 2>/dev/null \
|
|
| head -1 | sed 's/.*=//;s/[[:space:]]//g')
|
|
UPDATE_REL=$(grep -E '^WOLFBOOT_PARTITION_UPDATE_ADDRESS\?*=' "${WOLFBOOT_ROOT}/.config" 2>/dev/null \
|
|
| head -1 | sed 's/.*=//;s/[[:space:]]//g')
|
|
[ -z "$BOOT_ADDR" ] && BOOT_ADDR=0x70020000
|
|
[ -z "$UPDATE_REL" ] && UPDATE_REL=0x00120000
|
|
UPDATE_ADDR=$(printf "0x%08x" $(( 0x70000000 + ${UPDATE_REL} )))
|
|
|
|
# Boot ROM always copies FSBL to AXISRAM2 at this address
|
|
SRAM_ADDR=0x34180400
|
|
|
|
# STM32_SigningTool_CLI for Boot ROM FSBL header (use latest version)
|
|
SIGN_TOOL=""
|
|
for d in $(ls -rd /opt/st/stm32cubeide_*/plugins/com.st.stm32cube.ide.mcu.externaltools.cubeprogrammer.*/tools/bin 2>/dev/null); do
|
|
[ -x "$d/STM32_SigningTool_CLI" ] && SIGN_TOOL="$d/STM32_SigningTool_CLI" && break
|
|
done
|
|
|
|
check_tool() {
|
|
command -v "$1" &>/dev/null || { echo -e "${RED}Error: $1 not found${NC}"; exit 1; }
|
|
}
|
|
|
|
check_tool openocd
|
|
[ $SKIP_BUILD -eq 0 ] && check_tool arm-none-eabi-gcc
|
|
[ -f "${OPENOCD_CFG}" ] || { echo -e "${RED}Error: ${OPENOCD_CFG} not found${NC}"; exit 1; }
|
|
|
|
echo -e "${GREEN}=== STM32N6 Flash Script ===${NC}"
|
|
|
|
# Build
|
|
if [ $SKIP_BUILD -eq 0 ]; then
|
|
echo -e "${GREEN}[1/2] Building...${NC}"
|
|
|
|
if [ ! -f .config ]; then
|
|
[ -f config/examples/stm32n6.config ] || { echo -e "${RED}No .config found${NC}"; exit 1; }
|
|
cp config/examples/stm32n6.config .config
|
|
fi
|
|
|
|
TARGET_CHECK=$(grep -E '^TARGET\?*=' .config | head -1 | sed 's/.*=//;s/[[:space:]]//g')
|
|
[ "$TARGET_CHECK" = "stm32n6" ] || { echo -e "${RED}TARGET is '${TARGET_CHECK}', expected 'stm32n6'${NC}"; exit 1; }
|
|
|
|
make clean && make wolfboot.bin
|
|
echo -e "${GREEN}wolfboot.bin: $(stat -c%s wolfboot.bin 2>/dev/null || stat -f%z wolfboot.bin) bytes${NC}"
|
|
|
|
make test-app/image_v1_signed.bin
|
|
echo -e "${GREEN}image_v1_signed.bin: $(stat -c%s test-app/image_v1_signed.bin 2>/dev/null || stat -f%z test-app/image_v1_signed.bin) bytes${NC}"
|
|
|
|
if [ $TEST_UPDATE -eq 1 ]; then
|
|
SIGN_VALUE=$(grep -E '^SIGN\?*=' .config | head -1 | sed 's/.*=//;s/[[:space:]]//g')
|
|
HASH_VALUE=$(grep -E '^HASH\?*=' .config | head -1 | sed 's/.*=//;s/[[:space:]]//g')
|
|
HDR_SIZE=$(grep -E '^IMAGE_HEADER_SIZE\?*=' .config | head -1 | sed 's/.*=//;s/[[:space:]]//g')
|
|
[ -z "$HDR_SIZE" ] && HDR_SIZE=256
|
|
[ -f tools/keytools/sign ] || make -C tools/keytools
|
|
# sign tool reads IMAGE_HEADER_SIZE from env; must match wolfBoot build
|
|
IMAGE_HEADER_SIZE=$HDR_SIZE ./tools/keytools/sign \
|
|
--$(echo "$SIGN_VALUE" | tr '[:upper:]' '[:lower:]') \
|
|
--$(echo "$HASH_VALUE" | tr '[:upper:]' '[:lower:]') \
|
|
test-app/image.bin wolfboot_signing_private_key.der 2
|
|
echo -e "${GREEN}image_v2_signed.bin built${NC}"
|
|
fi
|
|
else
|
|
echo -e "${YELLOW}[1/2] Skipping build${NC}"
|
|
fi
|
|
|
|
# Verify binaries
|
|
[ $APP_ONLY -eq 0 ] && [ ! -f wolfboot.bin ] && { echo -e "${RED}wolfboot.bin not found${NC}"; exit 1; }
|
|
[ -f test-app/image_v1_signed.bin ] || { echo -e "${RED}image_v1_signed.bin not found${NC}"; exit 1; }
|
|
[ $TEST_UPDATE -eq 1 ] && [ ! -f test-app/image_v2_signed.bin ] && { echo -e "${RED}image_v2_signed.bin not found${NC}"; exit 1; }
|
|
|
|
# Flash via OpenOCD
|
|
echo -e "${GREEN}[2/2] Programming via OpenOCD...${NC}"
|
|
pkill -x openocd 2>/dev/null || true
|
|
sleep 1
|
|
|
|
OPENOCD_CMDS="reset init; "
|
|
|
|
if [ $APP_ONLY -eq 0 ]; then
|
|
# Generate Boot ROM FSBL header using STM32_SigningTool_CLI
|
|
if [ -n "$SIGN_TOOL" ]; then
|
|
TRUSTED_BIN="${WOLFBOOT_ROOT}/wolfboot-trusted.bin"
|
|
chmod u+w "${TRUSTED_BIN}" 2>/dev/null; rm -f "${TRUSTED_BIN}"
|
|
echo -e "${CYAN} Generating FSBL header (STM32_SigningTool_CLI)...${NC}"
|
|
# Match ST's reference template invocation (UM3234, Template_FSBL_XIP).
|
|
# Do NOT pass -la/-ep: the tool extracts the entry point (with the
|
|
# Thumb bit) from the Cortex-M vector table at offset 0x04 of the
|
|
# binary. Passing -ep <addr> writes <addr> verbatim into the header
|
|
# entry-point field with no Thumb bit, so the Boot ROM jumps to an
|
|
# ARM-mode instruction on a Cortex-M55 and instant hard faults.
|
|
if ! "$SIGN_TOOL" -bin "${WOLFBOOT_ROOT}/wolfboot.bin" -nk -of 0x80000000 -t fsbl -hv 2.3 -align -o "${TRUSTED_BIN}"; then
|
|
echo -e "${RED}Error: STM32_SigningTool_CLI failed${NC}"; exit 1
|
|
fi
|
|
[ -s "${TRUSTED_BIN}" ] || { echo -e "${RED}Failed to generate trusted binary${NC}"; exit 1; }
|
|
# Sanity-check magic ("STM\x32" little-endian = 0x324d5453 at offset 0)
|
|
MAGIC=$(od -A n -t x4 -N 4 "${TRUSTED_BIN}" | awk '{print $1}')
|
|
if [ "$MAGIC" != "324d5453" ]; then
|
|
echo -e "${RED}Error: bad FSBL header magic (${MAGIC})${NC}"; exit 1
|
|
fi
|
|
echo -e "${CYAN} wolfboot-trusted.bin -> NOR 0x70000000${NC}"
|
|
OPENOCD_CMDS+="flash write_image erase ${TRUSTED_BIN} 0x70000000; "
|
|
else
|
|
echo -e "${YELLOW} STM32_SigningTool_CLI not found, loading wolfBoot to SRAM only${NC}"
|
|
fi
|
|
|
|
# Also load wolfBoot directly to SRAM for immediate execution
|
|
echo -e "${CYAN} wolfboot.bin -> SRAM ${SRAM_ADDR}${NC}"
|
|
OPENOCD_CMDS+="load_image ${WOLFBOOT_ROOT}/wolfboot.bin ${SRAM_ADDR} bin; "
|
|
fi
|
|
|
|
echo -e "${CYAN} image_v1_signed.bin -> NOR ${BOOT_ADDR}${NC}"
|
|
OPENOCD_CMDS+="flash write_image erase ${WOLFBOOT_ROOT}/test-app/image_v1_signed.bin ${BOOT_ADDR}; "
|
|
|
|
if [ $TEST_UPDATE -eq 1 ]; then
|
|
echo -e "${CYAN} image_v2_signed.bin -> NOR ${UPDATE_ADDR}${NC}"
|
|
OPENOCD_CMDS+="flash write_image erase ${WOLFBOOT_ROOT}/test-app/image_v2_signed.bin ${UPDATE_ADDR}; "
|
|
|
|
# Write update trigger: "pBOOT" (0x70 0x42 0x4F 0x4F 0x54) at end of
|
|
# update partition. wolfBoot reads this trailer to detect a pending update.
|
|
# Address: UPDATE_ADDR + PARTITION_SIZE - 5
|
|
PART_SIZE=$(grep -E '^WOLFBOOT_PARTITION_SIZE' "${WOLFBOOT_ROOT}/.config" | head -1 | sed 's/.*=//;s/[[:space:]]//g')
|
|
TRIGGER_ADDR=$(printf "0x%08x" $(( ${UPDATE_ADDR} + ${PART_SIZE} - 5 )))
|
|
echo -e "${CYAN} Update trigger -> NOR ${TRIGGER_ADDR}${NC}"
|
|
printf 'pBOOT' > /tmp/trigger_magic.bin
|
|
OPENOCD_CMDS+="flash write_image /tmp/trigger_magic.bin ${TRIGGER_ADDR}; "
|
|
fi
|
|
|
|
# Boot wolfBoot from SRAM (also loaded to NOR for reset persistence)
|
|
if [ $APP_ONLY -eq 0 ]; then
|
|
# Extract initial SP (word 0) and entry point (word 1) from vector table
|
|
INIT_SP=$(od -A n -t x4 -N 4 "${WOLFBOOT_ROOT}/wolfboot.bin" | awk '{print "0x"$1}')
|
|
ENTRY_ADDR=$(od -A n -j 4 -t x4 -N 4 "${WOLFBOOT_ROOT}/wolfboot.bin" | awk '{print "0x"$1}')
|
|
ENTRY_THUMB=$(printf "0x%08x" $(( ${ENTRY_ADDR} | 1 )))
|
|
echo -e "${CYAN} Booting wolfBoot (SP: ${INIT_SP}, entry: ${ENTRY_THUMB})...${NC}"
|
|
OPENOCD_CMDS+="reg msplim_s 0x00000000; "
|
|
OPENOCD_CMDS+="reg psplim_s 0x00000000; "
|
|
OPENOCD_CMDS+="reg msp ${INIT_SP}; "
|
|
OPENOCD_CMDS+="mww 0xE000ED08 ${SRAM_ADDR}; " # VTOR
|
|
OPENOCD_CMDS+="mww 0xE000ED28 0xFFFFFFFF; " # Clear CFSR
|
|
OPENOCD_CMDS+="resume ${ENTRY_THUMB}; "
|
|
fi
|
|
|
|
if [ $LEAVE_RUNNING -eq 0 ]; then
|
|
OPENOCD_CMDS+="shutdown"
|
|
else
|
|
OPENOCD_CMDS+="echo {OpenOCD running. Connect via: telnet localhost 4444}"
|
|
fi
|
|
|
|
openocd -f "${OPENOCD_CFG}" -c "${OPENOCD_CMDS}"
|
|
|
|
echo -e "${GREEN}=== Done ===${NC}"
|