diff options
-rw-r--r-- | arch/x86/include/asm/pgtable.h | 3 | ||||
-rw-r--r-- | arch/x86/mm/dump_pagetables.c | 84 |
2 files changed, 56 insertions, 31 deletions
diff --git a/arch/x86/include/asm/pgtable.h b/arch/x86/include/asm/pgtable.h index 5ad38ad07890..938ef1d0458e 100644 --- a/arch/x86/include/asm/pgtable.h +++ b/arch/x86/include/asm/pgtable.h | |||
@@ -15,9 +15,10 @@ | |||
15 | : (prot)) | 15 | : (prot)) |
16 | 16 | ||
17 | #ifndef __ASSEMBLY__ | 17 | #ifndef __ASSEMBLY__ |
18 | |||
19 | #include <asm/x86_init.h> | 18 | #include <asm/x86_init.h> |
20 | 19 | ||
20 | void ptdump_walk_pgd_level(struct seq_file *m, pgd_t *pgd); | ||
21 | |||
21 | /* | 22 | /* |
22 | * ZERO_PAGE is a global shared page that is always zero: used | 23 | * ZERO_PAGE is a global shared page that is always zero: used |
23 | * for zero-mapped memory areas etc.. | 24 | * for zero-mapped memory areas etc.. |
diff --git a/arch/x86/mm/dump_pagetables.c b/arch/x86/mm/dump_pagetables.c index 0002a3a33081..20621d753d5f 100644 --- a/arch/x86/mm/dump_pagetables.c +++ b/arch/x86/mm/dump_pagetables.c | |||
@@ -30,6 +30,7 @@ struct pg_state { | |||
30 | unsigned long start_address; | 30 | unsigned long start_address; |
31 | unsigned long current_address; | 31 | unsigned long current_address; |
32 | const struct addr_marker *marker; | 32 | const struct addr_marker *marker; |
33 | bool to_dmesg; | ||
33 | }; | 34 | }; |
34 | 35 | ||
35 | struct addr_marker { | 36 | struct addr_marker { |
@@ -88,10 +89,28 @@ static struct addr_marker address_markers[] = { | |||
88 | #define PUD_LEVEL_MULT (PTRS_PER_PMD * PMD_LEVEL_MULT) | 89 | #define PUD_LEVEL_MULT (PTRS_PER_PMD * PMD_LEVEL_MULT) |
89 | #define PGD_LEVEL_MULT (PTRS_PER_PUD * PUD_LEVEL_MULT) | 90 | #define PGD_LEVEL_MULT (PTRS_PER_PUD * PUD_LEVEL_MULT) |
90 | 91 | ||
92 | #define pt_dump_seq_printf(m, to_dmesg, fmt, args...) \ | ||
93 | ({ \ | ||
94 | if (to_dmesg) \ | ||
95 | printk(KERN_INFO fmt, ##args); \ | ||
96 | else \ | ||
97 | if (m) \ | ||
98 | seq_printf(m, fmt, ##args); \ | ||
99 | }) | ||
100 | |||
101 | #define pt_dump_cont_printf(m, to_dmesg, fmt, args...) \ | ||
102 | ({ \ | ||
103 | if (to_dmesg) \ | ||
104 | printk(KERN_CONT fmt, ##args); \ | ||
105 | else \ | ||
106 | if (m) \ | ||
107 | seq_printf(m, fmt, ##args); \ | ||
108 | }) | ||
109 | |||
91 | /* | 110 | /* |
92 | * Print a readable form of a pgprot_t to the seq_file | 111 | * Print a readable form of a pgprot_t to the seq_file |
93 | */ | 112 | */ |
94 | static void printk_prot(struct seq_file *m, pgprot_t prot, int level) | 113 | static void printk_prot(struct seq_file *m, pgprot_t prot, int level, bool dmsg) |
95 | { | 114 | { |
96 | pgprotval_t pr = pgprot_val(prot); | 115 | pgprotval_t pr = pgprot_val(prot); |
97 | static const char * const level_name[] = | 116 | static const char * const level_name[] = |
@@ -99,47 +118,47 @@ static void printk_prot(struct seq_file *m, pgprot_t prot, int level) | |||
99 | 118 | ||
100 | if (!pgprot_val(prot)) { | 119 | if (!pgprot_val(prot)) { |
101 | /* Not present */ | 120 | /* Not present */ |
102 | seq_printf(m, " "); | 121 | pt_dump_cont_printf(m, dmsg, " "); |
103 | } else { | 122 | } else { |
104 | if (pr & _PAGE_USER) | 123 | if (pr & _PAGE_USER) |
105 | seq_printf(m, "USR "); | 124 | pt_dump_cont_printf(m, dmsg, "USR "); |
106 | else | 125 | else |
107 | seq_printf(m, " "); | 126 | pt_dump_cont_printf(m, dmsg, " "); |
108 | if (pr & _PAGE_RW) | 127 | if (pr & _PAGE_RW) |
109 | seq_printf(m, "RW "); | 128 | pt_dump_cont_printf(m, dmsg, "RW "); |
110 | else | 129 | else |
111 | seq_printf(m, "ro "); | 130 | pt_dump_cont_printf(m, dmsg, "ro "); |
112 | if (pr & _PAGE_PWT) | 131 | if (pr & _PAGE_PWT) |
113 | seq_printf(m, "PWT "); | 132 | pt_dump_cont_printf(m, dmsg, "PWT "); |
114 | else | 133 | else |
115 | seq_printf(m, " "); | 134 | pt_dump_cont_printf(m, dmsg, " "); |
116 | if (pr & _PAGE_PCD) | 135 | if (pr & _PAGE_PCD) |
117 | seq_printf(m, "PCD "); | 136 | pt_dump_cont_printf(m, dmsg, "PCD "); |
118 | else | 137 | else |
119 | seq_printf(m, " "); | 138 | pt_dump_cont_printf(m, dmsg, " "); |
120 | 139 | ||
121 | /* Bit 9 has a different meaning on level 3 vs 4 */ | 140 | /* Bit 9 has a different meaning on level 3 vs 4 */ |
122 | if (level <= 3) { | 141 | if (level <= 3) { |
123 | if (pr & _PAGE_PSE) | 142 | if (pr & _PAGE_PSE) |
124 | seq_printf(m, "PSE "); | 143 | pt_dump_cont_printf(m, dmsg, "PSE "); |
125 | else | 144 | else |
126 | seq_printf(m, " "); | 145 | pt_dump_cont_printf(m, dmsg, " "); |
127 | } else { | 146 | } else { |
128 | if (pr & _PAGE_PAT) | 147 | if (pr & _PAGE_PAT) |
129 | seq_printf(m, "pat "); | 148 | pt_dump_cont_printf(m, dmsg, "pat "); |
130 | else | 149 | else |
131 | seq_printf(m, " "); | 150 | pt_dump_cont_printf(m, dmsg, " "); |
132 | } | 151 | } |
133 | if (pr & _PAGE_GLOBAL) | 152 | if (pr & _PAGE_GLOBAL) |
134 | seq_printf(m, "GLB "); | 153 | pt_dump_cont_printf(m, dmsg, "GLB "); |
135 | else | 154 | else |
136 | seq_printf(m, " "); | 155 | pt_dump_cont_printf(m, dmsg, " "); |
137 | if (pr & _PAGE_NX) | 156 | if (pr & _PAGE_NX) |
138 | seq_printf(m, "NX "); | 157 | pt_dump_cont_printf(m, dmsg, "NX "); |
139 | else | 158 | else |
140 | seq_printf(m, "x "); | 159 | pt_dump_cont_printf(m, dmsg, "x "); |
141 | } | 160 | } |
142 | seq_printf(m, "%s\n", level_name[level]); | 161 | pt_dump_cont_printf(m, dmsg, "%s\n", level_name[level]); |
143 | } | 162 | } |
144 | 163 | ||
145 | /* | 164 | /* |
@@ -178,7 +197,8 @@ static void note_page(struct seq_file *m, struct pg_state *st, | |||
178 | st->current_prot = new_prot; | 197 | st->current_prot = new_prot; |
179 | st->level = level; | 198 | st->level = level; |
180 | st->marker = address_markers; | 199 | st->marker = address_markers; |
181 | seq_printf(m, "---[ %s ]---\n", st->marker->name); | 200 | pt_dump_seq_printf(m, st->to_dmesg, "---[ %s ]---\n", |
201 | st->marker->name); | ||
182 | } else if (prot != cur || level != st->level || | 202 | } else if (prot != cur || level != st->level || |
183 | st->current_address >= st->marker[1].start_address) { | 203 | st->current_address >= st->marker[1].start_address) { |
184 | const char *unit = units; | 204 | const char *unit = units; |
@@ -188,17 +208,17 @@ static void note_page(struct seq_file *m, struct pg_state *st, | |||
188 | /* | 208 | /* |
189 | * Now print the actual finished series | 209 | * Now print the actual finished series |
190 | */ | 210 | */ |
191 | seq_printf(m, "0x%0*lx-0x%0*lx ", | 211 | pt_dump_seq_printf(m, st->to_dmesg, "0x%0*lx-0x%0*lx ", |
192 | width, st->start_address, | 212 | width, st->start_address, |
193 | width, st->current_address); | 213 | width, st->current_address); |
194 | 214 | ||
195 | delta = (st->current_address - st->start_address) >> 10; | 215 | delta = (st->current_address - st->start_address) >> 10; |
196 | while (!(delta & 1023) && unit[1]) { | 216 | while (!(delta & 1023) && unit[1]) { |
197 | delta >>= 10; | 217 | delta >>= 10; |
198 | unit++; | 218 | unit++; |
199 | } | 219 | } |
200 | seq_printf(m, "%9lu%c ", delta, *unit); | 220 | pt_dump_cont_printf(m, st->to_dmesg, "%9lu%c ", delta, *unit); |
201 | printk_prot(m, st->current_prot, st->level); | 221 | printk_prot(m, st->current_prot, st->level, st->to_dmesg); |
202 | 222 | ||
203 | /* | 223 | /* |
204 | * We print markers for special areas of address space, | 224 | * We print markers for special areas of address space, |
@@ -207,7 +227,8 @@ static void note_page(struct seq_file *m, struct pg_state *st, | |||
207 | */ | 227 | */ |
208 | if (st->current_address >= st->marker[1].start_address) { | 228 | if (st->current_address >= st->marker[1].start_address) { |
209 | st->marker++; | 229 | st->marker++; |
210 | seq_printf(m, "---[ %s ]---\n", st->marker->name); | 230 | pt_dump_seq_printf(m, st->to_dmesg, "---[ %s ]---\n", |
231 | st->marker->name); | ||
211 | } | 232 | } |
212 | 233 | ||
213 | st->start_address = st->current_address; | 234 | st->start_address = st->current_address; |
@@ -296,7 +317,7 @@ static void walk_pud_level(struct seq_file *m, struct pg_state *st, pgd_t addr, | |||
296 | #define pgd_none(a) pud_none(__pud(pgd_val(a))) | 317 | #define pgd_none(a) pud_none(__pud(pgd_val(a))) |
297 | #endif | 318 | #endif |
298 | 319 | ||
299 | static void walk_pgd_level(struct seq_file *m) | 320 | void ptdump_walk_pgd_level(struct seq_file *m, pgd_t *pgd) |
300 | { | 321 | { |
301 | #ifdef CONFIG_X86_64 | 322 | #ifdef CONFIG_X86_64 |
302 | pgd_t *start = (pgd_t *) &init_level4_pgt; | 323 | pgd_t *start = (pgd_t *) &init_level4_pgt; |
@@ -304,9 +325,12 @@ static void walk_pgd_level(struct seq_file *m) | |||
304 | pgd_t *start = swapper_pg_dir; | 325 | pgd_t *start = swapper_pg_dir; |
305 | #endif | 326 | #endif |
306 | int i; | 327 | int i; |
307 | struct pg_state st; | 328 | struct pg_state st = {}; |
308 | 329 | ||
309 | memset(&st, 0, sizeof(st)); | 330 | if (pgd) { |
331 | start = pgd; | ||
332 | st.to_dmesg = true; | ||
333 | } | ||
310 | 334 | ||
311 | for (i = 0; i < PTRS_PER_PGD; i++) { | 335 | for (i = 0; i < PTRS_PER_PGD; i++) { |
312 | st.current_address = normalize_addr(i * PGD_LEVEL_MULT); | 336 | st.current_address = normalize_addr(i * PGD_LEVEL_MULT); |
@@ -331,7 +355,7 @@ static void walk_pgd_level(struct seq_file *m) | |||
331 | 355 | ||
332 | static int ptdump_show(struct seq_file *m, void *v) | 356 | static int ptdump_show(struct seq_file *m, void *v) |
333 | { | 357 | { |
334 | walk_pgd_level(m); | 358 | ptdump_walk_pgd_level(m, NULL); |
335 | return 0; | 359 | return 0; |
336 | } | 360 | } |
337 | 361 | ||