Rather than having to increment the 'depth' number by 1 in ptdump_hole(), let's change the meaning of 'level' in note_page() since that makes the code simplier. Note that for x86, the level numbers were previously increased by 1 in commit 45dcd2091363 ("x86/mm/dump_pagetables: Fix printout of p4d level") and the comment "Bit 7 has a different meaning" was not updated, so this change also makes the code match the comment again.
Unified · Split
| @@ -176,8 +176,7 @@ struct pg_level { · 175 unmodified lines | |||
| 176 | }; | 176 | }; |
| 177 | 177 | ||
| 178 | static struct pg_level pg_level[] = { | 178 | static struct pg_level pg_level[] = { |
| 179 | { | 179 | { /* pgd */ |
| 180 | }, { /* pgd */ | ||
| 181 | .name = "PGD", | 180 | .name = "PGD", |
| 182 | .bits = pte_bits, | 181 | .bits = pte_bits, |
| 183 | .num = ARRAY_SIZE(pte_bits), | 182 | .num = ARRAY_SIZE(pte_bits), |
| @@ -257,7 +256,7 @@ static void note_page(struct ptdump_state *pt_st, unsigned long addr, int level, · 73 unmodified lines | |||
| 257 | if (level >= 0) | 256 | if (level >= 0) |
| 258 | prot = val & pg_level[level].mask; | 257 | prot = val & pg_level[level].mask; |
| 259 | 258 | ||
| 260 | if (!st->level) { | 259 | if (st->level == -1) { |
| 261 | st->level = level; | 260 | st->level = level; |
| 262 | st->current_prot = prot; | 261 | st->current_prot = prot; |
| 263 | st->start_address = addr; | 262 | st->start_address = addr; |
| @@ -351,6 +350,7 @@ void ptdump_check_wx(void) · 87 unmodified lines | |||
| 351 | { 0, NULL}, | 350 | { 0, NULL}, |
| 352 | { -1, NULL}, | 351 | { -1, NULL}, |
| 353 | }, | 352 | }, |
| 353 | .level = -1, | ||
| 354 | .check_wx = true, | 354 | .check_wx = true, |
| 355 | .ptdump = { | 355 | .ptdump = { |
| 356 | .note_page = note_page, | 356 | .note_page = note_page, |
| @@ -180,7 +180,7 @@ static struct addr_marker address_markers[] = { · 179 unmodified lines | |||
| 180 | static void printk_prot(struct seq_file *m, pgprotval_t pr, int level, bool dmsg) | 180 | static void printk_prot(struct seq_file *m, pgprotval_t pr, int level, bool dmsg) |
| 181 | { | 181 | { |
| 182 | static const char * const level_name[] = | 182 | static const char * const level_name[] = |
| 183 | { "cr3", "pgd", "p4d", "pud", "pmd", "pte" }; | 183 | { "pgd", "p4d", "pud", "pmd", "pte" }; |
| 184 | 184 | ||
| 185 | if (!(pr & _PAGE_PRESENT)) { | 185 | if (!(pr & _PAGE_PRESENT)) { |
| 186 | /* Not present */ | 186 | /* Not present */ |
| @@ -204,12 +204,12 @@ static void printk_prot(struct seq_file *m, pgprotval_t pr, int level, bool dmsg · 17 unmodified lines | |||
| 204 | pt_dump_cont_printf(m, dmsg, " "); | 204 | pt_dump_cont_printf(m, dmsg, " "); |
| 205 | 205 | ||
| 206 | /* Bit 7 has a different meaning on level 3 vs 4 */ | 206 | /* Bit 7 has a different meaning on level 3 vs 4 */ |
| 207 | if (level <= 4 && pr & _PAGE_PSE) | 207 | if (level <= 3 && pr & _PAGE_PSE) |
| 208 | pt_dump_cont_printf(m, dmsg, "PSE "); | 208 | pt_dump_cont_printf(m, dmsg, "PSE "); |
| 209 | else | 209 | else |
| 210 | pt_dump_cont_printf(m, dmsg, " "); | 210 | pt_dump_cont_printf(m, dmsg, " "); |
| 211 | if ((level == 5 && pr & _PAGE_PAT) || | 211 | if ((level == 4 && pr & _PAGE_PAT) || |
| 212 | ((level == 4 || level == 3) && pr & _PAGE_PAT_LARGE)) | 212 | ((level == 3 || level == 2) && pr & _PAGE_PAT_LARGE)) |
| 213 | pt_dump_cont_printf(m, dmsg, "PAT "); | 213 | pt_dump_cont_printf(m, dmsg, "PAT "); |
| 214 | else | 214 | else |
| 215 | pt_dump_cont_printf(m, dmsg, " "); | 215 | pt_dump_cont_printf(m, dmsg, " "); |
| @@ -271,15 +271,15 @@ static void note_page(struct ptdump_state *pt_st, unsigned long addr, int level, · 55 unmodified lines | |||
| 271 | 271 | ||
| 272 | new_prot = val & PTE_FLAGS_MASK; | 272 | new_prot = val & PTE_FLAGS_MASK; |
| 273 | 273 | ||
| 274 | if (level > 1) { | 274 | if (level > 0) { |
| 275 | new_eff = effective_prot(st->prot_levels[level - 2], | 275 | new_eff = effective_prot(st->prot_levels[level - 1], |
| 276 | new_prot); | 276 | new_prot); |
| 277 | } else { | 277 | } else { |
| 278 | new_eff = new_prot; | 278 | new_eff = new_prot; |
| 279 | } | 279 | } |
| 280 | 280 | ||
| 281 | if (level > 0) | 281 | if (level >= 0) |
| 282 | st->prot_levels[level - 1] = new_eff; | 282 | st->prot_levels[level] = new_eff; |
| 283 | 283 | ||
| 284 | /* | 284 | /* |
| 285 | * If we have a "break" in the series, we need to flush the state that | 285 | * If we have a "break" in the series, we need to flush the state that |
| @@ -289,7 +289,7 @@ static void note_page(struct ptdump_state *pt_st, unsigned long addr, int level, · 3 unmodified lines | |||
| 289 | cur = st->current_prot; | 289 | cur = st->current_prot; |
| 290 | eff = st->effective_prot; | 290 | eff = st->effective_prot; |
| 291 | 291 | ||
| 292 | if (!st->level) { | 292 | if (st->level == -1) { |
| 293 | /* First entry */ | 293 | /* First entry */ |
| 294 | st->current_prot = new_prot; | 294 | st->current_prot = new_prot; |
| 295 | st->effective_prot = new_eff; | 295 | st->effective_prot = new_eff; |
| @@ -380,6 +380,7 @@ static void ptdump_walk_pgd_level_core(struct seq_file *m, pgd_t *pgd, · 84 unmodified lines | |||
| 380 | .note_page = note_page, | 380 | .note_page = note_page, |
| 381 | .range = ptdump_ranges | 381 | .range = ptdump_ranges |
| 382 | }, | 382 | }, |
| 383 | .level = -1, | ||
| 383 | .to_dmesg = dmesg, | 384 | .to_dmesg = dmesg, |
| 384 | .check_wx = checkwx, | 385 | .check_wx = checkwx, |
| 385 | .seq = m | 386 | .seq = m |
| @@ -11,6 +11,7 @@ struct ptdump_range { · 10 unmodified lines | |||
| 11 | }; | 11 | }; |
| 12 | 12 | ||
| 13 | struct ptdump_state { | 13 | struct ptdump_state { |
| 14 | /* level is 0:PGD to 4:PTE, or -1 if unknown */ | ||
| 14 | void (*note_page)(struct ptdump_state *st, unsigned long addr, | 15 | void (*note_page)(struct ptdump_state *st, unsigned long addr, |
| 15 | int level, unsigned long val); | 16 | int level, unsigned long val); |
| 16 | const struct ptdump_range *range; | 17 | const struct ptdump_range *range; |
| @@ -17,7 +17,7 @@ static inline int note_kasan_page_table(struct mm_walk *walk, · 16 unmodified lines | |||
| 17 | { | 17 | { |
| 18 | struct ptdump_state *st = walk->private; | 18 | struct ptdump_state *st = walk->private; |
| 19 | 19 | ||
| 20 | st->note_page(st, addr, 5, pte_val(kasan_early_shadow_pte[0])); | 20 | st->note_page(st, addr, 4, pte_val(kasan_early_shadow_pte[0])); |
| 21 | 21 | ||
| 22 | walk->action = ACTION_CONTINUE; | 22 | walk->action = ACTION_CONTINUE; |
| 23 | 23 | ||
| @@ -37,7 +37,7 @@ static int ptdump_pgd_entry(pgd_t *pgd, unsigned long addr, · 13 unmodified lines | |||
| 37 | #endif | 37 | #endif |
| 38 | 38 | ||
| 39 | if (pgd_leaf(val)) | 39 | if (pgd_leaf(val)) |
| 40 | st->note_page(st, addr, 1, pgd_val(val)); | 40 | st->note_page(st, addr, 0, pgd_val(val)); |
| 41 | 41 | ||
| 42 | return 0; | 42 | return 0; |
| 43 | } | 43 | } |
| @@ -54,7 +54,7 @@ static int ptdump_p4d_entry(p4d_t *p4d, unsigned long addr, · 10 unmodified lines | |||
| 54 | #endif | 54 | #endif |
| 55 | 55 | ||
| 56 | if (p4d_leaf(val)) | 56 | if (p4d_leaf(val)) |
| 57 | st->note_page(st, addr, 2, p4d_val(val)); | 57 | st->note_page(st, addr, 1, p4d_val(val)); |
| 58 | 58 | ||
| 59 | return 0; | 59 | return 0; |
| 60 | } | 60 | } |
| @@ -71,7 +71,7 @@ static int ptdump_pud_entry(pud_t *pud, unsigned long addr, · 10 unmodified lines | |||
| 71 | #endif | 71 | #endif |
| 72 | 72 | ||
| 73 | if (pud_leaf(val)) | 73 | if (pud_leaf(val)) |
| 74 | st->note_page(st, addr, 3, pud_val(val)); | 74 | st->note_page(st, addr, 2, pud_val(val)); |
| 75 | 75 | ||
| 76 | return 0; | 76 | return 0; |
| 77 | } | 77 | } |
| @@ -88,7 +88,7 @@ static int ptdump_pmd_entry(pmd_t *pmd, unsigned long addr, · 10 unmodified lines | |||
| 88 | #endif | 88 | #endif |
| 89 | 89 | ||
| 90 | if (pmd_leaf(val)) | 90 | if (pmd_leaf(val)) |
| 91 | st->note_page(st, addr, 4, pmd_val(val)); | 91 | st->note_page(st, addr, 3, pmd_val(val)); |
| 92 | 92 | ||
| 93 | return 0; | 93 | return 0; |
| 94 | } | 94 | } |
| @@ -98,7 +98,7 @@ static int ptdump_pte_entry(pte_t *pte, unsigned long addr, · 3 unmodified lines | |||
| 98 | { | 98 | { |
| 99 | struct ptdump_state *st = walk->private; | 99 | struct ptdump_state *st = walk->private; |
| 100 | 100 | ||
| 101 | st->note_page(st, addr, 5, pte_val(READ_ONCE(*pte))); | 101 | st->note_page(st, addr, 4, pte_val(READ_ONCE(*pte))); |
| 102 | 102 | ||
| 103 | return 0; | 103 | return 0; |
| 104 | } | 104 | } |
| @@ -108,7 +108,7 @@ static int ptdump_hole(unsigned long addr, unsigned long next, · 3 unmodified lines | |||
| 108 | { | 108 | { |
| 109 | struct ptdump_state *st = walk->private; | 109 | struct ptdump_state *st = walk->private; |
| 110 | 110 | ||
| 111 | st->note_page(st, addr, depth + 1, 0); | 111 | st->note_page(st, addr, depth, 0); |
| 112 | 112 | ||
| 113 | return 0; | 113 | return 0; |
| 114 | } | 114 | } |
| @@ -135,5 +135,5 @@ void ptdump_walk_pgd(struct ptdump_state *st, struct mm_struct *mm) · 20 unmodified lines | |||
| 135 | up_read(&mm->mmap_sem); | 135 | up_read(&mm->mmap_sem); |
| 136 | 136 | ||
| 137 | /* Flush out the last page */ | 137 | /* Flush out the last page */ |
| 138 | st->note_page(st, 0, 0, 0); | 138 | st->note_page(st, 0, -1, 0); |
| 139 | } | 139 | } |