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 | 178 | static struct pg_level pg_level[] = { |
| 179 | − { | |
| 180 | − }, { /* pgd */ | |
| 179 | + { /* pgd */ | |
| 181 | 180 | .name = "PGD", |
| 182 | 181 | .bits = pte_bits, |
| 183 | 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 | 256 | if (level >= 0) |
| 258 | 257 | prot = val & pg_level[level].mask; |
| 259 | 258 | |
| 260 | − if (!st->level) { | |
| 259 | + if (st->level == -1) { | |
| 261 | 260 | st->level = level; |
| 262 | 261 | st->current_prot = prot; |
| 263 | 262 | st->start_address = addr; |
| @@ -351,6 +350,7 @@ void ptdump_check_wx(void) · 87 unmodified lines | ||
| 351 | 350 | { 0, NULL}, |
| 352 | 351 | { -1, NULL}, |
| 353 | 352 | }, |
| 353 | + .level = -1, | |
| 354 | 354 | .check_wx = true, |
| 355 | 355 | .ptdump = { |
| 356 | 356 | .note_page = note_page, |
| @@ -180,7 +180,7 @@ static struct addr_marker address_markers[] = { · 179 unmodified lines | ||
| 180 | 180 | static void printk_prot(struct seq_file *m, pgprotval_t pr, int level, bool dmsg) |
| 181 | 181 | { |
| 182 | 182 | static const char * const level_name[] = |
| 183 | − { "cr3", "pgd", "p4d", "pud", "pmd", "pte" }; | |
| 183 | + { "pgd", "p4d", "pud", "pmd", "pte" }; | |
| 184 | 184 | |
| 185 | 185 | if (!(pr & _PAGE_PRESENT)) { |
| 186 | 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 | 204 | pt_dump_cont_printf(m, dmsg, " "); |
| 205 | 205 | |
| 206 | 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 | 208 | pt_dump_cont_printf(m, dmsg, "PSE "); |
| 209 | 209 | else |
| 210 | 210 | pt_dump_cont_printf(m, dmsg, " "); |
| 211 | − if ((level == 5 && pr & _PAGE_PAT) || | |
| 212 | − ((level == 4 || level == 3) && pr & _PAGE_PAT_LARGE)) | |
| 211 | + if ((level == 4 && pr & _PAGE_PAT) || | |
| 212 | + ((level == 3 || level == 2) && pr & _PAGE_PAT_LARGE)) | |
| 213 | 213 | pt_dump_cont_printf(m, dmsg, "PAT "); |
| 214 | 214 | else |
| 215 | 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 | 272 | new_prot = val & PTE_FLAGS_MASK; |
| 273 | 273 | |
| 274 | − if (level > 1) { | |
| 275 | − new_eff = effective_prot(st->prot_levels[level - 2], | |
| 274 | + if (level > 0) { | |
| 275 | + new_eff = effective_prot(st->prot_levels[level - 1], | |
| 276 | 276 | new_prot); |
| 277 | 277 | } else { |
| 278 | 278 | new_eff = new_prot; |
| 279 | 279 | } |
| 280 | 280 | |
| 281 | − if (level > 0) | |
| 282 | − st->prot_levels[level - 1] = new_eff; | |
| 281 | + if (level >= 0) | |
| 282 | + st->prot_levels[level] = new_eff; | |
| 283 | 283 | |
| 284 | 284 | /* |
| 285 | 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 | 289 | cur = st->current_prot; |
| 290 | 290 | eff = st->effective_prot; |
| 291 | 291 | |
| 292 | − if (!st->level) { | |
| 292 | + if (st->level == -1) { | |
| 293 | 293 | /* First entry */ |
| 294 | 294 | st->current_prot = new_prot; |
| 295 | 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 | 380 | .note_page = note_page, |
| 381 | 381 | .range = ptdump_ranges |
| 382 | 382 | }, |
| 383 | + .level = -1, | |
| 383 | 384 | .to_dmesg = dmesg, |
| 384 | 385 | .check_wx = checkwx, |
| 385 | 386 | .seq = m |
| @@ -11,6 +11,7 @@ struct ptdump_range { · 10 unmodified lines | ||
| 11 | 11 | }; |
| 12 | 12 | |
| 13 | 13 | struct ptdump_state { |
| 14 | + /* level is 0:PGD to 4:PTE, or -1 if unknown */ | |
| 14 | 15 | void (*note_page)(struct ptdump_state *st, unsigned long addr, |
| 15 | 16 | int level, unsigned long val); |
| 16 | 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 | 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 | 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 | 37 | #endif |
| 38 | 38 | |
| 39 | 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 | 42 | return 0; |
| 43 | 43 | } |
| @@ -54,7 +54,7 @@ static int ptdump_p4d_entry(p4d_t *p4d, unsigned long addr, · 10 unmodified lines | ||
| 54 | 54 | #endif |
| 55 | 55 | |
| 56 | 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 | 59 | return 0; |
| 60 | 60 | } |
| @@ -71,7 +71,7 @@ static int ptdump_pud_entry(pud_t *pud, unsigned long addr, · 10 unmodified lines | ||
| 71 | 71 | #endif |
| 72 | 72 | |
| 73 | 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 | 76 | return 0; |
| 77 | 77 | } |
| @@ -88,7 +88,7 @@ static int ptdump_pmd_entry(pmd_t *pmd, unsigned long addr, · 10 unmodified lines | ||
| 88 | 88 | #endif |
| 89 | 89 | |
| 90 | 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 | 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 | 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 | 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 | 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 | 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 | 135 | up_read(&mm->mmap_sem); |
| 136 | 136 | |
| 137 | 137 | /* Flush out the last page */ |
| 138 | − st->note_page(st, 0, 0, 0); | |
| 138 | + st->note_page(st, 0, -1, 0); | |
| 139 | 139 | } |