mail archive of the barebox mailing list
 help / color / mirror / Atom feed
* [PATCH v2 1/3] ARM: cpu: suppress arm_early_mmu_cache_invalidate if dcache enabled
@ 2026-08-25  8:13 Ahmad Fatoum
  2026-08-25  8:13 ` [PATCH v2 2/3] ARM: v7r: factor out armv7r_cache_enable Ahmad Fatoum
                   ` (3 more replies)
  0 siblings, 4 replies; 5+ messages in thread
From: Ahmad Fatoum @ 2026-08-25  8:13 UTC (permalink / raw)
  To: barebox; +Cc: Ahmad Fatoum

barebox built as EFI payload on ARM invalidates the data caches inside
barebox_arm_entry(), which may lead to memory corruption.

Generally, calling arm_early_mmu_cache_invalidate() while the caches are
enabled is a bad idea, so add a function that protects against that and
use it in common code.

Fixes: 742e78976dd4 ("ARM64: add optional EFI stub")
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
v1 -> v2:
  - rename dcache_invalidate_stale(to cache_invalidate_stale (Lucas)
---
 arch/arm/cpu/common.c        | 16 ++++++++++++++++
 arch/arm/cpu/entry_ll_32.S   |  2 +-
 arch/arm/cpu/entry_ll_64.S   |  2 +-
 arch/arm/include/asm/cache.h |  3 +++
 4 files changed, 21 insertions(+), 2 deletions(-)

diff --git a/arch/arm/cpu/common.c b/arch/arm/cpu/common.c
index adb5d6a02bc8..e079f55b8bb7 100644
--- a/arch/arm/cpu/common.c
+++ b/arch/arm/cpu/common.c
@@ -37,6 +37,22 @@ void sync_caches_for_execution(void)
 	arm_early_mmu_cache_flush();
 }
 
+/**
+ * cache_invalidate_stale - invalidate caches prior to enabling them
+ *
+ * Some SoCs can come up with invalid entries, but with the valid bit set.
+ * This function discards them, as that would lead to memory corruption
+ * otherwise.
+ */
+void cache_invalidate_stale(void)
+{
+	/* if caches are already enabled, don't cause data loss */
+	if (get_cr() & CR_C)
+		return;
+
+	arm_early_mmu_cache_invalidate();
+}
+
 void pbl_barebox_break(void)
 {
 	__asm__ __volatile__ (
diff --git a/arch/arm/cpu/entry_ll_32.S b/arch/arm/cpu/entry_ll_32.S
index 0d4c47c1c870..0763581fded4 100644
--- a/arch/arm/cpu/entry_ll_32.S
+++ b/arch/arm/cpu/entry_ll_32.S
@@ -15,7 +15,7 @@ ENTRY(__barebox_arm_entry)
 	mov	r4, r0
 	mov	r5, r1
 	mov	r6, r2
-	bl	arm_early_mmu_cache_invalidate
+	bl	cache_invalidate_stale
 	mov	r0, r4
 	mov	r1, r5
 	mov	r2, r6
diff --git a/arch/arm/cpu/entry_ll_64.S b/arch/arm/cpu/entry_ll_64.S
index 5eb6efed5baf..c80a23c6506d 100644
--- a/arch/arm/cpu/entry_ll_64.S
+++ b/arch/arm/cpu/entry_ll_64.S
@@ -15,7 +15,7 @@ ENTRY(__barebox_arm_entry)
 	mov	x19, x0
 	mov	x20, x1
 	mov	x21, x2
-	bl	arm_early_mmu_cache_invalidate
+	bl	cache_invalidate_stale
 	mov	x0, x19
 	mov	x1, x20
 	mov	x2, x21
diff --git a/arch/arm/include/asm/cache.h b/arch/arm/include/asm/cache.h
index ea78ae123aec..9dbf433356b9 100644
--- a/arch/arm/include/asm/cache.h
+++ b/arch/arm/include/asm/cache.h
@@ -26,6 +26,9 @@ static inline void icache_invalidate(void)
 #endif
 }
 
+
+void cache_invalidate_stale(void);
+
 void arm_early_mmu_cache_flush(void);
 void arm_early_mmu_cache_invalidate(void);
 
-- 
2.47.3




^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH v2 2/3] ARM: v7r: factor out armv7r_cache_enable
  2026-08-25  8:13 [PATCH v2 1/3] ARM: cpu: suppress arm_early_mmu_cache_invalidate if dcache enabled Ahmad Fatoum
@ 2026-08-25  8:13 ` Ahmad Fatoum
  2026-08-25  8:13 ` [PATCH v2 3/3] ARM: always call cache_invalidate_stale before enabling D-Cache Ahmad Fatoum
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 5+ messages in thread
From: Ahmad Fatoum @ 2026-08-25  8:13 UTC (permalink / raw)
  To: barebox; +Cc: Ahmad Fatoum

We enable caches early on ARMv7-R to speed up decompression.
On ARMv7-A, we need to enable the MMU as well, but for ARMv7-R enabling
the MPU is not necessary and so the code is a one-liner.

That one line will become two in a subsequent commit, so prepare for
that by moving it into an appropriately named helper function.

Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
v1 -> v2:
  - no change
---
 arch/arm/cpu/armv7r-mpu.c         | 5 +++++
 arch/arm/cpu/uncompress.c         | 3 ++-
 arch/arm/include/asm/armv7r-mpu.h | 2 ++
 3 files changed, 9 insertions(+), 1 deletion(-)

diff --git a/arch/arm/cpu/armv7r-mpu.c b/arch/arm/cpu/armv7r-mpu.c
index d96411a61632..d494aec583ef 100644
--- a/arch/arm/cpu/armv7r-mpu.c
+++ b/arch/arm/cpu/armv7r-mpu.c
@@ -32,6 +32,11 @@
  * [1] http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0460d/I1002400.html
  */
 
+void armv7r_cache_enable(void)
+{
+	set_cr(get_cr() | CR_C);
+}
+
 void armv7r_mpu_disable(void)
 {
 	u32 reg;
diff --git a/arch/arm/cpu/uncompress.c b/arch/arm/cpu/uncompress.c
index 55bbe0019cc4..8f0d0f55f862 100644
--- a/arch/arm/cpu/uncompress.c
+++ b/arch/arm/cpu/uncompress.c
@@ -18,6 +18,7 @@
 #include <asm/secure.h>
 #include <asm/cache.h>
 #include <asm/mmu.h>
+#include <asm/armv7r-mpu.h>
 #include <asm/unaligned.h>
 #include <compressed-dtb.h>
 #include <elf.h>
@@ -87,7 +88,7 @@ void __noreturn barebox_pbl_start(unsigned long membase, unsigned long memsize,
 	if (IS_ENABLED(CONFIG_MMU))
 		mmu_early_enable(membase, memsize);
 	else if (IS_ENABLED(CONFIG_ARMV7R_MPU))
-		set_cr(get_cr() | CR_C);
+		armv7r_cache_enable();
 
 	pr_debug("uncompressing barebox ELF at 0x%p (size 0x%08x) to 0x%08lx (uncompressed size: 0x%08x)\n",
 			pg_start, pg_len, barebox_base, uncompressed_len);
diff --git a/arch/arm/include/asm/armv7r-mpu.h b/arch/arm/include/asm/armv7r-mpu.h
index 8d737d6d1407..1d890ab90a67 100644
--- a/arch/arm/include/asm/armv7r-mpu.h
+++ b/arch/arm/include/asm/armv7r-mpu.h
@@ -91,6 +91,8 @@ struct mpu_region_config {
 	enum size reg_size;
 };
 
+void armv7r_cache_enable(void);
+
 void armv7r_mpu_disable(void);
 void armv7r_mpu_enable(void);
 int armv7r_mpu_enabled(void);
-- 
2.47.3




^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH v2 3/3] ARM: always call cache_invalidate_stale before enabling D-Cache
  2026-08-25  8:13 [PATCH v2 1/3] ARM: cpu: suppress arm_early_mmu_cache_invalidate if dcache enabled Ahmad Fatoum
  2026-08-25  8:13 ` [PATCH v2 2/3] ARM: v7r: factor out armv7r_cache_enable Ahmad Fatoum
@ 2026-08-25  8:13 ` Ahmad Fatoum
  2026-08-26  8:39 ` [PATCH v2 1/3] ARM: cpu: suppress arm_early_mmu_cache_invalidate if dcache enabled Lucas Stach
  2026-08-28 14:24 ` Sascha Hauer
  3 siblings, 0 replies; 5+ messages in thread
From: Ahmad Fatoum @ 2026-08-25  8:13 UTC (permalink / raw)
  To: barebox; +Cc: Ahmad Fatoum

cache_invalidate_stale() needs to be executed prior to enabling the
MMU. This was so far guaranteed by __barebox_arm_entry() invoking it
prior to barebox_pbl_start(), which does mmu_early_enable().

As there's more boot time to be saved by calling mmu_early_enable()
earlier, some SoC support has already started calling mmu_early_enable()
prior to barebox_pbl_start(). Should this be extended to older CPUs like
Cortex-A9, we would introduce a regression as the data cache would not be
discarded prior to enabling it.

Avoid this failure mode altogether by having cache_invalidate_stale()
precede the code that depends on it having run.

This function invalidates both I-Cache and D-Cache, but only D-Cache is
interesting to us here as I-Cache has already been invalidated in
arm_cpu_lowlevel_init().

Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
v1 -> v2:
  - point out that arm_cpu_lowlevel_init() invalidates (Lucas)
---
 arch/arm/cpu/armv7r-mpu.c  |  1 +
 arch/arm/cpu/entry_ll_32.S |  7 -------
 arch/arm/cpu/entry_ll_64.S |  7 -------
 arch/arm/cpu/mmu_32.c      |  2 ++
 arch/arm/cpu/uncompress.c  | 12 ++++++++++--
 5 files changed, 13 insertions(+), 16 deletions(-)

diff --git a/arch/arm/cpu/armv7r-mpu.c b/arch/arm/cpu/armv7r-mpu.c
index d494aec583ef..47e108133178 100644
--- a/arch/arm/cpu/armv7r-mpu.c
+++ b/arch/arm/cpu/armv7r-mpu.c
@@ -34,6 +34,7 @@
 
 void armv7r_cache_enable(void)
 {
+	cache_invalidate_stale();
 	set_cr(get_cr() | CR_C);
 }
 
diff --git a/arch/arm/cpu/entry_ll_32.S b/arch/arm/cpu/entry_ll_32.S
index 0763581fded4..981722ab7b05 100644
--- a/arch/arm/cpu/entry_ll_32.S
+++ b/arch/arm/cpu/entry_ll_32.S
@@ -12,12 +12,5 @@
 .section .text.__barebox_arm_entry
 ENTRY(__barebox_arm_entry)
 	mov	sp, r3
-	mov	r4, r0
-	mov	r5, r1
-	mov	r6, r2
-	bl	cache_invalidate_stale
-	mov	r0, r4
-	mov	r1, r5
-	mov	r2, r6
 	b	barebox_pbl_start
 ENDPROC(__barebox_arm_entry)
diff --git a/arch/arm/cpu/entry_ll_64.S b/arch/arm/cpu/entry_ll_64.S
index c80a23c6506d..71fb74b48f7e 100644
--- a/arch/arm/cpu/entry_ll_64.S
+++ b/arch/arm/cpu/entry_ll_64.S
@@ -12,12 +12,5 @@
 .section .text.__barebox_arm_entry
 ENTRY(__barebox_arm_entry)
 	mov	sp, x3
-	mov	x19, x0
-	mov	x20, x1
-	mov	x21, x2
-	bl	cache_invalidate_stale
-	mov	x0, x19
-	mov	x1, x20
-	mov	x2, x21
 	b	barebox_pbl_start
 ENDPROC(__barebox_arm_entry)
diff --git a/arch/arm/cpu/mmu_32.c b/arch/arm/cpu/mmu_32.c
index efdb867532f9..7b49643fd79b 100644
--- a/arch/arm/cpu/mmu_32.c
+++ b/arch/arm/cpu/mmu_32.c
@@ -613,6 +613,8 @@ void mmu_early_enable(unsigned long membase, unsigned long memsize)
 
 	pr_debug("enabling MMU, ttb @ 0x%p\n", ttb);
 
+	cache_invalidate_stale();
+
 	if (get_cr() & CR_M)
 		return;
 
diff --git a/arch/arm/cpu/uncompress.c b/arch/arm/cpu/uncompress.c
index 8f0d0f55f862..4d954b3eaaae 100644
--- a/arch/arm/cpu/uncompress.c
+++ b/arch/arm/cpu/uncompress.c
@@ -85,10 +85,18 @@ void __noreturn barebox_pbl_start(unsigned long membase, unsigned long memsize,
 #ifdef DEBUG
 	print_pbl_mem_layout(membase, endmem, barebox_base);
 #endif
-	if (IS_ENABLED(CONFIG_MMU))
+
+	/* Enable Caches to speed up the decompression below. */
+	if (IS_ENABLED(CONFIG_MMU)) {
 		mmu_early_enable(membase, memsize);
-	else if (IS_ENABLED(CONFIG_ARMV7R_MPU))
+	} else if (IS_ENABLED(CONFIG_ARMV7R_MPU)) {
 		armv7r_cache_enable();
+	} else {
+		/* Even if we don't use the cache right now, it may be used later.
+		 * Some CPUs may boot up with dirty cache lines, get rid of them.
+		 */
+		cache_invalidate_stale();
+	}
 
 	pr_debug("uncompressing barebox ELF at 0x%p (size 0x%08x) to 0x%08lx (uncompressed size: 0x%08x)\n",
 			pg_start, pg_len, barebox_base, uncompressed_len);
-- 
2.47.3




^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH v2 1/3] ARM: cpu: suppress arm_early_mmu_cache_invalidate if dcache enabled
  2026-08-25  8:13 [PATCH v2 1/3] ARM: cpu: suppress arm_early_mmu_cache_invalidate if dcache enabled Ahmad Fatoum
  2026-08-25  8:13 ` [PATCH v2 2/3] ARM: v7r: factor out armv7r_cache_enable Ahmad Fatoum
  2026-08-25  8:13 ` [PATCH v2 3/3] ARM: always call cache_invalidate_stale before enabling D-Cache Ahmad Fatoum
@ 2026-08-26  8:39 ` Lucas Stach
  2026-08-28 14:24 ` Sascha Hauer
  3 siblings, 0 replies; 5+ messages in thread
From: Lucas Stach @ 2026-08-26  8:39 UTC (permalink / raw)
  To: Ahmad Fatoum, barebox

Am Dienstag, dem 25.08.2026 um 10:13 +0200 schrieb Ahmad Fatoum:
> barebox built as EFI payload on ARM invalidates the data caches inside
> barebox_arm_entry(), which may lead to memory corruption.
> 
> Generally, calling arm_early_mmu_cache_invalidate() while the caches are
> enabled is a bad idea, so add a function that protects against that and
> use it in common code.
> 
> Fixes: 742e78976dd4 ("ARM64: add optional EFI stub")
> Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>

Entire series looks good to me.

Reviewed-by: Lucas Stach <l.stach@pengutronix.de>

> ---
> v1 -> v2:
>   - rename dcache_invalidate_stale(to cache_invalidate_stale (Lucas)
> ---
>  arch/arm/cpu/common.c        | 16 ++++++++++++++++
>  arch/arm/cpu/entry_ll_32.S   |  2 +-
>  arch/arm/cpu/entry_ll_64.S   |  2 +-
>  arch/arm/include/asm/cache.h |  3 +++
>  4 files changed, 21 insertions(+), 2 deletions(-)
> 
> diff --git a/arch/arm/cpu/common.c b/arch/arm/cpu/common.c
> index adb5d6a02bc8..e079f55b8bb7 100644
> --- a/arch/arm/cpu/common.c
> +++ b/arch/arm/cpu/common.c
> @@ -37,6 +37,22 @@ void sync_caches_for_execution(void)
>  	arm_early_mmu_cache_flush();
>  }
>  
> +/**
> + * cache_invalidate_stale - invalidate caches prior to enabling them
> + *
> + * Some SoCs can come up with invalid entries, but with the valid bit set.
> + * This function discards them, as that would lead to memory corruption
> + * otherwise.
> + */
> +void cache_invalidate_stale(void)
> +{
> +	/* if caches are already enabled, don't cause data loss */
> +	if (get_cr() & CR_C)
> +		return;
> +
> +	arm_early_mmu_cache_invalidate();
> +}
> +
>  void pbl_barebox_break(void)
>  {
>  	__asm__ __volatile__ (
> diff --git a/arch/arm/cpu/entry_ll_32.S b/arch/arm/cpu/entry_ll_32.S
> index 0d4c47c1c870..0763581fded4 100644
> --- a/arch/arm/cpu/entry_ll_32.S
> +++ b/arch/arm/cpu/entry_ll_32.S
> @@ -15,7 +15,7 @@ ENTRY(__barebox_arm_entry)
>  	mov	r4, r0
>  	mov	r5, r1
>  	mov	r6, r2
> -	bl	arm_early_mmu_cache_invalidate
> +	bl	cache_invalidate_stale
>  	mov	r0, r4
>  	mov	r1, r5
>  	mov	r2, r6
> diff --git a/arch/arm/cpu/entry_ll_64.S b/arch/arm/cpu/entry_ll_64.S
> index 5eb6efed5baf..c80a23c6506d 100644
> --- a/arch/arm/cpu/entry_ll_64.S
> +++ b/arch/arm/cpu/entry_ll_64.S
> @@ -15,7 +15,7 @@ ENTRY(__barebox_arm_entry)
>  	mov	x19, x0
>  	mov	x20, x1
>  	mov	x21, x2
> -	bl	arm_early_mmu_cache_invalidate
> +	bl	cache_invalidate_stale
>  	mov	x0, x19
>  	mov	x1, x20
>  	mov	x2, x21
> diff --git a/arch/arm/include/asm/cache.h b/arch/arm/include/asm/cache.h
> index ea78ae123aec..9dbf433356b9 100644
> --- a/arch/arm/include/asm/cache.h
> +++ b/arch/arm/include/asm/cache.h
> @@ -26,6 +26,9 @@ static inline void icache_invalidate(void)
>  #endif
>  }
>  
> +
> +void cache_invalidate_stale(void);
> +
>  void arm_early_mmu_cache_flush(void);
>  void arm_early_mmu_cache_invalidate(void);
>  



^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH v2 1/3] ARM: cpu: suppress arm_early_mmu_cache_invalidate if dcache enabled
  2026-08-25  8:13 [PATCH v2 1/3] ARM: cpu: suppress arm_early_mmu_cache_invalidate if dcache enabled Ahmad Fatoum
                   ` (2 preceding siblings ...)
  2026-08-26  8:39 ` [PATCH v2 1/3] ARM: cpu: suppress arm_early_mmu_cache_invalidate if dcache enabled Lucas Stach
@ 2026-08-28 14:24 ` Sascha Hauer
  3 siblings, 0 replies; 5+ messages in thread
From: Sascha Hauer @ 2026-08-28 14:24 UTC (permalink / raw)
  To: barebox, Ahmad Fatoum


On Tue, 25 Aug 2026 10:13:15 +0200, Ahmad Fatoum wrote:
> barebox built as EFI payload on ARM invalidates the data caches inside
> barebox_arm_entry(), which may lead to memory corruption.
> 
> Generally, calling arm_early_mmu_cache_invalidate() while the caches are
> enabled is a bad idea, so add a function that protects against that and
> use it in common code.
> 
> [...]

Applied, thanks!

[1/3] ARM: cpu: suppress arm_early_mmu_cache_invalidate if dcache enabled
      https://git.pengutronix.de/cgit/barebox/commit/?id=72faea821232 (link may not be stable)
[2/3] ARM: v7r: factor out armv7r_cache_enable
      https://git.pengutronix.de/cgit/barebox/commit/?id=14eafd21e89b (link may not be stable)
[3/3] ARM: always call cache_invalidate_stale before enabling D-Cache
      https://git.pengutronix.de/cgit/barebox/commit/?id=fcec14feed91 (link may not be stable)

Best regards,
-- 
Sascha Hauer <s.hauer@pengutronix.de>




^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2026-08-28 14:25 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-08-25  8:13 [PATCH v2 1/3] ARM: cpu: suppress arm_early_mmu_cache_invalidate if dcache enabled Ahmad Fatoum
2026-08-25  8:13 ` [PATCH v2 2/3] ARM: v7r: factor out armv7r_cache_enable Ahmad Fatoum
2026-08-25  8:13 ` [PATCH v2 3/3] ARM: always call cache_invalidate_stale before enabling D-Cache Ahmad Fatoum
2026-08-26  8:39 ` [PATCH v2 1/3] ARM: cpu: suppress arm_early_mmu_cache_invalidate if dcache enabled Lucas Stach
2026-08-28 14:24 ` Sascha Hauer

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox