xref: /openbmc/linux/arch/riscv/mm/kasan_init.c (revision a0a31fd84f8f66828790d860545d4167777d58c6)
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>
108ad8b727SNick Hu #include <asm/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,
268ad8b727SNick Hu 		 pfn_pmd(PFN_DOWN(__pa((uintptr_t)kasan_early_shadow_pte)),
278ad8b727SNick Hu 			__pgprot(_PAGE_TABLE)));
288ad8b727SNick Hu 
298ad8b727SNick Hu 	for (i = KASAN_SHADOW_START; i < KASAN_SHADOW_END;
308ad8b727SNick Hu 	     i += PGDIR_SIZE, ++pgd)
318ad8b727SNick Hu 		set_pgd(pgd,
328ad8b727SNick Hu 		 pfn_pgd(PFN_DOWN(__pa(((uintptr_t)kasan_early_shadow_pmd))),
338ad8b727SNick Hu 			__pgprot(_PAGE_TABLE)));
348ad8b727SNick Hu 
358ad8b727SNick Hu 	/* init for swapper_pg_dir */
368ad8b727SNick Hu 	pgd = pgd_offset_k(KASAN_SHADOW_START);
378ad8b727SNick Hu 
388ad8b727SNick Hu 	for (i = KASAN_SHADOW_START; i < KASAN_SHADOW_END;
398ad8b727SNick Hu 	     i += PGDIR_SIZE, ++pgd)
408ad8b727SNick Hu 		set_pgd(pgd,
418ad8b727SNick Hu 		 pfn_pgd(PFN_DOWN(__pa(((uintptr_t)kasan_early_shadow_pmd))),
428ad8b727SNick Hu 			__pgprot(_PAGE_TABLE)));
438ad8b727SNick Hu 
448ad8b727SNick Hu 	flush_tlb_all();
458ad8b727SNick Hu }
468ad8b727SNick Hu 
478ad8b727SNick Hu static void __init populate(void *start, void *end)
488ad8b727SNick Hu {
49*a0a31fd8SZong Li 	unsigned long i, offset;
508ad8b727SNick Hu 	unsigned long vaddr = (unsigned long)start & PAGE_MASK;
518ad8b727SNick Hu 	unsigned long vend = PAGE_ALIGN((unsigned long)end);
528ad8b727SNick Hu 	unsigned long n_pages = (vend - vaddr) / PAGE_SIZE;
53*a0a31fd8SZong Li 	unsigned long n_ptes =
54*a0a31fd8SZong Li 	    ((n_pages + PTRS_PER_PTE) & -PTRS_PER_PTE) / PTRS_PER_PTE;
558ad8b727SNick Hu 	unsigned long n_pmds =
56*a0a31fd8SZong Li 	    ((n_ptes + PTRS_PER_PMD) & -PTRS_PER_PMD) / PTRS_PER_PMD;
57*a0a31fd8SZong Li 
58*a0a31fd8SZong Li 	pte_t *pte =
59*a0a31fd8SZong Li 	    memblock_alloc(n_ptes * PTRS_PER_PTE * sizeof(pte_t), PAGE_SIZE);
60*a0a31fd8SZong Li 	pmd_t *pmd =
61*a0a31fd8SZong Li 	    memblock_alloc(n_pmds * PTRS_PER_PMD * sizeof(pmd_t), PAGE_SIZE);
628ad8b727SNick Hu 	pgd_t *pgd = pgd_offset_k(vaddr);
638ad8b727SNick Hu 
648ad8b727SNick Hu 	for (i = 0; i < n_pages; i++) {
658ad8b727SNick Hu 		phys_addr_t phys = memblock_phys_alloc(PAGE_SIZE, PAGE_SIZE);
66*a0a31fd8SZong Li 		set_pte(&pte[i], pfn_pte(PHYS_PFN(phys), PAGE_KERNEL));
678ad8b727SNick Hu 	}
688ad8b727SNick Hu 
69*a0a31fd8SZong Li 	for (i = 0, offset = 0; i < n_ptes; i++, offset += PTRS_PER_PTE)
70*a0a31fd8SZong Li 		set_pmd(&pmd[i],
71*a0a31fd8SZong Li 			pfn_pmd(PFN_DOWN(__pa(&pte[offset])),
728ad8b727SNick Hu 				__pgprot(_PAGE_TABLE)));
738ad8b727SNick Hu 
74*a0a31fd8SZong Li 	for (i = 0, offset = 0; i < n_pmds; i++, offset += PTRS_PER_PMD)
75*a0a31fd8SZong Li 		set_pgd(&pgd[i],
76*a0a31fd8SZong Li 			pfn_pgd(PFN_DOWN(__pa(&pmd[offset])),
778ad8b727SNick Hu 				__pgprot(_PAGE_TABLE)));
788ad8b727SNick Hu 
798ad8b727SNick Hu 	flush_tlb_all();
808ad8b727SNick Hu 	memset(start, 0, end - start);
818ad8b727SNick Hu }
828ad8b727SNick Hu 
838ad8b727SNick Hu void __init kasan_init(void)
848ad8b727SNick Hu {
858ad8b727SNick Hu 	struct memblock_region *reg;
868ad8b727SNick Hu 	unsigned long i;
878ad8b727SNick Hu 
888ad8b727SNick Hu 	kasan_populate_early_shadow((void *)KASAN_SHADOW_START,
898ad8b727SNick Hu 			(void *)kasan_mem_to_shadow((void *)VMALLOC_END));
908ad8b727SNick Hu 
918ad8b727SNick Hu 	for_each_memblock(memory, reg) {
928ad8b727SNick Hu 		void *start = (void *)__va(reg->base);
938ad8b727SNick Hu 		void *end = (void *)__va(reg->base + reg->size);
948ad8b727SNick Hu 
958ad8b727SNick Hu 		if (start >= end)
968ad8b727SNick Hu 			break;
978ad8b727SNick Hu 
988ad8b727SNick Hu 		populate(kasan_mem_to_shadow(start),
998ad8b727SNick Hu 			 kasan_mem_to_shadow(end));
1008ad8b727SNick Hu 	};
1018ad8b727SNick Hu 
1028ad8b727SNick Hu 	for (i = 0; i < PTRS_PER_PTE; i++)
1038ad8b727SNick Hu 		set_pte(&kasan_early_shadow_pte[i],
1048ad8b727SNick Hu 			mk_pte(virt_to_page(kasan_early_shadow_page),
1058ad8b727SNick Hu 			__pgprot(_PAGE_PRESENT | _PAGE_READ | _PAGE_ACCESSED)));
1068ad8b727SNick Hu 
1078ad8b727SNick Hu 	memset(kasan_early_shadow_page, 0, PAGE_SIZE);
1088ad8b727SNick Hu 	init_task.kasan_depth = 0;
1098ad8b727SNick Hu }
110