[v3] powerpc/xmon: Support dumping software pagetables

Message ID 1507546335-27120-1-git-send-email-mpe@ellerman.id.au
State New
Headers show
Series
  • [v3] powerpc/xmon: Support dumping software pagetables
Related show

Commit Message

Michael Ellerman Oct. 9, 2017, 10:52 a.m.
From: Balbir Singh <bsingharora@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@gmail.com>
[mpe: Bike shed the output format, show the pgdir]
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
---
 arch/powerpc/xmon/xmon.c | 111 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 111 insertions(+)

Comments

kbuild test robot Oct. 12, 2017, 8:57 a.m. | #1
Hi Balbir,

[auto build test ERROR on powerpc/next]
[also build test ERROR on v4.14-rc4 next-20171009]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Michael-Ellerman/powerpc-xmon-Support-dumping-software-pagetables/20171012-124024
base:   https://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux.git next
config: powerpc-ppc64e_defconfig (attached as .config)
compiler: powerpc64-linux-gnu-gcc (Debian 6.1.1-9) 6.1.1 20160705
reproduce:
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        make.cross ARCH=powerpc 

All error/warnings (new ones prefixed by >>):

   In file included from arch/powerpc/include/asm/nohash/pgtable.h:5:0,
                    from arch/powerpc/include/asm/pgtable.h:18,
                    from include/linux/memremap.h:7,
                    from include/linux/mm.h:26,
                    from arch/powerpc/xmon/xmon.c:18:
   arch/powerpc/xmon/xmon.c: In function 'show_pte':
>> arch/powerpc/include/asm/nohash/64/pgtable.h:158:40: error: right shift count >= width of type [-Werror=shift-count-overflow]
    #define pgd_index(address) (((address) >> (PGDIR_SHIFT)) & (PTRS_PER_PGD - 1))
                                           ^
>> arch/powerpc/include/asm/nohash/64/pgtable.h:160:47: note: in expansion of macro 'pgd_index'
    #define pgd_offset(mm, address)  ((mm)->pgd + pgd_index(address))
                                                  ^~~~~~~~~
>> arch/powerpc/include/asm/nohash/64/pgtable.h:173:31: note: in expansion of macro 'pgd_offset'
    #define pgd_offset_k(address) pgd_offset(&init_mm, address)
                                  ^~~~~~~~~~
>> arch/powerpc/xmon/xmon.c:2992:11: note: in expansion of macro 'pgd_offset_k'
      pgdir = pgd_offset_k(0);
              ^~~~~~~~~~~~
>> arch/powerpc/include/asm/nohash/64/pgtable.h:158:40: error: right shift count >= width of type [-Werror=shift-count-overflow]
    #define pgd_index(address) (((address) >> (PGDIR_SHIFT)) & (PTRS_PER_PGD - 1))
                                           ^
>> arch/powerpc/include/asm/nohash/64/pgtable.h:160:47: note: in expansion of macro 'pgd_index'
    #define pgd_offset(mm, address)  ((mm)->pgd + pgd_index(address))
                                                  ^~~~~~~~~
>> arch/powerpc/xmon/xmon.c:2995:11: note: in expansion of macro 'pgd_offset'
      pgdir = pgd_offset(mm, 0);
              ^~~~~~~~~~
   cc1: all warnings being treated as errors

vim +/pgd_offset +173 arch/powerpc/include/asm/nohash/64/pgtable.h

f281b5d5 arch/powerpc/include/asm/pgtable-ppc64.h Aneesh Kumar K.V 2015-12-01  153  
f88df14b include/asm-powerpc/pgtable-ppc64.h      David Gibson     2007-04-30  154  /*
f88df14b include/asm-powerpc/pgtable-ppc64.h      David Gibson     2007-04-30  155   * Find an entry in a page-table-directory.  We combine the address region
f88df14b include/asm-powerpc/pgtable-ppc64.h      David Gibson     2007-04-30  156   * (the high order N bits) and the pgd portion of the address.
f88df14b include/asm-powerpc/pgtable-ppc64.h      David Gibson     2007-04-30  157   */
0e5f35d0 arch/powerpc/include/asm/pgtable-ppc64.h Aneesh Kumar K.V 2013-04-28 @158  #define pgd_index(address) (((address) >> (PGDIR_SHIFT)) & (PTRS_PER_PGD - 1))
f88df14b include/asm-powerpc/pgtable-ppc64.h      David Gibson     2007-04-30  159  
f88df14b include/asm-powerpc/pgtable-ppc64.h      David Gibson     2007-04-30 @160  #define pgd_offset(mm, address)	 ((mm)->pgd + pgd_index(address))
f88df14b include/asm-powerpc/pgtable-ppc64.h      David Gibson     2007-04-30  161  
f88df14b include/asm-powerpc/pgtable-ppc64.h      David Gibson     2007-04-30  162  #define pmd_offset(pudp,addr) \
f88df14b include/asm-powerpc/pgtable-ppc64.h      David Gibson     2007-04-30  163    (((pmd_t *) pud_page_vaddr(*(pudp))) + (((addr) >> PMD_SHIFT) & (PTRS_PER_PMD - 1)))
f88df14b include/asm-powerpc/pgtable-ppc64.h      David Gibson     2007-04-30  164  
f88df14b include/asm-powerpc/pgtable-ppc64.h      David Gibson     2007-04-30  165  #define pte_offset_kernel(dir,addr) \
f88df14b include/asm-powerpc/pgtable-ppc64.h      David Gibson     2007-04-30  166    (((pte_t *) pmd_page_vaddr(*(dir))) + (((addr) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)))
f88df14b include/asm-powerpc/pgtable-ppc64.h      David Gibson     2007-04-30  167  
f88df14b include/asm-powerpc/pgtable-ppc64.h      David Gibson     2007-04-30  168  #define pte_offset_map(dir,addr)	pte_offset_kernel((dir), (addr))
f88df14b include/asm-powerpc/pgtable-ppc64.h      David Gibson     2007-04-30  169  #define pte_unmap(pte)			do { } while(0)
f88df14b include/asm-powerpc/pgtable-ppc64.h      David Gibson     2007-04-30  170  
f88df14b include/asm-powerpc/pgtable-ppc64.h      David Gibson     2007-04-30  171  /* to find an entry in a kernel page-table-directory */
f88df14b include/asm-powerpc/pgtable-ppc64.h      David Gibson     2007-04-30  172  /* This now only contains the vmalloc pages */
f88df14b include/asm-powerpc/pgtable-ppc64.h      David Gibson     2007-04-30 @173  #define pgd_offset_k(address) pgd_offset(&init_mm, address)
78f1dbde arch/powerpc/include/asm/pgtable-ppc64.h Aneesh Kumar K.V 2012-09-10  174  extern void hpte_need_flush(struct mm_struct *mm, unsigned long addr,
78f1dbde arch/powerpc/include/asm/pgtable-ppc64.h Aneesh Kumar K.V 2012-09-10  175  			    pte_t *ptep, unsigned long pte, int huge);
f88df14b include/asm-powerpc/pgtable-ppc64.h      David Gibson     2007-04-30  176  

:::::: The code at line 173 was first introduced by commit
:::::: f88df14b1f15cdeffa060580a40c1ce3e13bb79e [POWERPC] Remove arch/powerpc's dependence on asm-ppc/pg{alloc,table}.h

:::::: TO: David Gibson <david@gibson.dropbear.id.au>
:::::: CC: Paul Mackerras <paulus@samba.org>

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation
kbuild test robot Oct. 12, 2017, 10:20 a.m. | #2
Hi Balbir,

[auto build test ERROR on powerpc/next]
[also build test ERROR on v4.14-rc4 next-20171009]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Michael-Ellerman/powerpc-xmon-Support-dumping-software-pagetables/20171012-124024
base:   https://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux.git next
config: powerpc-ppc6xx_defconfig (attached as .config)
compiler: powerpc-linux-gnu-gcc (Debian 6.1.1-9) 6.1.1 20160705
reproduce:
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        make.cross ARCH=powerpc 

All error/warnings (new ones prefixed by >>):

   In file included from arch/powerpc/include/asm/book3s/pgtable.h:7:0,
                    from arch/powerpc/include/asm/pgtable.h:16,
                    from include/linux/memremap.h:7,
                    from include/linux/mm.h:26,
                    from arch/powerpc/xmon/xmon.c:18:
   arch/powerpc/xmon/xmon.c: In function 'show_pte':
>> arch/powerpc/include/asm/book3s/32/pgtable.h:282:13: error: implicit declaration of function 'kmap_atomic' [-Werror=implicit-function-declaration]
     ((pte_t *) kmap_atomic(pmd_page(*(dir))) + pte_index(addr))
                ^
>> arch/powerpc/xmon/xmon.c:3042:9: note: in expansion of macro 'pte_offset_map'
     ptep = pte_offset_map(pmdp, addr);
            ^~~~~~~~~~~~~~
   cc1: all warnings being treated as errors

vim +/pte_offset_map +3042 arch/powerpc/xmon/xmon.c

  3024	
  3025		printf("pudp @ 0x%016lx = 0x%016lx\n", pudp, pud_val(*pudp));
  3026	
  3027		pmdp = pmd_offset(pudp, addr);
  3028	
  3029		if (pmd_none(*pmdp)) {
  3030			printf("No valid PMD\n");
  3031			return;
  3032		}
  3033	
  3034	#ifdef CONFIG_HUGETLB_PAGE
  3035		if (pmd_huge(*pmdp)) {
  3036			format_pte(pmdp, pmd_val(*pmdp));
  3037			return;
  3038		}
  3039	#endif
  3040		printf("pmdp @ 0x%016lx = 0x%016lx\n", pmdp, pmd_val(*pmdp));
  3041	
> 3042		ptep = pte_offset_map(pmdp, addr);
  3043		if (pte_none(*ptep)) {
  3044			printf("no valid PTE\n");
  3045			return;
  3046		}
  3047	
  3048		format_pte(ptep, pte_val(*ptep));
  3049	
  3050		sync();
  3051		__delay(200);
  3052		catch_memory_errors = 0;
  3053	}
  3054	static void show_tasks(void)
  3055	{
  3056		unsigned long tskv;
  3057		struct task_struct *tsk = NULL;
  3058	
  3059		printf("     task_struct     ->thread.ksp    PID   PPID S  P CMD\n");
  3060	
  3061		if (scanhex(&tskv))
  3062			tsk = (struct task_struct *)tskv;
  3063	
  3064		if (setjmp(bus_error_jmp) != 0) {
  3065			catch_memory_errors = 0;
  3066			printf("*** Error dumping task %p\n", tsk);
  3067			return;
  3068		}
  3069	
  3070		catch_memory_errors = 1;
  3071		sync();
  3072	
  3073		if (tsk)
  3074			show_task(tsk);
  3075		else
  3076			for_each_process(tsk)
  3077				show_task(tsk);
  3078	
  3079		sync();
  3080		__delay(200);
  3081		catch_memory_errors = 0;
  3082	}
  3083	

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation
Balbir Singh Oct. 16, 2017, 2:49 a.m. | #3
On Thu, 12 Oct 2017 18:20:39 +0800
kbuild test robot <lkp@intel.com> wrote:

> Hi Balbir,
> 
> [auto build test ERROR on powerpc/next]
> [also build test ERROR on v4.14-rc4 next-20171009]
> [if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
> 
> url:    https://github.com/0day-ci/linux/commits/Michael-Ellerman/powerpc-xmon-Support-dumping-software-pagetables/20171012-124024
> base:   https://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux.git next
> config: powerpc-ppc6xx_defconfig (attached as .config)
> compiler: powerpc-linux-gnu-gcc (Debian 6.1.1-9) 6.1.1 20160705
> reproduce:
>         wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
>         chmod +x ~/bin/make.cross
>         # save the attached .config to linux build tree
>         make.cross ARCH=powerpc 
> 
> All error/warnings (new ones prefixed by >>):
> 
>    In file included from arch/powerpc/include/asm/book3s/pgtable.h:7:0,
>                     from arch/powerpc/include/asm/pgtable.h:16,
>                     from include/linux/memremap.h:7,
>                     from include/linux/mm.h:26,
>                     from arch/powerpc/xmon/xmon.c:18:
>    arch/powerpc/xmon/xmon.c: In function 'show_pte':
> >> arch/powerpc/include/asm/book3s/32/pgtable.h:282:13: error: implicit declaration of function 'kmap_atomic' [-Werror=implicit-function-declaration]  
>      ((pte_t *) kmap_atomic(pmd_page(*(dir))) + pte_index(addr))
>                 ^
> >> arch/powerpc/xmon/xmon.c:3042:9: note: in expansion of macro 'pte_offset_map'  
>      ptep = pte_offset_map(pmdp, addr);
>             ^~~~~~~~~~~~~~

for pte_offset_map() to work, we need linux/highmem.h to be included
in xmon.c.

Balbir Singh.
Aneesh Kumar K.V Oct. 16, 2017, 3:34 a.m. | #4
Michael Ellerman <mpe@ellerman.id.au> writes:

> From: Balbir Singh <bsingharora@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@gmail.com>
> [mpe: Bike shed the output format, show the pgdir]
> Signed-off-by: Michael Ellerman <mpe@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. 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.

-aneesh
Balbir Singh Oct. 16, 2017, 5:13 a.m. | #5
On Mon, Oct 16, 2017 at 2:34 PM, Aneesh Kumar K.V
<aneesh.kumar@linux.vnet.ibm.com> wrote:
> Michael Ellerman <mpe@ellerman.id.au> writes:
>
>> From: Balbir Singh <bsingharora@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@gmail.com>
>> [mpe: Bike shed the output format, show the pgdir]
>> Signed-off-by: Michael Ellerman <mpe@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
>
Aneesh Kumar K.V Oct. 16, 2017, 5:27 a.m. | #6
On 10/16/2017 10:43 AM, Balbir Singh wrote:
> On Mon, Oct 16, 2017 at 2:34 PM, Aneesh Kumar K.V
> <aneesh.kumar@linux.vnet.ibm.com> wrote:
>> Michael Ellerman <mpe@ellerman.id.au> writes:

>>> +
>>> +#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?
> 

__find_linux_pte doesn't require irq disabled. But i would suggest we 
add a comment there explaining why it is safe to use without being 
worried about irqs/THP split (ex: find_init_mm_pte()). Being in xmon we 
are safe there. We moved all the warning about irq disabled etc to 
higher level functions.

-aneesh

Patch

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
+
+	printf("pudp @ 0x%016lx = 0x%016lx\n", pudp, pud_val(*pudp));
+
+	pmdp = pmd_offset(pudp, addr);
+
+	if (pmd_none(*pmdp)) {
+		printf("No valid PMD\n");
+		return;
+	}
+
+#ifdef CONFIG_HUGETLB_PAGE
+	if (pmd_huge(*pmdp)) {
+		format_pte(pmdp, pmd_val(*pmdp));
+		return;
+	}
+#endif
+	printf("pmdp @ 0x%016lx = 0x%016lx\n", pmdp, pmd_val(*pmdp));
+
+	ptep = pte_offset_map(pmdp, addr);
+	if (pte_none(*ptep)) {
+		printf("no valid PTE\n");
+		return;
+	}
+
+	format_pte(ptep, pte_val(*ptep));
+
+	sync();
+	__delay(200);
+	catch_memory_errors = 0;
+}
 static void show_tasks(void)
 {
 	unsigned long tskv;