Merge tag 'pci-v4.16-fixes-1' of git://git.kernel.org/pub/scm/linux/kernel/git/helgaa...
[sfrench/cifs-2.6.git] / arch / arm / include / asm / kvm_mmu.h
index a2d176a308bd63ed4aeb89b8fda4f5b8a20b8a88..de1b919404e43a3c01cc8511b92862d4fa7c3f42 100644 (file)
@@ -37,6 +37,8 @@
 
 #include <linux/highmem.h>
 #include <asm/cacheflush.h>
+#include <asm/cputype.h>
+#include <asm/kvm_hyp.h>
 #include <asm/pgalloc.h>
 #include <asm/stage2_pgtable.h>
 
@@ -83,6 +85,18 @@ static inline pmd_t kvm_s2pmd_mkwrite(pmd_t pmd)
        return pmd;
 }
 
+static inline pte_t kvm_s2pte_mkexec(pte_t pte)
+{
+       pte_val(pte) &= ~L_PTE_XN;
+       return pte;
+}
+
+static inline pmd_t kvm_s2pmd_mkexec(pmd_t pmd)
+{
+       pmd_val(pmd) &= ~PMD_SECT_XN;
+       return pmd;
+}
+
 static inline void kvm_set_s2pte_readonly(pte_t *pte)
 {
        pte_val(*pte) = (pte_val(*pte) & ~L_PTE_S2_RDWR) | L_PTE_S2_RDONLY;
@@ -93,6 +107,11 @@ static inline bool kvm_s2pte_readonly(pte_t *pte)
        return (pte_val(*pte) & L_PTE_S2_RDWR) == L_PTE_S2_RDONLY;
 }
 
+static inline bool kvm_s2pte_exec(pte_t *pte)
+{
+       return !(pte_val(*pte) & L_PTE_XN);
+}
+
 static inline void kvm_set_s2pmd_readonly(pmd_t *pmd)
 {
        pmd_val(*pmd) = (pmd_val(*pmd) & ~L_PMD_S2_RDWR) | L_PMD_S2_RDONLY;
@@ -103,6 +122,11 @@ static inline bool kvm_s2pmd_readonly(pmd_t *pmd)
        return (pmd_val(*pmd) & L_PMD_S2_RDWR) == L_PMD_S2_RDONLY;
 }
 
+static inline bool kvm_s2pmd_exec(pmd_t *pmd)
+{
+       return !(pmd_val(*pmd) & PMD_SECT_XN);
+}
+
 static inline bool kvm_page_empty(void *ptr)
 {
        struct page *ptr_page = virt_to_page(ptr);
@@ -126,10 +150,36 @@ static inline bool vcpu_has_cache_enabled(struct kvm_vcpu *vcpu)
        return (vcpu_cp15(vcpu, c1_SCTLR) & 0b101) == 0b101;
 }
 
-static inline void __coherent_cache_guest_page(struct kvm_vcpu *vcpu,
-                                              kvm_pfn_t pfn,
-                                              unsigned long size)
+static inline void __clean_dcache_guest_page(kvm_pfn_t pfn, unsigned long size)
+{
+       /*
+        * Clean the dcache to the Point of Coherency.
+        *
+        * We need to do this through a kernel mapping (using the
+        * user-space mapping has proved to be the wrong
+        * solution). For that, we need to kmap one page at a time,
+        * and iterate over the range.
+        */
+
+       VM_BUG_ON(size & ~PAGE_MASK);
+
+       while (size) {
+               void *va = kmap_atomic_pfn(pfn);
+
+               kvm_flush_dcache_to_poc(va, PAGE_SIZE);
+
+               size -= PAGE_SIZE;
+               pfn++;
+
+               kunmap_atomic(va);
+       }
+}
+
+static inline void __invalidate_icache_guest_page(kvm_pfn_t pfn,
+                                                 unsigned long size)
 {
+       u32 iclsz;
+
        /*
         * If we are going to insert an instruction page and the icache is
         * either VIPT or PIPT, there is a potential problem where the host
@@ -141,23 +191,40 @@ static inline void __coherent_cache_guest_page(struct kvm_vcpu *vcpu,
         *
         * VIVT caches are tagged using both the ASID and the VMID and doesn't
         * need any kind of flushing (DDI 0406C.b - Page B3-1392).
-        *
-        * We need to do this through a kernel mapping (using the
-        * user-space mapping has proved to be the wrong
-        * solution). For that, we need to kmap one page at a time,
-        * and iterate over the range.
         */
 
        VM_BUG_ON(size & ~PAGE_MASK);
 
+       if (icache_is_vivt_asid_tagged())
+               return;
+
+       if (!icache_is_pipt()) {
+               /* any kind of VIPT cache */
+               __flush_icache_all();
+               return;
+       }
+
+       /*
+        * CTR IminLine contains Log2 of the number of words in the
+        * cache line, so we can get the number of words as
+        * 2 << (IminLine - 1).  To get the number of bytes, we
+        * multiply by 4 (the number of bytes in a 32-bit word), and
+        * get 4 << (IminLine).
+        */
+       iclsz = 4 << (read_cpuid(CPUID_CACHETYPE) & 0xf);
+
        while (size) {
                void *va = kmap_atomic_pfn(pfn);
+               void *end = va + PAGE_SIZE;
+               void *addr = va;
 
-               kvm_flush_dcache_to_poc(va, PAGE_SIZE);
+               do {
+                       write_sysreg(addr, ICIMVAU);
+                       addr += iclsz;
+               } while (addr < end);
 
-               if (icache_is_pipt())
-                       __cpuc_coherent_user_range((unsigned long)va,
-                                                  (unsigned long)va + PAGE_SIZE);
+               dsb(ishst);
+               isb();
 
                size -= PAGE_SIZE;
                pfn++;
@@ -165,9 +232,11 @@ static inline void __coherent_cache_guest_page(struct kvm_vcpu *vcpu,
                kunmap_atomic(va);
        }
 
-       if (!icache_is_pipt() && !icache_is_vivt_asid_tagged()) {
-               /* any kind of VIPT cache */
-               __flush_icache_all();
+       /* Check if we need to invalidate the BTB */
+       if ((read_cpuid_ext(CPUID_EXT_MMFR1) >> 28) != 4) {
+               write_sysreg(0, BPIALLIS);
+               dsb(ishst);
+               isb();
        }
 }