Skip to content

Commit 4bbe289

Browse files
dgarskedanielinux
authored andcommitted
Fixes to wolfBoot self-update (memcmp was used which is not a RAMFUNCTION).
1 parent b92e2ca commit 4bbe289

5 files changed

Lines changed: 234 additions & 209 deletions

File tree

docs/Targets.md

Lines changed: 24 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -3031,10 +3031,11 @@ The S32K1xx can be programmed and debugged using various tools. The recommended
30313031
**Using PEMicro (recommended for S32K EVB boards):**
30323032

30333033
1. Install PEMicro GDB Server from [pemicro.com](https://www.pemicro.com/products/product_viewDetails.cfm?product_id=15320167)
3034+
Linux: `~/.local/pemicro/`
30343035

30353036
2. Start PEMicro GDB Server:
30363037
```sh
3037-
pegdbserver_console -device=NXP_S32K1xx_S32K142 -startserver -serverport=7224
3038+
pegdbserver_console -device=NXP_S32K1xx_S32K142F256M15 -startserver -interface=OPENSDA -port=USB1 -serverport=7224 -speed=5000
30383039
```
30393040

30403041
3. In another terminal, connect with GDB and flash:
@@ -3068,41 +3069,6 @@ cp factory.srec /media/<user>/S32K142EVB/
30683069

30693070
The board will automatically program the flash and reset.
30703071

3071-
### NXP S32K1XX: Flash Script
3072-
3073-
A convenience script is provided for building and flashing S32K142:
3074-
3075-
```sh
3076-
./tools/scripts/nxp-s32k142-flash.sh [OPTIONS]
3077-
```
3078-
3079-
**Options:**
3080-
3081-
| Option | Description |
3082-
|--------|-------------|
3083-
| (none) | Build and flash `factory.srec` (v1 only) |
3084-
| `--test-update` | Build with v2 in update partition (use `trigger` command to start update) |
3085-
| `--update` | Build with v2 and auto-trigger (starts update on boot) |
3086-
| `--skip-build` | Skip build, use existing `.srec` file |
3087-
| `--skip-flash` | Skip flashing (just build) |
3088-
| `--skip-uart` | Skip UART monitoring |
3089-
| `--uart-only` | Only monitor UART (no build/flash) |
3090-
| `--interactive` | Keep UART open until Ctrl+C |
3091-
| `--timeout SECS` | UART capture duration (default: 5s) |
3092-
3093-
**Examples:**
3094-
3095-
```sh
3096-
# Build and flash factory image, monitor UART for 5 seconds
3097-
./tools/scripts/nxp-s32k142-flash.sh
3098-
3099-
# Build with v2 update, flash, and stay on UART
3100-
./tools/scripts/nxp-s32k142-flash.sh --test-update --interactive
3101-
3102-
# Just monitor UART
3103-
./tools/scripts/nxp-s32k142-flash.sh --uart-only --interactive
3104-
```
3105-
31063072
### NXP S32K1XX: Test Application
31073073

31083074
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.
31413107
Firmware Version: 1
31423108
31433109
=== Partition Information ===
3144-
Boot Partition @ 0xC000:
3110+
Boot Partition:
3111+
Address: 0x0000C000
31453112
Version: 1
3146-
State: SUCCESS (0x00)
3147-
Update Partition @ 0x25000:
3148-
Version: 0 (empty)
3149-
State: (no trailer)
3113+
State: SUCCESS
3114+
Update Partition:
3115+
Address: 0x00025000
3116+
Version: 0
3117+
State: SUCCESS
3118+
Swap Partition:
3119+
Address: 0x0003E000
3120+
Size: 2048 bytes
31503121
31513122
=== Keystore Information ===
3152-
Number of keys: 1
3153-
Key 0: ECDSA P-256 (secp256r1), SHA-256
3123+
Number of public keys: 1
3124+
Hash: SHA-256
3125+
3126+
Key #0:
3127+
Algorithm: ECDSA P-256 (secp256r1)
3128+
Size: 64 bytes
3129+
Data:
3130+
9a 33 e0 18 24 4b a7 29 51 90 15 f0 74 6e e4 a6
3131+
bf 2d 00 47 32 1f 32 5a d6 9a 30 32 d1 c3 30 3f
3132+
0a e3 1b 0d 0f 98 b2 e6 5c eb 42 1c 64 2b 32 db
3133+
a4 48 75 5b e3 49 94 45 12 64 e3 57 b4 5b 81 73
31543134
31553135
Type 'help' for available commands.
31563136
31573137
cmd>
31583138
```
31593139

3160-
**Testing Firmware Update:**
3161-
3162-
1. Flash with v2 image: `./tools/scripts/nxp-s32k142-flash.sh --test-update`
3163-
2. Connect to UART: `picocom -b 115200 /dev/ttyACM1`
3164-
3. Run `status` to verify v1 in boot, v2 in update
3165-
4. Run `trigger` to set update flag
3166-
5. Run `reboot` to start update
3167-
6. After reboot, LED changes from Green (v1) to Blue (v2)
3168-
7. Run `success` to mark v2 as good
3169-
3170-
### NXP S32K1XX: Flash Configuration Field (FCF)
3171-
3172-
The bootloader includes the Flash Configuration Field (FCF) at address 0x400-0x40F with the following settings:
3173-
- Flash security: Unsecured
3174-
- Flash protection: All regions unprotected
3175-
- Backdoor key access: Enabled
3176-
3177-
**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.
3178-
3179-
### NXP S32K1XX: Recovering a Locked/Unresponsive Device
3180-
3181-
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:
3182-
3183-
**Symptoms of a locked device:**
3184-
- Debugger cannot connect ("Soft reset failed", "Failed to enter debug mode")
3185-
- Device stuck in reset (D1 LED constantly on for S32K-EVB)
3186-
- J-Link reports "Readout protection is set" at address 0x400-0x40F
3187-
3188-
**Recovery Option 1: PEMicro Force Mass Erase**
3189-
3190-
```sh
3191-
pegdbserver_console -device=NXP_S32K1xx_S32K142 -interface=OPENSDA -port=USB1 -forcemasserase -singlesession
3192-
```
3193-
3194-
After mass erase completes, power cycle the board before attempting to reconnect.
3195-
3196-
**Recovery Option 2: J-Link Unlock**
3197-
3198-
```sh
3199-
JLinkExe -if swd -Device S32K142
3200-
unlock Kinetis
3201-
erase
3202-
r
3203-
q
3204-
```
3205-
3206-
Then power cycle the board.
3207-
3208-
### NXP S32K1XX: TODO / Future Enhancements
3209-
3210-
The following features are planned or available for contribution:
3140+
### NXP S32K1XX: TODO
32113141

3212-
- [x] **Sector swap update**: Full firmware update with sector swapping (completed)
3213-
- [x] **Interactive test application**: Console with status, trigger, success commands (completed)
3214-
- [x] **Flash automation script**: `tools/scripts/nxp-s32k142-flash.sh` (completed)
32153142
- [ ] **XMODEM improvements**: ISR-based UART RX for reliable high-speed transfers
32163143
- [ ] **SPLL + SOSC support**: Add external crystal oscillator and SPLL configuration for true 112 MHz operation in HSRUN mode
32173144
- [ ] **Hardware crypto acceleration**: Integrate CSEc (Cryptographic Services Engine) for hardware-accelerated crypto operations

hal/s32k1xx.c

Lines changed: 41 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,22 @@
4040
#define DSB() __asm__ volatile ("dsb")
4141
#define ISB() __asm__ volatile ("isb")
4242

43+
/* PRIMASK helpers for critical sections */
44+
#define __get_PRIMASK() ({ \
45+
uint32_t primask; \
46+
__asm__ volatile ("mrs %0, primask" : "=r" (primask)); \
47+
primask; \
48+
})
49+
50+
#define __set_PRIMASK(primask) \
51+
__asm__ volatile ("msr primask, %0" :: "r" (primask) : "memory")
52+
53+
#define __disable_irq() \
54+
__asm__ volatile ("cpsid i" ::: "memory")
55+
56+
#define __enable_irq() \
57+
__asm__ volatile ("cpsie i" ::: "memory")
58+
4359
#include "s32k1xx.h"
4460

4561
/* ============== Flash Configuration Field (FCF) ============== */
@@ -125,14 +141,6 @@ static void watchdog_enable(uint32_t timeout_ms)
125141
while (!(WDOG_CS & WDOG_CS_RCS)) {}
126142
}
127143

128-
/* Refresh (kick) the watchdog to prevent reset
129-
* Must be called periodically before timeout expires
130-
*/
131-
static void watchdog_refresh(void)
132-
{
133-
/* For CMD32EN mode, write refresh key as 32-bit value */
134-
WDOG_CNT = WDOG_CNT_REFRESH;
135-
}
136144
#endif /* WATCHDOG */
137145

138146
/* ============== Clock Configuration ============== */
@@ -352,13 +360,18 @@ static void RAMFUNCTION flash_clear_errors(void)
352360

353361
static int RAMFUNCTION flash_program_phrase(uint32_t address, const uint8_t *data)
354362
{
363+
/* Skip if phrase is all 0xFF (erased) */
364+
if (data[0] == 0xFF && data[1] == 0xFF && data[2] == 0xFF && data[3] == 0xFF &&
365+
data[4] == 0xFF && data[5] == 0xFF && data[6] == 0xFF && data[7] == 0xFF) {
366+
return 0;
367+
}
368+
355369
/* Wait for previous command to complete */
356370
flash_wait_complete();
357371
flash_clear_errors();
358372

359-
/* Set up Program Phrase command (0x07)
360-
* Programs 8 bytes at the specified address
361-
*/
373+
/* Set up Program Phrase command (0x07) */
374+
/* Programs 8 bytes at the specified address */
362375
FTFC_FCCOB0 = FTFC_CMD_PROGRAM_PHRASE;
363376
FTFC_FCCOB1 = (uint8_t)(address >> 16);
364377
FTFC_FCCOB2 = (uint8_t)(address >> 8);
@@ -384,7 +397,7 @@ static int RAMFUNCTION flash_program_phrase(uint32_t address, const uint8_t *dat
384397

385398
#ifdef WATCHDOG
386399
/* Refresh watchdog after flash operation */
387-
watchdog_refresh();
400+
WDOG_CNT = WDOG_CNT_REFRESH;
388401
#endif
389402

390403
/* Check for errors */
@@ -414,20 +427,20 @@ static int RAMFUNCTION flash_erase_sector_internal(uint32_t address)
414427
ISB();
415428

416429
/* Disable interrupts during flash operation to prevent code fetch from flash */
417-
__asm__ volatile ("mrs %0, primask\n\t"
418-
"cpsid i" : "=r" (primask) :: "memory");
430+
primask = __get_PRIMASK();
431+
__disable_irq();
419432

420433
FTFC_FSTAT = FTFC_FSTAT_CCIF;
421434

422435
/* Wait for completion */
423436
flash_wait_complete();
424437

425438
/* Re-enable interrupts */
426-
__asm__ volatile ("msr primask, %0" :: "r" (primask) : "memory");
439+
__set_PRIMASK(primask);
427440

428441
#ifdef WATCHDOG
429442
/* Refresh watchdog after potentially long flash operation */
430-
watchdog_refresh();
443+
WDOG_CNT = WDOG_CNT_REFRESH;
431444
#endif
432445

433446
/* Check for errors */
@@ -438,7 +451,6 @@ static int RAMFUNCTION flash_erase_sector_internal(uint32_t address)
438451
return 0;
439452
}
440453

441-
442454
/* ============== HAL Interface Functions ============== */
443455

444456
void hal_init(void)
@@ -510,92 +522,40 @@ void hal_prepare_boot(void)
510522

511523
int RAMFUNCTION hal_flash_write(uint32_t address, const uint8_t *data, int len)
512524
{
513-
int ret = 0;
514-
int i = 0;
525+
int ret, i = 0;
515526
uint8_t phrase_buf[FLASH_PHRASE_SIZE];
516-
const uint8_t empty_phrase[FLASH_PHRASE_SIZE] = {
517-
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
518-
};
519-
520-
/* CRITICAL: Protect the Flash Configuration Field (FCF) region.
521-
* Writing incorrect values to 0x400-0x40F can permanently lock the device!
522-
* The FCF is programmed once in the flash_config section and should never
523-
* be modified at runtime.
524-
*/
525-
if ((address < FCF_END_ADDR) && ((address + len) > FCF_START_ADDR)) {
526-
/* Requested write overlaps with FCF region - this is dangerous!
527-
* Skip the FCF portion to prevent device locking.
528-
*/
529-
if (address < FCF_START_ADDR) {
530-
/* Write portion before FCF */
531-
int pre_fcf_len = FCF_START_ADDR - address;
532-
ret = hal_flash_write(address, data, pre_fcf_len);
533-
if (ret != 0) return ret;
534-
address = FCF_END_ADDR;
535-
data += pre_fcf_len + (FCF_END_ADDR - FCF_START_ADDR);
536-
len -= pre_fcf_len + (FCF_END_ADDR - FCF_START_ADDR);
537-
} else if (address >= FCF_START_ADDR && address < FCF_END_ADDR) {
538-
/* Skip entirely within FCF region */
539-
int skip = FCF_END_ADDR - address;
540-
if (skip >= len) {
541-
return 0; /* Entire write is within FCF - skip it */
542-
}
543-
address = FCF_END_ADDR;
544-
data += skip;
545-
len -= skip;
546-
}
547-
if (len <= 0) return 0;
548-
}
549527

550528
while (len > 0) {
551-
/* Handle unaligned start or partial phrase */
552529
if ((len < FLASH_PHRASE_SIZE) || (address & (FLASH_PHRASE_SIZE - 1))) {
530+
/* Handle unaligned start or partial phrase */
553531
uint32_t aligned_addr = address & ~(FLASH_PHRASE_SIZE - 1);
554532
uint32_t offset = address - aligned_addr;
555-
int bytes_to_copy;
556-
557-
/* Read current phrase data */
558-
memcpy(phrase_buf, (void*)aligned_addr, FLASH_PHRASE_SIZE);
559-
560-
/* Calculate bytes to copy */
561-
bytes_to_copy = FLASH_PHRASE_SIZE - offset;
562-
if (bytes_to_copy > len) {
533+
int bytes_to_copy = FLASH_PHRASE_SIZE - offset;
534+
if (bytes_to_copy > len)
563535
bytes_to_copy = len;
564-
}
565536

566-
/* Merge new data */
537+
memcpy(phrase_buf, (void*)aligned_addr, FLASH_PHRASE_SIZE);
567538
memcpy(phrase_buf + offset, data + i, bytes_to_copy);
568539

569-
/* Only program if not all 0xFF */
570-
if (memcmp(phrase_buf, empty_phrase, FLASH_PHRASE_SIZE) != 0) {
571-
ret = flash_program_phrase(aligned_addr, phrase_buf);
572-
if (ret != 0) {
573-
return ret;
574-
}
575-
}
540+
ret = flash_program_phrase(aligned_addr, phrase_buf);
541+
if (ret != 0)
542+
return ret;
576543

577544
address += bytes_to_copy;
578545
i += bytes_to_copy;
579546
len -= bytes_to_copy;
580-
}
581-
else {
547+
} else {
582548
/* Program full phrases */
583549
while (len >= FLASH_PHRASE_SIZE) {
584-
/* Only program if not all 0xFF */
585-
if (memcmp(data + i, empty_phrase, FLASH_PHRASE_SIZE) != 0) {
586-
ret = flash_program_phrase(address, data + i);
587-
if (ret != 0) {
588-
return ret;
589-
}
590-
}
591-
550+
ret = flash_program_phrase(address, data + i);
551+
if (ret != 0)
552+
return ret;
592553
address += FLASH_PHRASE_SIZE;
593554
i += FLASH_PHRASE_SIZE;
594555
len -= FLASH_PHRASE_SIZE;
595556
}
596557
}
597558
}
598-
599559
return 0;
600560
}
601561

src/string.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,7 @@ size_t strlen(const char *s)
258258
#endif
259259

260260
#if !defined(__IAR_SYSTEMS_ICC__) && !defined(TARGET_X86_64_EFI)
261+
/* some of the hal_flash_ functions need this during updates */
261262
void RAMFUNCTION *memcpy(void *dst, const void *src, size_t n)
262263
{
263264
size_t i;

0 commit comments

Comments
 (0)