[PATCH v3] powerpc/xmon: Support dumping software pagetables

Balbir Singh bsingharora at gmail.com
Mon Oct 16 16:13:04 AEDT 2017


On Mon, Oct 16, 2017 at 2:34 PM, Aneesh Kumar K.V
<aneesh.kumar at linux.vnet.ibm.com> wrote:
> Michael Ellerman <mpe at ellerman.id.au> writes:
>
>> From: Balbir Singh <bsingharora at gmail.com>
>>
>> It would be nice to be able to dump page tables in a particular
>> context.
>>
>> eg: dumping vmalloc space:
>>
>>   0:mon> dv 0xd00037fffff00000
>>   pgd  @ 0xc0000000017c0000
>>   pgdp @ 0xc0000000017c00d8 = 0x00000000f10b1000
>>   pudp @ 0xc0000000f10b13f8 = 0x00000000f10d0000
>>   pmdp @ 0xc0000000f10d1ff8 = 0x00000000f1102000
>>   ptep @ 0xc0000000f1102780 = 0xc0000000f1ba018e
>>   Maps physical address = 0x00000000f1ba0000
>>   Flags = Accessed Dirty Read Write
>>
>> This patch does not replicate the complex code of dump_pagetable and
>> has no support for bolted linear mapping, thats why I've it's called
>> dump virtual page table support. The format of the PTE can be expanded
>> even further to add more useful information about the flags in the PTE
>> if required.
>>
>> Signed-off-by: Balbir Singh <bsingharora at gmail.com>
>> [mpe: Bike shed the output format, show the pgdir]
>> Signed-off-by: Michael Ellerman <mpe at ellerman.id.au>
>> ---
>>  arch/powerpc/xmon/xmon.c | 111 +++++++++++++++++++++++++++++++++++++++++++++++
>>  1 file changed, 111 insertions(+)
>>
>> diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c
>> index a41392dec822..d84bead0ac28 100644
>> --- a/arch/powerpc/xmon/xmon.c
>> +++ b/arch/powerpc/xmon/xmon.c
>> @@ -127,6 +127,7 @@ static void byterev(unsigned char *, int);
>>  static void memex(void);
>>  static int bsesc(void);
>>  static void dump(void);
>> +static void show_pte(unsigned long);
>>  static void prdump(unsigned long, long);
>>  static int ppc_inst_dump(unsigned long, long, int);
>>  static void dump_log_buf(void);
>> @@ -234,6 +235,7 @@ Commands:\n\
>>  #endif
>>    "\
>>    dr dump stream of raw bytes\n\
>> +  dv dump virtual address translation \n\
>>    dt dump the tracing buffers (uses printk)\n\
>>    dtc        dump the tracing buffers for current CPU (uses printk)\n\
>>  "
>> @@ -2639,6 +2641,9 @@ dump(void)
>>               dump_log_buf();
>>       } else if (c == 'o') {
>>               dump_opal_msglog();
>> +     } else if (c == 'v') {
>> +             /* dump virtual to physical translation */
>> +             show_pte(adrs);
>>       } else if (c == 'r') {
>>               scanhex(&ndump);
>>               if (ndump == 0)
>> @@ -2972,6 +2977,112 @@ static void show_task(struct task_struct *tsk)
>>               tsk->comm);
>>  }
>>
>> +void format_pte(void *ptep, unsigned long pte)
>> +{
>> +     printf("ptep @ 0x%016lx = 0x%016lx\n", (unsigned long)ptep, pte);;
>> +     printf("Maps physical address = 0x%016lx\n", pte & PTE_RPN_MASK);
>> +
>> +     printf("Flags = %s%s%s%s%s\n",
>> +            (pte & _PAGE_ACCESSED) ? "Accessed " : "",
>> +            (pte & _PAGE_DIRTY)    ? "Dirty " : "",
>> +            (pte & _PAGE_READ)     ? "Read " : "",
>> +            (pte & _PAGE_WRITE)    ? "Write " : "",
>> +            (pte & _PAGE_EXEC)     ? "Exec " : "");
>> +}
>> +
>> +static void show_pte(unsigned long addr)
>> +{
>> +     unsigned long tskv = 0;
>> +     struct task_struct *tsk = NULL;
>> +     struct mm_struct *mm;
>> +     pgd_t *pgdp, *pgdir;
>> +     pud_t *pudp;
>> +     pmd_t *pmdp;
>> +     pte_t *ptep;
>> +
>> +     if (!scanhex(&tskv))
>> +             mm = &init_mm;
>> +     else
>> +             tsk = (struct task_struct *)tskv;
>> +
>> +     if (tsk == NULL)
>> +             mm = &init_mm;
>> +     else
>> +             mm = tsk->active_mm;
>> +
>> +     if (setjmp(bus_error_jmp) != 0) {
>> +             catch_memory_errors = 0;
>> +             printf("*** Error dumping pte for task %p\n", tsk);
>> +             return;
>> +     }
>> +
>> +     catch_memory_errors = 1;
>> +     sync();
>> +
>> +     if (mm == &init_mm) {
>> +             pgdp = pgd_offset_k(addr);
>> +             pgdir = pgd_offset_k(0);
>> +     } else {
>> +             pgdp = pgd_offset(mm, addr);
>> +             pgdir = pgd_offset(mm, 0);
>> +     }
>> +
>> +     if (pgd_none(*pgdp)) {
>> +             printf("no linux page table for address\n");
>> +             return;
>> +     }
>> +
>> +     printf("pgd  @ 0x%016lx\n", pgdir);
>> +
>> +     if (pgd_huge(*pgdp)) {
>> +             format_pte(pgdp, pgd_val(*pgdp));
>> +             return;
>> +     }
>> +     printf("pgdp @ 0x%016lx = 0x%016lx\n", pgdp, pgd_val(*pgdp));
>> +
>> +     pudp = pud_offset(pgdp, addr);
>> +
>> +     if (pud_none(*pudp)) {
>> +             printf("No valid PUD\n");
>> +             return;
>> +     }
>> +
>> +#ifdef CONFIG_HUGETLB_PAGE
>> +     if (pud_huge(*pudp)) {
>> +             format_pte(pudp, pud_val(*pudp));
>> +             return;
>> +     }
>> +#endif
>
> For page table walking code we don't need to put #ifdef here.

OK.. I designed this for both, I'll take the #ifdef out for kernel page tables.

 Also how
> should we handle address that we map at pmd level even if hugetlb page
> is disabled ? (kernel linear mapping). Also where do we handle THP
> mapping ? You may want to look at __find_linux_pte() to write a page
> table walking code. or better use the helper.

I wanted to avoid using __find_linux_pte in xmon(), it needs irq's disabled.
I found the interface a bit cumbersome. If I fix the #ifdef's and make the
walking code 64 bit only I think we should be OK? Do you agree?

Balbir Singh.

>
> -aneesh
>


More information about the Linuxppc-dev mailing list