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 148ad8b727SNick Hu extern pgd_t early_pg_dir[PTRS_PER_PGD]; 158ad8b727SNick Hu asmlinkage void __init kasan_early_init(void) 168ad8b727SNick Hu { 178ad8b727SNick Hu uintptr_t i; 188ad8b727SNick Hu pgd_t *pgd = early_pg_dir + pgd_index(KASAN_SHADOW_START); 198ad8b727SNick Hu 208ad8b727SNick Hu for (i = 0; i < PTRS_PER_PTE; ++i) 218ad8b727SNick Hu set_pte(kasan_early_shadow_pte + i, 228ad8b727SNick Hu mk_pte(virt_to_page(kasan_early_shadow_page), 238ad8b727SNick Hu PAGE_KERNEL)); 248ad8b727SNick Hu 258ad8b727SNick Hu for (i = 0; i < PTRS_PER_PMD; ++i) 268ad8b727SNick Hu set_pmd(kasan_early_shadow_pmd + i, 278458ca14SZong Li pfn_pmd(PFN_DOWN 288458ca14SZong Li (__pa((uintptr_t) kasan_early_shadow_pte)), 298ad8b727SNick Hu __pgprot(_PAGE_TABLE))); 308ad8b727SNick Hu 318ad8b727SNick Hu for (i = KASAN_SHADOW_START; i < KASAN_SHADOW_END; 328ad8b727SNick Hu i += PGDIR_SIZE, ++pgd) 338ad8b727SNick Hu set_pgd(pgd, 348458ca14SZong Li pfn_pgd(PFN_DOWN 358458ca14SZong Li (__pa(((uintptr_t) kasan_early_shadow_pmd))), 368ad8b727SNick Hu __pgprot(_PAGE_TABLE))); 378ad8b727SNick Hu 388ad8b727SNick Hu /* init for swapper_pg_dir */ 398ad8b727SNick Hu pgd = pgd_offset_k(KASAN_SHADOW_START); 408ad8b727SNick Hu 418ad8b727SNick Hu for (i = KASAN_SHADOW_START; i < KASAN_SHADOW_END; 428ad8b727SNick Hu i += PGDIR_SIZE, ++pgd) 438ad8b727SNick Hu set_pgd(pgd, 448458ca14SZong Li pfn_pgd(PFN_DOWN 458458ca14SZong Li (__pa(((uintptr_t) kasan_early_shadow_pmd))), 468ad8b727SNick Hu __pgprot(_PAGE_TABLE))); 478ad8b727SNick Hu 484cb699d0SVincent Chen local_flush_tlb_all(); 498ad8b727SNick Hu } 508ad8b727SNick Hu 511987501bSJisheng Zhang static void __init kasan_populate_pte(pmd_t *pmd, unsigned long vaddr, unsigned long end) 528ad8b727SNick Hu { 53d127c19cSAlexandre Ghiti phys_addr_t phys_addr; 54d127c19cSAlexandre Ghiti pte_t *ptep, *base_pte; 55a0a31fd8SZong Li 56d127c19cSAlexandre Ghiti if (pmd_none(*pmd)) 57d127c19cSAlexandre Ghiti base_pte = memblock_alloc(PTRS_PER_PTE * sizeof(pte_t), PAGE_SIZE); 58d127c19cSAlexandre Ghiti else 59d127c19cSAlexandre Ghiti base_pte = (pte_t *)pmd_page_vaddr(*pmd); 608ad8b727SNick Hu 61d127c19cSAlexandre Ghiti ptep = base_pte + pte_index(vaddr); 62d127c19cSAlexandre Ghiti 63d127c19cSAlexandre Ghiti do { 64d127c19cSAlexandre Ghiti if (pte_none(*ptep)) { 65d127c19cSAlexandre Ghiti phys_addr = memblock_phys_alloc(PAGE_SIZE, PAGE_SIZE); 66d127c19cSAlexandre Ghiti set_pte(ptep, pfn_pte(PFN_DOWN(phys_addr), PAGE_KERNEL)); 67d127c19cSAlexandre Ghiti } 68d127c19cSAlexandre Ghiti } while (ptep++, vaddr += PAGE_SIZE, vaddr != end); 69d127c19cSAlexandre Ghiti 70d127c19cSAlexandre Ghiti set_pmd(pmd, pfn_pmd(PFN_DOWN(__pa(base_pte)), PAGE_TABLE)); 718ad8b727SNick Hu } 728ad8b727SNick Hu 731987501bSJisheng Zhang static void __init kasan_populate_pmd(pgd_t *pgd, unsigned long vaddr, unsigned long end) 74d127c19cSAlexandre Ghiti { 75d127c19cSAlexandre Ghiti phys_addr_t phys_addr; 76d127c19cSAlexandre Ghiti pmd_t *pmdp, *base_pmd; 77d127c19cSAlexandre Ghiti unsigned long next; 788ad8b727SNick Hu 79d127c19cSAlexandre Ghiti base_pmd = (pmd_t *)pgd_page_vaddr(*pgd); 80d127c19cSAlexandre Ghiti if (base_pmd == lm_alias(kasan_early_shadow_pmd)) 81d127c19cSAlexandre Ghiti base_pmd = memblock_alloc(PTRS_PER_PMD * sizeof(pmd_t), PAGE_SIZE); 82d127c19cSAlexandre Ghiti 83d127c19cSAlexandre Ghiti pmdp = base_pmd + pmd_index(vaddr); 84d127c19cSAlexandre Ghiti 85d127c19cSAlexandre Ghiti do { 86d127c19cSAlexandre Ghiti next = pmd_addr_end(vaddr, end); 87d7fbcf40SAlexandre Ghiti 88d7fbcf40SAlexandre Ghiti if (pmd_none(*pmdp) && IS_ALIGNED(vaddr, PMD_SIZE) && (next - vaddr) >= PMD_SIZE) { 89d7fbcf40SAlexandre Ghiti phys_addr = memblock_phys_alloc(PMD_SIZE, PMD_SIZE); 90d7fbcf40SAlexandre Ghiti if (phys_addr) { 91d7fbcf40SAlexandre Ghiti set_pmd(pmdp, pfn_pmd(PFN_DOWN(phys_addr), PAGE_KERNEL)); 92d7fbcf40SAlexandre Ghiti continue; 93d7fbcf40SAlexandre Ghiti } 94d7fbcf40SAlexandre Ghiti } 95d7fbcf40SAlexandre Ghiti 96d127c19cSAlexandre Ghiti kasan_populate_pte(pmdp, vaddr, next); 97d127c19cSAlexandre Ghiti } while (pmdp++, vaddr = next, vaddr != end); 98d127c19cSAlexandre Ghiti 99d127c19cSAlexandre Ghiti /* 100d127c19cSAlexandre Ghiti * Wait for the whole PGD to be populated before setting the PGD in 101d127c19cSAlexandre Ghiti * the page table, otherwise, if we did set the PGD before populating 102d127c19cSAlexandre Ghiti * it entirely, memblock could allocate a page at a physical address 103d127c19cSAlexandre Ghiti * where KASAN is not populated yet and then we'd get a page fault. 104d127c19cSAlexandre Ghiti */ 105d127c19cSAlexandre Ghiti set_pgd(pgd, pfn_pgd(PFN_DOWN(__pa(base_pmd)), PAGE_TABLE)); 106d127c19cSAlexandre Ghiti } 107d127c19cSAlexandre Ghiti 1081987501bSJisheng Zhang static void __init kasan_populate_pgd(unsigned long vaddr, unsigned long end) 109d127c19cSAlexandre Ghiti { 110d127c19cSAlexandre Ghiti phys_addr_t phys_addr; 111d127c19cSAlexandre Ghiti pgd_t *pgdp = pgd_offset_k(vaddr); 112d127c19cSAlexandre Ghiti unsigned long next; 113d127c19cSAlexandre Ghiti 114d127c19cSAlexandre Ghiti do { 115d127c19cSAlexandre Ghiti next = pgd_addr_end(vaddr, end); 116d7fbcf40SAlexandre Ghiti 117d7fbcf40SAlexandre Ghiti /* 118d7fbcf40SAlexandre Ghiti * pgdp can't be none since kasan_early_init initialized all KASAN 119d7fbcf40SAlexandre Ghiti * shadow region with kasan_early_shadow_pmd: if this is stillthe case, 120d7fbcf40SAlexandre Ghiti * that means we can try to allocate a hugepage as a replacement. 121d7fbcf40SAlexandre Ghiti */ 122d7fbcf40SAlexandre Ghiti if (pgd_page_vaddr(*pgdp) == (unsigned long)lm_alias(kasan_early_shadow_pmd) && 123d7fbcf40SAlexandre Ghiti IS_ALIGNED(vaddr, PGDIR_SIZE) && (next - vaddr) >= PGDIR_SIZE) { 124d7fbcf40SAlexandre Ghiti phys_addr = memblock_phys_alloc(PGDIR_SIZE, PGDIR_SIZE); 125d7fbcf40SAlexandre Ghiti if (phys_addr) { 126d7fbcf40SAlexandre Ghiti set_pgd(pgdp, pfn_pgd(PFN_DOWN(phys_addr), PAGE_KERNEL)); 127d7fbcf40SAlexandre Ghiti continue; 128d7fbcf40SAlexandre Ghiti } 129d7fbcf40SAlexandre Ghiti } 130d7fbcf40SAlexandre Ghiti 131d127c19cSAlexandre Ghiti kasan_populate_pmd(pgdp, vaddr, next); 132d127c19cSAlexandre Ghiti } while (pgdp++, vaddr = next, vaddr != end); 133d127c19cSAlexandre Ghiti } 134d127c19cSAlexandre Ghiti 135d127c19cSAlexandre Ghiti static void __init kasan_populate(void *start, void *end) 136d127c19cSAlexandre Ghiti { 137d127c19cSAlexandre Ghiti unsigned long vaddr = (unsigned long)start & PAGE_MASK; 138d127c19cSAlexandre Ghiti unsigned long vend = PAGE_ALIGN((unsigned long)end); 139d127c19cSAlexandre Ghiti 140d127c19cSAlexandre Ghiti kasan_populate_pgd(vaddr, vend); 1418ad8b727SNick Hu 1424cb699d0SVincent Chen local_flush_tlb_all(); 1439484e2aeSAlexandre Ghiti memset(start, KASAN_SHADOW_INIT, end - start); 1448ad8b727SNick Hu } 1458ad8b727SNick Hu 1462da073c1SAlexandre Ghiti static void __init kasan_shallow_populate_pgd(unsigned long vaddr, unsigned long end) 1472da073c1SAlexandre Ghiti { 1482da073c1SAlexandre Ghiti unsigned long next; 1492da073c1SAlexandre Ghiti void *p; 1502da073c1SAlexandre Ghiti pgd_t *pgd_k = pgd_offset_k(vaddr); 1512da073c1SAlexandre Ghiti 1522da073c1SAlexandre Ghiti do { 1532da073c1SAlexandre Ghiti next = pgd_addr_end(vaddr, end); 1542da073c1SAlexandre Ghiti if (pgd_page_vaddr(*pgd_k) == (unsigned long)lm_alias(kasan_early_shadow_pmd)) { 1552da073c1SAlexandre Ghiti p = memblock_alloc(PAGE_SIZE, PAGE_SIZE); 1562da073c1SAlexandre Ghiti set_pgd(pgd_k, pfn_pgd(PFN_DOWN(__pa(p)), PAGE_TABLE)); 1572da073c1SAlexandre Ghiti } 1582da073c1SAlexandre Ghiti } while (pgd_k++, vaddr = next, vaddr != end); 1592da073c1SAlexandre Ghiti } 1602da073c1SAlexandre Ghiti 16178947bdfSPalmer Dabbelt static void __init kasan_shallow_populate(void *start, void *end) 162e178d670SNylon Chen { 163e178d670SNylon Chen unsigned long vaddr = (unsigned long)start & PAGE_MASK; 164e178d670SNylon Chen unsigned long vend = PAGE_ALIGN((unsigned long)end); 165e178d670SNylon Chen 1662da073c1SAlexandre Ghiti kasan_shallow_populate_pgd(vaddr, vend); 167f3773dd0SAlexandre Ghiti local_flush_tlb_all(); 1688ad8b727SNick Hu } 1698ad8b727SNick Hu 1708ad8b727SNick Hu void __init kasan_init(void) 1718ad8b727SNick Hu { 172314b7817SJisheng Zhang phys_addr_t p_start, p_end; 173b10d6bcaSMike Rapoport u64 i; 1748ad8b727SNick Hu 1752bfc6cd8SAlexandre Ghiti /* 1762bfc6cd8SAlexandre Ghiti * Populate all kernel virtual address space with kasan_early_shadow_page 1772bfc6cd8SAlexandre Ghiti * except for the linear mapping and the modules/kernel/BPF mapping. 1782bfc6cd8SAlexandre Ghiti */ 1798ad8b727SNick Hu kasan_populate_early_shadow((void *)KASAN_SHADOW_START, 1808458ca14SZong Li (void *)kasan_mem_to_shadow((void *) 181e178d670SNylon Chen VMEMMAP_END)); 182e178d670SNylon Chen if (IS_ENABLED(CONFIG_KASAN_VMALLOC)) 183e178d670SNylon Chen kasan_shallow_populate( 184e178d670SNylon Chen (void *)kasan_mem_to_shadow((void *)VMALLOC_START), 185e178d670SNylon Chen (void *)kasan_mem_to_shadow((void *)VMALLOC_END)); 186e178d670SNylon Chen else 187e178d670SNylon Chen kasan_populate_early_shadow( 188e178d670SNylon Chen (void *)kasan_mem_to_shadow((void *)VMALLOC_START), 189e178d670SNylon Chen (void *)kasan_mem_to_shadow((void *)VMALLOC_END)); 1908ad8b727SNick Hu 1912bfc6cd8SAlexandre Ghiti /* Populate the linear mapping */ 192314b7817SJisheng Zhang for_each_mem_range(i, &p_start, &p_end) { 193314b7817SJisheng Zhang void *start = (void *)__va(p_start); 194314b7817SJisheng Zhang void *end = (void *)__va(p_end); 1958ad8b727SNick Hu 1968ad8b727SNick Hu if (start >= end) 1978ad8b727SNick Hu break; 1988ad8b727SNick Hu 199d127c19cSAlexandre Ghiti kasan_populate(kasan_mem_to_shadow(start), kasan_mem_to_shadow(end)); 2009d8c7d92SYang Li } 2018ad8b727SNick Hu 2022bfc6cd8SAlexandre Ghiti /* Populate kernel, BPF, modules mapping */ 2032bfc6cd8SAlexandre Ghiti kasan_populate(kasan_mem_to_shadow((const void *)MODULES_VADDR), 204*3a02764cSJisheng Zhang kasan_mem_to_shadow((const void *)MODULES_VADDR + SZ_2G)); 2052bfc6cd8SAlexandre Ghiti 2068ad8b727SNick Hu for (i = 0; i < PTRS_PER_PTE; i++) 2078ad8b727SNick Hu set_pte(&kasan_early_shadow_pte[i], 2088ad8b727SNick Hu mk_pte(virt_to_page(kasan_early_shadow_page), 2098458ca14SZong Li __pgprot(_PAGE_PRESENT | _PAGE_READ | 2108458ca14SZong Li _PAGE_ACCESSED))); 2118ad8b727SNick Hu 2129484e2aeSAlexandre Ghiti memset(kasan_early_shadow_page, KASAN_SHADOW_INIT, PAGE_SIZE); 2138ad8b727SNick Hu init_task.kasan_depth = 0; 2148ad8b727SNick Hu } 215