162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci// Copyright (C) 2019 Andes Technology Corporation 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci#include <linux/pfn.h> 562306a36Sopenharmony_ci#include <linux/init_task.h> 662306a36Sopenharmony_ci#include <linux/kasan.h> 762306a36Sopenharmony_ci#include <linux/kernel.h> 862306a36Sopenharmony_ci#include <linux/memblock.h> 962306a36Sopenharmony_ci#include <linux/pgtable.h> 1062306a36Sopenharmony_ci#include <asm/tlbflush.h> 1162306a36Sopenharmony_ci#include <asm/fixmap.h> 1262306a36Sopenharmony_ci#include <asm/pgalloc.h> 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci/* 1562306a36Sopenharmony_ci * Kasan shadow region must lie at a fixed address across sv39, sv48 and sv57 1662306a36Sopenharmony_ci * which is right before the kernel. 1762306a36Sopenharmony_ci * 1862306a36Sopenharmony_ci * For sv39, the region is aligned on PGDIR_SIZE so we only need to populate 1962306a36Sopenharmony_ci * the page global directory with kasan_early_shadow_pmd. 2062306a36Sopenharmony_ci * 2162306a36Sopenharmony_ci * For sv48 and sv57, the region start is aligned on PGDIR_SIZE whereas the end 2262306a36Sopenharmony_ci * region is not and then we have to go down to the PUD level. 2362306a36Sopenharmony_ci */ 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_cistatic pgd_t tmp_pg_dir[PTRS_PER_PGD] __page_aligned_bss; 2662306a36Sopenharmony_cistatic p4d_t tmp_p4d[PTRS_PER_P4D] __page_aligned_bss; 2762306a36Sopenharmony_cistatic pud_t tmp_pud[PTRS_PER_PUD] __page_aligned_bss; 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_cistatic void __init kasan_populate_pte(pmd_t *pmd, unsigned long vaddr, unsigned long end) 3062306a36Sopenharmony_ci{ 3162306a36Sopenharmony_ci phys_addr_t phys_addr; 3262306a36Sopenharmony_ci pte_t *ptep, *p; 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci if (pmd_none(*pmd)) { 3562306a36Sopenharmony_ci p = memblock_alloc(PTRS_PER_PTE * sizeof(pte_t), PAGE_SIZE); 3662306a36Sopenharmony_ci set_pmd(pmd, pfn_pmd(PFN_DOWN(__pa(p)), PAGE_TABLE)); 3762306a36Sopenharmony_ci } 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci ptep = pte_offset_kernel(pmd, vaddr); 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci do { 4262306a36Sopenharmony_ci if (pte_none(*ptep)) { 4362306a36Sopenharmony_ci phys_addr = memblock_phys_alloc(PAGE_SIZE, PAGE_SIZE); 4462306a36Sopenharmony_ci set_pte(ptep, pfn_pte(PFN_DOWN(phys_addr), PAGE_KERNEL)); 4562306a36Sopenharmony_ci memset(__va(phys_addr), KASAN_SHADOW_INIT, PAGE_SIZE); 4662306a36Sopenharmony_ci } 4762306a36Sopenharmony_ci } while (ptep++, vaddr += PAGE_SIZE, vaddr != end); 4862306a36Sopenharmony_ci} 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_cistatic void __init kasan_populate_pmd(pud_t *pud, unsigned long vaddr, unsigned long end) 5162306a36Sopenharmony_ci{ 5262306a36Sopenharmony_ci phys_addr_t phys_addr; 5362306a36Sopenharmony_ci pmd_t *pmdp, *p; 5462306a36Sopenharmony_ci unsigned long next; 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci if (pud_none(*pud)) { 5762306a36Sopenharmony_ci p = memblock_alloc(PTRS_PER_PMD * sizeof(pmd_t), PAGE_SIZE); 5862306a36Sopenharmony_ci set_pud(pud, pfn_pud(PFN_DOWN(__pa(p)), PAGE_TABLE)); 5962306a36Sopenharmony_ci } 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci pmdp = pmd_offset(pud, vaddr); 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci do { 6462306a36Sopenharmony_ci next = pmd_addr_end(vaddr, end); 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci if (pmd_none(*pmdp) && IS_ALIGNED(vaddr, PMD_SIZE) && (next - vaddr) >= PMD_SIZE) { 6762306a36Sopenharmony_ci phys_addr = memblock_phys_alloc(PMD_SIZE, PMD_SIZE); 6862306a36Sopenharmony_ci if (phys_addr) { 6962306a36Sopenharmony_ci set_pmd(pmdp, pfn_pmd(PFN_DOWN(phys_addr), PAGE_KERNEL)); 7062306a36Sopenharmony_ci memset(__va(phys_addr), KASAN_SHADOW_INIT, PMD_SIZE); 7162306a36Sopenharmony_ci continue; 7262306a36Sopenharmony_ci } 7362306a36Sopenharmony_ci } 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci kasan_populate_pte(pmdp, vaddr, next); 7662306a36Sopenharmony_ci } while (pmdp++, vaddr = next, vaddr != end); 7762306a36Sopenharmony_ci} 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_cistatic void __init kasan_populate_pud(p4d_t *p4d, 8062306a36Sopenharmony_ci unsigned long vaddr, unsigned long end) 8162306a36Sopenharmony_ci{ 8262306a36Sopenharmony_ci phys_addr_t phys_addr; 8362306a36Sopenharmony_ci pud_t *pudp, *p; 8462306a36Sopenharmony_ci unsigned long next; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci if (p4d_none(*p4d)) { 8762306a36Sopenharmony_ci p = memblock_alloc(PTRS_PER_PUD * sizeof(pud_t), PAGE_SIZE); 8862306a36Sopenharmony_ci set_p4d(p4d, pfn_p4d(PFN_DOWN(__pa(p)), PAGE_TABLE)); 8962306a36Sopenharmony_ci } 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci pudp = pud_offset(p4d, vaddr); 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci do { 9462306a36Sopenharmony_ci next = pud_addr_end(vaddr, end); 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci if (pud_none(*pudp) && IS_ALIGNED(vaddr, PUD_SIZE) && (next - vaddr) >= PUD_SIZE) { 9762306a36Sopenharmony_ci phys_addr = memblock_phys_alloc(PUD_SIZE, PUD_SIZE); 9862306a36Sopenharmony_ci if (phys_addr) { 9962306a36Sopenharmony_ci set_pud(pudp, pfn_pud(PFN_DOWN(phys_addr), PAGE_KERNEL)); 10062306a36Sopenharmony_ci memset(__va(phys_addr), KASAN_SHADOW_INIT, PUD_SIZE); 10162306a36Sopenharmony_ci continue; 10262306a36Sopenharmony_ci } 10362306a36Sopenharmony_ci } 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci kasan_populate_pmd(pudp, vaddr, next); 10662306a36Sopenharmony_ci } while (pudp++, vaddr = next, vaddr != end); 10762306a36Sopenharmony_ci} 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_cistatic void __init kasan_populate_p4d(pgd_t *pgd, 11062306a36Sopenharmony_ci unsigned long vaddr, unsigned long end) 11162306a36Sopenharmony_ci{ 11262306a36Sopenharmony_ci phys_addr_t phys_addr; 11362306a36Sopenharmony_ci p4d_t *p4dp, *p; 11462306a36Sopenharmony_ci unsigned long next; 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci if (pgd_none(*pgd)) { 11762306a36Sopenharmony_ci p = memblock_alloc(PTRS_PER_P4D * sizeof(p4d_t), PAGE_SIZE); 11862306a36Sopenharmony_ci set_pgd(pgd, pfn_pgd(PFN_DOWN(__pa(p)), PAGE_TABLE)); 11962306a36Sopenharmony_ci } 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci p4dp = p4d_offset(pgd, vaddr); 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci do { 12462306a36Sopenharmony_ci next = p4d_addr_end(vaddr, end); 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci if (p4d_none(*p4dp) && IS_ALIGNED(vaddr, P4D_SIZE) && (next - vaddr) >= P4D_SIZE) { 12762306a36Sopenharmony_ci phys_addr = memblock_phys_alloc(P4D_SIZE, P4D_SIZE); 12862306a36Sopenharmony_ci if (phys_addr) { 12962306a36Sopenharmony_ci set_p4d(p4dp, pfn_p4d(PFN_DOWN(phys_addr), PAGE_KERNEL)); 13062306a36Sopenharmony_ci memset(__va(phys_addr), KASAN_SHADOW_INIT, P4D_SIZE); 13162306a36Sopenharmony_ci continue; 13262306a36Sopenharmony_ci } 13362306a36Sopenharmony_ci } 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci kasan_populate_pud(p4dp, vaddr, next); 13662306a36Sopenharmony_ci } while (p4dp++, vaddr = next, vaddr != end); 13762306a36Sopenharmony_ci} 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_cistatic void __init kasan_populate_pgd(pgd_t *pgdp, 14062306a36Sopenharmony_ci unsigned long vaddr, unsigned long end) 14162306a36Sopenharmony_ci{ 14262306a36Sopenharmony_ci phys_addr_t phys_addr; 14362306a36Sopenharmony_ci unsigned long next; 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci do { 14662306a36Sopenharmony_ci next = pgd_addr_end(vaddr, end); 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci if (pgd_none(*pgdp) && IS_ALIGNED(vaddr, PGDIR_SIZE) && 14962306a36Sopenharmony_ci (next - vaddr) >= PGDIR_SIZE) { 15062306a36Sopenharmony_ci phys_addr = memblock_phys_alloc(PGDIR_SIZE, PGDIR_SIZE); 15162306a36Sopenharmony_ci if (phys_addr) { 15262306a36Sopenharmony_ci set_pgd(pgdp, pfn_pgd(PFN_DOWN(phys_addr), PAGE_KERNEL)); 15362306a36Sopenharmony_ci memset(__va(phys_addr), KASAN_SHADOW_INIT, PGDIR_SIZE); 15462306a36Sopenharmony_ci continue; 15562306a36Sopenharmony_ci } 15662306a36Sopenharmony_ci } 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci kasan_populate_p4d(pgdp, vaddr, next); 15962306a36Sopenharmony_ci } while (pgdp++, vaddr = next, vaddr != end); 16062306a36Sopenharmony_ci} 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_cistatic void __init kasan_early_clear_pud(p4d_t *p4dp, 16362306a36Sopenharmony_ci unsigned long vaddr, unsigned long end) 16462306a36Sopenharmony_ci{ 16562306a36Sopenharmony_ci pud_t *pudp, *base_pud; 16662306a36Sopenharmony_ci unsigned long next; 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci if (!pgtable_l4_enabled) { 16962306a36Sopenharmony_ci pudp = (pud_t *)p4dp; 17062306a36Sopenharmony_ci } else { 17162306a36Sopenharmony_ci base_pud = pt_ops.get_pud_virt(pfn_to_phys(_p4d_pfn(*p4dp))); 17262306a36Sopenharmony_ci pudp = base_pud + pud_index(vaddr); 17362306a36Sopenharmony_ci } 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci do { 17662306a36Sopenharmony_ci next = pud_addr_end(vaddr, end); 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci if (IS_ALIGNED(vaddr, PUD_SIZE) && (next - vaddr) >= PUD_SIZE) { 17962306a36Sopenharmony_ci pud_clear(pudp); 18062306a36Sopenharmony_ci continue; 18162306a36Sopenharmony_ci } 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci BUG(); 18462306a36Sopenharmony_ci } while (pudp++, vaddr = next, vaddr != end); 18562306a36Sopenharmony_ci} 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_cistatic void __init kasan_early_clear_p4d(pgd_t *pgdp, 18862306a36Sopenharmony_ci unsigned long vaddr, unsigned long end) 18962306a36Sopenharmony_ci{ 19062306a36Sopenharmony_ci p4d_t *p4dp, *base_p4d; 19162306a36Sopenharmony_ci unsigned long next; 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci if (!pgtable_l5_enabled) { 19462306a36Sopenharmony_ci p4dp = (p4d_t *)pgdp; 19562306a36Sopenharmony_ci } else { 19662306a36Sopenharmony_ci base_p4d = pt_ops.get_p4d_virt(pfn_to_phys(_pgd_pfn(*pgdp))); 19762306a36Sopenharmony_ci p4dp = base_p4d + p4d_index(vaddr); 19862306a36Sopenharmony_ci } 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci do { 20162306a36Sopenharmony_ci next = p4d_addr_end(vaddr, end); 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci if (pgtable_l4_enabled && IS_ALIGNED(vaddr, P4D_SIZE) && 20462306a36Sopenharmony_ci (next - vaddr) >= P4D_SIZE) { 20562306a36Sopenharmony_ci p4d_clear(p4dp); 20662306a36Sopenharmony_ci continue; 20762306a36Sopenharmony_ci } 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci kasan_early_clear_pud(p4dp, vaddr, next); 21062306a36Sopenharmony_ci } while (p4dp++, vaddr = next, vaddr != end); 21162306a36Sopenharmony_ci} 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_cistatic void __init kasan_early_clear_pgd(pgd_t *pgdp, 21462306a36Sopenharmony_ci unsigned long vaddr, unsigned long end) 21562306a36Sopenharmony_ci{ 21662306a36Sopenharmony_ci unsigned long next; 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci do { 21962306a36Sopenharmony_ci next = pgd_addr_end(vaddr, end); 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci if (pgtable_l5_enabled && IS_ALIGNED(vaddr, PGDIR_SIZE) && 22262306a36Sopenharmony_ci (next - vaddr) >= PGDIR_SIZE) { 22362306a36Sopenharmony_ci pgd_clear(pgdp); 22462306a36Sopenharmony_ci continue; 22562306a36Sopenharmony_ci } 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci kasan_early_clear_p4d(pgdp, vaddr, next); 22862306a36Sopenharmony_ci } while (pgdp++, vaddr = next, vaddr != end); 22962306a36Sopenharmony_ci} 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_cistatic void __init kasan_early_populate_pud(p4d_t *p4dp, 23262306a36Sopenharmony_ci unsigned long vaddr, 23362306a36Sopenharmony_ci unsigned long end) 23462306a36Sopenharmony_ci{ 23562306a36Sopenharmony_ci pud_t *pudp, *base_pud; 23662306a36Sopenharmony_ci phys_addr_t phys_addr; 23762306a36Sopenharmony_ci unsigned long next; 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci if (!pgtable_l4_enabled) { 24062306a36Sopenharmony_ci pudp = (pud_t *)p4dp; 24162306a36Sopenharmony_ci } else { 24262306a36Sopenharmony_ci base_pud = pt_ops.get_pud_virt(pfn_to_phys(_p4d_pfn(*p4dp))); 24362306a36Sopenharmony_ci pudp = base_pud + pud_index(vaddr); 24462306a36Sopenharmony_ci } 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci do { 24762306a36Sopenharmony_ci next = pud_addr_end(vaddr, end); 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci if (pud_none(*pudp) && IS_ALIGNED(vaddr, PUD_SIZE) && 25062306a36Sopenharmony_ci (next - vaddr) >= PUD_SIZE) { 25162306a36Sopenharmony_ci phys_addr = __pa((uintptr_t)kasan_early_shadow_pmd); 25262306a36Sopenharmony_ci set_pud(pudp, pfn_pud(PFN_DOWN(phys_addr), PAGE_TABLE)); 25362306a36Sopenharmony_ci continue; 25462306a36Sopenharmony_ci } 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci BUG(); 25762306a36Sopenharmony_ci } while (pudp++, vaddr = next, vaddr != end); 25862306a36Sopenharmony_ci} 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_cistatic void __init kasan_early_populate_p4d(pgd_t *pgdp, 26162306a36Sopenharmony_ci unsigned long vaddr, 26262306a36Sopenharmony_ci unsigned long end) 26362306a36Sopenharmony_ci{ 26462306a36Sopenharmony_ci p4d_t *p4dp, *base_p4d; 26562306a36Sopenharmony_ci phys_addr_t phys_addr; 26662306a36Sopenharmony_ci unsigned long next; 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci /* 26962306a36Sopenharmony_ci * We can't use pgd_page_vaddr here as it would return a linear 27062306a36Sopenharmony_ci * mapping address but it is not mapped yet, but when populating 27162306a36Sopenharmony_ci * early_pg_dir, we need the physical address and when populating 27262306a36Sopenharmony_ci * swapper_pg_dir, we need the kernel virtual address so use 27362306a36Sopenharmony_ci * pt_ops facility. 27462306a36Sopenharmony_ci * Note that this test is then completely equivalent to 27562306a36Sopenharmony_ci * p4dp = p4d_offset(pgdp, vaddr) 27662306a36Sopenharmony_ci */ 27762306a36Sopenharmony_ci if (!pgtable_l5_enabled) { 27862306a36Sopenharmony_ci p4dp = (p4d_t *)pgdp; 27962306a36Sopenharmony_ci } else { 28062306a36Sopenharmony_ci base_p4d = pt_ops.get_p4d_virt(pfn_to_phys(_pgd_pfn(*pgdp))); 28162306a36Sopenharmony_ci p4dp = base_p4d + p4d_index(vaddr); 28262306a36Sopenharmony_ci } 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci do { 28562306a36Sopenharmony_ci next = p4d_addr_end(vaddr, end); 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci if (p4d_none(*p4dp) && IS_ALIGNED(vaddr, P4D_SIZE) && 28862306a36Sopenharmony_ci (next - vaddr) >= P4D_SIZE) { 28962306a36Sopenharmony_ci phys_addr = __pa((uintptr_t)kasan_early_shadow_pud); 29062306a36Sopenharmony_ci set_p4d(p4dp, pfn_p4d(PFN_DOWN(phys_addr), PAGE_TABLE)); 29162306a36Sopenharmony_ci continue; 29262306a36Sopenharmony_ci } 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci kasan_early_populate_pud(p4dp, vaddr, next); 29562306a36Sopenharmony_ci } while (p4dp++, vaddr = next, vaddr != end); 29662306a36Sopenharmony_ci} 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_cistatic void __init kasan_early_populate_pgd(pgd_t *pgdp, 29962306a36Sopenharmony_ci unsigned long vaddr, 30062306a36Sopenharmony_ci unsigned long end) 30162306a36Sopenharmony_ci{ 30262306a36Sopenharmony_ci phys_addr_t phys_addr; 30362306a36Sopenharmony_ci unsigned long next; 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci do { 30662306a36Sopenharmony_ci next = pgd_addr_end(vaddr, end); 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci if (pgd_none(*pgdp) && IS_ALIGNED(vaddr, PGDIR_SIZE) && 30962306a36Sopenharmony_ci (next - vaddr) >= PGDIR_SIZE) { 31062306a36Sopenharmony_ci phys_addr = __pa((uintptr_t)kasan_early_shadow_p4d); 31162306a36Sopenharmony_ci set_pgd(pgdp, pfn_pgd(PFN_DOWN(phys_addr), PAGE_TABLE)); 31262306a36Sopenharmony_ci continue; 31362306a36Sopenharmony_ci } 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci kasan_early_populate_p4d(pgdp, vaddr, next); 31662306a36Sopenharmony_ci } while (pgdp++, vaddr = next, vaddr != end); 31762306a36Sopenharmony_ci} 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ciasmlinkage void __init kasan_early_init(void) 32062306a36Sopenharmony_ci{ 32162306a36Sopenharmony_ci uintptr_t i; 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci BUILD_BUG_ON(KASAN_SHADOW_OFFSET != 32462306a36Sopenharmony_ci KASAN_SHADOW_END - (1UL << (64 - KASAN_SHADOW_SCALE_SHIFT))); 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci for (i = 0; i < PTRS_PER_PTE; ++i) 32762306a36Sopenharmony_ci set_pte(kasan_early_shadow_pte + i, 32862306a36Sopenharmony_ci pfn_pte(virt_to_pfn(kasan_early_shadow_page), PAGE_KERNEL)); 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci for (i = 0; i < PTRS_PER_PMD; ++i) 33162306a36Sopenharmony_ci set_pmd(kasan_early_shadow_pmd + i, 33262306a36Sopenharmony_ci pfn_pmd(PFN_DOWN 33362306a36Sopenharmony_ci (__pa((uintptr_t)kasan_early_shadow_pte)), 33462306a36Sopenharmony_ci PAGE_TABLE)); 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci if (pgtable_l4_enabled) { 33762306a36Sopenharmony_ci for (i = 0; i < PTRS_PER_PUD; ++i) 33862306a36Sopenharmony_ci set_pud(kasan_early_shadow_pud + i, 33962306a36Sopenharmony_ci pfn_pud(PFN_DOWN 34062306a36Sopenharmony_ci (__pa(((uintptr_t)kasan_early_shadow_pmd))), 34162306a36Sopenharmony_ci PAGE_TABLE)); 34262306a36Sopenharmony_ci } 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci if (pgtable_l5_enabled) { 34562306a36Sopenharmony_ci for (i = 0; i < PTRS_PER_P4D; ++i) 34662306a36Sopenharmony_ci set_p4d(kasan_early_shadow_p4d + i, 34762306a36Sopenharmony_ci pfn_p4d(PFN_DOWN 34862306a36Sopenharmony_ci (__pa(((uintptr_t)kasan_early_shadow_pud))), 34962306a36Sopenharmony_ci PAGE_TABLE)); 35062306a36Sopenharmony_ci } 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci kasan_early_populate_pgd(early_pg_dir + pgd_index(KASAN_SHADOW_START), 35362306a36Sopenharmony_ci KASAN_SHADOW_START, KASAN_SHADOW_END); 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci local_flush_tlb_all(); 35662306a36Sopenharmony_ci} 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_civoid __init kasan_swapper_init(void) 35962306a36Sopenharmony_ci{ 36062306a36Sopenharmony_ci kasan_early_populate_pgd(pgd_offset_k(KASAN_SHADOW_START), 36162306a36Sopenharmony_ci KASAN_SHADOW_START, KASAN_SHADOW_END); 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci local_flush_tlb_all(); 36462306a36Sopenharmony_ci} 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_cistatic void __init kasan_populate(void *start, void *end) 36762306a36Sopenharmony_ci{ 36862306a36Sopenharmony_ci unsigned long vaddr = (unsigned long)start & PAGE_MASK; 36962306a36Sopenharmony_ci unsigned long vend = PAGE_ALIGN((unsigned long)end); 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci kasan_populate_pgd(pgd_offset_k(vaddr), vaddr, vend); 37262306a36Sopenharmony_ci} 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_cistatic void __init kasan_shallow_populate_pud(p4d_t *p4d, 37562306a36Sopenharmony_ci unsigned long vaddr, unsigned long end) 37662306a36Sopenharmony_ci{ 37762306a36Sopenharmony_ci unsigned long next; 37862306a36Sopenharmony_ci void *p; 37962306a36Sopenharmony_ci pud_t *pud_k = pud_offset(p4d, vaddr); 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci do { 38262306a36Sopenharmony_ci next = pud_addr_end(vaddr, end); 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci if (pud_none(*pud_k)) { 38562306a36Sopenharmony_ci p = memblock_alloc(PAGE_SIZE, PAGE_SIZE); 38662306a36Sopenharmony_ci set_pud(pud_k, pfn_pud(PFN_DOWN(__pa(p)), PAGE_TABLE)); 38762306a36Sopenharmony_ci continue; 38862306a36Sopenharmony_ci } 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci BUG(); 39162306a36Sopenharmony_ci } while (pud_k++, vaddr = next, vaddr != end); 39262306a36Sopenharmony_ci} 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_cistatic void __init kasan_shallow_populate_p4d(pgd_t *pgd, 39562306a36Sopenharmony_ci unsigned long vaddr, unsigned long end) 39662306a36Sopenharmony_ci{ 39762306a36Sopenharmony_ci unsigned long next; 39862306a36Sopenharmony_ci void *p; 39962306a36Sopenharmony_ci p4d_t *p4d_k = p4d_offset(pgd, vaddr); 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci do { 40262306a36Sopenharmony_ci next = p4d_addr_end(vaddr, end); 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci if (p4d_none(*p4d_k)) { 40562306a36Sopenharmony_ci p = memblock_alloc(PAGE_SIZE, PAGE_SIZE); 40662306a36Sopenharmony_ci set_p4d(p4d_k, pfn_p4d(PFN_DOWN(__pa(p)), PAGE_TABLE)); 40762306a36Sopenharmony_ci continue; 40862306a36Sopenharmony_ci } 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci kasan_shallow_populate_pud(p4d_k, vaddr, end); 41162306a36Sopenharmony_ci } while (p4d_k++, vaddr = next, vaddr != end); 41262306a36Sopenharmony_ci} 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_cistatic void __init kasan_shallow_populate_pgd(unsigned long vaddr, unsigned long end) 41562306a36Sopenharmony_ci{ 41662306a36Sopenharmony_ci unsigned long next; 41762306a36Sopenharmony_ci void *p; 41862306a36Sopenharmony_ci pgd_t *pgd_k = pgd_offset_k(vaddr); 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci do { 42162306a36Sopenharmony_ci next = pgd_addr_end(vaddr, end); 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci if (pgd_none(*pgd_k)) { 42462306a36Sopenharmony_ci p = memblock_alloc(PAGE_SIZE, PAGE_SIZE); 42562306a36Sopenharmony_ci set_pgd(pgd_k, pfn_pgd(PFN_DOWN(__pa(p)), PAGE_TABLE)); 42662306a36Sopenharmony_ci continue; 42762306a36Sopenharmony_ci } 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci kasan_shallow_populate_p4d(pgd_k, vaddr, next); 43062306a36Sopenharmony_ci } while (pgd_k++, vaddr = next, vaddr != end); 43162306a36Sopenharmony_ci} 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_cistatic void __init kasan_shallow_populate(void *start, void *end) 43462306a36Sopenharmony_ci{ 43562306a36Sopenharmony_ci unsigned long vaddr = (unsigned long)start & PAGE_MASK; 43662306a36Sopenharmony_ci unsigned long vend = PAGE_ALIGN((unsigned long)end); 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci kasan_shallow_populate_pgd(vaddr, vend); 43962306a36Sopenharmony_ci} 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_cistatic void __init create_tmp_mapping(void) 44262306a36Sopenharmony_ci{ 44362306a36Sopenharmony_ci void *ptr; 44462306a36Sopenharmony_ci p4d_t *base_p4d; 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci /* 44762306a36Sopenharmony_ci * We need to clean the early mapping: this is hard to achieve "in-place", 44862306a36Sopenharmony_ci * so install a temporary mapping like arm64 and x86 do. 44962306a36Sopenharmony_ci */ 45062306a36Sopenharmony_ci memcpy(tmp_pg_dir, swapper_pg_dir, sizeof(pgd_t) * PTRS_PER_PGD); 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci /* Copy the last p4d since it is shared with the kernel mapping. */ 45362306a36Sopenharmony_ci if (pgtable_l5_enabled) { 45462306a36Sopenharmony_ci ptr = (p4d_t *)pgd_page_vaddr(*pgd_offset_k(KASAN_SHADOW_END)); 45562306a36Sopenharmony_ci memcpy(tmp_p4d, ptr, sizeof(p4d_t) * PTRS_PER_P4D); 45662306a36Sopenharmony_ci set_pgd(&tmp_pg_dir[pgd_index(KASAN_SHADOW_END)], 45762306a36Sopenharmony_ci pfn_pgd(PFN_DOWN(__pa(tmp_p4d)), PAGE_TABLE)); 45862306a36Sopenharmony_ci base_p4d = tmp_p4d; 45962306a36Sopenharmony_ci } else { 46062306a36Sopenharmony_ci base_p4d = (p4d_t *)tmp_pg_dir; 46162306a36Sopenharmony_ci } 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci /* Copy the last pud since it is shared with the kernel mapping. */ 46462306a36Sopenharmony_ci if (pgtable_l4_enabled) { 46562306a36Sopenharmony_ci ptr = (pud_t *)p4d_page_vaddr(*(base_p4d + p4d_index(KASAN_SHADOW_END))); 46662306a36Sopenharmony_ci memcpy(tmp_pud, ptr, sizeof(pud_t) * PTRS_PER_PUD); 46762306a36Sopenharmony_ci set_p4d(&base_p4d[p4d_index(KASAN_SHADOW_END)], 46862306a36Sopenharmony_ci pfn_p4d(PFN_DOWN(__pa(tmp_pud)), PAGE_TABLE)); 46962306a36Sopenharmony_ci } 47062306a36Sopenharmony_ci} 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_civoid __init kasan_init(void) 47362306a36Sopenharmony_ci{ 47462306a36Sopenharmony_ci phys_addr_t p_start, p_end; 47562306a36Sopenharmony_ci u64 i; 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci create_tmp_mapping(); 47862306a36Sopenharmony_ci csr_write(CSR_SATP, PFN_DOWN(__pa(tmp_pg_dir)) | satp_mode); 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ci kasan_early_clear_pgd(pgd_offset_k(KASAN_SHADOW_START), 48162306a36Sopenharmony_ci KASAN_SHADOW_START, KASAN_SHADOW_END); 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci kasan_populate_early_shadow((void *)kasan_mem_to_shadow((void *)FIXADDR_START), 48462306a36Sopenharmony_ci (void *)kasan_mem_to_shadow((void *)VMALLOC_START)); 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_KASAN_VMALLOC)) { 48762306a36Sopenharmony_ci kasan_shallow_populate( 48862306a36Sopenharmony_ci (void *)kasan_mem_to_shadow((void *)VMALLOC_START), 48962306a36Sopenharmony_ci (void *)kasan_mem_to_shadow((void *)VMALLOC_END)); 49062306a36Sopenharmony_ci /* Shallow populate modules and BPF which are vmalloc-allocated */ 49162306a36Sopenharmony_ci kasan_shallow_populate( 49262306a36Sopenharmony_ci (void *)kasan_mem_to_shadow((void *)MODULES_VADDR), 49362306a36Sopenharmony_ci (void *)kasan_mem_to_shadow((void *)MODULES_END)); 49462306a36Sopenharmony_ci } else { 49562306a36Sopenharmony_ci kasan_populate_early_shadow((void *)kasan_mem_to_shadow((void *)VMALLOC_START), 49662306a36Sopenharmony_ci (void *)kasan_mem_to_shadow((void *)VMALLOC_END)); 49762306a36Sopenharmony_ci } 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci /* Populate the linear mapping */ 50062306a36Sopenharmony_ci for_each_mem_range(i, &p_start, &p_end) { 50162306a36Sopenharmony_ci void *start = (void *)__va(p_start); 50262306a36Sopenharmony_ci void *end = (void *)__va(p_end); 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci if (start >= end) 50562306a36Sopenharmony_ci break; 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci kasan_populate(kasan_mem_to_shadow(start), kasan_mem_to_shadow(end)); 50862306a36Sopenharmony_ci } 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci /* Populate kernel */ 51162306a36Sopenharmony_ci kasan_populate(kasan_mem_to_shadow((const void *)MODULES_END), 51262306a36Sopenharmony_ci kasan_mem_to_shadow((const void *)MODULES_VADDR + SZ_2G)); 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci for (i = 0; i < PTRS_PER_PTE; i++) 51562306a36Sopenharmony_ci set_pte(&kasan_early_shadow_pte[i], 51662306a36Sopenharmony_ci mk_pte(virt_to_page(kasan_early_shadow_page), 51762306a36Sopenharmony_ci __pgprot(_PAGE_PRESENT | _PAGE_READ | 51862306a36Sopenharmony_ci _PAGE_ACCESSED))); 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci memset(kasan_early_shadow_page, KASAN_SHADOW_INIT, PAGE_SIZE); 52162306a36Sopenharmony_ci init_task.kasan_depth = 0; 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci csr_write(CSR_SATP, PFN_DOWN(__pa(swapper_pg_dir)) | satp_mode); 52462306a36Sopenharmony_ci local_flush_tlb_all(); 52562306a36Sopenharmony_ci} 526