[Android-virt] [PATCH 4/6] ARM: KVM: Add support for IO mapping at the HYP level

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

 



On Mon, May 14, 2012 at 4:05 PM, Marc Zyngier <marc.zyngier at arm.com> wrote:
> Moving to the VGIC implies giving access to some ioremapped
> devices (the VGIC virtual interface control registers) to the
> hypervisor.
>
> Define create_hyp_io_mappings() as the IO aware sibling of
> create_hyp_mappings(), and extend the mapping functions
> to support a pte mapping backend.
>
> Signed-off-by: Marc Zyngier <marc.zyngier at arm.com>
> ---
> ?arch/arm/include/asm/kvm_mmu.h | ? ?1 +
> ?arch/arm/kvm/mmu.c ? ? ? ? ? ? | ? 46 +++++++++++++++++++++++++++++++++++----
> ?2 files changed, 42 insertions(+), 5 deletions(-)
>
> diff --git a/arch/arm/include/asm/kvm_mmu.h b/arch/arm/include/asm/kvm_mmu.h
> index 917edd7..eb05401 100644
> --- a/arch/arm/include/asm/kvm_mmu.h
> +++ b/arch/arm/include/asm/kvm_mmu.h
> @@ -31,6 +31,7 @@ extern pgd_t *kvm_hyp_pgd;
> ?extern struct mutex kvm_hyp_pgd_mutex;
>
> ?int create_hyp_mappings(pgd_t *hyp_pgd, void *from, void *to);
> +int create_hyp_io_mappings(pgd_t *hyp_pgd, void *from, void *to, phys_addr_t);
> ?void free_hyp_pmds(pgd_t *hyp_pgd);
>
> ?int kvm_alloc_stage2_pgd(struct kvm *kvm);
> diff --git a/arch/arm/kvm/mmu.c b/arch/arm/kvm/mmu.c
> index 8375aed..5c809b8 100644
> --- a/arch/arm/kvm/mmu.c
> +++ b/arch/arm/kvm/mmu.c
> @@ -16,11 +16,13 @@
>
> ?#include <linux/mman.h>
> ?#include <linux/kvm_host.h>
> +#include <linux/io.h>
> ?#include <trace/events/kvm.h>
> ?#include <asm/pgalloc.h>
> ?#include <asm/kvm_arm.h>
> ?#include <asm/kvm_mmu.h>
> ?#include <asm/kvm_emulate.h>
> +#include <asm/mach/map.h>
>
> ?#include "trace.h"
>
> @@ -72,8 +74,10 @@ void free_hyp_pmds(pgd_t *hyp_pgd)
> ? ? ? ?mutex_unlock(&kvm_hyp_pgd_mutex);
> ?}
>
> +typedef void (*hyp_pte_map_fn_t)(pmd_t *, unsigned long, unsigned long, unsigned long *);
> +
> ?static void create_hyp_pte_mappings(pmd_t *pmd, unsigned long start,
> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? unsigned long end)
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? unsigned long end, unsigned long *pfn_base)
> ?{
> ? ? ? ?pte_t *pte;
> ? ? ? ?struct page *page;
> @@ -88,8 +92,27 @@ static void create_hyp_pte_mappings(pmd_t *pmd, unsigned long start,
> ? ? ? ?}
> ?}
>
> +static void create_hyp_pte_io_mappings(pmd_t *pmd, unsigned long start,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?unsigned long end, unsigned long *pfn_base)
> +{
> + ? ? ? pte_t *pte;
> + ? ? ? unsigned long addr;
> + ? ? ? pgprot_t prot;
> +
> + ? ? ? prot = __pgprot(get_mem_type_prot_pte(MT_DEVICE) | L_PTE_USER);
> +
> + ? ? ? for (addr = start & PAGE_MASK; addr < end; addr += PAGE_SIZE) {
> + ? ? ? ? ? ? ? BUG_ON(pfn_valid(*pfn_base));
> + ? ? ? ? ? ? ? pte = pte_offset_kernel(pmd, addr);
> +
> + ? ? ? ? ? ? ? set_pte_ext(pte, pfn_pte(*pfn_base, prot), 0);
> + ? ? ? ? ? ? ? (*pfn_base)++;
> + ? ? ? }
> +}
> +

how about getting rid of all this function pointer stuff and just rely
on pfn_base != NULL meaning an i/o mapping? (we won't be assuming
physically contiguous normal page mappings anyhow right?) A small
comment in the top of the function should make this crystal clear to
anyone, imh(umble)o.

> ?static int create_hyp_pmd_mappings(pud_t *pud, unsigned long start,
> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?unsigned long end)
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?unsigned long end, hyp_pte_map_fn_t map_fn,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?unsigned long *pfn_base)
> ?{
> ? ? ? ?pmd_t *pmd;
> ? ? ? ?pte_t *pte;
> @@ -110,7 +133,7 @@ static int create_hyp_pmd_mappings(pud_t *pud, unsigned long start,
> ? ? ? ? ? ? ? ?}
>
> ? ? ? ? ? ? ? ?next = pmd_addr_end(addr, end);
> - ? ? ? ? ? ? ? create_hyp_pte_mappings(pmd, addr, next);
> + ? ? ? ? ? ? ? map_fn(pmd, addr, next, pfn_base);
> ? ? ? ?}
>
> ? ? ? ?return 0;
> @@ -127,7 +150,9 @@ static int create_hyp_pmd_mappings(pud_t *pud, unsigned long start,
> ?*
> ?* Note: Wrapping around zero in the "to" address is not supported.
> ?*/
> -int create_hyp_mappings(pgd_t *hyp_pgd, void *from, void *to)
> +static int __create_hyp_mappings(pgd_t *hyp_pgd, void *from, void *to,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?hyp_pte_map_fn_t map_fn,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?unsigned long *pfn_base)

this breaks the function documentation, the docs should follow the
non-static version.

> ?{
> ? ? ? ?unsigned long start = (unsigned long)from;
> ? ? ? ?unsigned long end = (unsigned long)to;
> @@ -157,7 +182,7 @@ int create_hyp_mappings(pgd_t *hyp_pgd, void *from, void *to)
> ? ? ? ? ? ? ? ?}
>
> ? ? ? ? ? ? ? ?next = pgd_addr_end(addr, end);
> - ? ? ? ? ? ? ? err = create_hyp_pmd_mappings(pud, addr, next);
> + ? ? ? ? ? ? ? err = create_hyp_pmd_mappings(pud, addr, next, map_fn, pfn_base);
> ? ? ? ? ? ? ? ?if (err)
> ? ? ? ? ? ? ? ? ? ? ? ?goto out;
> ? ? ? ?}
> @@ -166,6 +191,17 @@ out:
> ? ? ? ?return err;
> ?}
>
> +int create_hyp_mappings(pgd_t *hyp_pgd, void *from, void *to)
> +{
> + ? ? ? return __create_hyp_mappings(hyp_pgd, from, to, create_hyp_pte_mappings, NULL);
> +}
> +
> +int create_hyp_io_mappings(pgd_t *hyp_pgd, void *from, void *to, phys_addr_t addr)
> +{
> + ? ? ? unsigned long pfn = __phys_to_pfn(addr);
> + ? ? ? return __create_hyp_mappings(hyp_pgd, from, to, create_hyp_pte_io_mappings, &pfn);
> +}
> +

this function should have kdocs as well.

> ?/**
> ?* kvm_alloc_stage2_pgd - allocate level-1 table for stage-2 translation.
> ?* @kvm: ? ? ? The KVM struct pointer for the VM.
> --
> 1.7.7.1



[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