From: Christoffer Dall <cd...@cs.columbia.edu>

Adds support in the identity mapping feature that allows KVM to setup
identity mapping for the Hyp mode with the AP[1] bit set as required by
the specification and also supports freeing created sub pmd's after
finished use.

These two functions:
 - hyp_identity_mapping_add(pgd, addr, end);
 - hyp_identity_mapping_del(pgd, addr, end);
are essentially calls to the same function as the non-hyp versions but
with a different argument value. KVM calls these functions to setup
and teardown the identity mapping used to initialize the hypervisor.

Note, the hyp-version of the _del function actually frees the pmd's
pointed to by the pgd as opposed to the non-hyp version which just
clears them.

Signed-off-by: Christoffer Dall <c.d...@virtualopensystems.com>
---
 arch/arm/include/asm/pgtable-3level-hwdef.h |    1 +
 arch/arm/include/asm/pgtable.h              |    6 +++
 arch/arm/mm/idmap.c                         |   54 +++++++++++++++++++++++++++
 3 files changed, 60 insertions(+), 1 deletions(-)

diff --git a/arch/arm/include/asm/pgtable-3level-hwdef.h 
b/arch/arm/include/asm/pgtable-3level-hwdef.h
index d795282..a2d404e 100644
--- a/arch/arm/include/asm/pgtable-3level-hwdef.h
+++ b/arch/arm/include/asm/pgtable-3level-hwdef.h
@@ -44,6 +44,7 @@
 #define PMD_SECT_XN            (_AT(pmdval_t, 1) << 54)
 #define PMD_SECT_AP_WRITE      (_AT(pmdval_t, 0))
 #define PMD_SECT_AP_READ       (_AT(pmdval_t, 0))
+#define PMD_SECT_AP1           (_AT(pmdval_t, 1) << 6)
 #define PMD_SECT_TEX(x)                (_AT(pmdval_t, 0))
 
 /*
diff --git a/arch/arm/include/asm/pgtable.h b/arch/arm/include/asm/pgtable.h
index aec18ab..19456f4 100644
--- a/arch/arm/include/asm/pgtable.h
+++ b/arch/arm/include/asm/pgtable.h
@@ -318,6 +318,12 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
 void identity_mapping_add(pgd_t *, unsigned long, unsigned long);
 void identity_mapping_del(pgd_t *, unsigned long, unsigned long);
 
+#ifdef CONFIG_KVM_ARM_HOST
+void hyp_identity_mapping_add(pgd_t *, unsigned long, unsigned long);
+void hyp_identity_mapping_del(pgd_t *pgd, unsigned long addr,
+                             unsigned long end);
+#endif
+
 #endif /* !__ASSEMBLY__ */
 
 #endif /* CONFIG_MMU */
diff --git a/arch/arm/mm/idmap.c b/arch/arm/mm/idmap.c
index 267db72..e29903a 100644
--- a/arch/arm/mm/idmap.c
+++ b/arch/arm/mm/idmap.c
@@ -1,3 +1,4 @@
+#include <linux/module.h>
 #include <linux/kernel.h>
 
 #include <asm/cputype.h>
@@ -54,11 +55,18 @@ static void idmap_add_pud(pgd_t *pgd, unsigned long addr, 
unsigned long end,
        } while (pud++, addr = next, addr != end);
 }
 
-void identity_mapping_add(pgd_t *pgd, unsigned long addr, unsigned long end)
+static void __identity_mapping_add(pgd_t *pgd, unsigned long addr,
+                                  unsigned long end, bool hyp_mapping)
 {
        unsigned long prot, next;
 
        prot = PMD_TYPE_SECT | PMD_SECT_AP_WRITE | PMD_SECT_AF;
+
+#ifdef CONFIG_ARM_LPAE
+       if (hyp_mapping)
+               prot |= PMD_SECT_AP1;
+#endif
+
        if (cpu_architecture() <= CPU_ARCH_ARMv5TEJ && !cpu_is_xscale())
                prot |= PMD_BIT4;
 
@@ -69,6 +77,12 @@ void identity_mapping_add(pgd_t *pgd, unsigned long addr, 
unsigned long end)
        } while (pgd++, addr = next, addr != end);
 }
 
+void identity_mapping_add(pgd_t *pgd, unsigned long addr, unsigned long end)
+{
+       __identity_mapping_add(pgd, addr, end, false);
+}
+
+
 #ifdef CONFIG_SMP
 static void idmap_del_pmd(pud_t *pud, unsigned long addr, unsigned long end)
 {
@@ -103,6 +117,44 @@ void identity_mapping_del(pgd_t *pgd, unsigned long addr, 
unsigned long end)
 }
 #endif
 
+#ifdef CONFIG_KVM_ARM_HOST
+void hyp_identity_mapping_add(pgd_t *pgd, unsigned long addr, unsigned long 
end)
+{
+       __identity_mapping_add(pgd, addr, end, true);
+}
+EXPORT_SYMBOL_GPL(hyp_identity_mapping_add);
+
+static void hyp_idmap_del_pmd(pgd_t *pgd, unsigned long addr)
+{
+       pud_t *pud;
+       pmd_t *pmd;
+
+       pud = pud_offset(pgd, addr);
+       pmd = pmd_offset(pud, addr);
+       pmd_free(NULL, pmd);
+}
+
+/*
+ * This version actually frees the underlying pmds for all pgds in range and
+ * clear the pgds themselves afterwards.
+ */
+void hyp_identity_mapping_del(pgd_t *pgd, unsigned long addr, unsigned long 
end)
+{
+       unsigned long next;
+       pgd_t *next_pgd;
+
+       do {
+               next = pgd_addr_end(addr, end);
+               next_pgd = pgd + pgd_index(addr);
+               if (!pgd_none_or_clear_bad(next_pgd)) {
+                       hyp_idmap_del_pmd(next_pgd, addr);
+                       pgd_clear(next_pgd);
+               }
+       } while (addr = next, addr < end);
+}
+EXPORT_SYMBOL_GPL(hyp_identity_mapping_del);
+#endif
+
 /*
  * In order to soft-boot, we need to insert a 1:1 mapping in place of
  * the user-mode pages.  This will then ensure that we have predictable

--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to