Re: [Android-virt] [PATCH RFC 2/2] ARM: KVM: Add support for MMU notifiers

2012-02-09 Thread Alexander Graf

On 10.02.2012, at 02:13, Marc Zyngier wrote:

 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, 0xfff0);
 #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;

You might want to age pages one day. EPT on x86 does it by flushing them and 
refaulting, since the swapping benefit is higher than the overhead induced 
through the flushes.

 +}
 +
 +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}
 +
 + ldrdr2, r3, [r0, #KVM_VTTBR]
 + mcrrp15, 6, r2, r3, c2  @ Write VTTBR
 + isb
 + mcr p15, 0, r0, c8, c7, 0   @ TBLIALL
 + dsb
 + isb
 + mov r2, #0
 + mov r3, #0
 + mcrrp15, 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);
 @@ 

[PATCH RFC 2/2] ARM: KVM: Add support for MMU notifiers

2012-02-09 Thread Marc Zyngier
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, 0xfff0);
 #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}
+
+   ldrdr2, r3, [r0, #KVM_VTTBR]
+   mcrrp15, 6, r2, r3, c2  @ Write VTTBR
+   isb
+   mcr p15, 0, r0, c8, c7, 0   @ TBLIALL
+   dsb
+   isb
+   mov r2, #0
+   mov r3, #0
+   mcrrp15, 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,