summaryrefslogtreecommitdiff
path: root/virt/kvm
diff options
context:
space:
mode:
authorMarc Zyngier <marc.zyngier@arm.com>2018-02-13 14:00:29 +0300
committerMarc Zyngier <marc.zyngier@arm.com>2018-03-19 16:06:05 +0300
commitdc2e4633ff39c9fb5ef3a5443721f0e3499b36ed (patch)
treee515344be534277129313e93becfb4206f460e96 /virt/kvm
parent71dcb8be6d29cffff3f4a4463232f38786e97797 (diff)
downloadlinux-dc2e4633ff39c9fb5ef3a5443721f0e3499b36ed.tar.xz
arm/arm64: KVM: Introduce EL2-specific executable mappings
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. Acked-by: Catalin Marinas <catalin.marinas@arm.com> Reviewed-by: Andrew Jones <drjones@redhat.com> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
Diffstat (limited to 'virt/kvm')
-rw-r--r--virt/kvm/arm/mmu.c80
1 files changed, 59 insertions, 21 deletions
diff --git a/virt/kvm/arm/mmu.c b/virt/kvm/arm/mmu.c
index 394f41a65732..7f6a944db23d 100644
--- a/virt/kvm/arm/mmu.c
+++ b/virt/kvm/arm/mmu.c
@@ -734,30 +734,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 = 0;
- *kaddr = ioremap(phys_addr, size);
- if (!*kaddr)
- return -ENOMEM;
-
- if (is_kernel_in_hyp_mode()) {
- *haddr = *kaddr;
- return 0;
- }
-
mutex_lock(&kvm_hyp_pgd_mutex);
/*
@@ -791,19 +774,74 @@ 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);
out:
+ 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 HYP
+ * @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());
+
+ ret = __create_hyp_private_mapping(phys_addr, size,
+ &addr, PAGE_HYP_EXEC);
+ if (ret) {
+ *haddr = NULL;
return ret;
}
+ *haddr = (void *)addr;
return 0;
}