Merge pull request #538 from sandrine-bailleux-arm/sb/extend-memory-types

Extend memory attributes to map non-cacheable memory
diff --git a/include/lib/aarch64/arch.h b/include/lib/aarch64/arch.h
index 49efafc..a9b2dbb 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 0b5dbdf..d21100e 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 2f2ca81..d28731f 100644
--- a/lib/aarch64/xlat_tables.c
+++ b/lib/aarch64/xlat_tables.c
@@ -138,6 +138,7 @@
 					unsigned level)
 {
 	unsigned long desc = addr_pa;
+	int mem_type;
 
 	desc |= level == 3 ? TABLE_DESC : BLOCK_DESC;
 
@@ -147,16 +148,23 @@
 
 	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 @@
 					unsigned long size)
 {
 	int attr = mm->attr;
+	int old_mem_type, new_mem_type;
 
 	for (;;) {
 		++mm;
@@ -183,7 +192,20 @@
 		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 @@
 		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 */	\