dump_pagetables.c 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  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. *
  9. * This program is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU General Public License
  11. * as published by the Free Software Foundation; version 2
  12. * of the License.
  13. */
  14. #include <linux/module.h>
  15. #include <linux/seq_file.h>
  16. #include <linux/debugfs.h>
  17. #include <asm/pgtable.h>
  18. /*
  19. * The dumper groups pagetable entries of the same type into one, and for
  20. * that it needs to keep some state when walking, and flush this state
  21. * when a "break" in the continuity is found.
  22. */
  23. struct pg_state {
  24. int level;
  25. pgprot_t current_prot;
  26. unsigned long start_address;
  27. unsigned long current_address;
  28. int printed_vmalloc;
  29. int printed_modules;
  30. int printed_vmemmap;
  31. int printed_highmap;
  32. };
  33. /* Multipliers for offsets within the PTEs */
  34. #define LEVEL_4_MULT (PAGE_SIZE)
  35. #define LEVEL_3_MULT (512UL * LEVEL_4_MULT)
  36. #define LEVEL_2_MULT (512UL * LEVEL_3_MULT)
  37. #define LEVEL_1_MULT (512UL * LEVEL_2_MULT)
  38. /*
  39. * Print a readable form of a pgprot_t to the seq_file
  40. */
  41. static void printk_prot(struct seq_file *m, pgprot_t prot, int level)
  42. {
  43. unsigned long pr = pgprot_val(prot);
  44. if (pr & _PAGE_USER)
  45. seq_printf(m, "USR ");
  46. else
  47. seq_printf(m, " ");
  48. if (pr & _PAGE_RW)
  49. seq_printf(m, "RW ");
  50. else
  51. seq_printf(m, "ro ");
  52. if (pr & _PAGE_PWT)
  53. seq_printf(m, "PWT ");
  54. else
  55. seq_printf(m, " ");
  56. if (pr & _PAGE_PCD)
  57. seq_printf(m, "PCD ");
  58. else
  59. seq_printf(m, " ");
  60. /* Bit 9 has a different meaning on level 3 vs 4 */
  61. if (level <= 3) {
  62. if (pr & _PAGE_PSE)
  63. seq_printf(m, "PSE ");
  64. else
  65. seq_printf(m, " ");
  66. } else {
  67. if (pr & _PAGE_PAT)
  68. seq_printf(m, "pat ");
  69. else
  70. seq_printf(m, " ");
  71. }
  72. if (pr & _PAGE_GLOBAL)
  73. seq_printf(m, "GLB ");
  74. else
  75. seq_printf(m, " ");
  76. if (pr & _PAGE_NX)
  77. seq_printf(m, "NX ");
  78. else
  79. seq_printf(m, "x ");
  80. }
  81. /*
  82. * Sign-extend the 48 bit address to 64 bit
  83. */
  84. static unsigned long sign_extend(unsigned long u)
  85. {
  86. if (u>>47)
  87. u = u | (0xffffUL << 48);
  88. return u;
  89. }
  90. /*
  91. * This function gets called on a break in a continuous series
  92. * of PTE entries; the next one is different so we need to
  93. * print what we collected so far.
  94. */
  95. static void note_page(struct seq_file *m, struct pg_state *st,
  96. pgprot_t new_prot, int level)
  97. {
  98. unsigned long prot, cur;
  99. /*
  100. * If we have a "break" in the series, we need to flush the state that
  101. * we have now. "break" is either changing perms or a different level.
  102. */
  103. prot = pgprot_val(new_prot) & ~(PTE_MASK);
  104. cur = pgprot_val(st->current_prot) & ~(PTE_MASK);
  105. if ((prot != cur || level != st->level) &&
  106. st->current_address != st->start_address) {
  107. char unit = 'K';
  108. unsigned long delta;
  109. /*
  110. * We print markers for special areas of address space,
  111. * such as the start of vmalloc space etc.
  112. * This helps in the interpretation.
  113. */
  114. if (!st->printed_vmalloc &&
  115. st->start_address >= VMALLOC_START) {
  116. seq_printf(m, "---[ VMALLOC SPACE ]---\n");
  117. st->printed_vmalloc = 1;
  118. }
  119. if (!st->printed_modules &&
  120. st->start_address >= MODULES_VADDR) {
  121. seq_printf(m, "---[ MODULES SPACE ]---\n");
  122. st->printed_modules = 1;
  123. }
  124. if (st->printed_modules < 2 &&
  125. st->start_address >= MODULES_END) {
  126. seq_printf(m, "---[ END MODULES SPACE ]---\n");
  127. st->printed_modules = 2;
  128. }
  129. if (!st->printed_vmemmap &&
  130. st->start_address >= VMEMMAP_START) {
  131. seq_printf(m, "---[ VMMEMMAP SPACE ]---\n");
  132. st->printed_vmemmap = 1;
  133. }
  134. if (!st->printed_highmap &&
  135. st->start_address >= __START_KERNEL_map) {
  136. seq_printf(m, "---[ HIGH KERNEL MAPPING ]---\n");
  137. st->printed_highmap = 1;
  138. }
  139. /*
  140. * Now print the actual finished series
  141. */
  142. seq_printf(m, "[ %016lx - %016lx ",
  143. st->start_address, st->current_address);
  144. delta = (st->current_address - st->start_address) >> 10;
  145. if ((delta & 1023) == 0) {
  146. delta = delta >> 10;
  147. unit = 'M';
  148. }
  149. if (pgprot_val(st->current_prot)) {
  150. seq_printf(m, "Size %9lu%cb ", delta, unit);
  151. printk_prot(m, st->current_prot, st->level);
  152. seq_printf(m, "L%i]\n", st->level);
  153. } else {
  154. /* don't print protections on non-present memory */
  155. seq_printf(m, "%14lu%cb", delta, unit);
  156. seq_printf(m, " L%i]\n",
  157. st->level);
  158. }
  159. st->start_address = st->current_address;
  160. st->current_prot = new_prot;
  161. st->level = level;
  162. };
  163. }
  164. static void walk_level_4(struct seq_file *m, struct pg_state *st, pmd_t addr,
  165. unsigned long P)
  166. {
  167. int i;
  168. pte_t *start;
  169. start = (pte_t *) pmd_page_vaddr(addr);
  170. for (i = 0; i < PTRS_PER_PTE; i++) {
  171. pgprot_t prot = pte_pgprot(*start);
  172. st->current_address = sign_extend(P + i * LEVEL_4_MULT);
  173. note_page(m, st, prot, 4);
  174. start++;
  175. }
  176. }
  177. static void walk_level_3(struct seq_file *m, struct pg_state *st, pud_t addr,
  178. unsigned long P)
  179. {
  180. int i;
  181. pmd_t *start;
  182. start = (pmd_t *) pud_page_vaddr(addr);
  183. for (i = 0; i < PTRS_PER_PMD; i++) {
  184. st->current_address = sign_extend(P + i * LEVEL_3_MULT);
  185. if (!pmd_none(*start)) {
  186. unsigned long prot;
  187. prot = pmd_val(*start) & ~(PTE_MASK);
  188. /* Deal with 2Mb pages */
  189. if (pmd_large(*start))
  190. note_page(m, st, __pgprot(prot), 3);
  191. else
  192. walk_level_4(m, st, *start,
  193. P + i * LEVEL_3_MULT);
  194. } else
  195. note_page(m, st, __pgprot(0), 3);
  196. start++;
  197. }
  198. }
  199. static void walk_level_2(struct seq_file *m, struct pg_state *st, pgd_t addr,
  200. unsigned long P)
  201. {
  202. int i;
  203. pud_t *start;
  204. start = (pud_t *) pgd_page_vaddr(addr);
  205. for (i = 0; i < PTRS_PER_PUD; i++) {
  206. if (!pud_none(*start)) {
  207. unsigned long prot;
  208. prot = pud_val(*start) & ~(PTE_MASK);
  209. /* Deal with 1Gb pages */
  210. if (pud_large(*start))
  211. note_page(m, st, __pgprot(prot), 2);
  212. else
  213. walk_level_3(m, st, *start,
  214. P + i * LEVEL_2_MULT);
  215. } else
  216. note_page(m, st, __pgprot(0), 2);
  217. start++;
  218. }
  219. }
  220. static void walk_level_1(struct seq_file *m)
  221. {
  222. pgd_t *start = (pgd_t *) &init_level4_pgt;
  223. int i;
  224. struct pg_state st;
  225. memset(&st, 0, sizeof(st));
  226. st.level = 1;
  227. for (i = 0; i < PTRS_PER_PGD; i++) {
  228. if (!pgd_none(*start))
  229. walk_level_2(m, &st, *start, i * LEVEL_1_MULT);
  230. else
  231. note_page(m, &st, __pgprot(0), 1);
  232. start++;
  233. }
  234. }
  235. static int ptdump_show(struct seq_file *m, void *v)
  236. {
  237. seq_puts(m, "Kernel pagetable dump\n");
  238. walk_level_1(m);
  239. return 0;
  240. }
  241. static int ptdump_open(struct inode *inode, struct file *filp)
  242. {
  243. return single_open(filp, ptdump_show, NULL);
  244. }
  245. static const struct file_operations ptdump_fops = {
  246. .open = ptdump_open,
  247. .read = seq_read,
  248. .llseek = seq_lseek,
  249. .release = single_release,
  250. };
  251. int pt_dump_init(void)
  252. {
  253. struct dentry *pe;
  254. pe = debugfs_create_file("kernel_page_tables", 0600, NULL, NULL,
  255. &ptdump_fops);
  256. if (!pe)
  257. return -ENOMEM;
  258. return 0;
  259. }
  260. __initcall(pt_dump_init);
  261. MODULE_LICENSE("GPL");
  262. MODULE_AUTHOR("Arjan van de Ven <arjan@linux.intel.com>");
  263. MODULE_DESCRIPTION("Kernel debugging helper that dumps pagetables");