Add the necessary infrastructure to handle MMU notifiers on KVM/ARM.
As we don't have shadow page tables, the implementation is actually very
simple. The only supported operation is kvm_unmap_hva(), where we remove
the HVA from the 2nd stage translation. All other hooks are NOPs.

Signed-off-by: Marc Zyngier <marc.zyng...@arm.com>
---
 arch/arm/include/asm/kvm_asm.h  |    4 ++++
 arch/arm/include/asm/kvm_host.h |   19 +++++++++++++++++++
 arch/arm/kvm/Kconfig            |    3 ++-
 arch/arm/kvm/arm.c              |    4 ++--
 arch/arm/kvm/interrupts.S       |   23 +++++++++++++++++++++++
 arch/arm/kvm/mmu.c              |   21 ++++++++++++++++++---
 6 files changed, 68 insertions(+), 6 deletions(-)

diff --git a/arch/arm/include/asm/kvm_asm.h b/arch/arm/include/asm/kvm_asm.h
index 89c318ea..f933886 100644
--- a/arch/arm/include/asm/kvm_asm.h
+++ b/arch/arm/include/asm/kvm_asm.h
@@ -36,6 +36,7 @@ asm(".equ SMCHYP_HVBAR_W, 0xfffffff0");
 #endif /* __ASSEMBLY__ */
 
 #ifndef __ASSEMBLY__
+struct kvm;
 struct kvm_vcpu;
 
 extern char __kvm_hyp_init[];
@@ -46,6 +47,9 @@ extern char __kvm_hyp_vector_end[];
 
 extern int __kvm_vcpu_run(struct kvm_vcpu *vcpu);
 extern char __kvm_vcpu_run_end[];
+
+extern void __kvm_tlb_flush_vmid(struct kvm *kvm);
+extern char __kvm_hyp_code_end[];
 #endif
 
 #endif /* __ARM_KVM_ASM_H__ */
diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h
index 555a6f1..1c0c68b 100644
--- a/arch/arm/include/asm/kvm_host.h
+++ b/arch/arm/include/asm/kvm_host.h
@@ -109,4 +109,23 @@ struct kvm_vm_stat {
 struct kvm_vcpu_stat {
 };
 
+#define KVM_ARCH_WANT_MMU_NOTIFIER
+struct kvm;
+int kvm_unmap_hva(struct kvm *kvm, unsigned long hva);
+
+/* We do not have shadow page tables, hence the empty hooks */
+static inline int kvm_age_hva(struct kvm *kvm, unsigned long hva)
+{
+       return 0;
+}
+
+static inline int kvm_test_age_hva(struct kvm *kvm, unsigned long hva)
+{
+       return 0;
+}
+
+static inline void kvm_set_spte_hva(struct kvm *kvm, unsigned long hva, pte_t 
pte)
+{
+}
+
 #endif /* __ARM_KVM_HOST_H__ */
diff --git a/arch/arm/kvm/Kconfig b/arch/arm/kvm/Kconfig
index ccabbb3..f943dff 100644
--- a/arch/arm/kvm/Kconfig
+++ b/arch/arm/kvm/Kconfig
@@ -35,7 +35,8 @@ config KVM_ARM_HOST
        bool "KVM host support for ARM cpus."
        depends on KVM
        depends on MMU
-       depends on CPU_V7 || ARM_VIRT_EXT
+       depends on ARM_VIRT_EXT
+       select  MMU_NOTIFIER
        ---help---
          Provides host support for ARM processors.
 
diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c
index 14ccc4d..602e087 100644
--- a/arch/arm/kvm/arm.c
+++ b/arch/arm/kvm/arm.c
@@ -636,9 +636,9 @@ static int init_hyp_mode(void)
         * Map the world-switch code
         */
        err = create_hyp_mappings(kvm_hyp_pgd,
-                                 __kvm_vcpu_run, __kvm_vcpu_run_end);
+                                 __kvm_vcpu_run, __kvm_hyp_code_end);
        if (err) {
-               kvm_err(err, "Cannot map world-switch code");
+               kvm_err(err, "Cannot map hyp mode code");
                goto out_free_mappings;
        }
 
diff --git a/arch/arm/kvm/interrupts.S b/arch/arm/kvm/interrupts.S
index fbc26ca..c3d7adb 100644
--- a/arch/arm/kvm/interrupts.S
+++ b/arch/arm/kvm/interrupts.S
@@ -356,6 +356,29 @@ THUMB(     orr     lr, lr, #1)
 __kvm_vcpu_run_end:
        .globl __kvm_vcpu_run_end
 
+ENTRY(__kvm_tlb_flush_vmid)
+       hvc     #0                      @ Switch to Hyp mode
+       push    {r2, r3}
+
+       ldrd    r2, r3, [r0, #KVM_VTTBR]
+       mcrr    p15, 6, r2, r3, c2      @ Write VTTBR
+       isb
+       mcr     p15, 0, r0, c8, c7, 0   @ TBLIALL
+       dsb
+       isb
+       mov     r2, #0
+       mov     r3, #0
+       mcrr    p15, 6, r2, r3, c2      @ Back to VMID #0
+       isb
+
+       pop     {r2, r3}
+       hvc     #0                      @ Back to SVC
+       mov     pc, lr
+ENDPROC(__kvm_tlb_flush_vmid)
+       
+__kvm_hyp_code_end:
+       .globl  __kvm_hyp_code_end
+       
 
 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
 @  Hypervisor exception vector and handlers
diff --git a/arch/arm/kvm/mmu.c b/arch/arm/kvm/mmu.c
index baeb8a1..0e4480b 100644
--- a/arch/arm/kvm/mmu.c
+++ b/arch/arm/kvm/mmu.c
@@ -245,12 +245,12 @@ void kvm_free_stage2_pgd(struct kvm *kvm)
        kvm->arch.pgd = NULL;
 }
 
-static int __user_mem_abort(struct kvm *kvm, phys_addr_t addr, pfn_t pfn)
+static int stage2_set_pte(struct kvm *kvm, phys_addr_t addr, pte_t new_pte)
 {
        pgd_t *pgd;
        pud_t *pud;
        pmd_t *pmd;
-       pte_t *pte, new_pte;
+       pte_t *pte;
 
        /* Create 2nd stage page table mapping - Level 1 */
        pgd = kvm->arch.pgd + pgd_index(addr);
@@ -279,12 +279,18 @@ static int __user_mem_abort(struct kvm *kvm, phys_addr_t 
addr, pfn_t pfn)
                pte = pte_offset_kernel(pmd, addr);
 
        /* Create 2nd stage page table mapping - Level 3 */
-       new_pte = pfn_pte(pfn, PAGE_KVM_GUEST);
        set_pte_ext(pte, new_pte, 0);
 
        return 0;
 }
 
+static int __user_mem_abort(struct kvm *kvm, phys_addr_t addr, pfn_t pfn)
+{
+       pte_t new_pte = pfn_pte(pfn, PAGE_KVM_GUEST);
+
+       return stage2_set_pte(kvm, addr, new_pte);
+}
+
 static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
                          gfn_t gfn, struct kvm_memory_slot *memslot)
 {
@@ -510,3 +516,12 @@ int kvm_handle_guest_abort(struct kvm_vcpu *vcpu, struct 
kvm_run *run)
 
        return user_mem_abort(vcpu, fault_ipa, gfn, memslot);
 }
+
+static const pte_t null_pte;
+
+int kvm_unmap_hva(struct kvm *kvm, unsigned long hva)
+{
+       int ret = stage2_set_pte(kvm, (phys_addr_t)hva, null_pte);
+       __kvm_tlb_flush_vmid(kvm);
+       return ret;
+}
-- 
1.7.3.4

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