Skip to content

Commit 08c6673

Browse files
dgarskedanielinux
authored andcommitted
Fix Vorago VA416x0 IRAM shadow update (use word-aligned stores)
The VA416xx code RAM (IRAM at 0x00000000-0x0003FFFF) silently drops 8-bit and 16-bit stores when ROM_PROT.WREN=1 - only word-aligned 32-bit stores are honored, because the ECC machinery computes parity per 32-bit word and rejects sub-word writes (no fault is raised). wolfBoot's local memcpy()/memset() are byte-wise (ldrb/strb), so the IRAM shadow update in ext_flash_write/read/erase appeared to succeed but actually left the destination unchanged. The FRAM content was updated correctly, but after the swap wolfBoot branched into the partition at 0xB800 in IRAM where the stale image still lived, so the running app was the OLD version even though the partition header (read from FRAM) reported the new version. Add iram_write/iram_fill helpers that use 32-bit stores for the bulk of an aligned region and read-modify-write the containing word for any unaligned head/tail, and use them in ext_flash_write/read/erase in place of memcpy/memset for the shadow update. Partition addresses are sector-aligned so in practice the path is always pure 32-bit stores. Verified end-to-end on VA41630-EVK with build_test.sh update: app v1 boots, trigger sets, swap runs sector-by-sector, post-swap boot prints "Booting version: 0x2" and the running app prints v2-specific output in TESTING state. After wolfBoot_success() and a manual reset the second boot reports state CONFIRMED.
1 parent b94954e commit 08c6673

1 file changed

Lines changed: 77 additions & 7 deletions

File tree

hal/va416x0.c

Lines changed: 77 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -361,6 +361,77 @@ void ext_flash_unlock(void)
361361
VOR_SYSCONFIG->ROM_PROT |= SYSCONFIG_ROM_PROT_WREN_Msk;
362362
}
363363

364+
/* The VA416xx code RAM (IRAM, 0x00000000-0x0003FFFF) silently drops 8/16-bit
365+
* stores when WREN=1 - only word-aligned 32-bit stores stick (the ECC
366+
* machinery computes parity per word and rejects sub-word writes without
367+
* fault). A generic byte-wise memcpy/memset on the IRAM shadow appears
368+
* to succeed but leaves the destination unchanged. These helpers copy/fill
369+
* with 32-bit stores so the IRAM shadow update actually takes effect.
370+
*
371+
* Partition addresses (boot/update/swap) are sector-aligned (0x800) and the
372+
* swap engine moves whole sector-sized blocks, so in practice the IRAM
373+
* shadow path is always word-aligned. The unaligned head/tail fallbacks
374+
* exist for defense-in-depth. */
375+
static void iram_write(void *dst, const void *src, int len)
376+
{
377+
uintptr_t d = (uintptr_t)dst;
378+
uintptr_t s = (uintptr_t)src;
379+
/* Word-aligned bulk copy */
380+
if (((d | s) & 3u) == 0u) {
381+
uint32_t *wd = (uint32_t *)dst;
382+
const uint32_t *ws = (const uint32_t *)src;
383+
while (len >= 4) {
384+
*wd++ = *ws++;
385+
len -= 4;
386+
}
387+
/* Fall through with byte tail (typically zero on this target) */
388+
dst = wd;
389+
src = ws;
390+
}
391+
/* Byte tail/unaligned: do read-modify-write of the containing word
392+
* (sub-word stores are dropped by the hardware). */
393+
while (len > 0) {
394+
uintptr_t addr = (uintptr_t)dst & ~3u;
395+
uint32_t off = (uintptr_t)dst & 3u;
396+
uint32_t word = *(volatile uint32_t *)addr;
397+
uint8_t *wp = (uint8_t *)&word;
398+
while (len > 0 && off < 4u) {
399+
wp[off++] = *(const uint8_t *)src;
400+
src = (const uint8_t *)src + 1;
401+
dst = (uint8_t *)dst + 1;
402+
len--;
403+
}
404+
*(volatile uint32_t *)addr = word;
405+
}
406+
}
407+
408+
static void iram_fill(void *dst, uint8_t val, int len)
409+
{
410+
uint32_t pattern = ((uint32_t)val << 24) | ((uint32_t)val << 16) |
411+
((uint32_t)val << 8) | (uint32_t)val;
412+
uintptr_t d = (uintptr_t)dst;
413+
if ((d & 3u) == 0u) {
414+
uint32_t *wd = (uint32_t *)dst;
415+
while (len >= 4) {
416+
*wd++ = pattern;
417+
len -= 4;
418+
}
419+
dst = wd;
420+
}
421+
while (len > 0) {
422+
uintptr_t addr = (uintptr_t)dst & ~3u;
423+
uint32_t off = (uintptr_t)dst & 3u;
424+
uint32_t word = *(volatile uint32_t *)addr;
425+
uint8_t *wp = (uint8_t *)&word;
426+
while (len > 0 && off < 4u) {
427+
wp[off++] = val;
428+
dst = (uint8_t *)dst + 1;
429+
len--;
430+
}
431+
*(volatile uint32_t *)addr = word;
432+
}
433+
}
434+
364435
int ext_flash_write(uintptr_t address, const uint8_t *data, int len)
365436
{
366437
hal_status_t status;
@@ -370,8 +441,8 @@ int ext_flash_write(uintptr_t address, const uint8_t *data, int len)
370441
#endif
371442
status = FRAM_Write(ROM_SPI_BANK, address, (uint8_t*)data, len);
372443
if (status == hal_status_ok) {
373-
/* update the shadow IRAM */
374-
memcpy((void*)address, data, len);
444+
/* update the shadow IRAM (word-aligned stores; see iram_write) */
445+
iram_write((void*)address, data, len);
375446
}
376447
else {
377448
return -(int)status; /* convert to negative error code */
@@ -388,8 +459,8 @@ int ext_flash_read(uintptr_t address, uint8_t *data, int len)
388459
#endif
389460
status = FRAM_Read(ROM_SPI_BANK, address, data, len);
390461
if (status == hal_status_ok) {
391-
/* update the shadow IRAM */
392-
memcpy((void*)address, data, len);
462+
/* update the shadow IRAM (word-aligned stores; see iram_write) */
463+
iram_write((void*)address, data, len);
393464
}
394465
else {
395466
return -(int)status; /* convert to negative error code */
@@ -405,8 +476,8 @@ int ext_flash_erase(uintptr_t address, int len)
405476
#endif
406477
status = FRAM_Erase(ROM_SPI_BANK, address, len);
407478
if (status == hal_status_ok) {
408-
/* update the shadow IRAM */
409-
memset((void*)address, 0xFF, len);
479+
/* update the shadow IRAM (word-aligned stores; see iram_fill) */
480+
iram_fill((void*)address, 0xFF, len);
410481
}
411482
else {
412483
return -(int)status; /* convert to negative error code */
@@ -539,7 +610,6 @@ void hal_init(void)
539610
#ifdef TEST_EXT_FLASH
540611
test_ext_flash();
541612
#endif
542-
543613
}
544614

545615
void hal_prepare_boot(void)

0 commit comments

Comments
 (0)