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
This commit is contained in:
parent
e10af77b28
commit
f984ce84ba
|
@ -55,13 +55,14 @@ typedef enum {
|
||||||
* Structure for specifying a single region of memory.
|
* Structure for specifying a single region of memory.
|
||||||
*/
|
*/
|
||||||
typedef struct mmap_region {
|
typedef struct mmap_region {
|
||||||
unsigned long base;
|
unsigned long base_pa;
|
||||||
|
unsigned long base_va;
|
||||||
unsigned long size;
|
unsigned long size;
|
||||||
mmap_attr_t attr;
|
mmap_attr_t attr;
|
||||||
} mmap_region_t;
|
} mmap_region_t;
|
||||||
|
|
||||||
void mmap_add_region(unsigned long base, unsigned long size,
|
void mmap_add_region(unsigned long base_pa, unsigned long base_va,
|
||||||
unsigned attr);
|
unsigned long size, unsigned attr);
|
||||||
void mmap_add(const mmap_region_t *mm);
|
void mmap_add(const mmap_region_t *mm);
|
||||||
|
|
||||||
void init_xlat_tables(void);
|
void init_xlat_tables(void);
|
||||||
|
|
|
@ -72,26 +72,29 @@ static void print_mmap(void)
|
||||||
debug_print("mmap:\n");
|
debug_print("mmap:\n");
|
||||||
mmap_region_t *mm = mmap;
|
mmap_region_t *mm = mmap;
|
||||||
while (mm->size) {
|
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;
|
++mm;
|
||||||
};
|
};
|
||||||
debug_print("\n");
|
debug_print("\n");
|
||||||
#endif
|
#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 = mmap;
|
||||||
mmap_region_t *mm_last = mm + sizeof(mmap) / sizeof(mmap[0]) - 1;
|
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));
|
assert(IS_PAGE_ALIGNED(size));
|
||||||
|
|
||||||
if (!size)
|
if (!size)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* Find correct place in mmap to insert new region */
|
/* Find correct place in mmap to insert new region */
|
||||||
while (mm->base < base && mm->size)
|
while (mm->base_va < base_va && mm->size)
|
||||||
++mm;
|
++mm;
|
||||||
|
|
||||||
/* Make room for new region by moving other regions up by one place */
|
/* Make room for new region by moving other regions up by one place */
|
||||||
|
@ -100,7 +103,8 @@ void mmap_add_region(unsigned long base, unsigned long size, unsigned attr)
|
||||||
/* Check we haven't lost the empty sentinal from the end of the array */
|
/* Check we haven't lost the empty sentinal from the end of the array */
|
||||||
assert(mm_last->size == 0);
|
assert(mm_last->size == 0);
|
||||||
|
|
||||||
mm->base = base;
|
mm->base_pa = base_pa;
|
||||||
|
mm->base_va = base_va;
|
||||||
mm->size = size;
|
mm->size = size;
|
||||||
mm->attr = attr;
|
mm->attr = attr;
|
||||||
}
|
}
|
||||||
|
@ -108,15 +112,15 @@ void mmap_add_region(unsigned long base, unsigned long size, unsigned attr)
|
||||||
void mmap_add(const mmap_region_t *mm)
|
void mmap_add(const mmap_region_t *mm)
|
||||||
{
|
{
|
||||||
while (mm->size) {
|
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;
|
++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 level)
|
||||||
{
|
{
|
||||||
unsigned long desc = addr;
|
unsigned long desc = addr_pa;
|
||||||
|
|
||||||
desc |= level == 3 ? TABLE_DESC : BLOCK_DESC;
|
desc |= level == 3 ? TABLE_DESC : BLOCK_DESC;
|
||||||
|
|
||||||
|
@ -142,7 +146,7 @@ static unsigned long mmap_desc(unsigned attr, unsigned long addr,
|
||||||
return desc;
|
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)
|
unsigned long size)
|
||||||
{
|
{
|
||||||
int attr = mm->attr;
|
int attr = mm->attr;
|
||||||
|
@ -153,10 +157,10 @@ static int mmap_region_attr(mmap_region_t *mm, unsigned long base,
|
||||||
if (!mm->size)
|
if (!mm->size)
|
||||||
return attr; /* Reached end of list */
|
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 */
|
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 */
|
continue; /* Next region has already been overtaken */
|
||||||
|
|
||||||
if ((mm->attr & attr) == attr)
|
if ((mm->attr & attr) == attr)
|
||||||
|
@ -164,12 +168,14 @@ static int mmap_region_attr(mmap_region_t *mm, unsigned long base,
|
||||||
|
|
||||||
attr &= mm->attr;
|
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 */
|
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 long *table, unsigned level)
|
||||||
{
|
{
|
||||||
unsigned level_size_shift = L1_XLAT_ADDRESS_SHIFT - (level - 1) *
|
unsigned level_size_shift = L1_XLAT_ADDRESS_SHIFT - (level - 1) *
|
||||||
|
@ -184,23 +190,26 @@ static mmap_region_t *init_xlation_table(mmap_region_t *mm, unsigned long base,
|
||||||
do {
|
do {
|
||||||
unsigned long desc = UNSET_DESC;
|
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 */
|
/* Area now after the region so skip it */
|
||||||
++mm;
|
++mm;
|
||||||
continue;
|
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 */
|
/* Next region is after area so nothing to map yet */
|
||||||
desc = INVALID_DESC;
|
desc = INVALID_DESC;
|
||||||
} else if (mm->base <= base &&
|
} else if (mm->base_va <= base_va && mm->base_va + mm->size >=
|
||||||
mm->base + mm->size >= base + level_size) {
|
base_va + level_size) {
|
||||||
/* Next region covers all of area */
|
/* 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)
|
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 */
|
/* else Next region only partially covers area, so need */
|
||||||
|
|
||||||
|
@ -211,14 +220,15 @@ static mmap_region_t *init_xlation_table(mmap_region_t *mm, unsigned long base,
|
||||||
desc = TABLE_DESC | (unsigned long)new_table;
|
desc = TABLE_DESC | (unsigned long)new_table;
|
||||||
|
|
||||||
/* Recurse to fill in 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");
|
debug_print("\n");
|
||||||
|
|
||||||
*table++ = desc;
|
*table++ = desc;
|
||||||
base += level_size;
|
base_va += level_size;
|
||||||
} while (mm->size && (base & level_index_mask));
|
} while (mm->size && (base_va & level_index_mask));
|
||||||
|
|
||||||
return mm;
|
return mm;
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,17 +54,27 @@ static unsigned long fvp_config[CONFIG_LIMIT];
|
||||||
* configure_mmu_elx() will give the available subset of that,
|
* configure_mmu_elx() will give the available subset of that,
|
||||||
*/
|
*/
|
||||||
const mmap_region_t fvp_mmap[] = {
|
const mmap_region_t fvp_mmap[] = {
|
||||||
{ TZROM_BASE, TZROM_SIZE, MT_MEMORY | MT_RO | MT_SECURE },
|
{ TZROM_BASE, TZROM_BASE, TZROM_SIZE,
|
||||||
{ TZDRAM_BASE, TZDRAM_SIZE, MT_MEMORY | MT_RW | MT_SECURE },
|
MT_MEMORY | MT_RO | MT_SECURE },
|
||||||
{ FLASH0_BASE, FLASH0_SIZE, MT_MEMORY | MT_RO | MT_SECURE },
|
{ TZDRAM_BASE, TZDRAM_BASE, TZDRAM_SIZE,
|
||||||
{ FLASH1_BASE, FLASH1_SIZE, MT_MEMORY | MT_RO | MT_SECURE },
|
MT_MEMORY | MT_RW | MT_SECURE },
|
||||||
{ VRAM_BASE, VRAM_SIZE, MT_MEMORY | MT_RW | MT_SECURE },
|
{ FLASH0_BASE, FLASH0_BASE, FLASH0_SIZE,
|
||||||
{ DEVICE0_BASE, DEVICE0_SIZE, MT_DEVICE | MT_RW | MT_SECURE },
|
MT_MEMORY | MT_RO | MT_SECURE },
|
||||||
{ NSRAM_BASE, NSRAM_SIZE, MT_MEMORY | MT_RW | MT_NS },
|
{ FLASH1_BASE, FLASH1_BASE, FLASH1_SIZE,
|
||||||
{ DEVICE1_BASE, DEVICE1_SIZE, MT_DEVICE | MT_RW | MT_SECURE },
|
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...*/
|
/* 2nd GB as device for now...*/
|
||||||
{ 0x40000000, 0x40000000, MT_DEVICE | MT_RW | MT_SECURE },
|
{ 0x40000000, 0x40000000, 0x40000000,
|
||||||
{ DRAM1_BASE, DRAM1_SIZE, MT_MEMORY | MT_RW | MT_NS },
|
MT_DEVICE | MT_RW | MT_SECURE },
|
||||||
|
{ DRAM1_BASE, DRAM1_BASE, DRAM1_SIZE,
|
||||||
|
MT_MEMORY | MT_RW | MT_NS },
|
||||||
{0}
|
{0}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -73,19 +83,21 @@ const mmap_region_t fvp_mmap[] = {
|
||||||
* the platform memory map & initialize the mmu, for the given exception level
|
* the platform memory map & initialize the mmu, for the given exception level
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
#define DEFINE_CONFIGURE_MMU_EL(_el) \
|
#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 total_size, \
|
||||||
unsigned long ro_start, \
|
unsigned long ro_start, \
|
||||||
unsigned long ro_limit, \
|
unsigned long ro_limit, \
|
||||||
unsigned long coh_start, \
|
unsigned long coh_start, \
|
||||||
unsigned long coh_limit) \
|
unsigned long coh_limit) \
|
||||||
{ \
|
{ \
|
||||||
mmap_add_region(total_base, \
|
mmap_add_region(total_base, total_base, \
|
||||||
total_size, \
|
total_size, \
|
||||||
MT_MEMORY | MT_RW | MT_SECURE); \
|
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); \
|
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); \
|
MT_DEVICE | MT_RW | MT_SECURE); \
|
||||||
mmap_add(fvp_mmap); \
|
mmap_add(fvp_mmap); \
|
||||||
init_xlat_tables(); \
|
init_xlat_tables(); \
|
||||||
|
|
Loading…
Reference in New Issue