---
lib/arm/asm/setup.h | 1 +
lib/arm/mmu.c | 26 +++++++++++++++-----------
lib/arm/setup.c | 22 ++++++++++++++--------
3 files changed, 30 insertions(+), 19 deletions(-)
diff --git a/lib/arm/asm/setup.h b/lib/arm/asm/setup.h
index c8afb2493f8d..210c14f818fb 100644
--- a/lib/arm/asm/setup.h
+++ b/lib/arm/asm/setup.h
@@ -15,6 +15,7 @@ extern int nr_cpus;
#define MR_F_PRIMARY (1U << 0)
#define MR_F_IO (1U << 1)
+#define MR_F_CODE (1U << 2)
#define MR_F_UNKNOWN (1U << 31)
struct mem_region {
diff --git a/lib/arm/mmu.c b/lib/arm/mmu.c
index a7b7ae51afe3..edd2b9da809b 100644
--- a/lib/arm/mmu.c
+++ b/lib/arm/mmu.c
@@ -20,8 +20,6 @@
#include <linux/compiler.h>
-extern unsigned long etext;
-
#define MMU_MAX_PERSISTENT_MAPS 64
struct mmu_persistent_map {
@@ -208,7 +206,7 @@ void mmu_set_range_sect(pgd_t *pgtable, uintptr_t virt_offset,
void *setup_mmu(phys_addr_t phys_end)
{
- uintptr_t code_end = (uintptr_t)&etext;
+ struct mem_region *r;
/* 0G-1G = I/O, 1G-3G = identity, 3G-4G = vmalloc */
if (phys_end > (3ul << 30))
@@ -223,14 +221,20 @@ void *setup_mmu(phys_addr_t phys_end)
mmu_idmap = alloc_page();
- /* armv8 requires code shared between EL1 and EL0 to be read-only */
- mmu_set_range_ptes(mmu_idmap, PHYS_OFFSET,
- PHYS_OFFSET, code_end,
- __pgprot(PTE_WBWA | PTE_RDONLY | PTE_USER));
-
- mmu_set_range_ptes(mmu_idmap, code_end,
- code_end, phys_end,
- __pgprot(PTE_WBWA | PTE_USER));
+ for (r = mem_regions; r->end; ++r) {
+ if (r->flags & MR_F_IO) {
+ continue;
+ } else if (r->flags & MR_F_CODE) {
+ assert_msg(r->flags & MR_F_PRIMARY, "Unexpected code region");
+ /* armv8 requires code shared between EL1 and EL0 to be read-only */
+ mmu_set_range_ptes(mmu_idmap, r->start, r->start, r->end,
+ __pgprot(PTE_WBWA | PTE_USER | PTE_RDONLY));
+ } else {
+ assert_msg(r->flags & MR_F_PRIMARY, "Unexpected data region");
+ mmu_set_range_ptes(mmu_idmap, r->start, r->start, r->end,
+ __pgprot(PTE_WBWA | PTE_USER));
+ }
+ }
mmu_set_persistent_maps(mmu_idmap);
diff --git a/lib/arm/setup.c b/lib/arm/setup.c
index 9c16f6004e9f..9da5d24b0be9 100644
--- a/lib/arm/setup.c
+++ b/lib/arm/setup.c
@@ -31,6 +31,7 @@
#define NR_INITIAL_MEM_REGIONS 16
extern unsigned long stacktop;
+extern unsigned long etext;
struct timer_state __timer_state;
@@ -88,10 +89,12 @@ unsigned int mem_region_get_flags(phys_addr_t paddr)
static void mem_init(phys_addr_t freemem_start)
{
+ phys_addr_t code_end = (phys_addr_t)(unsigned long)&etext;
struct dt_pbus_reg regs[NR_INITIAL_MEM_REGIONS];
- struct mem_region primary, mem = {
+ struct mem_region mem = {
.start = (phys_addr_t)-1,
};
+ struct mem_region *primary = NULL;
phys_addr_t base, top;
int nr_regs, nr_io = 0, i;
@@ -110,8 +113,6 @@ static void mem_init(phys_addr_t freemem_start)
nr_regs = dt_get_memory_params(regs, NR_INITIAL_MEM_REGIONS - nr_io);
assert(nr_regs > 0);
- primary = (struct mem_region){ 0 };
-
for (i = 0; i < nr_regs; ++i) {
struct mem_region *r = &mem_regions[nr_io + i];
@@ -123,7 +124,7 @@ static void mem_init(phys_addr_t freemem_start)
*/
if (freemem_start >= r->start && freemem_start < r->end) {
r->flags |= MR_F_PRIMARY;
- primary = *r;
+ primary = r;
}
/*
@@ -135,13 +136,18 @@ static void mem_init(phys_addr_t freemem_start)
if (r->end > mem.end)
mem.end = r->end;
}
- assert(primary.end != 0);
+ assert(primary);
assert(!(mem.start & ~PHYS_MASK) && !((mem.end - 1) & ~PHYS_MASK));
- __phys_offset = primary.start; /* PHYS_OFFSET */
- __phys_end = primary.end; /* PHYS_END */
+ __phys_offset = primary->start; /* PHYS_OFFSET */
+ __phys_end = primary->end; /* PHYS_END */
+
+ /* Split the primary region into two regions; code and data */
+ mem.start = code_end, mem.end = primary->end, mem.flags = MR_F_PRIMARY;
+ mem_regions[nr_io + i] = mem;
+ primary->end = code_end, primary->flags |= MR_F_CODE;
- phys_alloc_init(freemem_start, primary.end - freemem_start);
+ phys_alloc_init(freemem_start, __phys_end - freemem_start);
phys_alloc_set_minimum_alignment(SMP_CACHE_BYTES);
phys_alloc_get_unused(&base, &top);