18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * This file contains kasan initialization code for ARM64. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2015 Samsung Electronics Co., Ltd. 68c2ecf20Sopenharmony_ci * Author: Andrey Ryabinin <ryabinin.a.a@gmail.com> 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#define pr_fmt(fmt) "kasan: " fmt 108c2ecf20Sopenharmony_ci#include <linux/kasan.h> 118c2ecf20Sopenharmony_ci#include <linux/kernel.h> 128c2ecf20Sopenharmony_ci#include <linux/sched/task.h> 138c2ecf20Sopenharmony_ci#include <linux/memblock.h> 148c2ecf20Sopenharmony_ci#include <linux/start_kernel.h> 158c2ecf20Sopenharmony_ci#include <linux/mm.h> 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#include <asm/mmu_context.h> 188c2ecf20Sopenharmony_ci#include <asm/kernel-pgtable.h> 198c2ecf20Sopenharmony_ci#include <asm/page.h> 208c2ecf20Sopenharmony_ci#include <asm/pgalloc.h> 218c2ecf20Sopenharmony_ci#include <asm/sections.h> 228c2ecf20Sopenharmony_ci#include <asm/tlbflush.h> 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_cistatic pgd_t tmp_pg_dir[PTRS_PER_PGD] __initdata __aligned(PGD_SIZE); 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci/* 278c2ecf20Sopenharmony_ci * The p*d_populate functions call virt_to_phys implicitly so they can't be used 288c2ecf20Sopenharmony_ci * directly on kernel symbols (bm_p*d). All the early functions are called too 298c2ecf20Sopenharmony_ci * early to use lm_alias so __p*d_populate functions must be used to populate 308c2ecf20Sopenharmony_ci * with the physical address from __pa_symbol. 318c2ecf20Sopenharmony_ci */ 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_cistatic phys_addr_t __init kasan_alloc_zeroed_page(int node) 348c2ecf20Sopenharmony_ci{ 358c2ecf20Sopenharmony_ci void *p = memblock_alloc_try_nid(PAGE_SIZE, PAGE_SIZE, 368c2ecf20Sopenharmony_ci __pa(MAX_DMA_ADDRESS), 378c2ecf20Sopenharmony_ci MEMBLOCK_ALLOC_KASAN, node); 388c2ecf20Sopenharmony_ci if (!p) 398c2ecf20Sopenharmony_ci panic("%s: Failed to allocate %lu bytes align=0x%lx nid=%d from=%llx\n", 408c2ecf20Sopenharmony_ci __func__, PAGE_SIZE, PAGE_SIZE, node, 418c2ecf20Sopenharmony_ci __pa(MAX_DMA_ADDRESS)); 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci return __pa(p); 448c2ecf20Sopenharmony_ci} 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_cistatic phys_addr_t __init kasan_alloc_raw_page(int node) 478c2ecf20Sopenharmony_ci{ 488c2ecf20Sopenharmony_ci void *p = memblock_alloc_try_nid_raw(PAGE_SIZE, PAGE_SIZE, 498c2ecf20Sopenharmony_ci __pa(MAX_DMA_ADDRESS), 508c2ecf20Sopenharmony_ci MEMBLOCK_ALLOC_KASAN, node); 518c2ecf20Sopenharmony_ci if (!p) 528c2ecf20Sopenharmony_ci panic("%s: Failed to allocate %lu bytes align=0x%lx nid=%d from=%llx\n", 538c2ecf20Sopenharmony_ci __func__, PAGE_SIZE, PAGE_SIZE, node, 548c2ecf20Sopenharmony_ci __pa(MAX_DMA_ADDRESS)); 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci return __pa(p); 578c2ecf20Sopenharmony_ci} 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_cistatic pte_t *__init kasan_pte_offset(pmd_t *pmdp, unsigned long addr, int node, 608c2ecf20Sopenharmony_ci bool early) 618c2ecf20Sopenharmony_ci{ 628c2ecf20Sopenharmony_ci if (pmd_none(READ_ONCE(*pmdp))) { 638c2ecf20Sopenharmony_ci phys_addr_t pte_phys = early ? 648c2ecf20Sopenharmony_ci __pa_symbol(kasan_early_shadow_pte) 658c2ecf20Sopenharmony_ci : kasan_alloc_zeroed_page(node); 668c2ecf20Sopenharmony_ci __pmd_populate(pmdp, pte_phys, PMD_TYPE_TABLE); 678c2ecf20Sopenharmony_ci } 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci return early ? pte_offset_kimg(pmdp, addr) 708c2ecf20Sopenharmony_ci : pte_offset_kernel(pmdp, addr); 718c2ecf20Sopenharmony_ci} 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_cistatic pmd_t *__init kasan_pmd_offset(pud_t *pudp, unsigned long addr, int node, 748c2ecf20Sopenharmony_ci bool early) 758c2ecf20Sopenharmony_ci{ 768c2ecf20Sopenharmony_ci if (pud_none(READ_ONCE(*pudp))) { 778c2ecf20Sopenharmony_ci phys_addr_t pmd_phys = early ? 788c2ecf20Sopenharmony_ci __pa_symbol(kasan_early_shadow_pmd) 798c2ecf20Sopenharmony_ci : kasan_alloc_zeroed_page(node); 808c2ecf20Sopenharmony_ci __pud_populate(pudp, pmd_phys, PMD_TYPE_TABLE); 818c2ecf20Sopenharmony_ci } 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci return early ? pmd_offset_kimg(pudp, addr) : pmd_offset(pudp, addr); 848c2ecf20Sopenharmony_ci} 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_cistatic pud_t *__init kasan_pud_offset(p4d_t *p4dp, unsigned long addr, int node, 878c2ecf20Sopenharmony_ci bool early) 888c2ecf20Sopenharmony_ci{ 898c2ecf20Sopenharmony_ci if (p4d_none(READ_ONCE(*p4dp))) { 908c2ecf20Sopenharmony_ci phys_addr_t pud_phys = early ? 918c2ecf20Sopenharmony_ci __pa_symbol(kasan_early_shadow_pud) 928c2ecf20Sopenharmony_ci : kasan_alloc_zeroed_page(node); 938c2ecf20Sopenharmony_ci __p4d_populate(p4dp, pud_phys, PMD_TYPE_TABLE); 948c2ecf20Sopenharmony_ci } 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci return early ? pud_offset_kimg(p4dp, addr) : pud_offset(p4dp, addr); 978c2ecf20Sopenharmony_ci} 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_cistatic void __init kasan_pte_populate(pmd_t *pmdp, unsigned long addr, 1008c2ecf20Sopenharmony_ci unsigned long end, int node, bool early) 1018c2ecf20Sopenharmony_ci{ 1028c2ecf20Sopenharmony_ci unsigned long next; 1038c2ecf20Sopenharmony_ci pte_t *ptep = kasan_pte_offset(pmdp, addr, node, early); 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci do { 1068c2ecf20Sopenharmony_ci phys_addr_t page_phys = early ? 1078c2ecf20Sopenharmony_ci __pa_symbol(kasan_early_shadow_page) 1088c2ecf20Sopenharmony_ci : kasan_alloc_raw_page(node); 1098c2ecf20Sopenharmony_ci if (!early) 1108c2ecf20Sopenharmony_ci memset(__va(page_phys), KASAN_SHADOW_INIT, PAGE_SIZE); 1118c2ecf20Sopenharmony_ci next = addr + PAGE_SIZE; 1128c2ecf20Sopenharmony_ci set_pte(ptep, pfn_pte(__phys_to_pfn(page_phys), PAGE_KERNEL)); 1138c2ecf20Sopenharmony_ci } while (ptep++, addr = next, addr != end && pte_none(READ_ONCE(*ptep))); 1148c2ecf20Sopenharmony_ci} 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_cistatic void __init kasan_pmd_populate(pud_t *pudp, unsigned long addr, 1178c2ecf20Sopenharmony_ci unsigned long end, int node, bool early) 1188c2ecf20Sopenharmony_ci{ 1198c2ecf20Sopenharmony_ci unsigned long next; 1208c2ecf20Sopenharmony_ci pmd_t *pmdp = kasan_pmd_offset(pudp, addr, node, early); 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci do { 1238c2ecf20Sopenharmony_ci next = pmd_addr_end(addr, end); 1248c2ecf20Sopenharmony_ci kasan_pte_populate(pmdp, addr, next, node, early); 1258c2ecf20Sopenharmony_ci } while (pmdp++, addr = next, addr != end && pmd_none(READ_ONCE(*pmdp))); 1268c2ecf20Sopenharmony_ci} 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_cistatic void __init kasan_pud_populate(p4d_t *p4dp, unsigned long addr, 1298c2ecf20Sopenharmony_ci unsigned long end, int node, bool early) 1308c2ecf20Sopenharmony_ci{ 1318c2ecf20Sopenharmony_ci unsigned long next; 1328c2ecf20Sopenharmony_ci pud_t *pudp = kasan_pud_offset(p4dp, addr, node, early); 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci do { 1358c2ecf20Sopenharmony_ci next = pud_addr_end(addr, end); 1368c2ecf20Sopenharmony_ci kasan_pmd_populate(pudp, addr, next, node, early); 1378c2ecf20Sopenharmony_ci } while (pudp++, addr = next, addr != end && pud_none(READ_ONCE(*pudp))); 1388c2ecf20Sopenharmony_ci} 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_cistatic void __init kasan_p4d_populate(pgd_t *pgdp, unsigned long addr, 1418c2ecf20Sopenharmony_ci unsigned long end, int node, bool early) 1428c2ecf20Sopenharmony_ci{ 1438c2ecf20Sopenharmony_ci unsigned long next; 1448c2ecf20Sopenharmony_ci p4d_t *p4dp = p4d_offset(pgdp, addr); 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci do { 1478c2ecf20Sopenharmony_ci next = p4d_addr_end(addr, end); 1488c2ecf20Sopenharmony_ci kasan_pud_populate(p4dp, addr, next, node, early); 1498c2ecf20Sopenharmony_ci } while (p4dp++, addr = next, addr != end); 1508c2ecf20Sopenharmony_ci} 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_cistatic void __init kasan_pgd_populate(unsigned long addr, unsigned long end, 1538c2ecf20Sopenharmony_ci int node, bool early) 1548c2ecf20Sopenharmony_ci{ 1558c2ecf20Sopenharmony_ci unsigned long next; 1568c2ecf20Sopenharmony_ci pgd_t *pgdp; 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci pgdp = pgd_offset_k(addr); 1598c2ecf20Sopenharmony_ci do { 1608c2ecf20Sopenharmony_ci next = pgd_addr_end(addr, end); 1618c2ecf20Sopenharmony_ci kasan_p4d_populate(pgdp, addr, next, node, early); 1628c2ecf20Sopenharmony_ci } while (pgdp++, addr = next, addr != end); 1638c2ecf20Sopenharmony_ci} 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci/* The early shadow maps everything to a single page of zeroes */ 1668c2ecf20Sopenharmony_ciasmlinkage void __init kasan_early_init(void) 1678c2ecf20Sopenharmony_ci{ 1688c2ecf20Sopenharmony_ci BUILD_BUG_ON(KASAN_SHADOW_OFFSET != 1698c2ecf20Sopenharmony_ci KASAN_SHADOW_END - (1UL << (64 - KASAN_SHADOW_SCALE_SHIFT))); 1708c2ecf20Sopenharmony_ci BUILD_BUG_ON(!IS_ALIGNED(_KASAN_SHADOW_START(VA_BITS), PGDIR_SIZE)); 1718c2ecf20Sopenharmony_ci BUILD_BUG_ON(!IS_ALIGNED(_KASAN_SHADOW_START(VA_BITS_MIN), PGDIR_SIZE)); 1728c2ecf20Sopenharmony_ci BUILD_BUG_ON(!IS_ALIGNED(KASAN_SHADOW_END, PGDIR_SIZE)); 1738c2ecf20Sopenharmony_ci kasan_pgd_populate(KASAN_SHADOW_START, KASAN_SHADOW_END, NUMA_NO_NODE, 1748c2ecf20Sopenharmony_ci true); 1758c2ecf20Sopenharmony_ci} 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci/* Set up full kasan mappings, ensuring that the mapped pages are zeroed */ 1788c2ecf20Sopenharmony_cistatic void __init kasan_map_populate(unsigned long start, unsigned long end, 1798c2ecf20Sopenharmony_ci int node) 1808c2ecf20Sopenharmony_ci{ 1818c2ecf20Sopenharmony_ci kasan_pgd_populate(start & PAGE_MASK, PAGE_ALIGN(end), node, false); 1828c2ecf20Sopenharmony_ci} 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci/* 1858c2ecf20Sopenharmony_ci * Copy the current shadow region into a new pgdir. 1868c2ecf20Sopenharmony_ci */ 1878c2ecf20Sopenharmony_civoid __init kasan_copy_shadow(pgd_t *pgdir) 1888c2ecf20Sopenharmony_ci{ 1898c2ecf20Sopenharmony_ci pgd_t *pgdp, *pgdp_new, *pgdp_end; 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci pgdp = pgd_offset_k(KASAN_SHADOW_START); 1928c2ecf20Sopenharmony_ci pgdp_end = pgd_offset_k(KASAN_SHADOW_END); 1938c2ecf20Sopenharmony_ci pgdp_new = pgd_offset_pgd(pgdir, KASAN_SHADOW_START); 1948c2ecf20Sopenharmony_ci do { 1958c2ecf20Sopenharmony_ci set_pgd(pgdp_new, READ_ONCE(*pgdp)); 1968c2ecf20Sopenharmony_ci } while (pgdp++, pgdp_new++, pgdp != pgdp_end); 1978c2ecf20Sopenharmony_ci} 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_cistatic void __init clear_pgds(unsigned long start, 2008c2ecf20Sopenharmony_ci unsigned long end) 2018c2ecf20Sopenharmony_ci{ 2028c2ecf20Sopenharmony_ci /* 2038c2ecf20Sopenharmony_ci * Remove references to kasan page tables from 2048c2ecf20Sopenharmony_ci * swapper_pg_dir. pgd_clear() can't be used 2058c2ecf20Sopenharmony_ci * here because it's nop on 2,3-level pagetable setups 2068c2ecf20Sopenharmony_ci */ 2078c2ecf20Sopenharmony_ci for (; start < end; start += PGDIR_SIZE) 2088c2ecf20Sopenharmony_ci set_pgd(pgd_offset_k(start), __pgd(0)); 2098c2ecf20Sopenharmony_ci} 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_civoid __init kasan_init(void) 2128c2ecf20Sopenharmony_ci{ 2138c2ecf20Sopenharmony_ci u64 kimg_shadow_start, kimg_shadow_end; 2148c2ecf20Sopenharmony_ci u64 mod_shadow_start, mod_shadow_end; 2158c2ecf20Sopenharmony_ci phys_addr_t pa_start, pa_end; 2168c2ecf20Sopenharmony_ci u64 i; 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci kimg_shadow_start = (u64)kasan_mem_to_shadow(_text) & PAGE_MASK; 2198c2ecf20Sopenharmony_ci kimg_shadow_end = PAGE_ALIGN((u64)kasan_mem_to_shadow(_end)); 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci mod_shadow_start = (u64)kasan_mem_to_shadow((void *)MODULES_VADDR); 2228c2ecf20Sopenharmony_ci mod_shadow_end = (u64)kasan_mem_to_shadow((void *)MODULES_END); 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci /* 2258c2ecf20Sopenharmony_ci * We are going to perform proper setup of shadow memory. 2268c2ecf20Sopenharmony_ci * At first we should unmap early shadow (clear_pgds() call below). 2278c2ecf20Sopenharmony_ci * However, instrumented code couldn't execute without shadow memory. 2288c2ecf20Sopenharmony_ci * tmp_pg_dir used to keep early shadow mapped until full shadow 2298c2ecf20Sopenharmony_ci * setup will be finished. 2308c2ecf20Sopenharmony_ci */ 2318c2ecf20Sopenharmony_ci memcpy(tmp_pg_dir, swapper_pg_dir, sizeof(tmp_pg_dir)); 2328c2ecf20Sopenharmony_ci dsb(ishst); 2338c2ecf20Sopenharmony_ci cpu_replace_ttbr1(lm_alias(tmp_pg_dir)); 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci clear_pgds(KASAN_SHADOW_START, KASAN_SHADOW_END); 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci kasan_map_populate(kimg_shadow_start, kimg_shadow_end, 2388c2ecf20Sopenharmony_ci early_pfn_to_nid(virt_to_pfn(lm_alias(_text)))); 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci kasan_populate_early_shadow(kasan_mem_to_shadow((void *)PAGE_END), 2418c2ecf20Sopenharmony_ci (void *)mod_shadow_start); 2428c2ecf20Sopenharmony_ci kasan_populate_early_shadow((void *)kimg_shadow_end, 2438c2ecf20Sopenharmony_ci (void *)KASAN_SHADOW_END); 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci if (kimg_shadow_start > mod_shadow_end) 2468c2ecf20Sopenharmony_ci kasan_populate_early_shadow((void *)mod_shadow_end, 2478c2ecf20Sopenharmony_ci (void *)kimg_shadow_start); 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci for_each_mem_range(i, &pa_start, &pa_end) { 2508c2ecf20Sopenharmony_ci void *start = (void *)__phys_to_virt(pa_start); 2518c2ecf20Sopenharmony_ci void *end = (void *)__phys_to_virt(pa_end); 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci if (start >= end) 2548c2ecf20Sopenharmony_ci break; 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci kasan_map_populate((unsigned long)kasan_mem_to_shadow(start), 2578c2ecf20Sopenharmony_ci (unsigned long)kasan_mem_to_shadow(end), 2588c2ecf20Sopenharmony_ci early_pfn_to_nid(virt_to_pfn(start))); 2598c2ecf20Sopenharmony_ci } 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci /* 2628c2ecf20Sopenharmony_ci * KAsan may reuse the contents of kasan_early_shadow_pte directly, 2638c2ecf20Sopenharmony_ci * so we should make sure that it maps the zero page read-only. 2648c2ecf20Sopenharmony_ci */ 2658c2ecf20Sopenharmony_ci for (i = 0; i < PTRS_PER_PTE; i++) 2668c2ecf20Sopenharmony_ci set_pte(&kasan_early_shadow_pte[i], 2678c2ecf20Sopenharmony_ci pfn_pte(sym_to_pfn(kasan_early_shadow_page), 2688c2ecf20Sopenharmony_ci PAGE_KERNEL_RO)); 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci memset(kasan_early_shadow_page, KASAN_SHADOW_INIT, PAGE_SIZE); 2718c2ecf20Sopenharmony_ci cpu_replace_ttbr1(lm_alias(swapper_pg_dir)); 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci /* At this point kasan is fully initialized. Enable error messages */ 2748c2ecf20Sopenharmony_ci init_task.kasan_depth = 0; 2758c2ecf20Sopenharmony_ci pr_info("KernelAddressSanitizer initialized\n"); 2768c2ecf20Sopenharmony_ci} 277