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 7 static int ptdump_show(struct seq_file *m, void *v) 8 { 9 ptdump_walk_pgd_level_debugfs(m, NULL, false); 10 return 0; 11 } 12 13 static int ptdump_open(struct inode *inode, struct file *filp) 14 { 15 return single_open(filp, ptdump_show, NULL); 16 } 17 18 static 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 26 static 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 36 static int ptdump_open_curknl(struct inode *inode, struct file *filp) 37 { 38 return single_open(filp, ptdump_show_curknl, NULL); 39 } 40 41 static 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 50 static struct dentry *pe_curusr; 51 52 static 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 62 static int ptdump_open_curusr(struct inode *inode, struct file *filp) 63 { 64 return single_open(filp, ptdump_show_curusr, NULL); 65 } 66 67 static 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) 77 static struct dentry *pe_efi; 78 79 static 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 86 static int ptdump_open_efi(struct inode *inode, struct file *filp) 87 { 88 return single_open(filp, ptdump_show_efi, NULL); 89 } 90 91 static 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 100 static struct dentry *dir, *pe_knl, *pe_curknl; 101 102 static 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; 132 err: 133 debugfs_remove_recursive(dir); 134 return -ENOMEM; 135 } 136 137 static void __exit pt_dump_debug_exit(void) 138 { 139 debugfs_remove_recursive(dir); 140 } 141 142 module_init(pt_dump_debug_init); 143 module_exit(pt_dump_debug_exit); 144 MODULE_LICENSE("GPL"); 145 MODULE_AUTHOR("Arjan van de Ven <arjan@linux.intel.com>"); 146 MODULE_DESCRIPTION("Kernel debugging helper that dumps pagetables"); 147