Skip to content

Commit d23c808

Browse files
committed
arm64: ptdump: Don't iterate kernel page tables using PTRS_PER_PXX
When 52-bit virtual addressing is enabled for userspace (CONFIG_ARM64_USER_VA_BITS_52=y), the kernel continues to utilise 48-bit virtual addressing in TTBR1. Consequently, PTRS_PER_PGD reflects the larger page table size for userspace and the pgd pointer for kernel page tables is offset before being written to TTBR1. This means that we can't use PTRS_PER_PGD to iterate over kernel page tables unless we apply the same offset, which is fiddly to get right and leads to some non-idiomatic walking code. Instead, just follow the usual pattern when walking page tables by using a while loop driven by pXd_offset() and pXd_addr_end(). Reported-by: Qian Cai <cai@lca.pw> Tested-by: Qian Cai <cai@lca.pw> Acked-by: Steve Capper <steve.capper@arm.com> Tested-by: Steve Capper <steve.capper@arm.com> Signed-off-by: Will Deacon <will.deacon@arm.com>
1 parent 8834f56 commit d23c808

File tree

1 file changed

+29
-30
lines changed

1 file changed

+29
-30
lines changed

arch/arm64/mm/dump.c

Lines changed: 29 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -286,74 +286,73 @@ static void note_page(struct pg_state *st, unsigned long addr, unsigned level,
286286

287287
}
288288

289-
static void walk_pte(struct pg_state *st, pmd_t *pmdp, unsigned long start)
289+
static void walk_pte(struct pg_state *st, pmd_t *pmdp, unsigned long start,
290+
unsigned long end)
290291
{
291-
pte_t *ptep = pte_offset_kernel(pmdp, 0UL);
292-
unsigned long addr;
293-
unsigned i;
292+
unsigned long addr = start;
293+
pte_t *ptep = pte_offset_kernel(pmdp, start);
294294

295-
for (i = 0; i < PTRS_PER_PTE; i++, ptep++) {
296-
addr = start + i * PAGE_SIZE;
295+
do {
297296
note_page(st, addr, 4, READ_ONCE(pte_val(*ptep)));
298-
}
297+
} while (ptep++, addr += PAGE_SIZE, addr != end);
299298
}
300299

301-
static void walk_pmd(struct pg_state *st, pud_t *pudp, unsigned long start)
300+
static void walk_pmd(struct pg_state *st, pud_t *pudp, unsigned long start,
301+
unsigned long end)
302302
{
303-
pmd_t *pmdp = pmd_offset(pudp, 0UL);
304-
unsigned long addr;
305-
unsigned i;
303+
unsigned long next, addr = start;
304+
pmd_t *pmdp = pmd_offset(pudp, start);
306305

307-
for (i = 0; i < PTRS_PER_PMD; i++, pmdp++) {
306+
do {
308307
pmd_t pmd = READ_ONCE(*pmdp);
308+
next = pmd_addr_end(addr, end);
309309

310-
addr = start + i * PMD_SIZE;
311310
if (pmd_none(pmd) || pmd_sect(pmd)) {
312311
note_page(st, addr, 3, pmd_val(pmd));
313312
} else {
314313
BUG_ON(pmd_bad(pmd));
315-
walk_pte(st, pmdp, addr);
314+
walk_pte(st, pmdp, addr, next);
316315
}
317-
}
316+
} while (pmdp++, addr = next, addr != end);
318317
}
319318

320-
static void walk_pud(struct pg_state *st, pgd_t *pgdp, unsigned long start)
319+
static void walk_pud(struct pg_state *st, pgd_t *pgdp, unsigned long start,
320+
unsigned long end)
321321
{
322-
pud_t *pudp = pud_offset(pgdp, 0UL);
323-
unsigned long addr;
324-
unsigned i;
322+
unsigned long next, addr = start;
323+
pud_t *pudp = pud_offset(pgdp, start);
325324

326-
for (i = 0; i < PTRS_PER_PUD; i++, pudp++) {
325+
do {
327326
pud_t pud = READ_ONCE(*pudp);
327+
next = pud_addr_end(addr, end);
328328

329-
addr = start + i * PUD_SIZE;
330329
if (pud_none(pud) || pud_sect(pud)) {
331330
note_page(st, addr, 2, pud_val(pud));
332331
} else {
333332
BUG_ON(pud_bad(pud));
334-
walk_pmd(st, pudp, addr);
333+
walk_pmd(st, pudp, addr, next);
335334
}
336-
}
335+
} while (pudp++, addr = next, addr != end);
337336
}
338337

339338
static void walk_pgd(struct pg_state *st, struct mm_struct *mm,
340339
unsigned long start)
341340
{
342-
pgd_t *pgdp = pgd_offset(mm, 0UL);
343-
unsigned i;
344-
unsigned long addr;
341+
unsigned long end = (start < TASK_SIZE_64) ? TASK_SIZE_64 : 0;
342+
unsigned long next, addr = start;
343+
pgd_t *pgdp = pgd_offset(mm, start);
345344

346-
for (i = 0; i < PTRS_PER_PGD; i++, pgdp++) {
345+
do {
347346
pgd_t pgd = READ_ONCE(*pgdp);
347+
next = pgd_addr_end(addr, end);
348348

349-
addr = start + i * PGDIR_SIZE;
350349
if (pgd_none(pgd)) {
351350
note_page(st, addr, 1, pgd_val(pgd));
352351
} else {
353352
BUG_ON(pgd_bad(pgd));
354-
walk_pud(st, pgdp, addr);
353+
walk_pud(st, pgdp, addr, next);
355354
}
356-
}
355+
} while (pgdp++, addr = next, addr != end);
357356
}
358357

359358
void ptdump_walk_pgd(struct seq_file *m, struct ptdump_info *info)

0 commit comments

Comments
 (0)