diff --git a/include/lib/aarch64/arch.h b/include/lib/aarch64/arch.h index 49efafc5e..a9b2dbb25 100644 --- a/include/lib/aarch64/arch.h +++ b/include/lib/aarch64/arch.h @@ -419,11 +419,11 @@ #define AP_RW (0x0 << 5) #define NS (0x1 << 3) -#define ATTR_SO_INDEX 0x2 +#define ATTR_NON_CACHEABLE_INDEX 0x2 #define ATTR_DEVICE_INDEX 0x1 #define ATTR_IWBWA_OWBWA_NTR_INDEX 0x0 #define LOWER_ATTRS(x) (((x) & 0xfff) << 2) -#define ATTR_SO (0x0) +#define ATTR_NON_CACHEABLE (0x44) #define ATTR_DEVICE (0x4) #define ATTR_IWBWA_OWBWA_NTR (0xff) #define MAIR_ATTR_SET(attr, index) (attr << (index << 3)) diff --git a/include/lib/aarch64/xlat_tables.h b/include/lib/aarch64/xlat_tables.h index 0b5dbdf26..d21100e3f 100644 --- a/include/lib/aarch64/xlat_tables.h +++ b/include/lib/aarch64/xlat_tables.h @@ -52,21 +52,41 @@ #define MAP_REGION(pa, va, sz, attr) {(pa), (va), (sz), (attr)} /* - * Flags for building up memory mapping attributes. - * These are organised so that a clear bit gives a more restrictive mapping - * that a set bit, that way a bitwise-and two sets of attributes will never give - * an attribute which has greater access rights that any of the original - * attributes. + * Shifts and masks to access fields of an mmap_attr_t + */ +#define MT_TYPE_MASK 0x7 +#define MT_TYPE(_attr) ((_attr) & MT_TYPE_MASK) +/* Access permissions (RO/RW) */ +#define MT_PERM_SHIFT 3 +/* Security state (SECURE/NS) */ +#define MT_SEC_SHIFT 4 + +/* + * Memory mapping attributes */ typedef enum { - MT_DEVICE = 0 << 0, - MT_MEMORY = 1 << 0, + /* + * Memory types supported. + * These are organised so that, going down the list, the memory types + * are getting weaker; conversely going up the list the memory types are + * getting stronger. + */ + MT_DEVICE, + MT_NON_CACHEABLE, + MT_MEMORY, + /* Values up to 7 are reserved to add new memory types in the future */ - MT_RO = 0 << 1, - MT_RW = 1 << 1, + /* + * The following values are organised so that a clear bit gives a more + * restrictive mapping than a set bit, that way a bitwise-and of two + * sets of attributes will never give an attribute which has greater + * access rights than any of the original attributes. + */ + MT_RO = 0 << MT_PERM_SHIFT, + MT_RW = 1 << MT_PERM_SHIFT, - MT_SECURE = 0 << 2, - MT_NS = 1 << 2 + MT_SECURE = 0 << MT_SEC_SHIFT, + MT_NS = 1 << MT_SEC_SHIFT, } mmap_attr_t; /* diff --git a/lib/aarch64/xlat_tables.c b/lib/aarch64/xlat_tables.c index 2f2ca814e..d28731f63 100644 --- a/lib/aarch64/xlat_tables.c +++ b/lib/aarch64/xlat_tables.c @@ -138,6 +138,7 @@ static unsigned long mmap_desc(unsigned attr, unsigned long addr_pa, unsigned level) { unsigned long desc = addr_pa; + int mem_type; desc |= level == 3 ? TABLE_DESC : BLOCK_DESC; @@ -147,16 +148,23 @@ static unsigned long mmap_desc(unsigned attr, unsigned long addr_pa, desc |= LOWER_ATTRS(ACCESS_FLAG); - if (attr & MT_MEMORY) { + mem_type = MT_TYPE(attr); + if (mem_type == MT_MEMORY) { desc |= LOWER_ATTRS(ATTR_IWBWA_OWBWA_NTR_INDEX | ISH); if (attr & MT_RW) desc |= UPPER_ATTRS(XN); + } else if (mem_type == MT_NON_CACHEABLE) { + desc |= LOWER_ATTRS(ATTR_NON_CACHEABLE_INDEX | OSH); + if (attr & MT_RW) + desc |= UPPER_ATTRS(XN); } else { + assert(mem_type == MT_DEVICE); desc |= LOWER_ATTRS(ATTR_DEVICE_INDEX | OSH); desc |= UPPER_ATTRS(XN); } - debug_print(attr & MT_MEMORY ? "MEM" : "DEV"); + debug_print((mem_type == MT_MEMORY) ? "MEM" : + ((mem_type == MT_NON_CACHEABLE) ? "NC" : "DEV")); debug_print(attr & MT_RW ? "-RW" : "-RO"); debug_print(attr & MT_NS ? "-NS" : "-S"); @@ -167,6 +175,7 @@ static int mmap_region_attr(mmap_region_t *mm, unsigned long base_va, unsigned long size) { int attr = mm->attr; + int old_mem_type, new_mem_type; for (;;) { ++mm; @@ -183,7 +192,20 @@ static int mmap_region_attr(mmap_region_t *mm, unsigned long base_va, if ((mm->attr & attr) == attr) continue; /* Region doesn't override attribs so skip */ + /* + * Update memory mapping attributes in 2 steps: + * 1) Update access permissions and security state flags + * 2) Update memory type. + * + * See xlat_tables.h for details about the attributes priority + * system and the rules dictating whether attributes should be + * updated. + */ + old_mem_type = MT_TYPE(attr); + new_mem_type = MT_TYPE(mm->attr); attr &= mm->attr; + if (new_mem_type < old_mem_type) + attr = (attr & ~MT_TYPE_MASK) | new_mem_type; if (mm->base_va > base_va || mm->base_va + mm->size < base_va + size) @@ -309,6 +331,8 @@ void init_xlat_tables(void) mair = MAIR_ATTR_SET(ATTR_DEVICE, ATTR_DEVICE_INDEX); \ mair |= MAIR_ATTR_SET(ATTR_IWBWA_OWBWA_NTR, \ ATTR_IWBWA_OWBWA_NTR_INDEX); \ + mair |= MAIR_ATTR_SET(ATTR_NON_CACHEABLE, \ + ATTR_NON_CACHEABLE_INDEX); \ write_mair_el##_el(mair); \ \ /* Invalidate TLBs at the current exception level */ \