From f984ce84bab84c821cc7be76c8362808c375c1c8 Mon Sep 17 00:00:00 2001 From: Lin Ma Date: Mon, 2 Jun 2014 11:45:36 -0700 Subject: [PATCH] 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 --- include/lib/aarch64/xlat_tables.h | 7 ++-- lib/aarch64/xlat_tables.c | 56 ++++++++++++++++++------------- plat/fvp/aarch64/fvp_common.c | 40 ++++++++++++++-------- 3 files changed, 63 insertions(+), 40 deletions(-) diff --git a/include/lib/aarch64/xlat_tables.h b/include/lib/aarch64/xlat_tables.h index 5df655bd..8e0adc7f 100644 --- a/include/lib/aarch64/xlat_tables.h +++ b/include/lib/aarch64/xlat_tables.h @@ -55,13 +55,14 @@ typedef enum { * 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 29b81dbd..1b99cc85 100644 --- a/lib/aarch64/xlat_tables.c +++ b/lib/aarch64/xlat_tables.c @@ -72,26 +72,29 @@ static void print_mmap(void) 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 @@ 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 */ 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_region(unsigned long base, unsigned long size, unsigned attr) 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 @@ static unsigned long mmap_desc(unsigned attr, unsigned long addr, 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 @@ static int mmap_region_attr(mmap_region_t *mm, unsigned long base, 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 @@ static int mmap_region_attr(mmap_region_t *mm, unsigned long base, 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 @@ static mmap_region_t *init_xlation_table(mmap_region_t *mm, unsigned long base, 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 @@ static mmap_region_t *init_xlation_table(mmap_region_t *mm, unsigned long base, 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 3a078448..41234cba 100644 --- a/plat/fvp/aarch64/fvp_common.c +++ b/plat/fvp/aarch64/fvp_common.c @@ -54,17 +54,27 @@ static unsigned long fvp_config[CONFIG_LIMIT]; * 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 @@ const mmap_region_t fvp_mmap[] = { * 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(); \ -- 2.30.2