VHE: Add helper to get attributes of a stage 1 va range.

This patch adds a new helper function mm_get_mode, similar to
mm_vm_get_mode, to get the attributes of a stage 1 va range. This is
useful to be able to get memory attributes of a EL0 partitions va range
for example. This patchset modifies the existing function
mm_vm_get_attrs to take flags as an argument so that the same function
can work with stage 1 tables as well. Also added helper function to
convert attributes to mode for stage 1 similar to stage 2 helper
function.

Change-Id: I9dd23a7728830641bec46970fb6fa711240f8516
Signed-off-by: Raghu Krishnamurthy <raghu.ncstate@gmail.com>
diff --git a/inc/hf/arch/mm.h b/inc/hf/arch/mm.h
index 714a6d5..ef64dd3 100644
--- a/inc/hf/arch/mm.h
+++ b/inc/hf/arch/mm.h
@@ -155,6 +155,11 @@
 uint32_t arch_mm_stage2_attrs_to_mode(uint64_t attrs);
 
 /**
+ * Converts the stage-1 block attributes back to the corresponding mode.
+ */
+uint32_t arch_mm_stage1_attrs_to_mode(uint64_t attrs);
+
+/**
  * Initializes the arch specific memory management.
  */
 bool arch_mm_init(paddr_t table);
diff --git a/inc/hf/mm.h b/inc/hf/mm.h
index 54d9f94..4bdae13 100644
--- a/inc/hf/mm.h
+++ b/inc/hf/mm.h
@@ -131,6 +131,8 @@
 void mm_vm_dump(struct mm_ptable *t);
 bool mm_vm_get_mode(struct mm_ptable *t, ipaddr_t begin, ipaddr_t end,
 		    uint32_t *mode);
+bool mm_get_mode(struct mm_ptable *t, vaddr_t begin, vaddr_t end,
+		 uint32_t *mode);
 
 struct mm_stage1_locked mm_lock_ptable_unsafe(struct mm_ptable *ptable);
 struct mm_stage1_locked mm_lock_stage1(void);
diff --git a/src/arch/aarch64/mm.c b/src/arch/aarch64/mm.c
index f3c90fd..7256c28 100644
--- a/src/arch/aarch64/mm.c
+++ b/src/arch/aarch64/mm.c
@@ -70,6 +70,10 @@
 #define TABLE_XNTABLE  (UINT64_C(1) << 60)
 #define TABLE_PXNTABLE (UINT64_C(1) << 59)
 
+/* The following are stage-1 software defined attributes. */
+#define STAGE1_SW_OWNED     (UINT64_C(1) << 55)
+#define STAGE1_SW_EXCLUSIVE (UINT64_C(1) << 56)
+
 /* The following are stage-2 software defined attributes. */
 #define STAGE2_SW_OWNED     (UINT64_C(1) << 55)
 #define STAGE2_SW_EXCLUSIVE (UINT64_C(1) << 56)
@@ -504,6 +508,16 @@
 		attrs |= STAGE1_ATTRINDX(STAGE1_NORMALINDX);
 	}
 
+	/* Define the ownership bit. */
+	if (!(mode & MM_MODE_UNOWNED)) {
+		attrs |= STAGE1_SW_OWNED;
+	}
+
+	/* Define the exclusivity bit. */
+	if (!(mode & MM_MODE_SHARED)) {
+		attrs |= STAGE1_SW_EXCLUSIVE;
+	}
+
 	/* Define the valid bit. */
 	if (!(mode & MM_MODE_INVALID)) {
 		attrs |= PTE_VALID;
@@ -512,6 +526,60 @@
 	return attrs;
 }
 
+uint32_t arch_mm_stage1_attrs_to_mode(uint64_t attrs)
+{
+	uint32_t mode = 0;
+
+#if SECURE_WORLD == 1
+	if (attrs & STAGE1_NS) {
+		mode |= MM_MODE_NS;
+	}
+#endif
+
+	if ((attrs & STAGE1_AP(STAGE1_READONLY)) ==
+	    STAGE1_AP(STAGE1_READONLY)) {
+		mode |= MM_MODE_R;
+	} else {
+		CHECK((attrs & STAGE1_AP(STAGE1_READWRITE)) ==
+		      STAGE1_AP(STAGE1_READWRITE));
+		mode |= MM_MODE_W | MM_MODE_R;
+	}
+
+	if (has_vhe_support() && (attrs & STAGE1_AP(STAGE1_AP_USER_RW))) {
+		mode |= MM_MODE_USER;
+	}
+
+	if (!(attrs & STAGE1_XN) || !(attrs & STAGE1_PXN)) {
+		mode |= MM_MODE_X;
+	}
+
+	if (has_vhe_support() && (attrs & STAGE1_NG)) {
+		mode |= MM_MODE_NG;
+	}
+
+	if (!((attrs & STAGE1_ATTRINDX(STAGE1_NORMALINDX)) ==
+	      STAGE1_ATTRINDX(STAGE1_NORMALINDX))) {
+		mode |= MM_MODE_D;
+	} else {
+		CHECK((attrs & STAGE1_ATTRINDX(STAGE1_NORMALINDX)) ==
+		      STAGE1_ATTRINDX(STAGE1_NORMALINDX));
+	}
+
+	if (!(attrs & STAGE1_SW_OWNED)) {
+		mode |= MM_MODE_UNOWNED;
+	}
+
+	if (!(attrs & STAGE1_SW_EXCLUSIVE)) {
+		mode |= MM_MODE_SHARED;
+	}
+
+	if (!(attrs & PTE_VALID)) {
+		mode |= MM_MODE_INVALID;
+	}
+
+	return mode;
+}
+
 uint64_t arch_mm_mode_to_stage2_attrs(uint32_t mode)
 {
 	uint64_t attrs = 0;
diff --git a/src/arch/fake/mm.c b/src/arch/fake/mm.c
index 9c6ed7d..e06a8b7 100644
--- a/src/arch/fake/mm.c
+++ b/src/arch/fake/mm.c
@@ -156,6 +156,11 @@
 	return attrs >> PTE_ATTR_MODE_SHIFT;
 }
 
+uint32_t arch_mm_stage1_attrs_to_mode(uint64_t attrs)
+{
+	return attrs >> PTE_ATTR_MODE_SHIFT;
+}
+
 bool arch_mm_init(paddr_t table)
 {
 	/* No initialization required. */
diff --git a/src/mm.c b/src/mm.c
index 00b1d14..c9c54db 100644
--- a/src/mm.c
+++ b/src/mm.c
@@ -790,17 +790,16 @@
 }
 
 /**
- * Gets the attributes applies to the given range of addresses in the stage-2
- * table.
+ * Gets the attributes applied to the given range of addresses in the page
+ * tables.
  *
  * The value returned in `attrs` is only valid if the function returns true.
  *
  * Returns true if the whole range has the same attributes and false otherwise.
  */
-static bool mm_vm_get_attrs(struct mm_ptable *t, ptable_addr_t begin,
-			    ptable_addr_t end, uint64_t *attrs)
+static bool mm_get_attrs(struct mm_ptable *t, ptable_addr_t begin,
+			 ptable_addr_t end, uint64_t *attrs, int flags)
 {
-	int flags = 0;
 	uint8_t max_level = mm_max_level(flags);
 	uint8_t root_level = max_level + 1;
 	size_t root_table_size = mm_entry_size(root_level);
@@ -992,7 +991,7 @@
 	uint64_t attrs;
 	bool ret;
 
-	ret = mm_vm_get_attrs(t, ipa_addr(begin), ipa_addr(end), &attrs);
+	ret = mm_get_attrs(t, ipa_addr(begin), ipa_addr(end), &attrs, 0);
 	if (ret) {
 		*mode = arch_mm_stage2_attrs_to_mode(attrs);
 	}
@@ -1000,6 +999,27 @@
 	return ret;
 }
 
+/**
+ * Gets the mode of the given range of virtual addresses if they
+ * are mapped with the same mode.
+ *
+ * Returns true if the range is mapped with the same mode and false otherwise.
+ */
+bool mm_get_mode(struct mm_ptable *t, vaddr_t begin, vaddr_t end,
+		 uint32_t *mode)
+{
+	uint64_t attrs;
+	bool ret;
+
+	ret = mm_get_attrs(t, va_addr(begin), va_addr(end), &attrs,
+			   MM_FLAG_STAGE1);
+	if (ret) {
+		*mode = arch_mm_stage1_attrs_to_mode(attrs);
+	}
+
+	return ret;
+}
+
 static struct mm_stage1_locked mm_stage1_lock_unsafe(void)
 {
 	return (struct mm_stage1_locked){.ptable = &ptable};