From: Christoffer Dall <c.dall@xxxxxxxxxxxxxxxxxxxxxx> 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_idmap_add(pgd, addr, end); - hyp_idmap_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.dall@xxxxxxxxxxxxxxxxxxxxxx> --- arch/arm/include/asm/pgtable-3level-hwdef.h | 1 + arch/arm/include/asm/pgtable.h | 5 +++ arch/arm/kvm/guest.c | 1 - arch/arm/mm/idmap.c | 47 +++++++++++++++++++++++++-- 4 files changed, 49 insertions(+), 5 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 f66626d..c7bd809 100644 --- a/arch/arm/include/asm/pgtable.h +++ b/arch/arm/include/asm/pgtable.h @@ -310,6 +310,11 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) #define pgtable_cache_init() do { } while (0) +#ifdef CONFIG_KVM_ARM_HOST +void hyp_idmap_add(pgd_t *, unsigned long, unsigned long); +void hyp_idmap_del(pgd_t *pgd, unsigned long addr, unsigned long end); +#endif + #endif /* !__ASSEMBLY__ */ #endif /* CONFIG_MMU */ diff --git a/arch/arm/kvm/guest.c b/arch/arm/kvm/guest.c index 9c75ec4..c0adab0 100644 --- a/arch/arm/kvm/guest.c +++ b/arch/arm/kvm/guest.c @@ -24,7 +24,6 @@ #include <asm/kvm_asm.h> #include <asm/kvm_emulate.h> - struct kvm_stats_debugfs_item debugfs_entries[] = { { NULL } }; diff --git a/arch/arm/mm/idmap.c b/arch/arm/mm/idmap.c index feacf4c..35902d7 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> @@ -58,11 +59,13 @@ static void idmap_add_pud(pgd_t *pgd, unsigned long addr, unsigned long end, } while (pud++, addr = next, addr != end); } -static 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, unsigned long prot) { - unsigned long prot, next; + unsigned long next; + + prot |= PMD_TYPE_SECT | PMD_SECT_AP_WRITE | PMD_SECT_AF; - prot = PMD_TYPE_SECT | PMD_SECT_AP_WRITE | PMD_SECT_AF; if (cpu_architecture() <= CPU_ARCH_ARMv5TEJ && !cpu_is_xscale()) prot |= PMD_BIT4; @@ -89,12 +92,48 @@ static int __init init_static_idmap(void) pr_info("Setting up static identity map for 0x%llx - 0x%llx\n", (long long)idmap_start, (long long)idmap_end); - identity_mapping_add(idmap_pgd, idmap_start, idmap_end); + identity_mapping_add(idmap_pgd, idmap_start, idmap_end, 0); return 0; } early_initcall(init_static_idmap); +#ifdef CONFIG_KVM_ARM_HOST +void hyp_idmap_add(pgd_t *pgd, unsigned long addr, unsigned long end) +{ + identity_mapping_add(pgd, addr, end, PMD_SECT_AP1); +} +EXPORT_SYMBOL_GPL(hyp_idmap_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); + pud_clear(pud); +} + +/* + * This version actually frees the underlying pmds for all pgds in range and + * clear the pgds themselves afterwards. + */ +void hyp_idmap_del(pgd_t *pgd, unsigned long addr, unsigned long end) +{ + unsigned long next; + + pgd += pgd_index(addr); + do { + next = pgd_addr_end(addr, end); + if (!pgd_none_or_clear_bad(pgd)) + hyp_idmap_del_pmd(pgd, addr); + } while (pgd++, addr = next, addr < end); +} +EXPORT_SYMBOL_GPL(hyp_idmap_del); +#endif + /* * In order to soft-boot, we need to switch to a 1:1 mapping for the * cpu_reset functions. 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 majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html