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 638ad8b727SNick Hu static void __init populate(void *start, void *end) 648ad8b727SNick Hu { 65a0a31fd8SZong Li unsigned long i, offset; 668ad8b727SNick Hu unsigned long vaddr = (unsigned long)start & PAGE_MASK; 678ad8b727SNick Hu unsigned long vend = PAGE_ALIGN((unsigned long)end); 688ad8b727SNick Hu unsigned long n_pages = (vend - vaddr) / PAGE_SIZE; 69a0a31fd8SZong Li unsigned long n_ptes = 70a0a31fd8SZong Li ((n_pages + PTRS_PER_PTE) & -PTRS_PER_PTE) / PTRS_PER_PTE; 718ad8b727SNick Hu unsigned long n_pmds = 72a0a31fd8SZong Li ((n_ptes + PTRS_PER_PMD) & -PTRS_PER_PMD) / PTRS_PER_PMD; 73a0a31fd8SZong Li 74a0a31fd8SZong Li pte_t *pte = 75a0a31fd8SZong Li memblock_alloc(n_ptes * PTRS_PER_PTE * sizeof(pte_t), PAGE_SIZE); 76a0a31fd8SZong Li pmd_t *pmd = 77a0a31fd8SZong Li memblock_alloc(n_pmds * PTRS_PER_PMD * sizeof(pmd_t), PAGE_SIZE); 788ad8b727SNick Hu pgd_t *pgd = pgd_offset_k(vaddr); 798ad8b727SNick Hu 808ad8b727SNick Hu for (i = 0; i < n_pages; i++) { 818ad8b727SNick Hu phys_addr_t phys = memblock_phys_alloc(PAGE_SIZE, PAGE_SIZE); 82a0a31fd8SZong Li set_pte(&pte[i], pfn_pte(PHYS_PFN(phys), PAGE_KERNEL)); 838ad8b727SNick Hu } 848ad8b727SNick Hu 85a0a31fd8SZong Li for (i = 0, offset = 0; i < n_ptes; i++, offset += PTRS_PER_PTE) 86a0a31fd8SZong Li set_pmd(&pmd[i], 87a0a31fd8SZong Li pfn_pmd(PFN_DOWN(__pa(&pte[offset])), 888ad8b727SNick Hu __pgprot(_PAGE_TABLE))); 898ad8b727SNick Hu 90a0a31fd8SZong Li for (i = 0, offset = 0; i < n_pmds; i++, offset += PTRS_PER_PMD) 91a0a31fd8SZong Li set_pgd(&pgd[i], 92a0a31fd8SZong Li pfn_pgd(PFN_DOWN(__pa(&pmd[offset])), 938ad8b727SNick Hu __pgprot(_PAGE_TABLE))); 948ad8b727SNick Hu 954cb699d0SVincent Chen local_flush_tlb_all(); 96*9484e2aeSAlexandre Ghiti memset(start, KASAN_SHADOW_INIT, end - start); 978ad8b727SNick Hu } 988ad8b727SNick Hu 99e178d670SNylon Chen void __init kasan_shallow_populate(void *start, void *end) 100e178d670SNylon Chen { 101e178d670SNylon Chen unsigned long vaddr = (unsigned long)start & PAGE_MASK; 102e178d670SNylon Chen unsigned long vend = PAGE_ALIGN((unsigned long)end); 103e178d670SNylon Chen unsigned long pfn; 104e178d670SNylon Chen int index; 105e178d670SNylon Chen void *p; 106e178d670SNylon Chen pud_t *pud_dir, *pud_k; 107e178d670SNylon Chen pgd_t *pgd_dir, *pgd_k; 108e178d670SNylon Chen p4d_t *p4d_dir, *p4d_k; 109e178d670SNylon Chen 110e178d670SNylon Chen while (vaddr < vend) { 111e178d670SNylon Chen index = pgd_index(vaddr); 112e178d670SNylon Chen pfn = csr_read(CSR_SATP) & SATP_PPN; 113e178d670SNylon Chen pgd_dir = (pgd_t *)pfn_to_virt(pfn) + index; 114e178d670SNylon Chen pgd_k = init_mm.pgd + index; 115e178d670SNylon Chen pgd_dir = pgd_offset_k(vaddr); 116e178d670SNylon Chen set_pgd(pgd_dir, *pgd_k); 117e178d670SNylon Chen 118e178d670SNylon Chen p4d_dir = p4d_offset(pgd_dir, vaddr); 119e178d670SNylon Chen p4d_k = p4d_offset(pgd_k, vaddr); 120e178d670SNylon Chen 121e178d670SNylon Chen vaddr = (vaddr + PUD_SIZE) & PUD_MASK; 122e178d670SNylon Chen pud_dir = pud_offset(p4d_dir, vaddr); 123e178d670SNylon Chen pud_k = pud_offset(p4d_k, vaddr); 124e178d670SNylon Chen 125e178d670SNylon Chen if (pud_present(*pud_dir)) { 126e178d670SNylon Chen p = early_alloc(PAGE_SIZE, NUMA_NO_NODE); 127e178d670SNylon Chen pud_populate(&init_mm, pud_dir, p); 128e178d670SNylon Chen } 129e178d670SNylon Chen vaddr += PAGE_SIZE; 130e178d670SNylon Chen } 131e178d670SNylon Chen } 132e178d670SNylon Chen 1338ad8b727SNick Hu void __init kasan_init(void) 1348ad8b727SNick Hu { 135b10d6bcaSMike Rapoport phys_addr_t _start, _end; 136b10d6bcaSMike Rapoport u64 i; 1378ad8b727SNick Hu 1388ad8b727SNick Hu kasan_populate_early_shadow((void *)KASAN_SHADOW_START, 1398458ca14SZong Li (void *)kasan_mem_to_shadow((void *) 140e178d670SNylon Chen VMEMMAP_END)); 141e178d670SNylon Chen if (IS_ENABLED(CONFIG_KASAN_VMALLOC)) 142e178d670SNylon Chen kasan_shallow_populate( 143e178d670SNylon Chen (void *)kasan_mem_to_shadow((void *)VMALLOC_START), 144e178d670SNylon Chen (void *)kasan_mem_to_shadow((void *)VMALLOC_END)); 145e178d670SNylon Chen else 146e178d670SNylon Chen kasan_populate_early_shadow( 147e178d670SNylon Chen (void *)kasan_mem_to_shadow((void *)VMALLOC_START), 148e178d670SNylon Chen (void *)kasan_mem_to_shadow((void *)VMALLOC_END)); 1498ad8b727SNick Hu 150b10d6bcaSMike Rapoport for_each_mem_range(i, &_start, &_end) { 151b10d6bcaSMike Rapoport void *start = (void *)_start; 152b10d6bcaSMike Rapoport void *end = (void *)_end; 1538ad8b727SNick Hu 1548ad8b727SNick Hu if (start >= end) 1558ad8b727SNick Hu break; 1568ad8b727SNick Hu 1578458ca14SZong Li populate(kasan_mem_to_shadow(start), kasan_mem_to_shadow(end)); 1588ad8b727SNick Hu }; 1598ad8b727SNick Hu 1608ad8b727SNick Hu for (i = 0; i < PTRS_PER_PTE; i++) 1618ad8b727SNick Hu set_pte(&kasan_early_shadow_pte[i], 1628ad8b727SNick Hu mk_pte(virt_to_page(kasan_early_shadow_page), 1638458ca14SZong Li __pgprot(_PAGE_PRESENT | _PAGE_READ | 1648458ca14SZong Li _PAGE_ACCESSED))); 1658ad8b727SNick Hu 166*9484e2aeSAlexandre Ghiti memset(kasan_early_shadow_page, KASAN_SHADOW_INIT, PAGE_SIZE); 1678ad8b727SNick Hu init_task.kasan_depth = 0; 1688ad8b727SNick Hu } 169