aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86/include/asm/pgtable.h3
-rw-r--r--arch/x86/mm/dump_pagetables.c84
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
20void 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
35struct addr_marker { 36struct 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 */
94static void printk_prot(struct seq_file *m, pgprot_t prot, int level) 113static 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
299static void walk_pgd_level(struct seq_file *m) 320void 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
332static int ptdump_show(struct seq_file *m, void *v) 356static 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