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> 98ad8b727SNick Hu #include <asm/tlbflush.h> 10*ca5999fdSMike Rapoport #include <linux/pgtable.h> 118ad8b727SNick Hu #include <asm/fixmap.h> 128ad8b727SNick Hu 138ad8b727SNick Hu extern pgd_t early_pg_dir[PTRS_PER_PGD]; 148ad8b727SNick Hu asmlinkage void __init kasan_early_init(void) 158ad8b727SNick Hu { 168ad8b727SNick Hu uintptr_t i; 178ad8b727SNick Hu pgd_t *pgd = early_pg_dir + pgd_index(KASAN_SHADOW_START); 188ad8b727SNick Hu 198ad8b727SNick Hu for (i = 0; i < PTRS_PER_PTE; ++i) 208ad8b727SNick Hu set_pte(kasan_early_shadow_pte + i, 218ad8b727SNick Hu mk_pte(virt_to_page(kasan_early_shadow_page), 228ad8b727SNick Hu PAGE_KERNEL)); 238ad8b727SNick Hu 248ad8b727SNick Hu for (i = 0; i < PTRS_PER_PMD; ++i) 258ad8b727SNick Hu set_pmd(kasan_early_shadow_pmd + i, 268458ca14SZong Li pfn_pmd(PFN_DOWN 278458ca14SZong Li (__pa((uintptr_t) kasan_early_shadow_pte)), 288ad8b727SNick Hu __pgprot(_PAGE_TABLE))); 298ad8b727SNick Hu 308ad8b727SNick Hu for (i = KASAN_SHADOW_START; i < KASAN_SHADOW_END; 318ad8b727SNick Hu i += PGDIR_SIZE, ++pgd) 328ad8b727SNick Hu set_pgd(pgd, 338458ca14SZong Li pfn_pgd(PFN_DOWN 348458ca14SZong Li (__pa(((uintptr_t) kasan_early_shadow_pmd))), 358ad8b727SNick Hu __pgprot(_PAGE_TABLE))); 368ad8b727SNick Hu 378ad8b727SNick Hu /* init for swapper_pg_dir */ 388ad8b727SNick Hu pgd = pgd_offset_k(KASAN_SHADOW_START); 398ad8b727SNick Hu 408ad8b727SNick Hu for (i = KASAN_SHADOW_START; i < KASAN_SHADOW_END; 418ad8b727SNick Hu i += PGDIR_SIZE, ++pgd) 428ad8b727SNick Hu set_pgd(pgd, 438458ca14SZong Li pfn_pgd(PFN_DOWN 448458ca14SZong Li (__pa(((uintptr_t) kasan_early_shadow_pmd))), 458ad8b727SNick Hu __pgprot(_PAGE_TABLE))); 468ad8b727SNick Hu 478ad8b727SNick Hu flush_tlb_all(); 488ad8b727SNick Hu } 498ad8b727SNick Hu 508ad8b727SNick Hu static void __init populate(void *start, void *end) 518ad8b727SNick Hu { 52a0a31fd8SZong Li unsigned long i, offset; 538ad8b727SNick Hu unsigned long vaddr = (unsigned long)start & PAGE_MASK; 548ad8b727SNick Hu unsigned long vend = PAGE_ALIGN((unsigned long)end); 558ad8b727SNick Hu unsigned long n_pages = (vend - vaddr) / PAGE_SIZE; 56a0a31fd8SZong Li unsigned long n_ptes = 57a0a31fd8SZong Li ((n_pages + PTRS_PER_PTE) & -PTRS_PER_PTE) / PTRS_PER_PTE; 588ad8b727SNick Hu unsigned long n_pmds = 59a0a31fd8SZong Li ((n_ptes + PTRS_PER_PMD) & -PTRS_PER_PMD) / PTRS_PER_PMD; 60a0a31fd8SZong Li 61a0a31fd8SZong Li pte_t *pte = 62a0a31fd8SZong Li memblock_alloc(n_ptes * PTRS_PER_PTE * sizeof(pte_t), PAGE_SIZE); 63a0a31fd8SZong Li pmd_t *pmd = 64a0a31fd8SZong Li memblock_alloc(n_pmds * PTRS_PER_PMD * sizeof(pmd_t), PAGE_SIZE); 658ad8b727SNick Hu pgd_t *pgd = pgd_offset_k(vaddr); 668ad8b727SNick Hu 678ad8b727SNick Hu for (i = 0; i < n_pages; i++) { 688ad8b727SNick Hu phys_addr_t phys = memblock_phys_alloc(PAGE_SIZE, PAGE_SIZE); 69a0a31fd8SZong Li set_pte(&pte[i], pfn_pte(PHYS_PFN(phys), PAGE_KERNEL)); 708ad8b727SNick Hu } 718ad8b727SNick Hu 72a0a31fd8SZong Li for (i = 0, offset = 0; i < n_ptes; i++, offset += PTRS_PER_PTE) 73a0a31fd8SZong Li set_pmd(&pmd[i], 74a0a31fd8SZong Li pfn_pmd(PFN_DOWN(__pa(&pte[offset])), 758ad8b727SNick Hu __pgprot(_PAGE_TABLE))); 768ad8b727SNick Hu 77a0a31fd8SZong Li for (i = 0, offset = 0; i < n_pmds; i++, offset += PTRS_PER_PMD) 78a0a31fd8SZong Li set_pgd(&pgd[i], 79a0a31fd8SZong Li pfn_pgd(PFN_DOWN(__pa(&pmd[offset])), 808ad8b727SNick Hu __pgprot(_PAGE_TABLE))); 818ad8b727SNick Hu 828ad8b727SNick Hu flush_tlb_all(); 838ad8b727SNick Hu memset(start, 0, end - start); 848ad8b727SNick Hu } 858ad8b727SNick Hu 868ad8b727SNick Hu void __init kasan_init(void) 878ad8b727SNick Hu { 888ad8b727SNick Hu struct memblock_region *reg; 898ad8b727SNick Hu unsigned long i; 908ad8b727SNick Hu 918ad8b727SNick Hu kasan_populate_early_shadow((void *)KASAN_SHADOW_START, 928458ca14SZong Li (void *)kasan_mem_to_shadow((void *) 938458ca14SZong Li VMALLOC_END)); 948ad8b727SNick Hu 958ad8b727SNick Hu for_each_memblock(memory, reg) { 968ad8b727SNick Hu void *start = (void *)__va(reg->base); 978ad8b727SNick Hu void *end = (void *)__va(reg->base + reg->size); 988ad8b727SNick Hu 998ad8b727SNick Hu if (start >= end) 1008ad8b727SNick Hu break; 1018ad8b727SNick Hu 1028458ca14SZong Li populate(kasan_mem_to_shadow(start), kasan_mem_to_shadow(end)); 1038ad8b727SNick Hu }; 1048ad8b727SNick Hu 1058ad8b727SNick Hu for (i = 0; i < PTRS_PER_PTE; i++) 1068ad8b727SNick Hu set_pte(&kasan_early_shadow_pte[i], 1078ad8b727SNick Hu mk_pte(virt_to_page(kasan_early_shadow_page), 1088458ca14SZong Li __pgprot(_PAGE_PRESENT | _PAGE_READ | 1098458ca14SZong Li _PAGE_ACCESSED))); 1108ad8b727SNick Hu 1118ad8b727SNick Hu memset(kasan_early_shadow_page, 0, PAGE_SIZE); 1128ad8b727SNick Hu init_task.kasan_depth = 0; 1138ad8b727SNick Hu } 114