18ad8b727SNick Hu // SPDX-License-Identifier: GPL-2.0 28ad8b727SNick Hu // Copyright (C) 2019 Andes Technology Corporation 38ad8b727SNick Hu 48ad8b727SNick Hu #include <linux/pfn.h> 58ad8b727SNick Hu #include <linux/init_task.h> 68ad8b727SNick Hu #include <linux/kasan.h> 78ad8b727SNick Hu #include <linux/kernel.h> 88ad8b727SNick Hu #include <linux/memblock.h> 9ca5999fdSMike Rapoport #include <linux/pgtable.h> 1065fddcfcSMike Rapoport #include <asm/tlbflush.h> 118ad8b727SNick Hu #include <asm/fixmap.h> 12e178d670SNylon Chen #include <asm/pgalloc.h> 13e178d670SNylon Chen 14e178d670SNylon Chen static __init void *early_alloc(size_t size, int node) 15e178d670SNylon Chen { 16e178d670SNylon Chen void *ptr = memblock_alloc_try_nid(size, size, 17e178d670SNylon Chen __pa(MAX_DMA_ADDRESS), MEMBLOCK_ALLOC_ACCESSIBLE, node); 18e178d670SNylon Chen 19e178d670SNylon Chen if (!ptr) 20e178d670SNylon Chen panic("%pS: Failed to allocate %zu bytes align=%zx nid=%d from=%llx\n", 21e178d670SNylon Chen __func__, size, size, node, (u64)__pa(MAX_DMA_ADDRESS)); 22e178d670SNylon Chen 23e178d670SNylon Chen return ptr; 24e178d670SNylon Chen } 258ad8b727SNick Hu 268ad8b727SNick Hu extern pgd_t early_pg_dir[PTRS_PER_PGD]; 278ad8b727SNick Hu asmlinkage void __init kasan_early_init(void) 288ad8b727SNick Hu { 298ad8b727SNick Hu uintptr_t i; 308ad8b727SNick Hu pgd_t *pgd = early_pg_dir + pgd_index(KASAN_SHADOW_START); 318ad8b727SNick Hu 328ad8b727SNick Hu for (i = 0; i < PTRS_PER_PTE; ++i) 338ad8b727SNick Hu set_pte(kasan_early_shadow_pte + i, 348ad8b727SNick Hu mk_pte(virt_to_page(kasan_early_shadow_page), 358ad8b727SNick Hu PAGE_KERNEL)); 368ad8b727SNick Hu 378ad8b727SNick Hu for (i = 0; i < PTRS_PER_PMD; ++i) 388ad8b727SNick Hu set_pmd(kasan_early_shadow_pmd + i, 398458ca14SZong Li pfn_pmd(PFN_DOWN 408458ca14SZong Li (__pa((uintptr_t) kasan_early_shadow_pte)), 418ad8b727SNick Hu __pgprot(_PAGE_TABLE))); 428ad8b727SNick Hu 438ad8b727SNick Hu for (i = KASAN_SHADOW_START; i < KASAN_SHADOW_END; 448ad8b727SNick Hu i += PGDIR_SIZE, ++pgd) 458ad8b727SNick Hu set_pgd(pgd, 468458ca14SZong Li pfn_pgd(PFN_DOWN 478458ca14SZong Li (__pa(((uintptr_t) kasan_early_shadow_pmd))), 488ad8b727SNick Hu __pgprot(_PAGE_TABLE))); 498ad8b727SNick Hu 508ad8b727SNick Hu /* init for swapper_pg_dir */ 518ad8b727SNick Hu pgd = pgd_offset_k(KASAN_SHADOW_START); 528ad8b727SNick Hu 538ad8b727SNick Hu for (i = KASAN_SHADOW_START; i < KASAN_SHADOW_END; 548ad8b727SNick Hu i += PGDIR_SIZE, ++pgd) 558ad8b727SNick Hu set_pgd(pgd, 568458ca14SZong Li pfn_pgd(PFN_DOWN 578458ca14SZong Li (__pa(((uintptr_t) kasan_early_shadow_pmd))), 588ad8b727SNick Hu __pgprot(_PAGE_TABLE))); 598ad8b727SNick Hu 604cb699d0SVincent Chen local_flush_tlb_all(); 618ad8b727SNick Hu } 628ad8b727SNick Hu 63*d127c19cSAlexandre Ghiti static void kasan_populate_pte(pmd_t *pmd, unsigned long vaddr, unsigned long end) 648ad8b727SNick Hu { 65*d127c19cSAlexandre Ghiti phys_addr_t phys_addr; 66*d127c19cSAlexandre Ghiti pte_t *ptep, *base_pte; 67a0a31fd8SZong Li 68*d127c19cSAlexandre Ghiti if (pmd_none(*pmd)) 69*d127c19cSAlexandre Ghiti base_pte = memblock_alloc(PTRS_PER_PTE * sizeof(pte_t), PAGE_SIZE); 70*d127c19cSAlexandre Ghiti else 71*d127c19cSAlexandre Ghiti base_pte = (pte_t *)pmd_page_vaddr(*pmd); 728ad8b727SNick Hu 73*d127c19cSAlexandre Ghiti ptep = base_pte + pte_index(vaddr); 74*d127c19cSAlexandre Ghiti 75*d127c19cSAlexandre Ghiti do { 76*d127c19cSAlexandre Ghiti if (pte_none(*ptep)) { 77*d127c19cSAlexandre Ghiti phys_addr = memblock_phys_alloc(PAGE_SIZE, PAGE_SIZE); 78*d127c19cSAlexandre Ghiti set_pte(ptep, pfn_pte(PFN_DOWN(phys_addr), PAGE_KERNEL)); 79*d127c19cSAlexandre Ghiti } 80*d127c19cSAlexandre Ghiti } while (ptep++, vaddr += PAGE_SIZE, vaddr != end); 81*d127c19cSAlexandre Ghiti 82*d127c19cSAlexandre Ghiti set_pmd(pmd, pfn_pmd(PFN_DOWN(__pa(base_pte)), PAGE_TABLE)); 838ad8b727SNick Hu } 848ad8b727SNick Hu 85*d127c19cSAlexandre Ghiti static void kasan_populate_pmd(pgd_t *pgd, unsigned long vaddr, unsigned long end) 86*d127c19cSAlexandre Ghiti { 87*d127c19cSAlexandre Ghiti phys_addr_t phys_addr; 88*d127c19cSAlexandre Ghiti pmd_t *pmdp, *base_pmd; 89*d127c19cSAlexandre Ghiti unsigned long next; 908ad8b727SNick Hu 91*d127c19cSAlexandre Ghiti base_pmd = (pmd_t *)pgd_page_vaddr(*pgd); 92*d127c19cSAlexandre Ghiti if (base_pmd == lm_alias(kasan_early_shadow_pmd)) 93*d127c19cSAlexandre Ghiti base_pmd = memblock_alloc(PTRS_PER_PMD * sizeof(pmd_t), PAGE_SIZE); 94*d127c19cSAlexandre Ghiti 95*d127c19cSAlexandre Ghiti pmdp = base_pmd + pmd_index(vaddr); 96*d127c19cSAlexandre Ghiti 97*d127c19cSAlexandre Ghiti do { 98*d127c19cSAlexandre Ghiti next = pmd_addr_end(vaddr, end); 99*d127c19cSAlexandre Ghiti kasan_populate_pte(pmdp, vaddr, next); 100*d127c19cSAlexandre Ghiti } while (pmdp++, vaddr = next, vaddr != end); 101*d127c19cSAlexandre Ghiti 102*d127c19cSAlexandre Ghiti /* 103*d127c19cSAlexandre Ghiti * Wait for the whole PGD to be populated before setting the PGD in 104*d127c19cSAlexandre Ghiti * the page table, otherwise, if we did set the PGD before populating 105*d127c19cSAlexandre Ghiti * it entirely, memblock could allocate a page at a physical address 106*d127c19cSAlexandre Ghiti * where KASAN is not populated yet and then we'd get a page fault. 107*d127c19cSAlexandre Ghiti */ 108*d127c19cSAlexandre Ghiti set_pgd(pgd, pfn_pgd(PFN_DOWN(__pa(base_pmd)), PAGE_TABLE)); 109*d127c19cSAlexandre Ghiti } 110*d127c19cSAlexandre Ghiti 111*d127c19cSAlexandre Ghiti static void kasan_populate_pgd(unsigned long vaddr, unsigned long end) 112*d127c19cSAlexandre Ghiti { 113*d127c19cSAlexandre Ghiti phys_addr_t phys_addr; 114*d127c19cSAlexandre Ghiti pgd_t *pgdp = pgd_offset_k(vaddr); 115*d127c19cSAlexandre Ghiti unsigned long next; 116*d127c19cSAlexandre Ghiti 117*d127c19cSAlexandre Ghiti do { 118*d127c19cSAlexandre Ghiti next = pgd_addr_end(vaddr, end); 119*d127c19cSAlexandre Ghiti kasan_populate_pmd(pgdp, vaddr, next); 120*d127c19cSAlexandre Ghiti } while (pgdp++, vaddr = next, vaddr != end); 121*d127c19cSAlexandre Ghiti } 122*d127c19cSAlexandre Ghiti 123*d127c19cSAlexandre Ghiti static void __init kasan_populate(void *start, void *end) 124*d127c19cSAlexandre Ghiti { 125*d127c19cSAlexandre Ghiti unsigned long vaddr = (unsigned long)start & PAGE_MASK; 126*d127c19cSAlexandre Ghiti unsigned long vend = PAGE_ALIGN((unsigned long)end); 127*d127c19cSAlexandre Ghiti 128*d127c19cSAlexandre Ghiti kasan_populate_pgd(vaddr, vend); 1298ad8b727SNick Hu 1304cb699d0SVincent Chen local_flush_tlb_all(); 1319484e2aeSAlexandre Ghiti memset(start, KASAN_SHADOW_INIT, end - start); 1328ad8b727SNick Hu } 1338ad8b727SNick Hu 134e178d670SNylon Chen void __init kasan_shallow_populate(void *start, void *end) 135e178d670SNylon Chen { 136e178d670SNylon Chen unsigned long vaddr = (unsigned long)start & PAGE_MASK; 137e178d670SNylon Chen unsigned long vend = PAGE_ALIGN((unsigned long)end); 138e178d670SNylon Chen unsigned long pfn; 139e178d670SNylon Chen int index; 140e178d670SNylon Chen void *p; 141e178d670SNylon Chen pud_t *pud_dir, *pud_k; 142e178d670SNylon Chen pgd_t *pgd_dir, *pgd_k; 143e178d670SNylon Chen p4d_t *p4d_dir, *p4d_k; 144e178d670SNylon Chen 145e178d670SNylon Chen while (vaddr < vend) { 146e178d670SNylon Chen index = pgd_index(vaddr); 147e178d670SNylon Chen pfn = csr_read(CSR_SATP) & SATP_PPN; 148e178d670SNylon Chen pgd_dir = (pgd_t *)pfn_to_virt(pfn) + index; 149e178d670SNylon Chen pgd_k = init_mm.pgd + index; 150e178d670SNylon Chen pgd_dir = pgd_offset_k(vaddr); 151e178d670SNylon Chen set_pgd(pgd_dir, *pgd_k); 152e178d670SNylon Chen 153e178d670SNylon Chen p4d_dir = p4d_offset(pgd_dir, vaddr); 154e178d670SNylon Chen p4d_k = p4d_offset(pgd_k, vaddr); 155e178d670SNylon Chen 156e178d670SNylon Chen vaddr = (vaddr + PUD_SIZE) & PUD_MASK; 157e178d670SNylon Chen pud_dir = pud_offset(p4d_dir, vaddr); 158e178d670SNylon Chen pud_k = pud_offset(p4d_k, vaddr); 159e178d670SNylon Chen 160e178d670SNylon Chen if (pud_present(*pud_dir)) { 161e178d670SNylon Chen p = early_alloc(PAGE_SIZE, NUMA_NO_NODE); 162e178d670SNylon Chen pud_populate(&init_mm, pud_dir, p); 163e178d670SNylon Chen } 164e178d670SNylon Chen vaddr += PAGE_SIZE; 165e178d670SNylon Chen } 166e178d670SNylon Chen } 167e178d670SNylon Chen 1688ad8b727SNick Hu void __init kasan_init(void) 1698ad8b727SNick Hu { 170b10d6bcaSMike Rapoport phys_addr_t _start, _end; 171b10d6bcaSMike Rapoport u64 i; 1728ad8b727SNick Hu 1738ad8b727SNick Hu kasan_populate_early_shadow((void *)KASAN_SHADOW_START, 1748458ca14SZong Li (void *)kasan_mem_to_shadow((void *) 175e178d670SNylon Chen VMEMMAP_END)); 176e178d670SNylon Chen if (IS_ENABLED(CONFIG_KASAN_VMALLOC)) 177e178d670SNylon Chen kasan_shallow_populate( 178e178d670SNylon Chen (void *)kasan_mem_to_shadow((void *)VMALLOC_START), 179e178d670SNylon Chen (void *)kasan_mem_to_shadow((void *)VMALLOC_END)); 180e178d670SNylon Chen else 181e178d670SNylon Chen kasan_populate_early_shadow( 182e178d670SNylon Chen (void *)kasan_mem_to_shadow((void *)VMALLOC_START), 183e178d670SNylon Chen (void *)kasan_mem_to_shadow((void *)VMALLOC_END)); 1848ad8b727SNick Hu 185b10d6bcaSMike Rapoport for_each_mem_range(i, &_start, &_end) { 186b10d6bcaSMike Rapoport void *start = (void *)_start; 187b10d6bcaSMike Rapoport void *end = (void *)_end; 1888ad8b727SNick Hu 1898ad8b727SNick Hu if (start >= end) 1908ad8b727SNick Hu break; 1918ad8b727SNick Hu 192*d127c19cSAlexandre Ghiti kasan_populate(kasan_mem_to_shadow(start), kasan_mem_to_shadow(end)); 1938ad8b727SNick Hu }; 1948ad8b727SNick Hu 1958ad8b727SNick Hu for (i = 0; i < PTRS_PER_PTE; i++) 1968ad8b727SNick Hu set_pte(&kasan_early_shadow_pte[i], 1978ad8b727SNick Hu mk_pte(virt_to_page(kasan_early_shadow_page), 1988458ca14SZong Li __pgprot(_PAGE_PRESENT | _PAGE_READ | 1998458ca14SZong Li _PAGE_ACCESSED))); 2008ad8b727SNick Hu 2019484e2aeSAlexandre Ghiti memset(kasan_early_shadow_page, KASAN_SHADOW_INIT, PAGE_SIZE); 2028ad8b727SNick Hu init_task.kasan_depth = 0; 2038ad8b727SNick Hu } 204