[PATCH] arm: armv8: mmu: fix DCACHE_OFF incorrectly unmapping region

Ilias Apalodimas ilias.apalodimas at linaro.org
Wed Jul 8 13:47:59 CEST 2026


Hi Akshay

On Wed, 8 Jul 2026 at 14:17, Akshay Belsare <akshay.belsare at amd.com> wrote:
>
> DCACHE_OFF is defined as (0 << 2) = 0, and PTE_TYPE_FAULT is defined
> as (0 << 0) = 0. In mmu_set_region_dcache_behaviour(), the cache
> attribute passed to set_regions() is computed as:
>   attrs = PMD_ATTRINDX(option >> 2)
> For DCACHE_OFF=0 this evaluates to PMD_ATTRINDX(0) = 0, which equals
> PTE_TYPE_FAULT.
>
> Commit 6468ca13ffd6f ("armv8: mmu: fix and optimise explicitly unmapping
> regions") added an unmap path to set_one_region() that
> triggers when attrs == PTE_TYPE_FAULT. Because DCACHE_OFF and
> PTE_TYPE_FAULT share the same numerical value (0), any call to
> mmu_set_region_dcache_behaviour() with DCACHE_OFF silently unmaps the
> target region instead of changing its cache attributes to non-cached.
>
> The subsequent flush_dcache_range() call at the end of
> mmu_set_region_dcache_behaviour() then crashes with a Level 3
> translation fault because the region it tries to flush has just been
> unmapped.
>
> The existing flag parameter already distinguishes the two callers:
>  - mmu_set_region_dcache_behaviour() always passes flag=false
>  - mmu_change_region_attr_nobreak() always passes flag=true, and is the
>    only legitimate caller that passes PTE_TYPE_FAULT to unmap a region
>
> Guard the unmap path with flag so that DCACHE_OFF attribute changes
> take the correct else branch, which ORs in the ATTRINDX bits only,
> leaving the PTE valid.

I don't really love the 'flag' attribute that distinguishes between
preserving or overwriting the permission bits...

However, this does fix an issue.

Reviewed-by: Ilias Apalodimas <ilias.apalodimas at linaro.org>

>
> This was observed as a boot crash on Versal, Versal Net, and ZynqMP
> platforms during network initialisation. The zynq_gem driver calls
> mmu_set_region_dcache_behaviour() with DCACHE_OFF to make its BD
> descriptor ring non-cached. With the bug the BD memory is unmapped,
> and the subsequent dcache flush inside
> mmu_set_region_dcache_behaviour() faults.
>
> Fixes: 6468ca13ffd6f ("armv8: mmu: fix and optimise explicitly unmapping regions")
> Signed-off-by: Akshay Belsare <akshay.belsare at amd.com>
> ---
>  arch/arm/cpu/armv8/cache_v8.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/arch/arm/cpu/armv8/cache_v8.c b/arch/arm/cpu/armv8/cache_v8.c
> index e59528e576e..ad232435eb2 100644
> --- a/arch/arm/cpu/armv8/cache_v8.c
> +++ b/arch/arm/cpu/armv8/cache_v8.c
> @@ -1006,7 +1006,7 @@ static u64 set_one_region(u64 start, u64 size, u64 attrs, bool flag, int level)
>
>         /* Can we can just modify the current level block/page? */
>         if (is_aligned(start, size, levelsize)) {
> -               if (attrs == PTE_TYPE_FAULT) {
> +               if (attrs == PTE_TYPE_FAULT && flag) {
>                         if (pte_type(pte) == PTE_TYPE_TABLE && level < 3)
>                                 *pte = 0;
>                         else
> --
> 2.25.1
>


More information about the U-Boot mailing list