1
2
3
4
5
6
7
8
9
10
11
12
13#include <linux/debugfs.h>
14#include <linux/fs.h>
15#include <linux/hugetlb.h>
16#include <linux/io.h>
17#include <linux/mm.h>
18#include <linux/highmem.h>
19#include <linux/sched.h>
20#include <linux/seq_file.h>
21#include <asm/fixmap.h>
22#include <linux/const.h>
23#include <asm/page.h>
24#include <asm/hugetlb.h>
25
26#include <mm/mmu_decl.h>
27
28#include "ptdump.h"
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56struct pg_state {
57 struct seq_file *seq;
58 const struct addr_marker *marker;
59 unsigned long start_address;
60 unsigned long start_pa;
61 unsigned long last_pa;
62 unsigned long page_size;
63 unsigned int level;
64 u64 current_flags;
65 bool check_wx;
66 unsigned long wx_pages;
67};
68
69struct addr_marker {
70 unsigned long start_address;
71 const char *name;
72};
73
74static struct addr_marker address_markers[] = {
75 { 0, "Start of kernel VM" },
76#ifdef MODULES_VADDR
77 { 0, "modules start" },
78 { 0, "modules end" },
79#endif
80 { 0, "vmalloc() Area" },
81 { 0, "vmalloc() End" },
82#ifdef CONFIG_PPC64
83 { 0, "isa I/O start" },
84 { 0, "isa I/O end" },
85 { 0, "phb I/O start" },
86 { 0, "phb I/O end" },
87 { 0, "I/O remap start" },
88 { 0, "I/O remap end" },
89 { 0, "vmemmap start" },
90#else
91 { 0, "Early I/O remap start" },
92 { 0, "Early I/O remap end" },
93#ifdef CONFIG_HIGHMEM
94 { 0, "Highmem PTEs start" },
95 { 0, "Highmem PTEs end" },
96#endif
97 { 0, "Fixmap start" },
98 { 0, "Fixmap end" },
99#endif
100#ifdef CONFIG_KASAN
101 { 0, "kasan shadow mem start" },
102 { 0, "kasan shadow mem end" },
103#endif
104 { -1, NULL },
105};
106
107#define pt_dump_seq_printf(m, fmt, args...) \
108({ \
109 if (m) \
110 seq_printf(m, fmt, ##args); \
111})
112
113#define pt_dump_seq_putc(m, c) \
114({ \
115 if (m) \
116 seq_putc(m, c); \
117})
118
119void pt_dump_size(struct seq_file *m, unsigned long size)
120{
121 static const char units[] = "KMGTPE";
122 const char *unit = units;
123
124
125 while (!(size & 1023) && unit[1]) {
126 size >>= 10;
127 unit++;
128 }
129 pt_dump_seq_printf(m, "%9lu%c ", size, *unit);
130}
131
132static void dump_flag_info(struct pg_state *st, const struct flag_info
133 *flag, u64 pte, int num)
134{
135 unsigned int i;
136
137 for (i = 0; i < num; i++, flag++) {
138 const char *s = NULL;
139 u64 val;
140
141
142 if (flag->mask == 0)
143 continue;
144
145 if (flag->is_val) {
146 val = pte & flag->val;
147 if (flag->shift)
148 val = val >> flag->shift;
149 pt_dump_seq_printf(st->seq, " %s:%llx", flag->set, val);
150 } else {
151 if ((pte & flag->mask) == flag->val)
152 s = flag->set;
153 else
154 s = flag->clear;
155 if (s)
156 pt_dump_seq_printf(st->seq, " %s", s);
157 }
158 st->current_flags &= ~flag->mask;
159 }
160 if (st->current_flags != 0)
161 pt_dump_seq_printf(st->seq, " unknown flags:%llx", st->current_flags);
162}
163
164static void dump_addr(struct pg_state *st, unsigned long addr)
165{
166 unsigned long delta;
167
168#ifdef CONFIG_PPC64
169#define REG "0x%016lx"
170#else
171#define REG "0x%08lx"
172#endif
173
174 pt_dump_seq_printf(st->seq, REG "-" REG " ", st->start_address, addr - 1);
175 if (st->start_pa == st->last_pa && st->start_address + st->page_size != addr) {
176 pt_dump_seq_printf(st->seq, "[" REG "]", st->start_pa);
177 delta = st->page_size >> 10;
178 } else {
179 pt_dump_seq_printf(st->seq, " " REG " ", st->start_pa);
180 delta = (addr - st->start_address) >> 10;
181 }
182 pt_dump_size(st->seq, delta);
183}
184
185static void note_prot_wx(struct pg_state *st, unsigned long addr)
186{
187 pte_t pte = __pte(st->current_flags);
188
189 if (!IS_ENABLED(CONFIG_PPC_DEBUG_WX) || !st->check_wx)
190 return;
191
192 if (!pte_write(pte) || !pte_exec(pte))
193 return;
194
195 WARN_ONCE(1, "powerpc/mm: Found insecure W+X mapping at address %p/%pS\n",
196 (void *)st->start_address, (void *)st->start_address);
197
198 st->wx_pages += (addr - st->start_address) / PAGE_SIZE;
199}
200
201static void note_page_update_state(struct pg_state *st, unsigned long addr,
202 unsigned int level, u64 val, unsigned long page_size)
203{
204 u64 flag = val & pg_level[level].mask;
205 u64 pa = val & PTE_RPN_MASK;
206
207 st->level = level;
208 st->current_flags = flag;
209 st->start_address = addr;
210 st->start_pa = pa;
211 st->page_size = page_size;
212
213 while (addr >= st->marker[1].start_address) {
214 st->marker++;
215 pt_dump_seq_printf(st->seq, "---[ %s ]---\n", st->marker->name);
216 }
217}
218
219static void note_page(struct pg_state *st, unsigned long addr,
220 unsigned int level, u64 val, unsigned long page_size)
221{
222 u64 flag = val & pg_level[level].mask;
223 u64 pa = val & PTE_RPN_MASK;
224
225
226 if (!st->level) {
227 pt_dump_seq_printf(st->seq, "---[ %s ]---\n", st->marker->name);
228 note_page_update_state(st, addr, level, val, page_size);
229
230
231
232
233
234
235
236
237 } else if (flag != st->current_flags || level != st->level ||
238 addr >= st->marker[1].start_address ||
239 (pa != st->last_pa + st->page_size &&
240 (pa != st->start_pa || st->start_pa != st->last_pa))) {
241
242
243 if (st->current_flags) {
244 note_prot_wx(st, addr);
245 dump_addr(st, addr);
246
247
248 if (pg_level[st->level].flag)
249 dump_flag_info(st, pg_level[st->level].flag,
250 st->current_flags,
251 pg_level[st->level].num);
252
253 pt_dump_seq_putc(st->seq, '\n');
254 }
255
256
257
258
259
260 note_page_update_state(st, addr, level, val, page_size);
261 }
262 st->last_pa = pa;
263}
264
265static void walk_pte(struct pg_state *st, pmd_t *pmd, unsigned long start)
266{
267 pte_t *pte = pte_offset_kernel(pmd, 0);
268 unsigned long addr;
269 unsigned int i;
270
271 for (i = 0; i < PTRS_PER_PTE; i++, pte++) {
272 addr = start + i * PAGE_SIZE;
273 note_page(st, addr, 4, pte_val(*pte), PAGE_SIZE);
274
275 }
276}
277
278static void walk_hugepd(struct pg_state *st, hugepd_t *phpd, unsigned long start,
279 int pdshift, int level)
280{
281#ifdef CONFIG_ARCH_HAS_HUGEPD
282 unsigned int i;
283 int shift = hugepd_shift(*phpd);
284 int ptrs_per_hpd = pdshift - shift > 0 ? 1 << (pdshift - shift) : 1;
285
286 if (start & ((1 << shift) - 1))
287 return;
288
289 for (i = 0; i < ptrs_per_hpd; i++) {
290 unsigned long addr = start + (i << shift);
291 pte_t *pte = hugepte_offset(*phpd, addr, pdshift);
292
293 note_page(st, addr, level + 1, pte_val(*pte), 1 << shift);
294 }
295#endif
296}
297
298static void walk_pmd(struct pg_state *st, pud_t *pud, unsigned long start)
299{
300 pmd_t *pmd = pmd_offset(pud, 0);
301 unsigned long addr;
302 unsigned int i;
303
304 for (i = 0; i < PTRS_PER_PMD; i++, pmd++) {
305 addr = start + i * PMD_SIZE;
306 if (!pmd_none(*pmd) && !pmd_is_leaf(*pmd))
307
308 walk_pte(st, pmd, addr);
309 else
310 note_page(st, addr, 3, pmd_val(*pmd), PMD_SIZE);
311 }
312}
313
314static void walk_pud(struct pg_state *st, p4d_t *p4d, unsigned long start)
315{
316 pud_t *pud = pud_offset(p4d, 0);
317 unsigned long addr;
318 unsigned int i;
319
320 for (i = 0; i < PTRS_PER_PUD; i++, pud++) {
321 addr = start + i * PUD_SIZE;
322 if (!pud_none(*pud) && !pud_is_leaf(*pud))
323
324 walk_pmd(st, pud, addr);
325 else
326 note_page(st, addr, 2, pud_val(*pud), PUD_SIZE);
327 }
328}
329
330static void walk_pagetables(struct pg_state *st)
331{
332 unsigned int i;
333 unsigned long addr = st->start_address & PGDIR_MASK;
334 pgd_t *pgd = pgd_offset_k(addr);
335
336
337
338
339
340 for (i = pgd_index(addr); i < PTRS_PER_PGD; i++, pgd++, addr += PGDIR_SIZE) {
341 p4d_t *p4d = p4d_offset(pgd, 0);
342
343 if (p4d_none(*p4d) || p4d_is_leaf(*p4d))
344 note_page(st, addr, 1, p4d_val(*p4d), PGDIR_SIZE);
345 else if (is_hugepd(__hugepd(p4d_val(*p4d))))
346 walk_hugepd(st, (hugepd_t *)p4d, addr, PGDIR_SHIFT, 1);
347 else
348
349 walk_pud(st, p4d, addr);
350 }
351}
352
353static void populate_markers(void)
354{
355 int i = 0;
356
357#ifdef CONFIG_PPC64
358 address_markers[i++].start_address = PAGE_OFFSET;
359#else
360 address_markers[i++].start_address = TASK_SIZE;
361#endif
362#ifdef MODULES_VADDR
363 address_markers[i++].start_address = MODULES_VADDR;
364 address_markers[i++].start_address = MODULES_END;
365#endif
366 address_markers[i++].start_address = VMALLOC_START;
367 address_markers[i++].start_address = VMALLOC_END;
368#ifdef CONFIG_PPC64
369 address_markers[i++].start_address = ISA_IO_BASE;
370 address_markers[i++].start_address = ISA_IO_END;
371 address_markers[i++].start_address = PHB_IO_BASE;
372 address_markers[i++].start_address = PHB_IO_END;
373 address_markers[i++].start_address = IOREMAP_BASE;
374 address_markers[i++].start_address = IOREMAP_END;
375
376#ifdef CONFIG_PPC_BOOK3S_64
377 address_markers[i++].start_address = H_VMEMMAP_START;
378#else
379 address_markers[i++].start_address = VMEMMAP_BASE;
380#endif
381#else
382 address_markers[i++].start_address = ioremap_bot;
383 address_markers[i++].start_address = IOREMAP_TOP;
384#ifdef CONFIG_HIGHMEM
385 address_markers[i++].start_address = PKMAP_BASE;
386 address_markers[i++].start_address = PKMAP_ADDR(LAST_PKMAP);
387#endif
388 address_markers[i++].start_address = FIXADDR_START;
389 address_markers[i++].start_address = FIXADDR_TOP;
390#ifdef CONFIG_KASAN
391 address_markers[i++].start_address = KASAN_SHADOW_START;
392 address_markers[i++].start_address = KASAN_SHADOW_END;
393#endif
394#endif
395}
396
397static int ptdump_show(struct seq_file *m, void *v)
398{
399 struct pg_state st = {
400 .seq = m,
401 .marker = address_markers,
402 .start_address = IS_ENABLED(CONFIG_PPC64) ? PAGE_OFFSET : TASK_SIZE,
403 };
404
405#ifdef CONFIG_PPC64
406 if (!radix_enabled())
407 st.start_address = KERN_VIRT_START;
408#endif
409
410
411 walk_pagetables(&st);
412 note_page(&st, 0, 0, 0, 0);
413 return 0;
414}
415
416
417static int ptdump_open(struct inode *inode, struct file *file)
418{
419 return single_open(file, ptdump_show, NULL);
420}
421
422static const struct file_operations ptdump_fops = {
423 .open = ptdump_open,
424 .read = seq_read,
425 .llseek = seq_lseek,
426 .release = single_release,
427};
428
429static void build_pgtable_complete_mask(void)
430{
431 unsigned int i, j;
432
433 for (i = 0; i < ARRAY_SIZE(pg_level); i++)
434 if (pg_level[i].flag)
435 for (j = 0; j < pg_level[i].num; j++)
436 pg_level[i].mask |= pg_level[i].flag[j].mask;
437}
438
439#ifdef CONFIG_PPC_DEBUG_WX
440void ptdump_check_wx(void)
441{
442 struct pg_state st = {
443 .seq = NULL,
444 .marker = address_markers,
445 .check_wx = true,
446 .start_address = IS_ENABLED(CONFIG_PPC64) ? PAGE_OFFSET : TASK_SIZE,
447 };
448
449#ifdef CONFIG_PPC64
450 if (!radix_enabled())
451 st.start_address = KERN_VIRT_START;
452#endif
453
454 walk_pagetables(&st);
455
456 if (st.wx_pages)
457 pr_warn("Checked W+X mappings: FAILED, %lu W+X pages found\n",
458 st.wx_pages);
459 else
460 pr_info("Checked W+X mappings: passed, no W+X pages found\n");
461}
462#endif
463
464static int ptdump_init(void)
465{
466 populate_markers();
467 build_pgtable_complete_mask();
468 debugfs_create_file("kernel_page_tables", 0400, NULL, NULL,
469 &ptdump_fops);
470 return 0;
471}
472device_initcall(ptdump_init);
473