summaryrefslogtreecommitdiffstats
path: root/arch/arm/cpu
diff options
context:
space:
mode:
authorSascha Hauer <s.hauer@pengutronix.de>2019-05-10 18:15:49 +0200
committerSascha Hauer <s.hauer@pengutronix.de>2019-05-10 18:15:49 +0200
commit0439f42e2021441b19583f694500921f53ebbbd2 (patch)
tree19e3e43c0ac9128a8679e47a64fe8bd1ca584dd6 /arch/arm/cpu
parent94420265227df2bbe221293f9e10466030387209 (diff)
parent0198567c423cd7b939f3bc5b8e76a68c2def2589 (diff)
downloadbarebox-0439f42e2021441b19583f694500921f53ebbbd2.tar.gz
barebox-0439f42e2021441b19583f694500921f53ebbbd2.tar.xz
Merge branch 'for-next/arm'
Diffstat (limited to 'arch/arm/cpu')
-rw-r--r--arch/arm/cpu/cache-armv7.S13
-rw-r--r--arch/arm/cpu/lowlevel_64.S7
-rw-r--r--arch/arm/cpu/mmu-early.c27
-rw-r--r--arch/arm/cpu/mmu.c16
-rw-r--r--arch/arm/cpu/mmu.h8
5 files changed, 60 insertions, 11 deletions
diff --git a/arch/arm/cpu/cache-armv7.S b/arch/arm/cpu/cache-armv7.S
index 7a1c5c0189..6a8aff8bb1 100644
--- a/arch/arm/cpu/cache-armv7.S
+++ b/arch/arm/cpu/cache-armv7.S
@@ -83,7 +83,10 @@ hierarchical:
ands r3, r0, #0x7000000 @ extract loc from clidr
mov r3, r3, lsr #23 @ left align loc bit field
beq finished @ if loc is 0, then no need to clean
- mov r12, #0 @ start clean at cache level 0
+ cmp r8, #0
+THUMB( ite eq )
+ moveq r12, #0
+ subne r12, r3, #2 @ start invalidate at outmost cache level
loop1:
add r2, r12, r12, lsr #1 @ work out 3x current cache level
mov r1, r0, lsr r2 @ extract cache type bits from clidr
@@ -118,8 +121,16 @@ THUMB( ite eq )
subs r7, r7, #1 @ decrement the index
bge loop2
skip:
+ cmp r8, #0
+ bne inval_check
add r12, r12, #2 @ increment cache number
cmp r3, r12
+ b loop_end_check
+inval_check:
+ cmp r12, #0
+ sub r12, r12, #2 @ decrement cache number
+loop_end_check:
+ dsb @ work-around Cortex-A7 erratum 814220
bgt loop1
finished:
ldmfd sp!, {r4-r11}
diff --git a/arch/arm/cpu/lowlevel_64.S b/arch/arm/cpu/lowlevel_64.S
index af1cd8b5bc..6a23132ed1 100644
--- a/arch/arm/cpu/lowlevel_64.S
+++ b/arch/arm/cpu/lowlevel_64.S
@@ -12,6 +12,13 @@ ENTRY(arm_cpu_lowlevel_init)
orr x0, x0, #(1 << 10) /* 64-bit EL2 */
msr scr_el3, x0
msr cptr_el3, xzr
+
+ mrs x0, sctlr_el3
+ ldr x1, =SCTLR_ELx_FLAGS
+ bic x0, x0, x1
+ msr sctlr_el3, x0
+ isb
+
b done
2:
diff --git a/arch/arm/cpu/mmu-early.c b/arch/arm/cpu/mmu-early.c
index d39a03ed95..2f5876fc46 100644
--- a/arch/arm/cpu/mmu-early.c
+++ b/arch/arm/cpu/mmu-early.c
@@ -5,17 +5,20 @@
#include <asm/memory.h>
#include <asm/system.h>
#include <asm/cache.h>
+#include <asm-generic/sections.h>
#include "mmu.h"
static uint32_t *ttb;
-static void map_cachable(unsigned long start, unsigned long size)
+static inline void map_region(unsigned long start, unsigned long size,
+ uint64_t flags)
+
{
start = ALIGN_DOWN(start, SZ_1M);
size = ALIGN(size, SZ_1M);
- create_sections(ttb, start, start + size - 1, PMD_SECT_DEF_CACHED);
+ create_sections(ttb, start, start + size - 1, flags);
}
void mmu_early_enable(unsigned long membase, unsigned long memsize,
@@ -28,9 +31,27 @@ void mmu_early_enable(unsigned long membase, unsigned long memsize,
set_ttbr(ttb);
set_domain(DOMAIN_MANAGER);
+ /*
+ * This marks the whole address space as uncachable as well as
+ * unexecutable if possible
+ */
create_flat_mapping(ttb);
- map_cachable(membase, memsize);
+ /*
+ * There can be SoCs that have a section shared between device memory
+ * and the on-chip RAM hosting the PBL. Thus mark this section
+ * uncachable, but executable.
+ * On such SoCs, executing from OCRAM could cause the instruction
+ * prefetcher to speculatively access that device memory, triggering
+ * potential errant behavior.
+ *
+ * If your SoC has such a memory layout, you should rewrite the code
+ * here to map the OCRAM page-wise.
+ */
+ map_region((unsigned long)_stext, _etext - _stext, PMD_SECT_DEF_UNCACHED);
+
+ /* maps main memory as cachable */
+ map_region(membase, memsize, PMD_SECT_DEF_CACHED);
__mmu_cache_on();
}
diff --git a/arch/arm/cpu/mmu.c b/arch/arm/cpu/mmu.c
index 29816ad563..123e19e9e5 100644
--- a/arch/arm/cpu/mmu.c
+++ b/arch/arm/cpu/mmu.c
@@ -34,7 +34,6 @@
#include "mmu.h"
-#define PMD_SECT_DEF_CACHED (PMD_SECT_WB | PMD_SECT_DEF_UNCACHED)
#define PTRS_PER_PTE (PGDIR_SIZE / PAGE_SIZE)
#define ARCH_MAP_WRITECOMBINE ((unsigned)-1)
@@ -58,11 +57,13 @@ static inline void tlb_invalidate(void)
}
#define PTE_FLAGS_CACHED_V7 (PTE_EXT_TEX(1) | PTE_BUFFERABLE | PTE_CACHEABLE)
-#define PTE_FLAGS_WC_V7 PTE_EXT_TEX(1)
-#define PTE_FLAGS_UNCACHED_V7 (0)
+#define PTE_FLAGS_WC_V7 (PTE_EXT_TEX(1) | PTE_EXT_XN)
+#define PTE_FLAGS_UNCACHED_V7 PTE_EXT_XN
#define PTE_FLAGS_CACHED_V4 (PTE_SMALL_AP_UNO_SRW | PTE_BUFFERABLE | PTE_CACHEABLE)
#define PTE_FLAGS_UNCACHED_V4 PTE_SMALL_AP_UNO_SRW
-#define PGD_FLAGS_WC_V7 (PMD_SECT_TEX(1) | PMD_TYPE_SECT | PMD_SECT_BUFFERABLE)
+#define PGD_FLAGS_WC_V7 (PMD_SECT_TEX(1) | PMD_TYPE_SECT | PMD_SECT_BUFFERABLE | \
+ PMD_SECT_XN)
+#define PGD_FLAGS_UNCACHED_V7 (PMD_SECT_DEF_UNCACHED | PMD_SECT_XN)
/*
* PTE flags to set cached and uncached areas.
@@ -72,6 +73,7 @@ static uint32_t pte_flags_cached;
static uint32_t pte_flags_wc;
static uint32_t pte_flags_uncached;
static uint32_t pgd_flags_wc;
+static uint32_t pgd_flags_uncached;
#define PTE_MASK ((1 << 12) - 1)
@@ -164,7 +166,7 @@ int arch_remap_range(void *start, size_t size, unsigned flags)
break;
case MAP_UNCACHED:
pte_flags = pte_flags_uncached;
- pgd_flags = PMD_SECT_DEF_UNCACHED;
+ pgd_flags = pgd_flags_uncached;
break;
case ARCH_MAP_WRITECOMBINE:
pte_flags = pte_flags_wc;
@@ -247,7 +249,7 @@ void *map_io_sections(unsigned long phys, void *_start, size_t size)
unsigned long start = (unsigned long)_start, sec;
for (sec = start; sec < start + size; sec += PGDIR_SIZE, phys += PGDIR_SIZE)
- ttb[pgd_index(sec)] = phys | PMD_SECT_DEF_UNCACHED;
+ ttb[pgd_index(sec)] = phys | pgd_flags_uncached;
dma_flush_range(ttb, 0x4000);
tlb_invalidate();
@@ -411,11 +413,13 @@ void __mmu_init(bool mmu_on)
pte_flags_cached = PTE_FLAGS_CACHED_V7;
pte_flags_wc = PTE_FLAGS_WC_V7;
pgd_flags_wc = PGD_FLAGS_WC_V7;
+ pgd_flags_uncached = PGD_FLAGS_UNCACHED_V7;
pte_flags_uncached = PTE_FLAGS_UNCACHED_V7;
} else {
pte_flags_cached = PTE_FLAGS_CACHED_V4;
pte_flags_wc = PTE_FLAGS_UNCACHED_V4;
pgd_flags_wc = PMD_SECT_DEF_UNCACHED;
+ pgd_flags_uncached = PMD_SECT_DEF_UNCACHED;
pte_flags_uncached = PTE_FLAGS_UNCACHED_V4;
}
diff --git a/arch/arm/cpu/mmu.h b/arch/arm/cpu/mmu.h
index 338728aacd..c911ee209f 100644
--- a/arch/arm/cpu/mmu.h
+++ b/arch/arm/cpu/mmu.h
@@ -3,6 +3,7 @@
#include <asm/pgtable.h>
#include <linux/sizes.h>
+#include <asm/system_info.h>
#include "mmu-common.h"
@@ -62,8 +63,13 @@ create_sections(uint32_t *ttb, unsigned long first,
static inline void create_flat_mapping(uint32_t *ttb)
{
+ unsigned int flags = PMD_SECT_DEF_UNCACHED;
+
+ if (cpu_architecture() >= CPU_ARCH_ARMv7)
+ flags |= PMD_SECT_XN;
+
/* create a flat mapping using 1MiB sections */
- create_sections(ttb, 0, 0xffffffff, PMD_SECT_DEF_UNCACHED);
+ create_sections(ttb, 0, 0xffffffff, flags);
}
#endif /* __ARM_MMU_H */