dump_pagetables.c (da25e628c4c231a281b1c1de3168a36ab9bfe473) dump_pagetables.c (e1a58320a38dfa72be48a0f1a3a92273663ba6db)
1/*
2 * Debug helper to dump the current kernel pagetables of the system
3 * so that we can see what the various memory ranges are set to.
4 *
5 * (C) Copyright 2008 Intel Corporation
6 *
7 * Author: Arjan van de Ven <arjan@linux.intel.com>
8 *

--- 18 unchanged lines hidden (view full) ---

27struct pg_state {
28 int level;
29 pgprot_t current_prot;
30 unsigned long start_address;
31 unsigned long current_address;
32 const struct addr_marker *marker;
33 unsigned long lines;
34 bool to_dmesg;
1/*
2 * Debug helper to dump the current kernel pagetables of the system
3 * so that we can see what the various memory ranges are set to.
4 *
5 * (C) Copyright 2008 Intel Corporation
6 *
7 * Author: Arjan van de Ven <arjan@linux.intel.com>
8 *

--- 18 unchanged lines hidden (view full) ---

27struct pg_state {
28 int level;
29 pgprot_t current_prot;
30 unsigned long start_address;
31 unsigned long current_address;
32 const struct addr_marker *marker;
33 unsigned long lines;
34 bool to_dmesg;
35 bool check_wx;
36 unsigned long wx_pages;
35};
36
37struct addr_marker {
38 unsigned long start_address;
39 const char *name;
40 unsigned long max_lines;
41};
42

--- 166 unchanged lines hidden (view full) ---

209 st->lines = 0;
210 pt_dump_seq_printf(m, st->to_dmesg, "---[ %s ]---\n",
211 st->marker->name);
212 } else if (prot != cur || level != st->level ||
213 st->current_address >= st->marker[1].start_address) {
214 const char *unit = units;
215 unsigned long delta;
216 int width = sizeof(unsigned long) * 2;
37};
38
39struct addr_marker {
40 unsigned long start_address;
41 const char *name;
42 unsigned long max_lines;
43};
44

--- 166 unchanged lines hidden (view full) ---

211 st->lines = 0;
212 pt_dump_seq_printf(m, st->to_dmesg, "---[ %s ]---\n",
213 st->marker->name);
214 } else if (prot != cur || level != st->level ||
215 st->current_address >= st->marker[1].start_address) {
216 const char *unit = units;
217 unsigned long delta;
218 int width = sizeof(unsigned long) * 2;
219 pgprotval_t pr = pgprot_val(st->current_prot);
217
220
221 if (st->check_wx && (pr & _PAGE_RW) && !(pr & _PAGE_NX)) {
222 WARN_ONCE(1,
223 "x86/mm: Found insecure W+X mapping at address %p/%pS\n",
224 (void *)st->start_address,
225 (void *)st->start_address);
226 st->wx_pages += (st->current_address -
227 st->start_address) / PAGE_SIZE;
228 }
229
218 /*
219 * Now print the actual finished series
220 */
221 if (!st->marker->max_lines ||
222 st->lines < st->marker->max_lines) {
223 pt_dump_seq_printf(m, st->to_dmesg,
224 "0x%0*lx-0x%0*lx ",
225 width, st->start_address,

--- 115 unchanged lines hidden (view full) ---

341}
342
343#else
344#define walk_pud_level(m,s,a,p) walk_pmd_level(m,s,__pud(pgd_val(a)),p)
345#define pgd_large(a) pud_large(__pud(pgd_val(a)))
346#define pgd_none(a) pud_none(__pud(pgd_val(a)))
347#endif
348
230 /*
231 * Now print the actual finished series
232 */
233 if (!st->marker->max_lines ||
234 st->lines < st->marker->max_lines) {
235 pt_dump_seq_printf(m, st->to_dmesg,
236 "0x%0*lx-0x%0*lx ",
237 width, st->start_address,

--- 115 unchanged lines hidden (view full) ---

353}
354
355#else
356#define walk_pud_level(m,s,a,p) walk_pmd_level(m,s,__pud(pgd_val(a)),p)
357#define pgd_large(a) pud_large(__pud(pgd_val(a)))
358#define pgd_none(a) pud_none(__pud(pgd_val(a)))
359#endif
360
349void ptdump_walk_pgd_level(struct seq_file *m, pgd_t *pgd)
361static void ptdump_walk_pgd_level_core(struct seq_file *m, pgd_t *pgd,
362 bool checkwx)
350{
351#ifdef CONFIG_X86_64
352 pgd_t *start = (pgd_t *) &init_level4_pgt;
353#else
354 pgd_t *start = swapper_pg_dir;
355#endif
356 pgprotval_t prot;
357 int i;
358 struct pg_state st = {};
359
360 if (pgd) {
361 start = pgd;
362 st.to_dmesg = true;
363 }
364
363{
364#ifdef CONFIG_X86_64
365 pgd_t *start = (pgd_t *) &init_level4_pgt;
366#else
367 pgd_t *start = swapper_pg_dir;
368#endif
369 pgprotval_t prot;
370 int i;
371 struct pg_state st = {};
372
373 if (pgd) {
374 start = pgd;
375 st.to_dmesg = true;
376 }
377
378 st.check_wx = checkwx;
379 if (checkwx)
380 st.wx_pages = 0;
381
365 for (i = 0; i < PTRS_PER_PGD; i++) {
366 st.current_address = normalize_addr(i * PGD_LEVEL_MULT);
367 if (!pgd_none(*start)) {
368 if (pgd_large(*start) || !pgd_present(*start)) {
369 prot = pgd_flags(*start);
370 note_page(m, &st, __pgprot(prot), 1);
371 } else {
372 walk_pud_level(m, &st, *start,
373 i * PGD_LEVEL_MULT);
374 }
375 } else
376 note_page(m, &st, __pgprot(0), 1);
377
378 start++;
379 }
380
381 /* Flush out the last page */
382 st.current_address = normalize_addr(PTRS_PER_PGD*PGD_LEVEL_MULT);
383 note_page(m, &st, __pgprot(0), 0);
382 for (i = 0; i < PTRS_PER_PGD; i++) {
383 st.current_address = normalize_addr(i * PGD_LEVEL_MULT);
384 if (!pgd_none(*start)) {
385 if (pgd_large(*start) || !pgd_present(*start)) {
386 prot = pgd_flags(*start);
387 note_page(m, &st, __pgprot(prot), 1);
388 } else {
389 walk_pud_level(m, &st, *start,
390 i * PGD_LEVEL_MULT);
391 }
392 } else
393 note_page(m, &st, __pgprot(0), 1);
394
395 start++;
396 }
397
398 /* Flush out the last page */
399 st.current_address = normalize_addr(PTRS_PER_PGD*PGD_LEVEL_MULT);
400 note_page(m, &st, __pgprot(0), 0);
401 if (!checkwx)
402 return;
403 if (st.wx_pages)
404 pr_info("x86/mm: Checked W+X mappings: FAILED, %lu W+X pages found.\n",
405 st.wx_pages);
406 else
407 pr_info("x86/mm: Checked W+X mappings: passed, no W+X pages found.\n");
384}
385
408}
409
410void ptdump_walk_pgd_level(struct seq_file *m, pgd_t *pgd)
411{
412 ptdump_walk_pgd_level_core(m, pgd, false);
413}
414
415void ptdump_walk_pgd_level_checkwx(void)
416{
417 ptdump_walk_pgd_level_core(NULL, NULL, true);
418}
419
420#ifdef CONFIG_X86_PTDUMP
386static int ptdump_show(struct seq_file *m, void *v)
387{
388 ptdump_walk_pgd_level(m, NULL);
389 return 0;
390}
391
392static int ptdump_open(struct inode *inode, struct file *filp)
393{
394 return single_open(filp, ptdump_show, NULL);
395}
396
397static const struct file_operations ptdump_fops = {
398 .open = ptdump_open,
399 .read = seq_read,
400 .llseek = seq_lseek,
401 .release = single_release,
402};
421static int ptdump_show(struct seq_file *m, void *v)
422{
423 ptdump_walk_pgd_level(m, NULL);
424 return 0;
425}
426
427static int ptdump_open(struct inode *inode, struct file *filp)
428{
429 return single_open(filp, ptdump_show, NULL);
430}
431
432static const struct file_operations ptdump_fops = {
433 .open = ptdump_open,
434 .read = seq_read,
435 .llseek = seq_lseek,
436 .release = single_release,
437};
438#endif
403
404static int pt_dump_init(void)
405{
439
440static int pt_dump_init(void)
441{
442#ifdef CONFIG_X86_PTDUMP
406 struct dentry *pe;
443 struct dentry *pe;
444#endif
407
408#ifdef CONFIG_X86_32
409 /* Not a compile-time constant on x86-32 */
410 address_markers[VMALLOC_START_NR].start_address = VMALLOC_START;
411 address_markers[VMALLOC_END_NR].start_address = VMALLOC_END;
412# ifdef CONFIG_HIGHMEM
413 address_markers[PKMAP_BASE_NR].start_address = PKMAP_BASE;
414# endif
415 address_markers[FIXADDR_START_NR].start_address = FIXADDR_START;
416#endif
417
445
446#ifdef CONFIG_X86_32
447 /* Not a compile-time constant on x86-32 */
448 address_markers[VMALLOC_START_NR].start_address = VMALLOC_START;
449 address_markers[VMALLOC_END_NR].start_address = VMALLOC_END;
450# ifdef CONFIG_HIGHMEM
451 address_markers[PKMAP_BASE_NR].start_address = PKMAP_BASE;
452# endif
453 address_markers[FIXADDR_START_NR].start_address = FIXADDR_START;
454#endif
455
456#ifdef CONFIG_X86_PTDUMP
418 pe = debugfs_create_file("kernel_page_tables", 0600, NULL, NULL,
419 &ptdump_fops);
420 if (!pe)
421 return -ENOMEM;
457 pe = debugfs_create_file("kernel_page_tables", 0600, NULL, NULL,
458 &ptdump_fops);
459 if (!pe)
460 return -ENOMEM;
461#endif
422
423 return 0;
424}
425
426__initcall(pt_dump_init);
427MODULE_LICENSE("GPL");
428MODULE_AUTHOR("Arjan van de Ven <arjan@linux.intel.com>");
429MODULE_DESCRIPTION("Kernel debugging helper that dumps pagetables");
462
463 return 0;
464}
465
466__initcall(pt_dump_init);
467MODULE_LICENSE("GPL");
468MODULE_AUTHOR("Arjan van de Ven <arjan@linux.intel.com>");
469MODULE_DESCRIPTION("Kernel debugging helper that dumps pagetables");