* [PATCH 1/3] ARM: cpu: suppress arm_early_mmu_cache_invalidate if dcache enabled
@ 2026-07-07 8:05 Ahmad Fatoum
2026-07-07 8:05 ` [PATCH 2/3] ARM: v7r: factor out armv7r_cache_enable Ahmad Fatoum
` (2 more replies)
0 siblings, 3 replies; 5+ messages in thread
From: Ahmad Fatoum @ 2026-07-07 8:05 UTC (permalink / raw)
To: barebox; +Cc: lst, 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>
---
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..d41da73d7e83 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();
}
+/**
+ * dcache_invalidate_stale - invalidate data cache prior to enabling it
+ *
+ * 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 dcache_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..eb1793b54e66 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 dcache_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..3404f6d05802 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 dcache_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..64f369f865db 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 dcache_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 2/3] ARM: v7r: factor out armv7r_cache_enable
2026-07-07 8:05 [PATCH 1/3] ARM: cpu: suppress arm_early_mmu_cache_invalidate if dcache enabled Ahmad Fatoum
@ 2026-07-07 8:05 ` Ahmad Fatoum
2026-07-07 8:05 ` [PATCH 3/3] ARM: always call dcache_invalidate_stale before enabling D-Cache Ahmad Fatoum
2026-07-07 15:22 ` [PATCH 1/3] ARM: cpu: suppress arm_early_mmu_cache_invalidate if dcache enabled Lucas Stach
2 siblings, 0 replies; 5+ messages in thread
From: Ahmad Fatoum @ 2026-07-07 8:05 UTC (permalink / raw)
To: barebox; +Cc: lst, 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>
---
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 3/3] ARM: always call dcache_invalidate_stale before enabling D-Cache
2026-07-07 8:05 [PATCH 1/3] ARM: cpu: suppress arm_early_mmu_cache_invalidate if dcache enabled Ahmad Fatoum
2026-07-07 8:05 ` [PATCH 2/3] ARM: v7r: factor out armv7r_cache_enable Ahmad Fatoum
@ 2026-07-07 8:05 ` Ahmad Fatoum
2026-07-07 15:22 ` [PATCH 1/3] ARM: cpu: suppress arm_early_mmu_cache_invalidate if dcache enabled Lucas Stach
2 siblings, 0 replies; 5+ messages in thread
From: Ahmad Fatoum @ 2026-07-07 8:05 UTC (permalink / raw)
To: barebox; +Cc: lst, Ahmad Fatoum
dcache_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 dcache_invalidate_stale()
precede the code that depends on it having run.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
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..7f43d617c251 100644
--- a/arch/arm/cpu/armv7r-mpu.c
+++ b/arch/arm/cpu/armv7r-mpu.c
@@ -34,6 +34,7 @@
void armv7r_cache_enable(void)
{
+ dcache_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 eb1793b54e66..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 dcache_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 3404f6d05802..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 dcache_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..e8c4ae2cc259 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);
+ dcache_invalidate_stale();
+
if (get_cr() & CR_M)
return;
diff --git a/arch/arm/cpu/uncompress.c b/arch/arm/cpu/uncompress.c
index 8f0d0f55f862..13cfaff18350 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.
+ */
+ dcache_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 1/3] ARM: cpu: suppress arm_early_mmu_cache_invalidate if dcache enabled
2026-07-07 8:05 [PATCH 1/3] ARM: cpu: suppress arm_early_mmu_cache_invalidate if dcache enabled Ahmad Fatoum
2026-07-07 8:05 ` [PATCH 2/3] ARM: v7r: factor out armv7r_cache_enable Ahmad Fatoum
2026-07-07 8:05 ` [PATCH 3/3] ARM: always call dcache_invalidate_stale before enabling D-Cache Ahmad Fatoum
@ 2026-07-07 15:22 ` Lucas Stach
2026-07-07 17:20 ` Ahmad Fatoum
2 siblings, 1 reply; 5+ messages in thread
From: Lucas Stach @ 2026-07-07 15:22 UTC (permalink / raw)
To: Ahmad Fatoum, barebox
Am Dienstag, dem 07.07.2026 um 10:05 +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>
> ---
> 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..d41da73d7e83 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();
> }
>
> +/**
> + * dcache_invalidate_stale - invalidate data cache prior to enabling it
> + *
> + * 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 dcache_invalidate_stale(void)
I don't like the naming of this function, as
arm_early_mmu_cache_invalidate() invalidates both the D and I cache, as
well as a unified cache after the PoU if it's part of the architected
hierarchy. This is the desired behavior, as both the I and D side can
come up with invalid entries.
It's okay to only check for CR_C, as invalidating the I side when there
are already cached entries only has a minor impact on performance, but
won't affect correctness.
Also, by moving the call to a later point in the init flow later in the
series, are you sure that the invalidate happens before the I cache
gets enabled in arm_cpu_lowlevel_init()?
Regards,
Lucas
> +{
> + /* 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..eb1793b54e66 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 dcache_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..3404f6d05802 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 dcache_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..64f369f865db 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 dcache_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 1/3] ARM: cpu: suppress arm_early_mmu_cache_invalidate if dcache enabled
2026-07-07 15:22 ` [PATCH 1/3] ARM: cpu: suppress arm_early_mmu_cache_invalidate if dcache enabled Lucas Stach
@ 2026-07-07 17:20 ` Ahmad Fatoum
0 siblings, 0 replies; 5+ messages in thread
From: Ahmad Fatoum @ 2026-07-07 17:20 UTC (permalink / raw)
To: Lucas Stach, barebox
Hello Lucas,
On 7/7/26 5:22 PM, Lucas Stach wrote:
> Am Dienstag, dem 07.07.2026 um 10:05 +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")
>> +/**
>> + * dcache_invalidate_stale - invalidate data cache prior to enabling it
>> + *
>> + * 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 dcache_invalidate_stale(void)
>
> I don't like the naming of this function, as
> arm_early_mmu_cache_invalidate() invalidates both the D and I cache, as
> well as a unified cache after the PoU if it's part of the architected
> hierarchy. This is the desired behavior, as both the I and D side can
> come up with invalid entries.
Ah, I had not thought much about the I cache having invalid entries as well.
How about cache_invalidate_stale()?
> It's okay to only check for CR_C, as invalidating the I side when there
> are already cached entries only has a minor impact on performance, but
> won't affect correctness.
I thought that it might be too surprising to change the semantics of
this function in such a way, especially as it has a number of users in
low level board code.
But yes, if we don't see a legitimate use case for calling the function
with caches enabled, we can also just turn it into a no-op in that case.
> Also, by moving the call to a later point in the init flow later in the
> series, are you sure that the invalidate happens before the I cache
> gets enabled in arm_cpu_lowlevel_init()?
arm_cpu_lowlevel_init() invalidates I cache on ARMv6 and ARMv7.
I believe on ARMv8, it's not necessary?
Interestingly, for ARMv8, I-Cache looks like it is only enabled early
for EL3, but for EL2/1, it's enabled in mmu_early_enable(). Any reason
for that?
Thanks,
Ahmad
>
> Regards,
> Lucas
>
>> +{
>> + /* 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..eb1793b54e66 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 dcache_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..3404f6d05802 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 dcache_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..64f369f865db 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 dcache_invalidate_stale(void);
>> +
>> void arm_early_mmu_cache_flush(void);
>> void arm_early_mmu_cache_invalidate(void);
>>
>
--
Pengutronix e.K. | |
Steuerwalder Str. 21 | http://www.pengutronix.de/ |
31137 Hildesheim, Germany | Phone: +49-5121-206917-0 |
Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-07-07 17:21 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-07-07 8:05 [PATCH 1/3] ARM: cpu: suppress arm_early_mmu_cache_invalidate if dcache enabled Ahmad Fatoum
2026-07-07 8:05 ` [PATCH 2/3] ARM: v7r: factor out armv7r_cache_enable Ahmad Fatoum
2026-07-07 8:05 ` [PATCH 3/3] ARM: always call dcache_invalidate_stale before enabling D-Cache Ahmad Fatoum
2026-07-07 15:22 ` [PATCH 1/3] ARM: cpu: suppress arm_early_mmu_cache_invalidate if dcache enabled Lucas Stach
2026-07-07 17:20 ` Ahmad Fatoum
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox