Enable mapping higher physical address
Current ATF uses a direct physical-to-virtual mapping, that is, a physical
address is mapped to the same address in the virtual space. For example,
physical address 0x8000_0000 is mapped to 0x8000_0000 virtual. This
approach works fine for FVP as all its physical addresses fall into 0 to
4GB range. But for other platform where all I/O addresses are 48-bit long,
If we follow the same direct mapping, we would need virtual address range
from 0 to 0x8fff_ffff_ffff, which is about 144TB. This requires a
significant amount of memory for MMU tables and it is not necessary to use
that much virtual space in ATF.
The patch is to enable mapping a physical address range to an arbitrary
virtual address range (instead of flat mapping)
Changed "base" to "base_va" and added "base_pa" in mmap_region_t and
modified functions such as mmap_add_region and init_xlation_table etc.
Fixes ARM-software/tf-issues#158
diff --git a/include/lib/aarch64/xlat_tables.h b/include/lib/aarch64/xlat_tables.h
index 5df655b..8e0adc7 100644
--- a/include/lib/aarch64/xlat_tables.h
+++ b/include/lib/aarch64/xlat_tables.h
@@ -55,13 +55,14 @@
* Structure for specifying a single region of memory.
*/
typedef struct mmap_region {
- unsigned long base;
+ unsigned long base_pa;
+ unsigned long base_va;
unsigned long size;
mmap_attr_t attr;
} mmap_region_t;
-void mmap_add_region(unsigned long base, unsigned long size,
- unsigned attr);
+void mmap_add_region(unsigned long base_pa, unsigned long base_va,
+ unsigned long size, unsigned attr);
void mmap_add(const mmap_region_t *mm);
void init_xlat_tables(void);
diff --git a/lib/aarch64/xlat_tables.c b/lib/aarch64/xlat_tables.c
index 29b81db..1b99cc8 100644
--- a/lib/aarch64/xlat_tables.c
+++ b/lib/aarch64/xlat_tables.c
@@ -72,26 +72,29 @@
debug_print("mmap:\n");
mmap_region_t *mm = mmap;
while (mm->size) {
- debug_print(" %010lx %10lx %x\n", mm->base, mm->size, mm->attr);
+ debug_print(" %010lx %010lx %10lx %x\n", mm->base_va,
+ mm->base_pa, mm->size, mm->attr);
++mm;
};
debug_print("\n");
#endif
}
-void mmap_add_region(unsigned long base, unsigned long size, unsigned attr)
+void mmap_add_region(unsigned long base_pa, unsigned long base_va,
+ unsigned long size, unsigned attr)
{
mmap_region_t *mm = mmap;
mmap_region_t *mm_last = mm + sizeof(mmap) / sizeof(mmap[0]) - 1;
- assert(IS_PAGE_ALIGNED(base));
+ assert(IS_PAGE_ALIGNED(base_pa));
+ assert(IS_PAGE_ALIGNED(base_va));
assert(IS_PAGE_ALIGNED(size));
if (!size)
return;
/* Find correct place in mmap to insert new region */
- while (mm->base < base && mm->size)
+ while (mm->base_va < base_va && mm->size)
++mm;
/* Make room for new region by moving other regions up by one place */
@@ -100,7 +103,8 @@
/* Check we haven't lost the empty sentinal from the end of the array */
assert(mm_last->size == 0);
- mm->base = base;
+ mm->base_pa = base_pa;
+ mm->base_va = base_va;
mm->size = size;
mm->attr = attr;
}
@@ -108,15 +112,15 @@
void mmap_add(const mmap_region_t *mm)
{
while (mm->size) {
- mmap_add_region(mm->base, mm->size, mm->attr);
+ mmap_add_region(mm->base_pa, mm->base_va, mm->size, mm->attr);
++mm;
}
}
-static unsigned long mmap_desc(unsigned attr, unsigned long addr,
+static unsigned long mmap_desc(unsigned attr, unsigned long addr_pa,
unsigned level)
{
- unsigned long desc = addr;
+ unsigned long desc = addr_pa;
desc |= level == 3 ? TABLE_DESC : BLOCK_DESC;
@@ -142,7 +146,7 @@
return desc;
}
-static int mmap_region_attr(mmap_region_t *mm, unsigned long base,
+static int mmap_region_attr(mmap_region_t *mm, unsigned long base_va,
unsigned long size)
{
int attr = mm->attr;
@@ -153,10 +157,10 @@
if (!mm->size)
return attr; /* Reached end of list */
- if (mm->base >= base + size)
+ if (mm->base_va >= base_va + size)
return attr; /* Next region is after area so end */
- if (mm->base + mm->size <= base)
+ if (mm->base_va + mm->size <= base_va)
continue; /* Next region has already been overtaken */
if ((mm->attr & attr) == attr)
@@ -164,12 +168,14 @@
attr &= mm->attr;
- if (mm->base > base || mm->base + mm->size < base + size)
+ if (mm->base_va > base_va ||
+ mm->base_va + mm->size < base_va + size)
return -1; /* Region doesn't fully cover our area */
}
}
-static mmap_region_t *init_xlation_table(mmap_region_t *mm, unsigned long base,
+static mmap_region_t *init_xlation_table(mmap_region_t *mm,
+ unsigned long base_va,
unsigned long *table, unsigned level)
{
unsigned level_size_shift = L1_XLAT_ADDRESS_SHIFT - (level - 1) *
@@ -184,23 +190,26 @@
do {
unsigned long desc = UNSET_DESC;
- if (mm->base + mm->size <= base) {
+ if (mm->base_va + mm->size <= base_va) {
/* Area now after the region so skip it */
++mm;
continue;
}
- debug_print(" %010lx %8lx " + 6 - 2 * level, base, level_size);
+ debug_print(" %010lx %8lx " + 6 - 2 * level, base_va,
+ level_size);
- if (mm->base >= base + level_size) {
+ if (mm->base_va >= base_va + level_size) {
/* Next region is after area so nothing to map yet */
desc = INVALID_DESC;
- } else if (mm->base <= base &&
- mm->base + mm->size >= base + level_size) {
+ } else if (mm->base_va <= base_va && mm->base_va + mm->size >=
+ base_va + level_size) {
/* Next region covers all of area */
- int attr = mmap_region_attr(mm, base, level_size);
+ int attr = mmap_region_attr(mm, base_va, level_size);
if (attr >= 0)
- desc = mmap_desc(attr, base, level);
+ desc = mmap_desc(attr,
+ base_va - mm->base_va + mm->base_pa,
+ level);
}
/* else Next region only partially covers area, so need */
@@ -211,14 +220,15 @@
desc = TABLE_DESC | (unsigned long)new_table;
/* Recurse to fill in new table */
- mm = init_xlation_table(mm, base, new_table, level+1);
+ mm = init_xlation_table(mm, base_va,
+ new_table, level+1);
}
debug_print("\n");
*table++ = desc;
- base += level_size;
- } while (mm->size && (base & level_index_mask));
+ base_va += level_size;
+ } while (mm->size && (base_va & level_index_mask));
return mm;
}
diff --git a/plat/fvp/aarch64/fvp_common.c b/plat/fvp/aarch64/fvp_common.c
index 3a07844..41234cb 100644
--- a/plat/fvp/aarch64/fvp_common.c
+++ b/plat/fvp/aarch64/fvp_common.c
@@ -54,17 +54,27 @@
* configure_mmu_elx() will give the available subset of that,
*/
const mmap_region_t fvp_mmap[] = {
- { TZROM_BASE, TZROM_SIZE, MT_MEMORY | MT_RO | MT_SECURE },
- { TZDRAM_BASE, TZDRAM_SIZE, MT_MEMORY | MT_RW | MT_SECURE },
- { FLASH0_BASE, FLASH0_SIZE, MT_MEMORY | MT_RO | MT_SECURE },
- { FLASH1_BASE, FLASH1_SIZE, MT_MEMORY | MT_RO | MT_SECURE },
- { VRAM_BASE, VRAM_SIZE, MT_MEMORY | MT_RW | MT_SECURE },
- { DEVICE0_BASE, DEVICE0_SIZE, MT_DEVICE | MT_RW | MT_SECURE },
- { NSRAM_BASE, NSRAM_SIZE, MT_MEMORY | MT_RW | MT_NS },
- { DEVICE1_BASE, DEVICE1_SIZE, MT_DEVICE | MT_RW | MT_SECURE },
+ { TZROM_BASE, TZROM_BASE, TZROM_SIZE,
+ MT_MEMORY | MT_RO | MT_SECURE },
+ { TZDRAM_BASE, TZDRAM_BASE, TZDRAM_SIZE,
+ MT_MEMORY | MT_RW | MT_SECURE },
+ { FLASH0_BASE, FLASH0_BASE, FLASH0_SIZE,
+ MT_MEMORY | MT_RO | MT_SECURE },
+ { FLASH1_BASE, FLASH1_BASE, FLASH1_SIZE,
+ MT_MEMORY | MT_RO | MT_SECURE },
+ { VRAM_BASE, VRAM_BASE, VRAM_SIZE,
+ MT_MEMORY | MT_RW | MT_SECURE },
+ { DEVICE0_BASE, DEVICE0_BASE, DEVICE0_SIZE,
+ MT_DEVICE | MT_RW | MT_SECURE },
+ { NSRAM_BASE, NSRAM_BASE, NSRAM_SIZE,
+ MT_MEMORY | MT_RW | MT_NS },
+ { DEVICE1_BASE, DEVICE1_BASE, DEVICE1_SIZE,
+ MT_DEVICE | MT_RW | MT_SECURE },
/* 2nd GB as device for now...*/
- { 0x40000000, 0x40000000, MT_DEVICE | MT_RW | MT_SECURE },
- { DRAM1_BASE, DRAM1_SIZE, MT_MEMORY | MT_RW | MT_NS },
+ { 0x40000000, 0x40000000, 0x40000000,
+ MT_DEVICE | MT_RW | MT_SECURE },
+ { DRAM1_BASE, DRAM1_BASE, DRAM1_SIZE,
+ MT_MEMORY | MT_RW | MT_NS },
{0}
};
@@ -73,19 +83,21 @@
* the platform memory map & initialize the mmu, for the given exception level
******************************************************************************/
#define DEFINE_CONFIGURE_MMU_EL(_el) \
- void fvp_configure_mmu_el##_el(unsigned long total_base, \
+ void fvp_configure_mmu_el##_el(unsigned long total_base, \
unsigned long total_size, \
unsigned long ro_start, \
unsigned long ro_limit, \
unsigned long coh_start, \
unsigned long coh_limit) \
{ \
- mmap_add_region(total_base, \
+ mmap_add_region(total_base, total_base, \
total_size, \
MT_MEMORY | MT_RW | MT_SECURE); \
- mmap_add_region(ro_start, ro_limit - ro_start, \
+ mmap_add_region(ro_start, ro_start, \
+ ro_limit - ro_start, \
MT_MEMORY | MT_RO | MT_SECURE); \
- mmap_add_region(coh_start, coh_limit - coh_start, \
+ mmap_add_region(coh_start, coh_start, \
+ coh_limit - coh_start, \
MT_DEVICE | MT_RW | MT_SECURE); \
mmap_add(fvp_mmap); \
init_xlat_tables(); \