PolarFire SoC: address PR review

- wolfBoot_fit_memcpy: return int so a failed PDMA copy propagates instead
  of being swallowed. The weak default (memcpy) returns 0; the MPFS250 PDMA
  override returns -1 if any chunk's mpfs_pdma_memcpy() fails. Callers now
  fail closed: fit_load_image_inner returns NULL (kernel load then panics
  via update_disk.c), the update_disk DTS copy panics, and hal_dts_fixup
  returns an error on a failed L2->DDR copy-back.
- options.mk: gate -DSTACK_SIZE_PER_HART behind RISC-V arch (RISCV/RISCV64).
  The macro is only consumed by the RISC-V startup asm and the mpfs250-m.ld
  sed token, so it is no longer emitted for PPC/ARM/other targets. The
  unconditional default (?= 0) is kept because the linker sed always needs
  a value to substitute.
pull/844/head
David Garske 2026-06-25 10:33:45 -07:00 committed by Daniele Lacamera
parent 6b3612f4b9
commit 5f40400e57
9 changed files with 84 additions and 24 deletions

View File

@ -477,7 +477,7 @@ void hal_init(void)
* inner retry inside mpfs_ddr_init() exhausts (typically because
* MTC wedged after the first failure), come back here for a full
* controller re-init. Empirical: per-attempt failure rate ~30%, so
* 3 outer attempts cover ~99.7% of boots. */
* MPFS_DDR_MAX_OUTER_RETRY (6) outer attempts cover ~99.9% of boots. */
for (outer_retry = 0; outer_retry < MPFS_DDR_MAX_OUTER_RETRY;
outer_retry++) {
if (outer_retry > 0) {
@ -752,12 +752,18 @@ static int mpfs_dts_fixup_inplace(void* dts_addr)
* through the PDMA master. A DDR source is read via its non-cached alias so
* PDMA sees real DDR; mpfs_pdma_memcpy remaps the dst 0x8x->0xCx and flushes
* L2. Chunked + WDT-petted for kernel-sized copies. */
void wolfBoot_fit_memcpy(void *dst, const void *src, uint32_t len)
int wolfBoot_fit_memcpy(void *dst, const void *src, uint32_t len)
{
uintptr_t d = (uintptr_t)dst;
uintptr_t s = (uintptr_t)src;
volatile const uint8_t *ncd;
const uint8_t *ncs;
uint32_t off = 0;
uint32_t chunk;
uint32_t k;
int retry;
int mism;
int rc = 0;
if ((s & 0xF0000000UL) == 0x80000000UL) {
s |= 0x40000000UL; /* non-cached source alias */
@ -767,17 +773,51 @@ void wolfBoot_fit_memcpy(void *dst, const void *src, uint32_t len)
if (chunk > (1024U * 1024U)) {
chunk = 1024U * 1024U;
}
(void)mpfs_pdma_memcpy((void *)(d + off),
(const void *)(s + off), chunk);
/* Refresh all five MSS watchdogs (they always count and reset the
* chip and cannot be disabled) during the multi-MB kernel copy. */
MSS_WDT_REFRESH(MSS_WDT_E51_BASE) = 0xDEADC0DEU;
MSS_WDT_REFRESH(MSS_WDT_U54_1_BASE) = 0xDEADC0DEU;
MSS_WDT_REFRESH(MSS_WDT_U54_2_BASE) = 0xDEADC0DEU;
MSS_WDT_REFRESH(MSS_WDT_U54_3_BASE) = 0xDEADC0DEU;
MSS_WDT_REFRESH(MSS_WDT_U54_4_BASE) = 0xDEADC0DEU;
/* mpfs_pdma_memcpy always returns 0, so the read-back verify below is
* the authoritative success check for this chunk. The PDMA->DDR write
* intermittently drops a block, so re-PDMA on a mismatch (same pattern
* as sdhci_platform_block_copy). A DDR destination (0x8xxxxxxx) is
* read back through its non-cached alias (| 0x40000000) so we compare
* what actually landed in DDR, not stale L2; this makes the caller's
* fail-closed rc real for the signature-uncovered kernel/dtb copies.
* A non-DDR destination (e.g. an L2 scratch buffer) lands directly, so
* a single copy suffices. */
mism = 1;
for (retry = 0; retry < 8 && mism != 0; retry++) {
(void)mpfs_pdma_memcpy((void *)(d + off),
(const void *)(s + off), chunk);
/* Refresh all five MSS watchdogs (they always count and reset the
* chip and cannot be disabled) during the multi-MB kernel copy
* and its read-back verify. */
MSS_WDT_REFRESH(MSS_WDT_E51_BASE) = 0xDEADC0DEU;
MSS_WDT_REFRESH(MSS_WDT_U54_1_BASE) = 0xDEADC0DEU;
MSS_WDT_REFRESH(MSS_WDT_U54_2_BASE) = 0xDEADC0DEU;
MSS_WDT_REFRESH(MSS_WDT_U54_3_BASE) = 0xDEADC0DEU;
MSS_WDT_REFRESH(MSS_WDT_U54_4_BASE) = 0xDEADC0DEU;
if ((d & 0xF0000000UL) != 0x80000000UL) {
mism = 0; /* non-DDR dst lands on the first copy */
break;
}
__asm__ volatile("fence iorw,iorw" ::: "memory");
ncd = (volatile const uint8_t *)((d + off) | 0x40000000UL);
ncs = (const uint8_t *)(s + off);
mism = 0;
for (k = 0; k < chunk; k++) {
if (ncd[k] != ncs[k]) {
mism = 1;
break;
}
}
}
if (mism != 0) {
/* Copy could not be verified within the retry budget; remember the
* failure so the caller fails closed rather than boot corrupt,
* no-longer-signature-covered data. */
rc = -1;
}
off += chunk;
}
return rc;
}
/* L2 round-trip wrapper around mpfs_dts_fixup_inplace(). The dtb lives in DDR
@ -816,7 +856,11 @@ int hal_dts_fixup(void* dts_addr)
/* fixup in the CPU-writable L2 buffer */
ret = mpfs_dts_fixup_inplace(l2_dtb);
/* L2 -> DDR via PDMA (expanded totalsize) */
wolfBoot_fit_memcpy(dts_addr, l2_dtb, (uint32_t)fdt_totalsize(l2_dtb));
if (wolfBoot_fit_memcpy(dts_addr, l2_dtb,
(uint32_t)fdt_totalsize(l2_dtb)) != 0) {
wolfBoot_printf("FDT: dtb copy-back to DDR failed\n");
return -1;
}
return ret;
}
#else

View File

@ -36,8 +36,10 @@ extern "C" {
#if defined(MMU) || defined(WOLFBOOT_FDT)
extern void do_boot(const uint32_t *app_offset, const uint32_t* dts_offset);
/* Weak copy hook for FIT subimages (kernel/dtb): default memcpy; boards where
* CPU writes to the load address don't land override it with a DMA copy. */
extern void wolfBoot_fit_memcpy(void *dst, const void *src, uint32_t len);
* CPU writes to the load address don't land override it with a DMA copy.
* Returns 0 on success or a negative value if the copy failed, so callers can
* fail closed instead of running on stale data. */
extern int wolfBoot_fit_memcpy(void *dst, const void *src, uint32_t len);
#else
extern void do_boot(const uint32_t *app_offset);
#endif

View File

@ -1440,9 +1440,13 @@ endif
# Per-hart secondary stack size: single source of truth shared by the
# startup asm (via this -D) and the linker script (via @STACK_SIZE_PER_HART@
# substitution in the LSCRIPT rule). Set in the target .config; defaults to
# 0 (no secondary park/wake stacks).
# 0 (no secondary park/wake stacks). The concept (and the consuming startup
# asm) is RISC-V only, so gate the -D to RISC-V; the default is kept
# unconditional because the LSCRIPT sed always needs a value to substitute.
STACK_SIZE_PER_HART ?= 0
CFLAGS+=-DSTACK_SIZE_PER_HART=$(STACK_SIZE_PER_HART)
ifneq (,$(filter RISCV RISCV64,$(ARCH)))
CFLAGS+=-DSTACK_SIZE_PER_HART=$(STACK_SIZE_PER_HART)
endif
CFLAGS+=$(CFLAGS_EXTRA)
OBJS+=$(OBJS_EXTRA)

View File

@ -148,7 +148,7 @@ int WEAKFUNCTION hal_dts_fixup(void* dts_addr)
*
*/
#ifdef MMU
#if defined(MMU) || defined(WOLFBOOT_FDT)
void RAMFUNCTION do_boot(const uint32_t *app_offset, const uint32_t* dts_offset)
#else
void RAMFUNCTION do_boot(const uint32_t *app_offset)

View File

@ -55,7 +55,7 @@ void boot_entry_C(void)
*
*/
#ifdef MMU
#if defined(MMU) || defined(WOLFBOOT_FDT)
void RAMFUNCTION do_boot(const uint32_t *app_offset, const uint32_t* dts_offset)
#else
void RAMFUNCTION do_boot(const uint32_t *app_offset)

View File

@ -409,7 +409,7 @@ void RAMFUNCTION wolfBoot_os64bit_jump(os64bit_entry_t entry,
}
#endif /* ENABLE_OS64BIT */
#ifdef MMU
#if defined(MMU) || defined(WOLFBOOT_FDT)
void do_boot(const uint32_t *app_offset, const uint32_t* dts_offset)
#else
void do_boot(const uint32_t *app_offset)

View File

@ -36,7 +36,7 @@ extern unsigned int *END_STACK;
extern void RAMFUNCTION x86_64_efi_do_boot(uint8_t *kernel);
#ifdef MMU
#if defined(MMU) || defined(WOLFBOOT_FDT)
void RAMFUNCTION do_boot(const uint32_t *app_offset, const uint32_t* dts_offset)
#else
void RAMFUNCTION do_boot(const uint32_t *app_offset)

View File

@ -1135,11 +1135,14 @@ int fit_load_ramdisk(void* fit, const char* ramdisk_node, void* dts_addr)
/* Weak copy hook for FIT subimages (kernel/dtb). Default is a plain memcpy;
* boards where CPU writes to the load destination do not land (e.g. the
* PolarFire MPFS250 DDR, where cached writes thrash L2 Scratch) override this
* with a DMA-based copy (see hal/mpfs250.c). */
void __attribute__((weak)) wolfBoot_fit_memcpy(void *dst, const void *src,
* with a DMA-based copy (see hal/mpfs250.c). Returns 0 on success or a
* negative value if the copy failed, so callers can fail closed rather than
* run on a partially written destination. */
int __attribute__((weak)) wolfBoot_fit_memcpy(void *dst, const void *src,
uint32_t len)
{
memcpy(dst, src, len);
return 0;
}
/* Inner implementation shared by fit_load_image_ex and fit_load_image_to.
@ -1236,7 +1239,11 @@ static void* fit_load_image_inner(void* fdt, const char* image, int* lenp,
}
wolfBoot_printf("Loading Image %s: %p -> %p "
"(%d bytes)\n", image, data, load, len);
wolfBoot_fit_memcpy(load, data, (uint32_t)len);
if (wolfBoot_fit_memcpy(load, data, (uint32_t)len) != 0) {
wolfBoot_printf("FIT: copy of %s to %p failed\n",
image, load);
return NULL;
}
}
/* No per-image hash-1 re-verification here. Per the

View File

@ -631,7 +631,10 @@ void RAMFUNCTION wolfBoot_start(void)
dts_addr = (uint8_t*)WOLFBOOT_LOAD_DTS_ADDRESS;
wolfBoot_printf("Loading DTS: %p -> %p (%d bytes)\n",
dts_ptr, dts_addr, dts_size);
wolfBoot_fit_memcpy(dts_addr, dts_ptr, dts_size);
if (wolfBoot_fit_memcpy(dts_addr, dts_ptr, dts_size) != 0) {
wolfBoot_printf("FIT: failed to load DTS\r\n");
wolfBoot_panic();
}
}
}
#ifdef WOLFBOOT_FIT_RAMDISK