Blame view
mm/ptdump.c
3.79 KB
30d621f67 mm: add generic p... |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
// SPDX-License-Identifier: GPL-2.0 #include <linux/pagewalk.h> #include <linux/ptdump.h> #include <linux/kasan.h> #ifdef CONFIG_KASAN /* * This is an optimization for KASAN=y case. Since all kasan page tables * eventually point to the kasan_early_shadow_page we could call note_page() * right away without walking through lower level page tables. This saves * us dozens of seconds (minutes for 5-level config) while checking for * W+X mapping or reading kernel_page_tables debugfs file. */ static inline int note_kasan_page_table(struct mm_walk *walk, unsigned long addr) { struct ptdump_state *st = walk->private; |
f8f0d0b6f mm: ptdump: reduc... |
19 |
st->note_page(st, addr, 4, pte_val(kasan_early_shadow_pte[0])); |
30d621f67 mm: add generic p... |
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
walk->action = ACTION_CONTINUE; return 0; } #endif static int ptdump_pgd_entry(pgd_t *pgd, unsigned long addr, unsigned long next, struct mm_walk *walk) { struct ptdump_state *st = walk->private; pgd_t val = READ_ONCE(*pgd); #if CONFIG_PGTABLE_LEVELS > 4 && defined(CONFIG_KASAN) if (pgd_page(val) == virt_to_page(lm_alias(kasan_early_shadow_p4d))) return note_kasan_page_table(walk, addr); #endif |
1494e0c38 x86: mm: ptdump: ... |
37 38 |
if (st->effective_prot) st->effective_prot(st, 0, pgd_val(val)); |
30d621f67 mm: add generic p... |
39 |
if (pgd_leaf(val)) |
f8f0d0b6f mm: ptdump: reduc... |
40 |
st->note_page(st, addr, 0, pgd_val(val)); |
30d621f67 mm: add generic p... |
41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
return 0; } static int ptdump_p4d_entry(p4d_t *p4d, unsigned long addr, unsigned long next, struct mm_walk *walk) { struct ptdump_state *st = walk->private; p4d_t val = READ_ONCE(*p4d); #if CONFIG_PGTABLE_LEVELS > 3 && defined(CONFIG_KASAN) if (p4d_page(val) == virt_to_page(lm_alias(kasan_early_shadow_pud))) return note_kasan_page_table(walk, addr); #endif |
1494e0c38 x86: mm: ptdump: ... |
55 56 |
if (st->effective_prot) st->effective_prot(st, 1, p4d_val(val)); |
30d621f67 mm: add generic p... |
57 |
if (p4d_leaf(val)) |
f8f0d0b6f mm: ptdump: reduc... |
58 |
st->note_page(st, addr, 1, p4d_val(val)); |
30d621f67 mm: add generic p... |
59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
return 0; } static int ptdump_pud_entry(pud_t *pud, unsigned long addr, unsigned long next, struct mm_walk *walk) { struct ptdump_state *st = walk->private; pud_t val = READ_ONCE(*pud); #if CONFIG_PGTABLE_LEVELS > 2 && defined(CONFIG_KASAN) if (pud_page(val) == virt_to_page(lm_alias(kasan_early_shadow_pmd))) return note_kasan_page_table(walk, addr); #endif |
1494e0c38 x86: mm: ptdump: ... |
73 74 |
if (st->effective_prot) st->effective_prot(st, 2, pud_val(val)); |
30d621f67 mm: add generic p... |
75 |
if (pud_leaf(val)) |
f8f0d0b6f mm: ptdump: reduc... |
76 |
st->note_page(st, addr, 2, pud_val(val)); |
30d621f67 mm: add generic p... |
77 78 79 80 81 82 83 84 85 86 87 88 89 90 |
return 0; } static int ptdump_pmd_entry(pmd_t *pmd, unsigned long addr, unsigned long next, struct mm_walk *walk) { struct ptdump_state *st = walk->private; pmd_t val = READ_ONCE(*pmd); #if defined(CONFIG_KASAN) if (pmd_page(val) == virt_to_page(lm_alias(kasan_early_shadow_pte))) return note_kasan_page_table(walk, addr); #endif |
1494e0c38 x86: mm: ptdump: ... |
91 92 |
if (st->effective_prot) st->effective_prot(st, 3, pmd_val(val)); |
30d621f67 mm: add generic p... |
93 |
if (pmd_leaf(val)) |
f8f0d0b6f mm: ptdump: reduc... |
94 |
st->note_page(st, addr, 3, pmd_val(val)); |
30d621f67 mm: add generic p... |
95 96 97 98 99 100 101 102 |
return 0; } static int ptdump_pte_entry(pte_t *pte, unsigned long addr, unsigned long next, struct mm_walk *walk) { struct ptdump_state *st = walk->private; |
1494e0c38 x86: mm: ptdump: ... |
103 104 105 106 |
pte_t val = READ_ONCE(*pte); if (st->effective_prot) st->effective_prot(st, 4, pte_val(val)); |
30d621f67 mm: add generic p... |
107 |
|
1494e0c38 x86: mm: ptdump: ... |
108 |
st->note_page(st, addr, 4, pte_val(val)); |
30d621f67 mm: add generic p... |
109 110 111 112 113 114 115 116 |
return 0; } static int ptdump_hole(unsigned long addr, unsigned long next, int depth, struct mm_walk *walk) { struct ptdump_state *st = walk->private; |
f8f0d0b6f mm: ptdump: reduc... |
117 |
st->note_page(st, addr, depth, 0); |
30d621f67 mm: add generic p... |
118 119 120 121 122 123 124 125 126 127 128 129 |
return 0; } static const struct mm_walk_ops ptdump_ops = { .pgd_entry = ptdump_pgd_entry, .p4d_entry = ptdump_p4d_entry, .pud_entry = ptdump_pud_entry, .pmd_entry = ptdump_pmd_entry, .pte_entry = ptdump_pte_entry, .pte_hole = ptdump_hole, }; |
e47690d75 x86: mm: avoid al... |
130 |
void ptdump_walk_pgd(struct ptdump_state *st, struct mm_struct *mm, pgd_t *pgd) |
30d621f67 mm: add generic p... |
131 132 |
{ const struct ptdump_range *range = st->range; |
d8ed45c5d mmap locking API:... |
133 |
mmap_read_lock(mm); |
30d621f67 mm: add generic p... |
134 135 |
while (range->start != range->end) { walk_page_range_novma(mm, range->start, range->end, |
e47690d75 x86: mm: avoid al... |
136 |
&ptdump_ops, pgd, st); |
30d621f67 mm: add generic p... |
137 138 |
range++; } |
d8ed45c5d mmap locking API:... |
139 |
mmap_read_unlock(mm); |
30d621f67 mm: add generic p... |
140 141 |
/* Flush out the last page */ |
f8f0d0b6f mm: ptdump: reduc... |
142 |
st->note_page(st, 0, -1, 0); |
30d621f67 mm: add generic p... |
143 |
} |