mirror of https://github.com/wolfSSL/wolfBoot.git
Fixes to wolfBoot self-update (memcmp was used which is not a RAMFUNCTION).
parent
b92e2ca0cd
commit
4bbe28920c
121
docs/Targets.md
121
docs/Targets.md
|
|
@ -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
|
||||
|
|
|
|||
122
hal/s32k1xx.c
122
hal/s32k1xx.c
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
Loading…
Reference in New Issue