]> git.baikalelectronics.ru Git - kernel.git/commitdiff
arm/arm64: KVM: Introduce EL2-specific executable mappings
authorMarc Zyngier <marc.zyngier@arm.com>
Tue, 13 Feb 2018 11:00:29 +0000 (11:00 +0000)
committerMarc Zyngier <marc.zyngier@arm.com>
Mon, 19 Mar 2018 13:06:05 +0000 (13:06 +0000)
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>
arch/arm/include/asm/kvm_mmu.h
arch/arm64/include/asm/kvm_mmu.h
virt/kvm/arm/mmu.c

index b0b0cde77ca66c8b37388bd695e0056a784aff3e..707a1f06dc5d5e207f0d2c18e0b37844569ca199 100644 (file)
@@ -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);
index 65dc225d019c920bec696ca27619f98c64e18ce6..eb04437d50fa00947c5e173f67646bf95e22a97a 100644 (file)
@@ -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);
index 394f41a657329f16eecec2d0f6b424a719c1e83c..7f6a944db23d6c471d87e0d58effc4c0d1ac01a4 100644 (file)
@@ -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;
 }