Commit | Line | Data |
---|---|---|
c633544a MF |
1 | /* |
2 | * Xtensa KASAN shadow map initialization | |
3 | * | |
4 | * This file is subject to the terms and conditions of the GNU General Public | |
5 | * License. See the file "COPYING" in the main directory of this archive | |
6 | * for more details. | |
7 | * | |
8 | * Copyright (C) 2017 Cadence Design Systems Inc. | |
9 | */ | |
10 | ||
57c8a661 | 11 | #include <linux/memblock.h> |
c633544a MF |
12 | #include <linux/init_task.h> |
13 | #include <linux/kasan.h> | |
14 | #include <linux/kernel.h> | |
c633544a MF |
15 | #include <asm/initialize_mmu.h> |
16 | #include <asm/tlbflush.h> | |
17 | #include <asm/traps.h> | |
18 | ||
19 | void __init kasan_early_init(void) | |
20 | { | |
21 | unsigned long vaddr = KASAN_SHADOW_START; | |
22 | pgd_t *pgd = pgd_offset_k(vaddr); | |
23 | pmd_t *pmd = pmd_offset(pgd, vaddr); | |
24 | int i; | |
25 | ||
26 | for (i = 0; i < PTRS_PER_PTE; ++i) | |
27 | set_pte(kasan_zero_pte + i, | |
28 | mk_pte(virt_to_page(kasan_zero_page), PAGE_KERNEL)); | |
29 | ||
30 | for (vaddr = 0; vaddr < KASAN_SHADOW_SIZE; vaddr += PMD_SIZE, ++pmd) { | |
31 | BUG_ON(!pmd_none(*pmd)); | |
32 | set_pmd(pmd, __pmd((unsigned long)kasan_zero_pte)); | |
33 | } | |
34 | early_trap_init(); | |
35 | } | |
36 | ||
37 | static void __init populate(void *start, void *end) | |
38 | { | |
39 | unsigned long n_pages = (end - start) / PAGE_SIZE; | |
40 | unsigned long n_pmds = n_pages / PTRS_PER_PTE; | |
41 | unsigned long i, j; | |
42 | unsigned long vaddr = (unsigned long)start; | |
43 | pgd_t *pgd = pgd_offset_k(vaddr); | |
44 | pmd_t *pmd = pmd_offset(pgd, vaddr); | |
eb31d559 | 45 | pte_t *pte = memblock_alloc(n_pages * sizeof(pte_t), PAGE_SIZE); |
c633544a MF |
46 | |
47 | pr_debug("%s: %p - %p\n", __func__, start, end); | |
48 | ||
49 | for (i = j = 0; i < n_pmds; ++i) { | |
50 | int k; | |
51 | ||
52 | for (k = 0; k < PTRS_PER_PTE; ++k, ++j) { | |
53 | phys_addr_t phys = | |
54 | memblock_alloc_base(PAGE_SIZE, PAGE_SIZE, | |
55 | MEMBLOCK_ALLOC_ANYWHERE); | |
56 | ||
57 | set_pte(pte + j, pfn_pte(PHYS_PFN(phys), PAGE_KERNEL)); | |
58 | } | |
59 | } | |
60 | ||
61 | for (i = 0; i < n_pmds ; ++i, pte += PTRS_PER_PTE) | |
62 | set_pmd(pmd + i, __pmd((unsigned long)pte)); | |
63 | ||
64 | local_flush_tlb_all(); | |
65 | memset(start, 0, end - start); | |
66 | } | |
67 | ||
68 | void __init kasan_init(void) | |
69 | { | |
70 | int i; | |
71 | ||
72 | BUILD_BUG_ON(KASAN_SHADOW_OFFSET != KASAN_SHADOW_START - | |
73 | (KASAN_START_VADDR >> KASAN_SHADOW_SCALE_SHIFT)); | |
74 | BUILD_BUG_ON(VMALLOC_START < KASAN_START_VADDR); | |
75 | ||
76 | /* | |
77 | * Replace shadow map pages that cover addresses from VMALLOC area | |
78 | * start to the end of KSEG with clean writable pages. | |
79 | */ | |
80 | populate(kasan_mem_to_shadow((void *)VMALLOC_START), | |
81 | kasan_mem_to_shadow((void *)XCHAL_KSEG_BYPASS_VADDR)); | |
82 | ||
83 | /* Write protect kasan_zero_page and zero-initialize it again. */ | |
84 | for (i = 0; i < PTRS_PER_PTE; ++i) | |
85 | set_pte(kasan_zero_pte + i, | |
86 | mk_pte(virt_to_page(kasan_zero_page), PAGE_KERNEL_RO)); | |
87 | ||
88 | local_flush_tlb_all(); | |
89 | memset(kasan_zero_page, 0, PAGE_SIZE); | |
90 | ||
91 | /* At this point kasan is fully initialized. Enable error messages. */ | |
92 | current->kasan_depth = 0; | |
93 | pr_info("KernelAddressSanitizer initialized\n"); | |
94 | } |