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.zyngier@xxxxxxx> --- 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 majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html