1#include <linux/debugfs.h> 2#include <linux/efi.h> 3#include <linux/module.h> 4#include <linux/seq_file.h> 5#include <asm/pgtable.h> 6 7static int ptdump_show(struct seq_file *m, void *v) 8{ 9 ptdump_walk_pgd_level_debugfs(m, NULL, false); 10 return 0; 11} 12 13static int ptdump_open(struct inode *inode, struct file *filp) 14{ 15 return single_open(filp, ptdump_show, NULL); 16} 17 18static const struct file_operations ptdump_fops = { 19 .owner = THIS_MODULE, 20 .open = ptdump_open, 21 .read = seq_read, 22 .llseek = seq_lseek, 23 .release = single_release, 24}; 25 26static int ptdump_show_curknl(struct seq_file *m, void *v) 27{ 28 if (current->mm->pgd) { 29 down_read(¤t->mm->mmap_sem); 30 ptdump_walk_pgd_level_debugfs(m, current->mm->pgd, false); 31 up_read(¤t->mm->mmap_sem); 32 } 33 return 0; 34} 35 36static int ptdump_open_curknl(struct inode *inode, struct file *filp) 37{ 38 return single_open(filp, ptdump_show_curknl, NULL); 39} 40 41static const struct file_operations ptdump_curknl_fops = { 42 .owner = THIS_MODULE, 43 .open = ptdump_open_curknl, 44 .read = seq_read, 45 .llseek = seq_lseek, 46 .release = single_release, 47}; 48 49#ifdef CONFIG_PAGE_TABLE_ISOLATION 50static struct dentry *pe_curusr; 51 52static int ptdump_show_curusr(struct seq_file *m, void *v) 53{ 54 if (current->mm->pgd) { 55 down_read(¤t->mm->mmap_sem); 56 ptdump_walk_pgd_level_debugfs(m, current->mm->pgd, true); 57 up_read(¤t->mm->mmap_sem); 58 } 59 return 0; 60} 61 62static int ptdump_open_curusr(struct inode *inode, struct file *filp) 63{ 64 return single_open(filp, ptdump_show_curusr, NULL); 65} 66 67static const struct file_operations ptdump_curusr_fops = { 68 .owner = THIS_MODULE, 69 .open = ptdump_open_curusr, 70 .read = seq_read, 71 .llseek = seq_lseek, 72 .release = single_release, 73}; 74#endif 75 76#if defined(CONFIG_EFI) && defined(CONFIG_X86_64) 77static struct dentry *pe_efi; 78 79static int ptdump_show_efi(struct seq_file *m, void *v) 80{ 81 if (efi_mm.pgd) 82 ptdump_walk_pgd_level_debugfs(m, efi_mm.pgd, false); 83 return 0; 84} 85 86static int ptdump_open_efi(struct inode *inode, struct file *filp) 87{ 88 return single_open(filp, ptdump_show_efi, NULL); 89} 90 91static const struct file_operations ptdump_efi_fops = { 92 .owner = THIS_MODULE, 93 .open = ptdump_open_efi, 94 .read = seq_read, 95 .llseek = seq_lseek, 96 .release = single_release, 97}; 98#endif 99 100static struct dentry *dir, *pe_knl, *pe_curknl; 101 102static int __init pt_dump_debug_init(void) 103{ 104 dir = debugfs_create_dir("page_tables", NULL); 105 if (!dir) 106 return -ENOMEM; 107 108 pe_knl = debugfs_create_file("kernel", 0400, dir, NULL, 109 &ptdump_fops); 110 if (!pe_knl) 111 goto err; 112 113 pe_curknl = debugfs_create_file("current_kernel", 0400, 114 dir, NULL, &ptdump_curknl_fops); 115 if (!pe_curknl) 116 goto err; 117 118#ifdef CONFIG_PAGE_TABLE_ISOLATION 119 pe_curusr = debugfs_create_file("current_user", 0400, 120 dir, NULL, &ptdump_curusr_fops); 121 if (!pe_curusr) 122 goto err; 123#endif 124 125#if defined(CONFIG_EFI) && defined(CONFIG_X86_64) 126 pe_efi = debugfs_create_file("efi", 0400, dir, NULL, &ptdump_efi_fops); 127 if (!pe_efi) 128 goto err; 129#endif 130 131 return 0; 132err: 133 debugfs_remove_recursive(dir); 134 return -ENOMEM; 135} 136 137static void __exit pt_dump_debug_exit(void) 138{ 139 debugfs_remove_recursive(dir); 140} 141 142module_init(pt_dump_debug_init); 143module_exit(pt_dump_debug_exit); 144MODULE_LICENSE("GPL"); 145MODULE_AUTHOR("Arjan van de Ven <arjan@linux.intel.com>"); 146MODULE_DESCRIPTION("Kernel debugging helper that dumps pagetables"); 147