diff options
| -rw-r--r-- | arch/arm64/Kconfig.debug | 10 | ||||
| -rw-r--r-- | arch/arm64/mm/mmu.c | 72 |
2 files changed, 82 insertions, 0 deletions
diff --git a/arch/arm64/Kconfig.debug b/arch/arm64/Kconfig.debug index 04fb73b973f1..8c80724c8774 100644 --- a/arch/arm64/Kconfig.debug +++ b/arch/arm64/Kconfig.debug @@ -85,6 +85,16 @@ config DEBUG_ALIGN_RODATA If in doubt, say N +config FORCE_PAGES + bool "Force lowmem to be mapped with 4K pages" + help + There are some advanced debug features that can only be done when + memory is mapped with pages instead of sections. Enable this option + to always map lowmem pages with pages. This may have a performance + cost due to increased TLB pressure. + + If unsure say N. + source "drivers/hwtracing/coresight/Kconfig" endmenu diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c index a652d959ffaa..5cf16a160e76 100644 --- a/arch/arm64/mm/mmu.c +++ b/arch/arm64/mm/mmu.c @@ -442,6 +442,77 @@ static void __init map_mem(void) /* Limit no longer required. */ memblock_set_current_limit(MEMBLOCK_ALLOC_ANYWHERE); } +#ifdef CONFIG_FORCE_PAGES +static noinline void split_and_set_pmd(pmd_t *pmd, unsigned long addr, + unsigned long end, unsigned long pfn) +{ + pte_t *pte, *start_pte; + + start_pte = early_alloc(PTRS_PER_PTE * sizeof(pte_t)); + pte = start_pte; + + do { + set_pte(pte, pfn_pte(pfn, PAGE_KERNEL_EXEC)); + pfn++; + } while (pte++, addr += PAGE_SIZE, addr != end); + + set_pmd(pmd, __pmd((__pa(start_pte)) | PMD_TYPE_TABLE)); +} + +static noinline void __init remap_pages(void) +{ + struct memblock_region *reg; + + for_each_memblock(memory, reg) { + phys_addr_t phys_pgd = reg->base; + phys_addr_t phys_end = reg->base + reg->size; + unsigned long addr_pgd = (unsigned long)__va(phys_pgd); + unsigned long end = (unsigned long)__va(phys_end); + pmd_t *pmd = NULL; + pud_t *pud = NULL; + pgd_t *pgd = NULL; + unsigned long next_pud, next_pmd, next_pgd; + unsigned long addr_pmd, addr_pud; + phys_addr_t phys_pud, phys_pmd; + + if (phys_pgd >= phys_end) + break; + + pgd = pgd_offset(&init_mm, addr_pgd); + do { + next_pgd = pgd_addr_end(addr_pgd, end); + pud = pud_offset(pgd, addr_pgd); + addr_pud = addr_pgd; + phys_pud = phys_pgd; + do { + next_pud = pud_addr_end(addr_pud, next_pgd); + pmd = pmd_offset(pud, addr_pud); + addr_pmd = addr_pud; + phys_pmd = phys_pud; + do { + next_pmd = pmd_addr_end(addr_pmd, + next_pud); + if (pmd_none(*pmd) || pmd_bad(*pmd)) + split_and_set_pmd(pmd, addr_pmd, + next_pmd, __phys_to_pfn(phys_pmd)); + pmd++; + phys_pmd += next_pmd - addr_pmd; + } while (addr_pmd = next_pmd, + addr_pmd < next_pud); + phys_pud += next_pud - addr_pud; + } while (pud++, addr_pud = next_pud, + addr_pud < next_pgd); + phys_pgd += next_pgd - addr_pgd; + } while (pgd++, addr_pgd = next_pgd, addr_pgd < end); + } +} + +#else +static void __init remap_pages(void) +{ + +} +#endif static void __init fixup_executable(void) { @@ -494,6 +565,7 @@ void __init paging_init(void) map_mem(); fixup_executable(); dma_contiguous_remap(); + remap_pages(); /* * Finally flush the caches and tlb to ensure that we're in a |
