diff options
author | Toshi Kani <toshi.kani@hpe.com> | 2015-09-17 14:24:19 -0400 |
---|---|---|
committer | Thomas Gleixner <tglx@linutronix.de> | 2015-09-22 15:27:32 -0400 |
commit | da25e628c4c231a281b1c1de3168a36ab9bfe473 (patch) | |
tree | 04c1ea8e88dc523fcce73ca4d8ae4358e8a818c1 | |
parent | bbac8c6deadab921f4b7d00ce675ffa4f358ec7f (diff) |
x86/mm: Fix page table dump to show PAT bit
/sys/kernel/debug/kernel_page_tables does not show the PAT bit for
PUD/PMD mappings. This is because walk_pud_level(), walk_pmd_level()
and note_page() mask the flags with PTE_FLAGS_MASK, which does not
cover their PAT bit, _PAGE_PAT_LARGE.
Fix it by replacing the use of PTE_FLAGS_MASK with p?d_flags(),
which masks the flags properly.
Also change to show the PAT bit as "PAT" to be consistent with
other bits.
Reported-by: Robert Elliott <elliott@hpe.com>
Signed-off-by: Toshi Kani <toshi.kani@hpe.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Juergen Gross <jgross@suse.com>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Konrad Wilk <konrad.wilk@oracle.com>
Cc: Robert Elliot <elliott@hpe.com>
Cc: linux-mm@kvack.org
Link: http://lkml.kernel.org/r/1442514264-12475-7-git-send-email-toshi.kani@hpe.com
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
-rw-r--r-- | arch/x86/mm/dump_pagetables.c | 39 |
1 files changed, 21 insertions, 18 deletions
diff --git a/arch/x86/mm/dump_pagetables.c b/arch/x86/mm/dump_pagetables.c index f0cedf3395af..71ab2d741024 100644 --- a/arch/x86/mm/dump_pagetables.c +++ b/arch/x86/mm/dump_pagetables.c | |||
@@ -155,7 +155,7 @@ static void printk_prot(struct seq_file *m, pgprot_t prot, int level, bool dmsg) | |||
155 | pt_dump_cont_printf(m, dmsg, " "); | 155 | pt_dump_cont_printf(m, dmsg, " "); |
156 | if ((level == 4 && pr & _PAGE_PAT) || | 156 | if ((level == 4 && pr & _PAGE_PAT) || |
157 | ((level == 3 || level == 2) && pr & _PAGE_PAT_LARGE)) | 157 | ((level == 3 || level == 2) && pr & _PAGE_PAT_LARGE)) |
158 | pt_dump_cont_printf(m, dmsg, "pat "); | 158 | pt_dump_cont_printf(m, dmsg, "PAT "); |
159 | else | 159 | else |
160 | pt_dump_cont_printf(m, dmsg, " "); | 160 | pt_dump_cont_printf(m, dmsg, " "); |
161 | if (pr & _PAGE_GLOBAL) | 161 | if (pr & _PAGE_GLOBAL) |
@@ -198,8 +198,8 @@ static void note_page(struct seq_file *m, struct pg_state *st, | |||
198 | * we have now. "break" is either changing perms, levels or | 198 | * we have now. "break" is either changing perms, levels or |
199 | * address space marker. | 199 | * address space marker. |
200 | */ | 200 | */ |
201 | prot = pgprot_val(new_prot) & PTE_FLAGS_MASK; | 201 | prot = pgprot_val(new_prot); |
202 | cur = pgprot_val(st->current_prot) & PTE_FLAGS_MASK; | 202 | cur = pgprot_val(st->current_prot); |
203 | 203 | ||
204 | if (!st->level) { | 204 | if (!st->level) { |
205 | /* First entry */ | 205 | /* First entry */ |
@@ -269,13 +269,13 @@ static void walk_pte_level(struct seq_file *m, struct pg_state *st, pmd_t addr, | |||
269 | { | 269 | { |
270 | int i; | 270 | int i; |
271 | pte_t *start; | 271 | pte_t *start; |
272 | pgprotval_t prot; | ||
272 | 273 | ||
273 | start = (pte_t *) pmd_page_vaddr(addr); | 274 | start = (pte_t *) pmd_page_vaddr(addr); |
274 | for (i = 0; i < PTRS_PER_PTE; i++) { | 275 | for (i = 0; i < PTRS_PER_PTE; i++) { |
275 | pgprot_t prot = pte_pgprot(*start); | 276 | prot = pte_flags(*start); |
276 | |||
277 | st->current_address = normalize_addr(P + i * PTE_LEVEL_MULT); | 277 | st->current_address = normalize_addr(P + i * PTE_LEVEL_MULT); |
278 | note_page(m, st, prot, 4); | 278 | note_page(m, st, __pgprot(prot), 4); |
279 | start++; | 279 | start++; |
280 | } | 280 | } |
281 | } | 281 | } |
@@ -287,18 +287,19 @@ static void walk_pmd_level(struct seq_file *m, struct pg_state *st, pud_t addr, | |||
287 | { | 287 | { |
288 | int i; | 288 | int i; |
289 | pmd_t *start; | 289 | pmd_t *start; |
290 | pgprotval_t prot; | ||
290 | 291 | ||
291 | start = (pmd_t *) pud_page_vaddr(addr); | 292 | start = (pmd_t *) pud_page_vaddr(addr); |
292 | for (i = 0; i < PTRS_PER_PMD; i++) { | 293 | for (i = 0; i < PTRS_PER_PMD; i++) { |
293 | st->current_address = normalize_addr(P + i * PMD_LEVEL_MULT); | 294 | st->current_address = normalize_addr(P + i * PMD_LEVEL_MULT); |
294 | if (!pmd_none(*start)) { | 295 | if (!pmd_none(*start)) { |
295 | pgprotval_t prot = pmd_val(*start) & PTE_FLAGS_MASK; | 296 | if (pmd_large(*start) || !pmd_present(*start)) { |
296 | 297 | prot = pmd_flags(*start); | |
297 | if (pmd_large(*start) || !pmd_present(*start)) | ||
298 | note_page(m, st, __pgprot(prot), 3); | 298 | note_page(m, st, __pgprot(prot), 3); |
299 | else | 299 | } else { |
300 | walk_pte_level(m, st, *start, | 300 | walk_pte_level(m, st, *start, |
301 | P + i * PMD_LEVEL_MULT); | 301 | P + i * PMD_LEVEL_MULT); |
302 | } | ||
302 | } else | 303 | } else |
303 | note_page(m, st, __pgprot(0), 3); | 304 | note_page(m, st, __pgprot(0), 3); |
304 | start++; | 305 | start++; |
@@ -318,19 +319,20 @@ static void walk_pud_level(struct seq_file *m, struct pg_state *st, pgd_t addr, | |||
318 | { | 319 | { |
319 | int i; | 320 | int i; |
320 | pud_t *start; | 321 | pud_t *start; |
322 | pgprotval_t prot; | ||
321 | 323 | ||
322 | start = (pud_t *) pgd_page_vaddr(addr); | 324 | start = (pud_t *) pgd_page_vaddr(addr); |
323 | 325 | ||
324 | for (i = 0; i < PTRS_PER_PUD; i++) { | 326 | for (i = 0; i < PTRS_PER_PUD; i++) { |
325 | st->current_address = normalize_addr(P + i * PUD_LEVEL_MULT); | 327 | st->current_address = normalize_addr(P + i * PUD_LEVEL_MULT); |
326 | if (!pud_none(*start)) { | 328 | if (!pud_none(*start)) { |
327 | pgprotval_t prot = pud_val(*start) & PTE_FLAGS_MASK; | 329 | if (pud_large(*start) || !pud_present(*start)) { |
328 | 330 | prot = pud_flags(*start); | |
329 | if (pud_large(*start) || !pud_present(*start)) | ||
330 | note_page(m, st, __pgprot(prot), 2); | 331 | note_page(m, st, __pgprot(prot), 2); |
331 | else | 332 | } else { |
332 | walk_pmd_level(m, st, *start, | 333 | walk_pmd_level(m, st, *start, |
333 | P + i * PUD_LEVEL_MULT); | 334 | P + i * PUD_LEVEL_MULT); |
335 | } | ||
334 | } else | 336 | } else |
335 | note_page(m, st, __pgprot(0), 2); | 337 | note_page(m, st, __pgprot(0), 2); |
336 | 338 | ||
@@ -351,6 +353,7 @@ void ptdump_walk_pgd_level(struct seq_file *m, pgd_t *pgd) | |||
351 | #else | 353 | #else |
352 | pgd_t *start = swapper_pg_dir; | 354 | pgd_t *start = swapper_pg_dir; |
353 | #endif | 355 | #endif |
356 | pgprotval_t prot; | ||
354 | int i; | 357 | int i; |
355 | struct pg_state st = {}; | 358 | struct pg_state st = {}; |
356 | 359 | ||
@@ -362,13 +365,13 @@ void ptdump_walk_pgd_level(struct seq_file *m, pgd_t *pgd) | |||
362 | for (i = 0; i < PTRS_PER_PGD; i++) { | 365 | for (i = 0; i < PTRS_PER_PGD; i++) { |
363 | st.current_address = normalize_addr(i * PGD_LEVEL_MULT); | 366 | st.current_address = normalize_addr(i * PGD_LEVEL_MULT); |
364 | if (!pgd_none(*start)) { | 367 | if (!pgd_none(*start)) { |
365 | pgprotval_t prot = pgd_val(*start) & PTE_FLAGS_MASK; | 368 | if (pgd_large(*start) || !pgd_present(*start)) { |
366 | 369 | prot = pgd_flags(*start); | |
367 | if (pgd_large(*start) || !pgd_present(*start)) | ||
368 | note_page(m, &st, __pgprot(prot), 1); | 370 | note_page(m, &st, __pgprot(prot), 1); |
369 | else | 371 | } else { |
370 | walk_pud_level(m, &st, *start, | 372 | walk_pud_level(m, &st, *start, |
371 | i * PGD_LEVEL_MULT); | 373 | i * PGD_LEVEL_MULT); |
374 | } | ||
372 | } else | 375 | } else |
373 | note_page(m, &st, __pgprot(0), 1); | 376 | note_page(m, &st, __pgprot(0), 1); |
374 | 377 | ||