@@ -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 {
@@ -20,8 +20,6 @@
#include <linux/compiler.h>
-extern unsigned long etext;
-
pgd_t *mmu_idmap;
/* CPU 0 starts with disabled MMU */
@@ -157,7 +155,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;
/* 3G-4G region is reserved for vmalloc, cap phys_end at 3G */
if (phys_end > (3ul << 30))
@@ -173,14 +171,20 @@ void *setup_mmu(phys_addr_t phys_end)
if (!mmu_idmap)
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_enable(mmu_idmap);
return mmu_idmap;
@@ -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,25 @@ 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_regions[nr_io + i] = (struct mem_region){
+ .start = code_end,
+ .end = primary->end,
+ .flags = MR_F_PRIMARY,
+ };
+ *primary = (struct mem_region){
+ .start = primary->start,
+ .end = code_end,
+ .flags = MR_F_PRIMARY | 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);