Fixes to wolfBoot self-update (memcmp was used which is not a RAMFUNCTION).

pull/672/head
David Garske 2026-01-14 14:33:52 -08:00 committed by Daniele Lacamera
parent b92e2ca0cd
commit 4bbe28920c
5 changed files with 234 additions and 209 deletions

View File

@ -3031,10 +3031,11 @@ The S32K1xx can be programmed and debugged using various tools. The recommended
**Using PEMicro (recommended for S32K EVB boards):**
1. Install PEMicro GDB Server from [pemicro.com](https://www.pemicro.com/products/product_viewDetails.cfm?product_id=15320167)
Linux: `~/.local/pemicro/`
2. Start PEMicro GDB Server:
```sh
pegdbserver_console -device=NXP_S32K1xx_S32K142 -startserver -serverport=7224
pegdbserver_console -device=NXP_S32K1xx_S32K142F256M15 -startserver -interface=OPENSDA -port=USB1 -serverport=7224 -speed=5000
```
3. In another terminal, connect with GDB and flash:
@ -3068,41 +3069,6 @@ cp factory.srec /media/<user>/S32K142EVB/
The board will automatically program the flash and reset.
### NXP S32K1XX: Flash Script
A convenience script is provided for building and flashing S32K142:
```sh
./tools/scripts/nxp-s32k142-flash.sh [OPTIONS]
```
**Options:**
| Option | Description |
|--------|-------------|
| (none) | Build and flash `factory.srec` (v1 only) |
| `--test-update` | Build with v2 in update partition (use `trigger` command to start update) |
| `--update` | Build with v2 and auto-trigger (starts update on boot) |
| `--skip-build` | Skip build, use existing `.srec` file |
| `--skip-flash` | Skip flashing (just build) |
| `--skip-uart` | Skip UART monitoring |
| `--uart-only` | Only monitor UART (no build/flash) |
| `--interactive` | Keep UART open until Ctrl+C |
| `--timeout SECS` | UART capture duration (default: 5s) |
**Examples:**
```sh
# Build and flash factory image, monitor UART for 5 seconds
./tools/scripts/nxp-s32k142-flash.sh
# Build with v2 update, flash, and stay on UART
./tools/scripts/nxp-s32k142-flash.sh --test-update --interactive
# Just monitor UART
./tools/scripts/nxp-s32k142-flash.sh --uart-only --interactive
```
### NXP S32K1XX: Test Application
The S32K1xx test application (`test-app/app_s32k1xx.c`) provides a feature-rich demo application for testing wolfBoot functionality.
@ -3141,77 +3107,38 @@ Copyright 2025 wolfSSL Inc.
Firmware Version: 1
=== Partition Information ===
Boot Partition @ 0xC000:
Boot Partition:
Address: 0x0000C000
Version: 1
State: SUCCESS (0x00)
Update Partition @ 0x25000:
Version: 0 (empty)
State: (no trailer)
State: SUCCESS
Update Partition:
Address: 0x00025000
Version: 0
State: SUCCESS
Swap Partition:
Address: 0x0003E000
Size: 2048 bytes
=== Keystore Information ===
Number of keys: 1
Key 0: ECDSA P-256 (secp256r1), SHA-256
Number of public keys: 1
Hash: SHA-256
Key #0:
Algorithm: ECDSA P-256 (secp256r1)
Size: 64 bytes
Data:
9a 33 e0 18 24 4b a7 29 51 90 15 f0 74 6e e4 a6
bf 2d 00 47 32 1f 32 5a d6 9a 30 32 d1 c3 30 3f
0a e3 1b 0d 0f 98 b2 e6 5c eb 42 1c 64 2b 32 db
a4 48 75 5b e3 49 94 45 12 64 e3 57 b4 5b 81 73
Type 'help' for available commands.
cmd>
```
**Testing Firmware Update:**
### NXP S32K1XX: TODO
1. Flash with v2 image: `./tools/scripts/nxp-s32k142-flash.sh --test-update`
2. Connect to UART: `picocom -b 115200 /dev/ttyACM1`
3. Run `status` to verify v1 in boot, v2 in update
4. Run `trigger` to set update flag
5. Run `reboot` to start update
6. After reboot, LED changes from Green (v1) to Blue (v2)
7. Run `success` to mark v2 as good
### NXP S32K1XX: Flash Configuration Field (FCF)
The bootloader includes the Flash Configuration Field (FCF) at address 0x400-0x40F with the following settings:
- Flash security: Unsecured
- Flash protection: All regions unprotected
- Backdoor key access: Enabled
**CRITICAL WARNING:** The FCF region at 0x400-0x40F controls device security settings. Writing incorrect values can **permanently lock the device**, making it irrecoverable. The wolfBoot HAL includes protection to prevent accidental writes to this region.
### NXP S32K1XX: Recovering a Locked/Unresponsive Device
If your S32K device becomes locked or unresponsive (e.g., stuck in reset with D1 LED illuminated on S32K-EVB boards), try these recovery procedures:
**Symptoms of a locked device:**
- Debugger cannot connect ("Soft reset failed", "Failed to enter debug mode")
- Device stuck in reset (D1 LED constantly on for S32K-EVB)
- J-Link reports "Readout protection is set" at address 0x400-0x40F
**Recovery Option 1: PEMicro Force Mass Erase**
```sh
pegdbserver_console -device=NXP_S32K1xx_S32K142 -interface=OPENSDA -port=USB1 -forcemasserase -singlesession
```
After mass erase completes, power cycle the board before attempting to reconnect.
**Recovery Option 2: J-Link Unlock**
```sh
JLinkExe -if swd -Device S32K142
unlock Kinetis
erase
r
q
```
Then power cycle the board.
### NXP S32K1XX: TODO / Future Enhancements
The following features are planned or available for contribution:
- [x] **Sector swap update**: Full firmware update with sector swapping (completed)
- [x] **Interactive test application**: Console with status, trigger, success commands (completed)
- [x] **Flash automation script**: `tools/scripts/nxp-s32k142-flash.sh` (completed)
- [ ] **XMODEM improvements**: ISR-based UART RX for reliable high-speed transfers
- [ ] **SPLL + SOSC support**: Add external crystal oscillator and SPLL configuration for true 112 MHz operation in HSRUN mode
- [ ] **Hardware crypto acceleration**: Integrate CSEc (Cryptographic Services Engine) for hardware-accelerated crypto operations

View File

@ -40,6 +40,22 @@
#define DSB() __asm__ volatile ("dsb")
#define ISB() __asm__ volatile ("isb")
/* PRIMASK helpers for critical sections */
#define __get_PRIMASK() ({ \
uint32_t primask; \
__asm__ volatile ("mrs %0, primask" : "=r" (primask)); \
primask; \
})
#define __set_PRIMASK(primask) \
__asm__ volatile ("msr primask, %0" :: "r" (primask) : "memory")
#define __disable_irq() \
__asm__ volatile ("cpsid i" ::: "memory")
#define __enable_irq() \
__asm__ volatile ("cpsie i" ::: "memory")
#include "s32k1xx.h"
/* ============== Flash Configuration Field (FCF) ============== */
@ -125,14 +141,6 @@ static void watchdog_enable(uint32_t timeout_ms)
while (!(WDOG_CS & WDOG_CS_RCS)) {}
}
/* Refresh (kick) the watchdog to prevent reset
* Must be called periodically before timeout expires
*/
static void watchdog_refresh(void)
{
/* For CMD32EN mode, write refresh key as 32-bit value */
WDOG_CNT = WDOG_CNT_REFRESH;
}
#endif /* WATCHDOG */
/* ============== Clock Configuration ============== */
@ -352,13 +360,18 @@ static void RAMFUNCTION flash_clear_errors(void)
static int RAMFUNCTION flash_program_phrase(uint32_t address, const uint8_t *data)
{
/* Skip if phrase is all 0xFF (erased) */
if (data[0] == 0xFF && data[1] == 0xFF && data[2] == 0xFF && data[3] == 0xFF &&
data[4] == 0xFF && data[5] == 0xFF && data[6] == 0xFF && data[7] == 0xFF) {
return 0;
}
/* Wait for previous command to complete */
flash_wait_complete();
flash_clear_errors();
/* Set up Program Phrase command (0x07)
* Programs 8 bytes at the specified address
*/
/* Set up Program Phrase command (0x07) */
/* Programs 8 bytes at the specified address */
FTFC_FCCOB0 = FTFC_CMD_PROGRAM_PHRASE;
FTFC_FCCOB1 = (uint8_t)(address >> 16);
FTFC_FCCOB2 = (uint8_t)(address >> 8);
@ -384,7 +397,7 @@ static int RAMFUNCTION flash_program_phrase(uint32_t address, const uint8_t *dat
#ifdef WATCHDOG
/* Refresh watchdog after flash operation */
watchdog_refresh();
WDOG_CNT = WDOG_CNT_REFRESH;
#endif
/* Check for errors */
@ -414,8 +427,8 @@ static int RAMFUNCTION flash_erase_sector_internal(uint32_t address)
ISB();
/* Disable interrupts during flash operation to prevent code fetch from flash */
__asm__ volatile ("mrs %0, primask\n\t"
"cpsid i" : "=r" (primask) :: "memory");
primask = __get_PRIMASK();
__disable_irq();
FTFC_FSTAT = FTFC_FSTAT_CCIF;
@ -423,11 +436,11 @@ static int RAMFUNCTION flash_erase_sector_internal(uint32_t address)
flash_wait_complete();
/* Re-enable interrupts */
__asm__ volatile ("msr primask, %0" :: "r" (primask) : "memory");
__set_PRIMASK(primask);
#ifdef WATCHDOG
/* Refresh watchdog after potentially long flash operation */
watchdog_refresh();
WDOG_CNT = WDOG_CNT_REFRESH;
#endif
/* Check for errors */
@ -438,7 +451,6 @@ static int RAMFUNCTION flash_erase_sector_internal(uint32_t address)
return 0;
}
/* ============== HAL Interface Functions ============== */
void hal_init(void)
@ -510,92 +522,40 @@ void hal_prepare_boot(void)
int RAMFUNCTION hal_flash_write(uint32_t address, const uint8_t *data, int len)
{
int ret = 0;
int i = 0;
int ret, i = 0;
uint8_t phrase_buf[FLASH_PHRASE_SIZE];
const uint8_t empty_phrase[FLASH_PHRASE_SIZE] = {
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
};
/* CRITICAL: Protect the Flash Configuration Field (FCF) region.
* Writing incorrect values to 0x400-0x40F can permanently lock the device!
* The FCF is programmed once in the flash_config section and should never
* be modified at runtime.
*/
if ((address < FCF_END_ADDR) && ((address + len) > FCF_START_ADDR)) {
/* Requested write overlaps with FCF region - this is dangerous!
* Skip the FCF portion to prevent device locking.
*/
if (address < FCF_START_ADDR) {
/* Write portion before FCF */
int pre_fcf_len = FCF_START_ADDR - address;
ret = hal_flash_write(address, data, pre_fcf_len);
if (ret != 0) return ret;
address = FCF_END_ADDR;
data += pre_fcf_len + (FCF_END_ADDR - FCF_START_ADDR);
len -= pre_fcf_len + (FCF_END_ADDR - FCF_START_ADDR);
} else if (address >= FCF_START_ADDR && address < FCF_END_ADDR) {
/* Skip entirely within FCF region */
int skip = FCF_END_ADDR - address;
if (skip >= len) {
return 0; /* Entire write is within FCF - skip it */
}
address = FCF_END_ADDR;
data += skip;
len -= skip;
}
if (len <= 0) return 0;
}
while (len > 0) {
/* Handle unaligned start or partial phrase */
if ((len < FLASH_PHRASE_SIZE) || (address & (FLASH_PHRASE_SIZE - 1))) {
/* Handle unaligned start or partial phrase */
uint32_t aligned_addr = address & ~(FLASH_PHRASE_SIZE - 1);
uint32_t offset = address - aligned_addr;
int bytes_to_copy;
/* Read current phrase data */
memcpy(phrase_buf, (void*)aligned_addr, FLASH_PHRASE_SIZE);
/* Calculate bytes to copy */
bytes_to_copy = FLASH_PHRASE_SIZE - offset;
if (bytes_to_copy > len) {
int bytes_to_copy = FLASH_PHRASE_SIZE - offset;
if (bytes_to_copy > len)
bytes_to_copy = len;
}
/* Merge new data */
memcpy(phrase_buf, (void*)aligned_addr, FLASH_PHRASE_SIZE);
memcpy(phrase_buf + offset, data + i, bytes_to_copy);
/* Only program if not all 0xFF */
if (memcmp(phrase_buf, empty_phrase, FLASH_PHRASE_SIZE) != 0) {
ret = flash_program_phrase(aligned_addr, phrase_buf);
if (ret != 0) {
return ret;
}
}
ret = flash_program_phrase(aligned_addr, phrase_buf);
if (ret != 0)
return ret;
address += bytes_to_copy;
i += bytes_to_copy;
len -= bytes_to_copy;
}
else {
} else {
/* Program full phrases */
while (len >= FLASH_PHRASE_SIZE) {
/* Only program if not all 0xFF */
if (memcmp(data + i, empty_phrase, FLASH_PHRASE_SIZE) != 0) {
ret = flash_program_phrase(address, data + i);
if (ret != 0) {
return ret;
}
}
ret = flash_program_phrase(address, data + i);
if (ret != 0)
return ret;
address += FLASH_PHRASE_SIZE;
i += FLASH_PHRASE_SIZE;
len -= FLASH_PHRASE_SIZE;
}
}
}
return 0;
}

View File

@ -258,6 +258,7 @@ size_t strlen(const char *s)
#endif
#if !defined(__IAR_SYSTEMS_ICC__) && !defined(TARGET_X86_64_EFI)
/* some of the hal_flash_ functions need this during updates */
void RAMFUNCTION *memcpy(void *dst, const void *src, size_t n)
{
size_t i;

View File

@ -76,6 +76,11 @@ static void RAMFUNCTION wolfBoot_self_update(struct wolfBoot_image *src)
{
uintptr_t pos = 0;
uintptr_t src_offset = IMAGE_HEADER_SIZE;
#ifdef ARCH_SIM
uintptr_t start_text = ARCH_FLASH_OFFSET;
#else
uintptr_t start_text = (uintptr_t)&_start_text; /* save off before erase */
#endif
hal_flash_unlock();
wolfBoot_erase_bootloader();
@ -84,37 +89,23 @@ static void RAMFUNCTION wolfBoot_self_update(struct wolfBoot_image *src)
while (pos < src->fw_size) {
uint8_t buffer[FLASHBUFFER_SIZE];
if (src_offset + pos < (src->fw_size + IMAGE_HEADER_SIZE + FLASHBUFFER_SIZE)) {
#ifdef ARCH_SIM
/* Use ARCH_FLASH_OFFSET for simulator: flash is mmap'd at runtime,
* so the linker symbol _start_text does not point to simulated flash */
uintptr_t opos = pos + ARCH_FLASH_OFFSET;
#else
uintptr_t opos = pos + ((uintptr_t)&_start_text);
#endif
ext_flash_check_read((uintptr_t)(src->hdr) + src_offset + pos, (void*)buffer, FLASHBUFFER_SIZE);
hal_flash_write(opos, buffer, FLASHBUFFER_SIZE);
hal_flash_write(start_text + pos, buffer, FLASHBUFFER_SIZE);
}
pos += FLASHBUFFER_SIZE;
}
goto lock_and_reset;
}
else
#endif
while (pos < src->fw_size) {
if (src_offset + pos < (src->fw_size + IMAGE_HEADER_SIZE + FLASHBUFFER_SIZE)) {
uint8_t *orig = (uint8_t*)(src->hdr + src_offset + pos);
#ifdef ARCH_SIM
/* Use ARCH_FLASH_OFFSET for simulator: flash is mmap'd at runtime,
* so the linker symbol _start_text does not point to simulated flash */
hal_flash_write(pos + ARCH_FLASH_OFFSET, orig, FLASHBUFFER_SIZE);
#else
hal_flash_write(pos + (uintptr_t)&_start_text, orig, FLASHBUFFER_SIZE);
#endif
{
while (pos < src->fw_size) {
if (src_offset + pos < (src->fw_size + IMAGE_HEADER_SIZE + FLASHBUFFER_SIZE)) {
uint8_t *orig = (uint8_t*)(src->hdr + src_offset + pos);
hal_flash_write(pos + start_text, orig, FLASHBUFFER_SIZE);
}
pos += FLASHBUFFER_SIZE;
}
pos += FLASHBUFFER_SIZE;
}
#ifdef EXT_FLASH
lock_and_reset:
#endif
hal_flash_lock();
arch_reboot();
}

View File

@ -40,16 +40,19 @@ UART_ONLY=0
INTERACTIVE=0
BUILD_UPDATE=0
TEST_UPDATE=0
TEST_SELFUPDATE=0
usage() {
echo "Usage: $0 [OPTIONS]"
echo ""
echo "Options:"
echo " --test-update Build test-update.srec with v2 image in update partition"
echo " (no trigger - use test-app 'trigger' command to start update)"
echo " --update Build update.srec with v2 image + trigger magic"
echo " (auto-starts update on boot - may cause issues)"
echo " --skip-build Skip the build step (use existing .srec)"
echo " --test-update Build test-update.srec with v2 image in update partition"
echo " (no trigger - use test-app 'trigger' command to start update)"
echo " --test-selfupdate Build test-selfupdate.srec with bootloader v1 + v2 bootloader update"
echo " (tests bootloader self-update - requires RAM_CODE=1)"
echo " --update Build update.srec with v2 image + trigger magic"
echo " (auto-starts update on boot - may cause issues)"
echo " --skip-build Skip the build step (use existing .srec)"
echo " --skip-flash Skip flashing (just monitor UART)"
echo " --skip-uart Skip UART monitoring (just build and flash)"
echo " --uart-only Only monitor UART (same as --skip-build --skip-flash)"
@ -63,6 +66,7 @@ usage() {
echo "Examples:"
echo " $0 # Build and flash factory.srec (v1 only)"
echo " $0 --test-update # Build with v2 in update partition, use 'trigger' cmd"
echo " $0 --test-selfupdate # Build with bootloader v2 update, tests self-update"
echo " $0 --skip-uart # Flash without UART monitoring"
echo " $0 --uart-only # Just monitor UART"
exit 0
@ -80,6 +84,11 @@ while [[ $# -gt 0 ]]; do
SREC_FILE="update.srec"
shift
;;
--test-selfupdate)
TEST_SELFUPDATE=1
SREC_FILE="test-selfupdate.srec"
shift
;;
--skip-build)
SKIP_BUILD=1
shift
@ -139,6 +148,39 @@ trap cleanup EXIT
echo -e "${GREEN}=== NXP S32K142 Flash and Monitor Script ===${NC}"
# Function to parse SIGN and HASH from .config file
parse_config_signing() {
local config_file="$1"
if [ ! -f "$config_file" ]; then
echo -e "${RED}Error: Config file not found: ${config_file}${NC}"
exit 1
fi
# Extract SIGN value (e.g., SIGN?=ECC256 -> ECC256)
SIGN_VALUE=$(grep -E "^SIGN" "$config_file" | head -1 | sed -E 's/^SIGN\??=//' | tr -d '[:space:]')
# Extract HASH value (e.g., HASH?=SHA256 -> SHA256)
HASH_VALUE=$(grep -E "^HASH" "$config_file" | head -1 | sed -E 's/^HASH\??=//' | tr -d '[:space:]')
if [ -z "$SIGN_VALUE" ]; then
echo -e "${RED}Error: SIGN not found in config file${NC}"
exit 1
fi
if [ -z "$HASH_VALUE" ]; then
echo -e "${RED}Error: HASH not found in config file${NC}"
exit 1
fi
# Convert SIGN to lowercase flag format
SIGN_FLAG=$(echo "$SIGN_VALUE" | tr '[:upper:]' '[:lower:]')
SIGN_FLAG="--${SIGN_FLAG}"
# Convert HASH to lowercase flag format
HASH_FLAG=$(echo "$HASH_VALUE" | tr '[:upper:]' '[:lower:]')
HASH_FLAG="--${HASH_FLAG}"
echo -e "${CYAN}Using signing: ${SIGN_VALUE} / ${HASH_VALUE}${NC}"
}
# Change to wolfboot root directory
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
WOLFBOOT_ROOT="$(cd "${SCRIPT_DIR}/../.." && pwd)"
@ -156,9 +198,113 @@ if [ $SKIP_BUILD -eq 0 ]; then
cp "${CONFIG_FILE}" .config
echo "Copied ${CONFIG_FILE} to .config"
# Parse signing configuration from .config
parse_config_signing .config
# Step 2: Build
echo ""
if [ $TEST_UPDATE -eq 1 ]; then
if [ $TEST_SELFUPDATE -eq 1 ]; then
echo -e "${GREEN}[2/4] Building test-selfupdate.srec (bootloader v1 + v2 bootloader update)...${NC}"
echo -e "${CYAN}NOTE: This tests bootloader self-update functionality${NC}"
# Step 2a: Build bootloader v1
echo ""
echo -e "${CYAN}Building bootloader v1...${NC}"
make clean
make wolfboot.bin RAM_CODE=1 WOLFBOOT_VERSION=1
if [ ! -f "wolfboot.bin" ]; then
echo -e "${RED}Error: Failed to build wolfboot.bin v1${NC}"
exit 1
fi
cp wolfboot.bin wolfboot_v1.bin
echo -e "${GREEN}Bootloader v1 built successfully${NC}"
# Build factory.srec to get the v1 application image
echo ""
echo -e "${CYAN}Building factory image with v1 application...${NC}"
make factory.srec
if [ ! -f "factory.srec" ]; then
echo -e "${RED}Error: Failed to build factory.srec${NC}"
exit 1
fi
if [ ! -f "test-app/image_v1_signed.bin" ]; then
echo -e "${RED}Error: test-app/image_v1_signed.bin not found${NC}"
exit 1
fi
# Preserve v1 application image before clean (copy outside test-app to survive clean)
cp test-app/image_v1_signed.bin image_v1_signed_backup.bin
echo -e "${GREEN}Preserved v1 application image${NC}"
# Step 2b: Build bootloader v2
echo ""
echo -e "${CYAN}Building bootloader v2...${NC}"
make clean
make wolfboot.bin RAM_CODE=1 WOLFBOOT_VERSION=2
if [ ! -f "wolfboot.bin" ]; then
echo -e "${RED}Error: Failed to build wolfboot.bin v2${NC}"
exit 1
fi
# Step 2c: Sign bootloader v2 with --wolfboot-update flag
echo ""
echo -e "${CYAN}Signing bootloader v2 with --wolfboot-update flag...${NC}"
# Ensure sign tool is built
if [ ! -f "tools/keytools/sign" ]; then
echo -e "${YELLOW}Building sign tool...${NC}"
make -C tools/keytools
fi
# Check if key exists
if [ ! -f "wolfboot_signing_private_key.der" ]; then
echo -e "${RED}Error: wolfboot_signing_private_key.der not found${NC}"
echo "Please generate keys first with: make keys"
exit 1
fi
# Sign with --wolfboot-update flag (version 2) using config values
./tools/keytools/sign ${SIGN_FLAG} ${HASH_FLAG} --wolfboot-update wolfboot.bin wolfboot_signing_private_key.der 2
if [ ! -f "wolfboot_v2_signed.bin" ]; then
echo -e "${RED}Error: Failed to sign bootloader v2${NC}"
exit 1
fi
echo -e "${GREEN}Bootloader v2 signed successfully${NC}"
# Step 2e: Assemble test-selfupdate.bin
echo ""
echo -e "${CYAN}Assembling test-selfupdate.bin...${NC}"
echo " wolfboot_v1.bin @ 0x0 (bootloader v1)"
echo " image_v1_signed.bin @ ${WOLFBOOT_PARTITION_BOOT_ADDRESS} (boot partition)"
echo " wolfboot_v2_signed.bin @ ${WOLFBOOT_PARTITION_UPDATE_ADDRESS} (update partition)"
# Ensure bin-assemble tool is built
if [ ! -f "tools/bin-assemble/bin-assemble" ]; then
echo -e "${YELLOW}Building bin-assemble tool...${NC}"
make -C tools/bin-assemble
fi
./tools/bin-assemble/bin-assemble \
test-selfupdate.bin \
0x0 wolfboot_v1.bin \
${WOLFBOOT_PARTITION_BOOT_ADDRESS} image_v1_signed_backup.bin \
${WOLFBOOT_PARTITION_UPDATE_ADDRESS} wolfboot_v2_signed.bin
if [ ! -f "test-selfupdate.bin" ]; then
echo -e "${RED}Error: Failed to assemble test-selfupdate.bin${NC}"
exit 1
fi
# Step 2f: Convert to SREC
echo ""
echo -e "${CYAN}Converting to test-selfupdate.srec...${NC}"
arm-none-eabi-objcopy -I binary -O srec --srec-forceS3 test-selfupdate.bin test-selfupdate.srec
# Cleanup temp files
rm -f trigger_magic.bin
rm -f wolfboot_v1.bin
rm -f image_v1_signed_backup.bin
echo -e "${GREEN}Build successful: test-selfupdate.srec${NC}"
elif [ $TEST_UPDATE -eq 1 ]; then
echo -e "${GREEN}[2/4] Building test-update.srec (v1 boot + v2 update, no trigger)...${NC}"
make clean
make factory.srec
@ -167,7 +313,7 @@ if [ $SKIP_BUILD -eq 0 ]; then
echo ""
echo -e "${CYAN}Signing test-app with version 2...${NC}"
cp test-app/image_v1_signed.bin test-app/image_v1_signed_backup.bin
./tools/keytools/sign --ecc256 --sha256 test-app/image.bin wolfboot_signing_private_key.der 2
./tools/keytools/sign ${SIGN_FLAG} ${HASH_FLAG} test-app/image.bin wolfboot_signing_private_key.der 2
echo -e "${CYAN}Assembling test-update.bin...${NC}"
echo " wolfboot.bin @ 0x0"
@ -206,7 +352,7 @@ if [ $SKIP_BUILD -eq 0 ]; then
echo ""
echo -e "${CYAN}Signing test-app with version 2...${NC}"
cp test-app/image_v1_signed.bin test-app/image_v1_signed_backup.bin
./tools/keytools/sign --ecc256 --sha256 test-app/image.bin wolfboot_signing_private_key.der 2
./tools/keytools/sign ${SIGN_FLAG} ${HASH_FLAG} test-app/image.bin wolfboot_signing_private_key.der 2
# Sign tool outputs to image_v2_signed.bin directly
# Create trigger magic: 'p' (IMG_STATE_UPDATING = 0x70) + "BOOT"