[U-Boot] [RFC PATCH] armv8: Extend modification of MMU tables

Stephen Warren swarren at wwwdotorg.org
Fri Feb 10 17:34:00 UTC 2017


On 02/03/2017 03:24 PM, York Sun wrote:
> Device memory needs to be set along with PXN and UNX bits. Normal memory
> must clear these bits. To support modification of PXN, UXN bits, extend
> existing function mmu_set_region_dcache_behaviour() to accept attributes
> directly. Also fix parsing d-cache option by removing extra shifting.

I'm not sure that this "extra shifting" refers to; I don't see any shift 
changes in the patch.

> Signed-off-by: York Sun <york.sun at nxp.com>
> CC: Alexander Graf <agraf at suse.de>
> ---
> Looks like original function mmu_set_region_dcache_behaviour() was written
> to support changing d-cache option. However the PMD_ATTRINDX(option) shifts
> it further higher. Maybe this function wasn't really used for ARMv8.

It's used in at least a couple of cases:

1) The Raspberry Pi framebuffer code calls this function, and the rpi_3 
board is ARMv8. (Although I vaguely recall strange cache behaviour 
w.r.t. the framebuffer on the rpi_3 port, so perhaps this is related)

2) 64-bit Tegra that support PCIe and have an RTL8169 Ethernet card 
attached use noncached_alloc(), which internally calls 
mmu_set_region_dcache_behaviour() to set up the noncached region.

(Those are just the systems I have experience with; there could well be 
other cases)

> I have a need to update existing MMU table with a little bit more than
> d-cache options. With a recent debug on memory barrier, it came to my
> attention that code should run on "normal" memory, while "device" memory
> should have PXN and UXN bits set. A new function mmu_set_region_attr() is
> hence introduced and mmu_set_region_dcache_behaviour() becomes a wrapper.
>
> BTW, if we don't plan to use "read_start" and "real_size" variables, they
> should be removed.

> diff --git a/arch/arm/cpu/armv8/cache_v8.c b/arch/arm/cpu/armv8/cache_v8.c

> @@ -509,8 +509,8 @@ static u64 set_one_region(u64 start, u64 size, u64 attrs, int level)
>
>  	/* Can we can just modify the current level block PTE? */
>  	if (is_aligned(start, size, levelsize)) {
> -		*pte &= ~PMD_ATTRINDX_MASK;
> -		*pte |= attrs;
> +		*pte &= ~PMD_ATTRMASK;
> +		*pte |= attrs & PMD_ATTRMASK;

This (plus the value chosen for PMD_ATTRMASK) modifies the function so 
that the PXN and UXN bits are over-written with the values take from 
attrs. However, set_on_region() is called from mmu_set_region_attr() 
which is called from mmu_set_region_dcache_behaviour(), which uses enum 
dcache_option values for attrs. However, the values of enum 
dcache_option do not include the PXN/UXN bits, so I believe this change 
will corrupt the page tables if PXN or UXN are already set.

Still, I looked at all the "struct mm_region" tables in U-Boot and 
couldn't find any that set PXN/UXN for normal memory, and I don't 
believe this function will be called for anything other than normal 
memory. As such, this change should be fine in practice. However, I'm 
still a bit hesitant about this change. Can updating PXN/UXN be made 
optional? Related: Why would we need to change PXN/UXN at run-time; 
shouldn't the base struct mm_region table be set up correctly from the 
start?

> +void mmu_set_region_attr(phys_addr_t start, size_t size, u64 attrs)
...
>  	/* We're done modifying page tables, switch back to our primary ones */
> +	flush_dcache_range(gd->arch.tlb_addr,
> +			   gd->arch.tlb_addr + gd->arch.tlb_size);
>  	__asm_switch_ttbr(gd->arch.tlb_addr);

Are the page table walks not coherent with the dcache? If not, I'm 
surprised we haven't had issues with this before. I think this change 
should be in a separate patch since it feels unrelated.


More information about the U-Boot mailing list