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};