These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / arch / arm / mm / mmu.c
index 7186382..4867f5d 100644 (file)
@@ -38,6 +38,7 @@
 #include <asm/mach/pci.h>
 #include <asm/fixmap.h>
 
+#include "fault.h"
 #include "mm.h"
 #include "tcm.h"
 
@@ -291,13 +292,13 @@ static struct mem_type mem_types[] = {
                .prot_pte  = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY |
                                L_PTE_RDONLY,
                .prot_l1   = PMD_TYPE_TABLE,
-               .domain    = DOMAIN_USER,
+               .domain    = DOMAIN_VECTORS,
        },
        [MT_HIGH_VECTORS] = {
                .prot_pte  = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY |
                                L_PTE_USER | L_PTE_RDONLY,
                .prot_l1   = PMD_TYPE_TABLE,
-               .domain    = DOMAIN_USER,
+               .domain    = DOMAIN_VECTORS,
        },
        [MT_MEMORY_RWX] = {
                .prot_pte  = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY,
@@ -357,6 +358,47 @@ const struct mem_type *get_mem_type(unsigned int type)
 }
 EXPORT_SYMBOL(get_mem_type);
 
+static pte_t *(*pte_offset_fixmap)(pmd_t *dir, unsigned long addr);
+
+static pte_t bm_pte[PTRS_PER_PTE + PTE_HWTABLE_PTRS]
+       __aligned(PTE_HWTABLE_OFF + PTE_HWTABLE_SIZE) __initdata;
+
+static pte_t * __init pte_offset_early_fixmap(pmd_t *dir, unsigned long addr)
+{
+       return &bm_pte[pte_index(addr)];
+}
+
+static pte_t *pte_offset_late_fixmap(pmd_t *dir, unsigned long addr)
+{
+       return pte_offset_kernel(dir, addr);
+}
+
+static inline pmd_t * __init fixmap_pmd(unsigned long addr)
+{
+       pgd_t *pgd = pgd_offset_k(addr);
+       pud_t *pud = pud_offset(pgd, addr);
+       pmd_t *pmd = pmd_offset(pud, addr);
+
+       return pmd;
+}
+
+void __init early_fixmap_init(void)
+{
+       pmd_t *pmd;
+
+       /*
+        * The early fixmap range spans multiple pmds, for which
+        * we are not prepared:
+        */
+       BUILD_BUG_ON((__fix_to_virt(__end_of_permanent_fixed_addresses) >> PMD_SHIFT)
+                    != FIXADDR_TOP >> PMD_SHIFT);
+
+       pmd = fixmap_pmd(FIXADDR_TOP);
+       pmd_populate_kernel(&init_mm, pmd, bm_pte);
+
+       pte_offset_fixmap = pte_offset_early_fixmap;
+}
+
 /*
  * To avoid TLB flush broadcasts, this uses local_flush_tlb_kernel_range().
  * As a result, this can only be called with preemption disabled, as under
@@ -365,7 +407,7 @@ EXPORT_SYMBOL(get_mem_type);
 void __set_fixmap(enum fixed_addresses idx, phys_addr_t phys, pgprot_t prot)
 {
        unsigned long vaddr = __fix_to_virt(idx);
-       pte_t *pte = pte_offset_kernel(pmd_off_k(vaddr), vaddr);
+       pte_t *pte = pte_offset_fixmap(pmd_off_k(vaddr), vaddr);
 
        /* Make sure fixmap region does not exceed available allocation. */
        BUILD_BUG_ON(FIXADDR_START + (__end_of_fixed_addresses * PAGE_SIZE) >
@@ -855,7 +897,7 @@ static void __init create_mapping(struct map_desc *md)
        }
 
        if ((md->type == MT_DEVICE || md->type == MT_ROM) &&
-           md->virtual >= PAGE_OFFSET &&
+           md->virtual >= PAGE_OFFSET && md->virtual < FIXADDR_START &&
            (md->virtual < VMALLOC_START || md->virtual >= VMALLOC_END)) {
                pr_warn("BUG: mapping for 0x%08llx at 0x%08lx out of vmalloc space\n",
                        (long long)__pfn_to_phys((u64)md->pfn), md->virtual);
@@ -1072,6 +1114,7 @@ void __init sanity_check_meminfo(void)
        int highmem = 0;
        phys_addr_t vmalloc_limit = __pa(vmalloc_min - 1) + 1;
        struct memblock_region *reg;
+       bool should_use_highmem = false;
 
        for_each_memblock(memory, reg) {
                phys_addr_t block_start = reg->base;
@@ -1090,6 +1133,7 @@ void __init sanity_check_meminfo(void)
                                pr_notice("Ignoring RAM at %pa-%pa (!CONFIG_HIGHMEM)\n",
                                          &block_start, &block_end);
                                memblock_remove(reg->base, reg->size);
+                               should_use_highmem = true;
                                continue;
                        }
 
@@ -1100,6 +1144,7 @@ void __init sanity_check_meminfo(void)
                                          &block_start, &block_end, &vmalloc_limit);
                                memblock_remove(vmalloc_limit, overlap_size);
                                block_end = vmalloc_limit;
+                               should_use_highmem = true;
                        }
                }
 
@@ -1134,6 +1179,9 @@ void __init sanity_check_meminfo(void)
                }
        }
 
+       if (should_use_highmem)
+               pr_notice("Consider using a HIGHMEM enabled kernel.\n");
+
        high_memory = __va(arm_lowmem_limit - 1) + 1;
 
        /*
@@ -1213,10 +1261,10 @@ void __init arm_mm_memblock_reserve(void)
 
 /*
  * Set up the device mappings.  Since we clear out the page tables for all
- * mappings above VMALLOC_START, we will remove any debug device mappings.
- * This means you have to be careful how you debug this function, or any
- * called function.  This means you can't use any function or debugging
- * method which may touch any device, otherwise the kernel _will_ crash.
+ * mappings above VMALLOC_START, except early fixmap, we might remove debug
+ * device mappings.  This means earlycon can be used to debug this function
+ * Any other function or debugging method which may touch any device _will_
+ * crash the kernel.
  */
 static void __init devicemaps_init(const struct machine_desc *mdesc)
 {
@@ -1231,7 +1279,10 @@ static void __init devicemaps_init(const struct machine_desc *mdesc)
 
        early_trap_init(vectors);
 
-       for (addr = VMALLOC_START; addr; addr += PMD_SIZE)
+       /*
+        * Clear page table except top pmd used by early fixmaps
+        */
+       for (addr = VMALLOC_START; addr < (FIXADDR_TOP & PMD_MASK); addr += PMD_SIZE)
                pmd_clear(pmd_off_k(addr));
 
        /*
@@ -1313,6 +1364,9 @@ static void __init devicemaps_init(const struct machine_desc *mdesc)
         */
        local_flush_tlb_all();
        flush_cache_all();
+
+       /* Enable asynchronous aborts */
+       early_abt_enable();
 }
 
 static void __init kmap_init(void)
@@ -1387,127 +1441,131 @@ static void __init map_lowmem(void)
        }
 }
 
-#ifdef CONFIG_ARM_LPAE
+#ifdef CONFIG_ARM_PV_FIXUP
+extern unsigned long __atags_pointer;
+typedef void pgtables_remap(long long offset, unsigned long pgd, void *bdata);
+pgtables_remap lpae_pgtables_remap_asm;
+
 /*
  * early_paging_init() recreates boot time page table setup, allowing machines
  * to switch over to a high (>4G) address space on LPAE systems
  */
-void __init early_paging_init(const struct machine_desc *mdesc,
-                             struct proc_info_list *procinfo)
+void __init early_paging_init(const struct machine_desc *mdesc)
 {
-       pmdval_t pmdprot = procinfo->__cpu_mm_mmu_flags;
-       unsigned long map_start, map_end;
-       pgd_t *pgd0, *pgdk;
-       pud_t *pud0, *pudk, *pud_start;
-       pmd_t *pmd0, *pmdk;
-       phys_addr_t phys;
-       int i;
+       pgtables_remap *lpae_pgtables_remap;
+       unsigned long pa_pgd;
+       unsigned int cr, ttbcr;
+       long long offset;
+       void *boot_data;
 
-       if (!(mdesc->init_meminfo))
+       if (!mdesc->pv_fixup)
                return;
 
-       /* remap kernel code and data */
-       map_start = init_mm.start_code & PMD_MASK;
-       map_end   = ALIGN(init_mm.brk, PMD_SIZE);
+       offset = mdesc->pv_fixup();
+       if (offset == 0)
+               return;
 
-       /* get a handle on things... */
-       pgd0 = pgd_offset_k(0);
-       pud_start = pud0 = pud_offset(pgd0, 0);
-       pmd0 = pmd_offset(pud0, 0);
+       /*
+        * Get the address of the remap function in the 1:1 identity
+        * mapping setup by the early page table assembly code.  We
+        * must get this prior to the pv update.  The following barrier
+        * ensures that this is complete before we fixup any P:V offsets.
+        */
+       lpae_pgtables_remap = (pgtables_remap *)(unsigned long)__pa(lpae_pgtables_remap_asm);
+       pa_pgd = __pa(swapper_pg_dir);
+       boot_data = __va(__atags_pointer);
+       barrier();
 
-       pgdk = pgd_offset_k(map_start);
-       pudk = pud_offset(pgdk, map_start);
-       pmdk = pmd_offset(pudk, map_start);
+       pr_info("Switching physical address space to 0x%08llx\n",
+               (u64)PHYS_OFFSET + offset);
 
-       mdesc->init_meminfo();
+       /* Re-set the phys pfn offset, and the pv offset */
+       __pv_offset += offset;
+       __pv_phys_pfn_offset += PFN_DOWN(offset);
 
        /* Run the patch stub to update the constants */
        fixup_pv_table(&__pv_table_begin,
                (&__pv_table_end - &__pv_table_begin) << 2);
 
        /*
-        * Cache cleaning operations for self-modifying code
-        * We should clean the entries by MVA but running a
-        * for loop over every pv_table entry pointer would
-        * just complicate the code.
-        */
-       flush_cache_louis();
-       dsb(ishst);
-       isb();
-
-       /*
-        * FIXME: This code is not architecturally compliant: we modify
-        * the mappings in-place, indeed while they are in use by this
-        * very same code.  This may lead to unpredictable behaviour of
-        * the CPU.
-        *
-        * Even modifying the mappings in a separate page table does
-        * not resolve this.
-        *
-        * The architecture strongly recommends that when a mapping is
-        * changed, that it is changed by first going via an invalid
-        * mapping and back to the new mapping.  This is to ensure that
-        * no TLB conflicts (caused by the TLB having more than one TLB
-        * entry match a translation) can occur.  However, doing that
-        * here will result in unmapping the code we are running.
-        */
-       pr_warn("WARNING: unsafe modification of in-place page tables - tainting kernel\n");
-       add_taint(TAINT_CPU_OUT_OF_SPEC, LOCKDEP_STILL_OK);
-
-       /*
-        * Remap level 1 table.  This changes the physical addresses
-        * used to refer to the level 2 page tables to the high
-        * physical address alias, leaving everything else the same.
-        */
-       for (i = 0; i < PTRS_PER_PGD; pud0++, i++) {
-               set_pud(pud0,
-                       __pud(__pa(pmd0) | PMD_TYPE_TABLE | L_PGD_SWAPPER));
-               pmd0 += PTRS_PER_PMD;
-       }
-
-       /*
-        * Remap the level 2 table, pointing the mappings at the high
-        * physical address alias of these pages.
-        */
-       phys = __pa(map_start);
-       do {
-               *pmdk++ = __pmd(phys | pmdprot);
-               phys += PMD_SIZE;
-       } while (phys < map_end);
-
-       /*
-        * Ensure that the above updates are flushed out of the cache.
-        * This is not strictly correct; on a system where the caches
-        * are coherent with each other, but the MMU page table walks
-        * may not be coherent, flush_cache_all() may be a no-op, and
-        * this will fail.
+        * We changing not only the virtual to physical mapping, but also
+        * the physical addresses used to access memory.  We need to flush
+        * all levels of cache in the system with caching disabled to
+        * ensure that all data is written back, and nothing is prefetched
+        * into the caches.  We also need to prevent the TLB walkers
+        * allocating into the caches too.  Note that this is ARMv7 LPAE
+        * specific.
         */
+       cr = get_cr();
+       set_cr(cr & ~(CR_I | CR_C));
+       asm("mrc p15, 0, %0, c2, c0, 2" : "=r" (ttbcr));
+       asm volatile("mcr p15, 0, %0, c2, c0, 2"
+               : : "r" (ttbcr & ~(3 << 8 | 3 << 10)));
        flush_cache_all();
 
        /*
-        * Re-write the TTBR values to point them at the high physical
-        * alias of the page tables.  We expect __va() will work on
-        * cpu_get_pgd(), which returns the value of TTBR0.
+        * Fixup the page tables - this must be in the idmap region as
+        * we need to disable the MMU to do this safely, and hence it
+        * needs to be assembly.  It's fairly simple, as we're using the
+        * temporary tables setup by the initial assembly code.
         */
-       cpu_switch_mm(pgd0, &init_mm);
-       cpu_set_ttbr(1, __pa(pgd0) + TTBR1_OFFSET);
+       lpae_pgtables_remap(offset, pa_pgd, boot_data);
 
-       /* Finally flush any stale TLB values. */
-       local_flush_bp_all();
-       local_flush_tlb_all();
+       /* Re-enable the caches and cacheable TLB walks */
+       asm volatile("mcr p15, 0, %0, c2, c0, 2" : : "r" (ttbcr));
+       set_cr(cr);
 }
 
 #else
 
-void __init early_paging_init(const struct machine_desc *mdesc,
-                             struct proc_info_list *procinfo)
+void __init early_paging_init(const struct machine_desc *mdesc)
 {
-       if (mdesc->init_meminfo)
-               mdesc->init_meminfo();
+       long long offset;
+
+       if (!mdesc->pv_fixup)
+               return;
+
+       offset = mdesc->pv_fixup();
+       if (offset == 0)
+               return;
+
+       pr_crit("Physical address space modification is only to support Keystone2.\n");
+       pr_crit("Please enable ARM_LPAE and ARM_PATCH_PHYS_VIRT support to use this\n");
+       pr_crit("feature. Your kernel may crash now, have a good day.\n");
+       add_taint(TAINT_CPU_OUT_OF_SPEC, LOCKDEP_STILL_OK);
 }
 
 #endif
 
+static void __init early_fixmap_shutdown(void)
+{
+       int i;
+       unsigned long va = fix_to_virt(__end_of_permanent_fixed_addresses - 1);
+
+       pte_offset_fixmap = pte_offset_late_fixmap;
+       pmd_clear(fixmap_pmd(va));
+       local_flush_tlb_kernel_page(va);
+
+       for (i = 0; i < __end_of_permanent_fixed_addresses; i++) {
+               pte_t *pte;
+               struct map_desc map;
+
+               map.virtual = fix_to_virt(i);
+               pte = pte_offset_early_fixmap(pmd_off_k(map.virtual), map.virtual);
+
+               /* Only i/o device mappings are supported ATM */
+               if (pte_none(*pte) ||
+                   (pte_val(*pte) & L_PTE_MT_MASK) != L_PTE_MT_DEV_SHARED)
+                       continue;
+
+               map.pfn = pte_pfn(*pte);
+               map.type = MT_DEVICE;
+               map.length = PAGE_SIZE;
+
+               create_mapping(&map);
+       }
+}
+
 /*
  * paging_init() sets up the page tables, initialises the zone memory
  * maps, and sets up the zero page, bad page and bad page tables.
@@ -1519,7 +1577,9 @@ void __init paging_init(const struct machine_desc *mdesc)
        build_mem_type_table();
        prepare_page_table();
        map_lowmem();
+       memblock_set_current_limit(arm_lowmem_limit);
        dma_contiguous_remap();
+       early_fixmap_shutdown();
        devicemaps_init(mdesc);
        kmap_init();
        tcm_init();