[PATCH 1/2] powerpc/xmon: support dumping software pagetables
Ram Pai
linuxram at us.ibm.com
Sat Jul 22 03:08:18 AEST 2017
On Fri, Jul 21, 2017 at 03:24:05PM +1000, Balbir Singh wrote:
> It would be nice to be able to dump page tables in a
> particular context
>
> Example use cases
>
> Dumping PTE contents to see the keys (useful for debugging)
>
> c0000000ba48c880 c0000000bab438b0 2677 2675 T 2 protection_keys
> 0:mon> ds c0000000ba48c880 0x7ffff7f70000
> translating tsk c0000000ba48c880, addr 7ffff7f70000
> G: 0xb95b6400 U: 0xb6334000 M: 0xb6543000 PA: 0x012c0000, PTE: 0xd4800000012c0504
>
> Dumping vmalloc space
>
> 0:mon> ds 0 d000000000000000
> translating tsk (null), addr d000000000000000
> G: 0x3d450400 U: 0xbc184000 M: 0x3d460000 PA: 0x7e010000, PTE: 0xc08000007e01018e
>
> I did not replicate the complex code of dump_pagetable and have no support
> for bolted linear mapping, thats why I've called it software pagetable
> dumping support. The format of the PTE can be expanded to add more useful
> information about the flags in the PTE if required.
yes. a nice way of dumping all the flags in the PTE will be handy.
especially; my favorite, protection key values.
>
> Signed-off-by: Balbir Singh <bsingharora at gmail.com>
> ---
> arch/powerpc/xmon/xmon.c | 97 ++++++++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 97 insertions(+)
>
> diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c
> index 08e367e..8aedfff 100644
> --- a/arch/powerpc/xmon/xmon.c
> +++ b/arch/powerpc/xmon/xmon.c
> @@ -126,6 +126,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);
> @@ -233,6 +234,7 @@ Commands:\n\
> #endif
> "\
> dr dump stream of raw bytes\n\
> + ds dump software PTEs\n\
> dt dump the tracing buffers (uses printk)\n\
> "
> #ifdef CONFIG_PPC_POWERNV
> @@ -2528,6 +2530,9 @@ dump(void)
> } else if (c == 't') {
> ftrace_dump(DUMP_ALL);
> tracing_on();
> + } else if (c == 's') {
> + /* dump software pte */
> + show_pte(adrs);
> } else if (c == 'r') {
> scanhex(&ndump);
> if (ndump == 0)
> @@ -2860,7 +2865,99 @@ static void show_task(struct task_struct *tsk)
> state, task_thread_info(tsk)->cpu,
> tsk->comm);
> }
> +void format_pte(unsigned long pte)
> +{
> + unsigned long pa = pte & PTE_RPN_MASK;
> +
> + printf("PA: 0x%08lx, PTE: 0x%08lx\n", pa, pte);
> +}
> +
> +static void show_pte(unsigned long tskv)
> +{
> + unsigned long addr = 0;
> + struct task_struct *tsk = NULL;
> + struct mm_struct *mm;
> + pgd_t *pgdp;
> + pud_t *pudp;
> + pmd_t *pmdp;
> + pte_t *ptep;
> +
> + tsk = (struct task_struct *)tskv;
> + if (tsk == NULL)
> + mm = &init_mm;
> + else
> + mm = tsk->active_mm;
> +
> + if (mm == NULL)
> + mm = &init_mm;
> +
> + if (!scanhex(&addr))
> + printf("need address to translate\n");
> +
> + 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);
> + else
> + pgdp = pgd_offset(mm, addr);
> +
> + if (pgd_none(*pgdp)) {
> + printf("no linux page table for address\n");
> + return;
> + }
>
> + if (pgd_huge(*pgdp)) {
> + format_pte(pgd_val(*pgdp));
> + return;
> + }
> + printf("G: 0x%8lx\t", pgd_val(*pgdp));
> +
> + pudp = pud_offset(pgdp, addr);
> +
> + if (pud_none(*pudp)) {
> + printf("No valid PUD\n");
> + return;
> + }
> +
> + if (pud_huge(*pudp)) {
> + format_pte(pud_val(*pudp));
> + return;
> + }
> + printf("U: 0x%8lx\t", pud_val(*pudp));
> +
> + pmdp = pmd_offset(pudp, addr);
> +
> + if (pmd_none(*pmdp)) {
> + printf("No valid PMD\n");
> + return;
> + }
> +
> + if (pmd_huge(*pmdp)) {
> + format_pte(pmd_val(*pmdp));
> + return;
> + }
> + printf("M: 0x%8lx\t", pmd_val(*pmdp));
> +
> + /* pte_offset_map is the same as pte_offset_kernel */
> + ptep = pte_offset_kernel(pmdp, addr);
> + if (pte_none(*ptep)) {
> + printf("no valid PTE\n");
> + return;
> + }
> +
> + format_pte(pte_val(*ptep));
> +
These two lines below always go togather. A nice macro
#define sync_delay() { sync(); __delay(200); }
can help.
> + sync();
> + __delay(200);
> + catch_memory_errors = 0;
> +}
> static void show_tasks(void)
> {
> unsigned long tskv;
> --
> 2.9.4
--
Ram Pai
More information about the Linuxppc-dev
mailing list