162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci 362306a36Sopenharmony_ci#define DISABLE_BRANCH_PROFILING 462306a36Sopenharmony_ci 562306a36Sopenharmony_ci#include <linux/kasan.h> 662306a36Sopenharmony_ci#include <linux/printk.h> 762306a36Sopenharmony_ci#include <linux/memblock.h> 862306a36Sopenharmony_ci#include <linux/sched/task.h> 962306a36Sopenharmony_ci#include <asm/pgalloc.h> 1062306a36Sopenharmony_ci#include <asm/code-patching.h> 1162306a36Sopenharmony_ci#include <mm/mmu_decl.h> 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_cistatic pgprot_t __init kasan_prot_ro(void) 1462306a36Sopenharmony_ci{ 1562306a36Sopenharmony_ci if (early_mmu_has_feature(MMU_FTR_HPTE_TABLE)) 1662306a36Sopenharmony_ci return PAGE_READONLY; 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci return PAGE_KERNEL_RO; 1962306a36Sopenharmony_ci} 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_cistatic void __init kasan_populate_pte(pte_t *ptep, pgprot_t prot) 2262306a36Sopenharmony_ci{ 2362306a36Sopenharmony_ci unsigned long va = (unsigned long)kasan_early_shadow_page; 2462306a36Sopenharmony_ci phys_addr_t pa = __pa(kasan_early_shadow_page); 2562306a36Sopenharmony_ci int i; 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci for (i = 0; i < PTRS_PER_PTE; i++, ptep++) 2862306a36Sopenharmony_ci __set_pte_at(&init_mm, va, ptep, pfn_pte(PHYS_PFN(pa), prot), 1); 2962306a36Sopenharmony_ci} 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ciint __init kasan_init_shadow_page_tables(unsigned long k_start, unsigned long k_end) 3262306a36Sopenharmony_ci{ 3362306a36Sopenharmony_ci pmd_t *pmd; 3462306a36Sopenharmony_ci unsigned long k_cur, k_next; 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci pmd = pmd_off_k(k_start); 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci for (k_cur = k_start; k_cur != k_end; k_cur = k_next, pmd++) { 3962306a36Sopenharmony_ci pte_t *new; 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci k_next = pgd_addr_end(k_cur, k_end); 4262306a36Sopenharmony_ci if ((void *)pmd_page_vaddr(*pmd) != kasan_early_shadow_pte) 4362306a36Sopenharmony_ci continue; 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci new = memblock_alloc(PTE_FRAG_SIZE, PTE_FRAG_SIZE); 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci if (!new) 4862306a36Sopenharmony_ci return -ENOMEM; 4962306a36Sopenharmony_ci kasan_populate_pte(new, PAGE_KERNEL); 5062306a36Sopenharmony_ci pmd_populate_kernel(&init_mm, pmd, new); 5162306a36Sopenharmony_ci } 5262306a36Sopenharmony_ci return 0; 5362306a36Sopenharmony_ci} 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ciint __init __weak kasan_init_region(void *start, size_t size) 5662306a36Sopenharmony_ci{ 5762306a36Sopenharmony_ci unsigned long k_start = (unsigned long)kasan_mem_to_shadow(start); 5862306a36Sopenharmony_ci unsigned long k_end = (unsigned long)kasan_mem_to_shadow(start + size); 5962306a36Sopenharmony_ci unsigned long k_cur; 6062306a36Sopenharmony_ci int ret; 6162306a36Sopenharmony_ci void *block; 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci ret = kasan_init_shadow_page_tables(k_start, k_end); 6462306a36Sopenharmony_ci if (ret) 6562306a36Sopenharmony_ci return ret; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci k_start = k_start & PAGE_MASK; 6862306a36Sopenharmony_ci block = memblock_alloc(k_end - k_start, PAGE_SIZE); 6962306a36Sopenharmony_ci if (!block) 7062306a36Sopenharmony_ci return -ENOMEM; 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci for (k_cur = k_start & PAGE_MASK; k_cur < k_end; k_cur += PAGE_SIZE) { 7362306a36Sopenharmony_ci pmd_t *pmd = pmd_off_k(k_cur); 7462306a36Sopenharmony_ci void *va = block + k_cur - k_start; 7562306a36Sopenharmony_ci pte_t pte = pfn_pte(PHYS_PFN(__pa(va)), PAGE_KERNEL); 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci __set_pte_at(&init_mm, k_cur, pte_offset_kernel(pmd, k_cur), pte, 0); 7862306a36Sopenharmony_ci } 7962306a36Sopenharmony_ci flush_tlb_kernel_range(k_start, k_end); 8062306a36Sopenharmony_ci return 0; 8162306a36Sopenharmony_ci} 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_civoid __init 8462306a36Sopenharmony_cikasan_update_early_region(unsigned long k_start, unsigned long k_end, pte_t pte) 8562306a36Sopenharmony_ci{ 8662306a36Sopenharmony_ci unsigned long k_cur; 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci for (k_cur = k_start; k_cur != k_end; k_cur += PAGE_SIZE) { 8962306a36Sopenharmony_ci pmd_t *pmd = pmd_off_k(k_cur); 9062306a36Sopenharmony_ci pte_t *ptep = pte_offset_kernel(pmd, k_cur); 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci if (pte_page(*ptep) != virt_to_page(lm_alias(kasan_early_shadow_page))) 9362306a36Sopenharmony_ci continue; 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci __set_pte_at(&init_mm, k_cur, ptep, pte, 0); 9662306a36Sopenharmony_ci } 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci flush_tlb_kernel_range(k_start, k_end); 9962306a36Sopenharmony_ci} 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_cistatic void __init kasan_remap_early_shadow_ro(void) 10262306a36Sopenharmony_ci{ 10362306a36Sopenharmony_ci pgprot_t prot = kasan_prot_ro(); 10462306a36Sopenharmony_ci phys_addr_t pa = __pa(kasan_early_shadow_page); 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci kasan_populate_pte(kasan_early_shadow_pte, prot); 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci kasan_update_early_region(KASAN_SHADOW_START, KASAN_SHADOW_END, 10962306a36Sopenharmony_ci pfn_pte(PHYS_PFN(pa), prot)); 11062306a36Sopenharmony_ci} 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_cistatic void __init kasan_unmap_early_shadow_vmalloc(void) 11362306a36Sopenharmony_ci{ 11462306a36Sopenharmony_ci unsigned long k_start = (unsigned long)kasan_mem_to_shadow((void *)VMALLOC_START); 11562306a36Sopenharmony_ci unsigned long k_end = (unsigned long)kasan_mem_to_shadow((void *)VMALLOC_END); 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci kasan_update_early_region(k_start, k_end, __pte(0)); 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci#ifdef MODULES_VADDR 12062306a36Sopenharmony_ci k_start = (unsigned long)kasan_mem_to_shadow((void *)MODULES_VADDR); 12162306a36Sopenharmony_ci k_end = (unsigned long)kasan_mem_to_shadow((void *)MODULES_END); 12262306a36Sopenharmony_ci kasan_update_early_region(k_start, k_end, __pte(0)); 12362306a36Sopenharmony_ci#endif 12462306a36Sopenharmony_ci} 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_civoid __init kasan_mmu_init(void) 12762306a36Sopenharmony_ci{ 12862306a36Sopenharmony_ci int ret; 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci if (early_mmu_has_feature(MMU_FTR_HPTE_TABLE)) { 13162306a36Sopenharmony_ci ret = kasan_init_shadow_page_tables(KASAN_SHADOW_START, KASAN_SHADOW_END); 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci if (ret) 13462306a36Sopenharmony_ci panic("kasan: kasan_init_shadow_page_tables() failed"); 13562306a36Sopenharmony_ci } 13662306a36Sopenharmony_ci} 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_civoid __init kasan_init(void) 13962306a36Sopenharmony_ci{ 14062306a36Sopenharmony_ci phys_addr_t base, end; 14162306a36Sopenharmony_ci u64 i; 14262306a36Sopenharmony_ci int ret; 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci for_each_mem_range(i, &base, &end) { 14562306a36Sopenharmony_ci phys_addr_t top = min(end, total_lowmem); 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci if (base >= top) 14862306a36Sopenharmony_ci continue; 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci ret = kasan_init_region(__va(base), top - base); 15162306a36Sopenharmony_ci if (ret) 15262306a36Sopenharmony_ci panic("kasan: kasan_init_region() failed"); 15362306a36Sopenharmony_ci } 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_KASAN_VMALLOC)) { 15662306a36Sopenharmony_ci ret = kasan_init_shadow_page_tables(KASAN_SHADOW_START, KASAN_SHADOW_END); 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci if (ret) 15962306a36Sopenharmony_ci panic("kasan: kasan_init_shadow_page_tables() failed"); 16062306a36Sopenharmony_ci } 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci kasan_remap_early_shadow_ro(); 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci clear_page(kasan_early_shadow_page); 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci /* At this point kasan is fully initialized. Enable error messages */ 16762306a36Sopenharmony_ci init_task.kasan_depth = 0; 16862306a36Sopenharmony_ci pr_info("KASAN init done\n"); 16962306a36Sopenharmony_ci} 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_civoid __init kasan_late_init(void) 17262306a36Sopenharmony_ci{ 17362306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_KASAN_VMALLOC)) 17462306a36Sopenharmony_ci kasan_unmap_early_shadow_vmalloc(); 17562306a36Sopenharmony_ci} 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_civoid __init kasan_early_init(void) 17862306a36Sopenharmony_ci{ 17962306a36Sopenharmony_ci unsigned long addr = KASAN_SHADOW_START; 18062306a36Sopenharmony_ci unsigned long end = KASAN_SHADOW_END; 18162306a36Sopenharmony_ci unsigned long next; 18262306a36Sopenharmony_ci pmd_t *pmd = pmd_off_k(addr); 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci BUILD_BUG_ON(KASAN_SHADOW_START & ~PGDIR_MASK); 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci kasan_populate_pte(kasan_early_shadow_pte, PAGE_KERNEL); 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci do { 18962306a36Sopenharmony_ci next = pgd_addr_end(addr, end); 19062306a36Sopenharmony_ci pmd_populate_kernel(&init_mm, pmd, kasan_early_shadow_pte); 19162306a36Sopenharmony_ci } while (pmd++, addr = next, addr != end); 19262306a36Sopenharmony_ci} 193