
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.
Signed-off-by: York Sun york.sun@nxp.com CC: Alexander Graf agraf@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. 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.
arch/arm/cpu/armv8/cache_v8.c | 28 +++++++++++++++++++--------- arch/arm/include/asm/armv8/mmu.h | 1 + arch/arm/include/asm/system.h | 1 + 3 files changed, 21 insertions(+), 9 deletions(-)
diff --git a/arch/arm/cpu/armv8/cache_v8.c b/arch/arm/cpu/armv8/cache_v8.c index afa76c1..3b2f3f8 100644 --- 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; debug("Set attrs=%llx pte=%p level=%d\n", attrs, pte, level);
return levelsize; @@ -532,13 +532,8 @@ static u64 set_one_region(u64 start, u64 size, u64 attrs, int level) return 0; }
-void mmu_set_region_dcache_behaviour(phys_addr_t start, size_t size, - enum dcache_option option) +void mmu_set_region_attr(phys_addr_t start, size_t size, u64 attrs) { - u64 attrs = PMD_ATTRINDX(option); - u64 real_start = start; - u64 real_size = size; - debug("start=%lx size=%lx\n", (ulong)start, (ulong)size);
if (!gd->arch.tlb_emerg) @@ -572,7 +567,19 @@ void mmu_set_region_dcache_behaviour(phys_addr_t start, size_t size, }
/* 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); +} + +void mmu_set_region_dcache_behaviour(phys_addr_t start, size_t size, + enum dcache_option option) +{ + u64 attrs = option; + u64 real_start = start; + u64 real_size = size; + + mmu_set_region_attr(start, size, attrs);
/* * Make sure there's nothing stale in dcache for a region that might @@ -580,7 +587,6 @@ void mmu_set_region_dcache_behaviour(phys_addr_t start, size_t size, */ flush_dcache_range(real_start, real_start + real_size); } - #else /* CONFIG_SYS_DCACHE_OFF */
/* @@ -613,6 +619,10 @@ int dcache_status(void) return 0; }
+void mmu_set_region_attr(phys_addr_t start, size_t size, u64 attrs) +{ +} + void mmu_set_region_dcache_behaviour(phys_addr_t start, size_t size, enum dcache_option option) { diff --git a/arch/arm/include/asm/armv8/mmu.h b/arch/arm/include/asm/armv8/mmu.h index 58aecb9..c1cff23 100644 --- a/arch/arm/include/asm/armv8/mmu.h +++ b/arch/arm/include/asm/armv8/mmu.h @@ -86,6 +86,7 @@ */ #define PMD_ATTRINDX(t) ((t) << 2) #define PMD_ATTRINDX_MASK (7 << 2) +#define PMD_ATTRMASK (PTE_BLOCK_PXN | PTE_BLOCK_UXN | PMD_ATTRINDX_MASK)
/* * TCR flags. diff --git a/arch/arm/include/asm/system.h b/arch/arm/include/asm/system.h index dc4c991..81709ec 100644 --- a/arch/arm/include/asm/system.h +++ b/arch/arm/include/asm/system.h @@ -224,6 +224,7 @@ void protect_secure_region(void); void smp_kick_all_cpus(void);
void flush_l3_cache(void); +void mmu_set_region_attr(phys_addr_t start, size_t size, u64 attrs);
/* *Issue a secure monitor call in accordance with ARM "SMC Calling convention",