Everything the primary core writes before the MMU is enabled bypasses
the data cache: the saved firmware arguments, the boot stack, .data,
.bss and then the translation tables built by z_arm64_mm_init(). Lines
a previous boot stage left over that RAM are untouched by those writes.
A clean one is read back in place of what was written once
enable_mmu_el1() turns on the MMU and data cache, and a dirty one can be
written back over it at any point before then. Either way the first
table walk or data access after the MMU enable may see garbage, which
shows up as a random crash right at that point.
Commit 6c6f1a5e99 ("arch: arm64: mmu: revert useless cache handling")
removed the invalidation setup_page_tables() used to do over these
ranges along with the per-mapping one, leaving nothing to cover this.
Invalidate the image RAM by VA in reset.S as soon as the primary core is
known, before the firmware arguments and the boot stack are written.
DC IVAC reaches caches beyond the cluster, which set/way operations do
not, and invalidating rather than cleaning avoids writing the stale
lines back. The boot vote before that point only writes
arm64_cpu_boot_params in .data, which the loader must already have left
clean, so lines over it can only be clean and are dropped as well.
Secondary cores must not do this: they start while the primary core
runs with its data cache on.
This does not depend on CONFIG_DCACHE: the data cache is enabled along
with the MMU either way.
Reproduced on fvp_corstone1000/a320 with cache state modelling enabled
and code standing in for a previous boot stage that leaves dirty lines
over .bss before jumping to Zephyr: the boot hangs without this change
and completes with it.
Signed-off-by: Nicolas Pitre <npitre@baylibre.com>