[PATCH v6 23/26] arm/arm64: KVM: Introduce EL2-specific executable mappings
Andrew Jones
drjones at redhat.com
Thu Mar 15 08:03:20 PDT 2018
On Wed, Mar 14, 2018 at 04:50:46PM +0000, Marc Zyngier wrote:
> Until now, all EL2 executable mappings were derived from their
> EL1 VA. Since we want to decouple the vectors mapping from
> the rest of the hypervisor, we need to be able to map some
> text somewhere else.
>
> The "idmap" region (for lack of a better name) is ideally suited
> for this, as we have a huge range that hardly has anything in it.
>
> Let's extend the IO allocator to also deal with executable mappings,
> thus providing the required feature.
>
> Signed-off-by: Marc Zyngier <marc.zyngier at arm.com>
> ---
> arch/arm/include/asm/kvm_mmu.h | 2 +
> arch/arm64/include/asm/kvm_mmu.h | 2 +
> virt/kvm/arm/mmu.c | 80 +++++++++++++++++++++++++++++-----------
> 3 files changed, 63 insertions(+), 21 deletions(-)
>
> diff --git a/arch/arm/include/asm/kvm_mmu.h b/arch/arm/include/asm/kvm_mmu.h
> index 26eb6b1cec9b..1b7f592eae57 100644
> --- a/arch/arm/include/asm/kvm_mmu.h
> +++ b/arch/arm/include/asm/kvm_mmu.h
> @@ -56,6 +56,8 @@ int create_hyp_mappings(void *from, void *to, pgprot_t prot);
> int create_hyp_io_mappings(phys_addr_t phys_addr, size_t size,
> void __iomem **kaddr,
> void __iomem **haddr);
> +int create_hyp_exec_mappings(phys_addr_t phys_addr, size_t size,
> + void **haddr);
> void free_hyp_pgds(void);
>
> void stage2_unmap_vm(struct kvm *kvm);
> diff --git a/arch/arm64/include/asm/kvm_mmu.h b/arch/arm64/include/asm/kvm_mmu.h
> index c2beb2d25170..97af11065bbd 100644
> --- a/arch/arm64/include/asm/kvm_mmu.h
> +++ b/arch/arm64/include/asm/kvm_mmu.h
> @@ -151,6 +151,8 @@ int create_hyp_mappings(void *from, void *to, pgprot_t prot);
> int create_hyp_io_mappings(phys_addr_t phys_addr, size_t size,
> void __iomem **kaddr,
> void __iomem **haddr);
> +int create_hyp_exec_mappings(phys_addr_t phys_addr, size_t size,
> + void **haddr);
> void free_hyp_pgds(void);
>
> void stage2_unmap_vm(struct kvm *kvm);
> diff --git a/virt/kvm/arm/mmu.c b/virt/kvm/arm/mmu.c
> index b4d1948c8dd6..554ad5493e7d 100644
> --- a/virt/kvm/arm/mmu.c
> +++ b/virt/kvm/arm/mmu.c
> @@ -737,30 +737,13 @@ int create_hyp_mappings(void *from, void *to, pgprot_t prot)
> return 0;
> }
>
> -/**
> - * create_hyp_io_mappings - Map IO into both kernel and HYP
> - * @phys_addr: The physical start address which gets mapped
> - * @size: Size of the region being mapped
> - * @kaddr: Kernel VA for this mapping
> - * @haddr: HYP VA for this mapping
> - */
> -int create_hyp_io_mappings(phys_addr_t phys_addr, size_t size,
> - void __iomem **kaddr,
> - void __iomem **haddr)
> +static int __create_hyp_private_mapping(phys_addr_t phys_addr, size_t size,
> + unsigned long *haddr, pgprot_t prot)
> {
> pgd_t *pgd = hyp_pgd;
> unsigned long base;
> int ret;
>
> - *kaddr = ioremap(phys_addr, size);
> - if (!*kaddr)
> - return -ENOMEM;
> -
> - if (is_kernel_in_hyp_mode()) {
> - *haddr = *kaddr;
> - return 0;
> - }
> -
> mutex_lock(&io_map_lock);
>
> /*
> @@ -789,22 +772,77 @@ int create_hyp_io_mappings(phys_addr_t phys_addr, size_t size,
>
> ret = __create_hyp_mappings(pgd, __kvm_idmap_ptrs_per_pgd(),
> base, base + size,
> - __phys_to_pfn(phys_addr), PAGE_HYP_DEVICE);
> + __phys_to_pfn(phys_addr), prot);
> if (ret)
> goto out;
>
> - *haddr = (void __iomem *)base + offset_in_page(phys_addr);
> + *haddr = base + offset_in_page(phys_addr);
> io_map_base = base;
>
> out:
> mutex_unlock(&io_map_lock);
>
> + return ret;
> +}
> +
> +/**
> + * create_hyp_io_mappings - Map IO into both kernel and HYP
> + * @phys_addr: The physical start address which gets mapped
> + * @size: Size of the region being mapped
> + * @kaddr: Kernel VA for this mapping
> + * @haddr: HYP VA for this mapping
> + */
> +int create_hyp_io_mappings(phys_addr_t phys_addr, size_t size,
> + void __iomem **kaddr,
> + void __iomem **haddr)
> +{
> + unsigned long addr;
> + int ret;
> +
> + *kaddr = ioremap(phys_addr, size);
> + if (!*kaddr)
> + return -ENOMEM;
> +
> + if (is_kernel_in_hyp_mode()) {
> + *haddr = *kaddr;
> + return 0;
> + }
> +
> + ret = __create_hyp_private_mapping(phys_addr, size,
> + &addr, PAGE_HYP_DEVICE);
> if (ret) {
> iounmap(*kaddr);
> *kaddr = NULL;
> + *haddr = NULL;
> + return ret;
> + }
> +
> + *haddr = (void __iomem *)addr;
> + return 0;
> +}
> +
> +/**
> + * create_hyp_exec_mappings - Map an executable range into into HYP
s/into into/into/
> + * @phys_addr: The physical start address which gets mapped
> + * @size: Size of the region being mapped
> + * @haddr: HYP VA for this mapping
> + */
> +int create_hyp_exec_mappings(phys_addr_t phys_addr, size_t size,
> + void **haddr)
> +{
> + unsigned long addr;
> + int ret;
> +
> + BUG_ON(is_kernel_in_hyp_mode());
Why BUG_ON instead of just giving the caller the same address, similar
to what create_hyp_io_mappings() does?
> +
> + ret = __create_hyp_private_mapping(phys_addr, size,
> + &addr, PAGE_HYP_EXEC);
> + if (ret) {
> + *haddr = NULL;
> return ret;
> }
>
> + *haddr = (void *)addr;
> return 0;
> }
>
> --
> 2.14.2
>
Otherwise
Reviewed-by: Andrew Jones <drjones at redhat.com>
More information about the linux-arm-kernel
mailing list