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

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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.zyngier at 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;

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}
> +
> +	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);

I haven't checked the implementation of stage2_set_pte, but are you sure it takes an hva, not a gpa as argument?


Alex




[Index of Archives]     [Linux KVM]     [Spice Development]     [Libvirt]     [Libvirt Users]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux