Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

powerpc/xmon: Support dumping software pagetables

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, fix build failures]
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>

authored by

Balbir Singh and committed by
Michael Ellerman
80eff6c4 bf751e30

+116
+116
arch/powerpc/xmon/xmon.c
··· 28 28 #include <linux/bug.h> 29 29 #include <linux/nmi.h> 30 30 #include <linux/ctype.h> 31 + #include <linux/highmem.h> 31 32 32 33 #include <asm/debugfs.h> 33 34 #include <asm/ptrace.h> ··· 128 127 static void memex(void); 129 128 static int bsesc(void); 130 129 static void dump(void); 130 + static void show_pte(unsigned long); 131 131 static void prdump(unsigned long, long); 132 132 static int ppc_inst_dump(unsigned long, long, int); 133 133 static void dump_log_buf(void); ··· 236 234 #endif 237 235 "\ 238 236 dr dump stream of raw bytes\n\ 237 + dv dump virtual address translation \n\ 239 238 dt dump the tracing buffers (uses printk)\n\ 240 239 dtc dump the tracing buffers for current CPU (uses printk)\n\ 241 240 " ··· 2616 2613 dump_log_buf(); 2617 2614 } else if (c == 'o') { 2618 2615 dump_opal_msglog(); 2616 + } else if (c == 'v') { 2617 + /* dump virtual to physical translation */ 2618 + show_pte(adrs); 2619 2619 } else if (c == 'r') { 2620 2620 scanhex(&ndump); 2621 2621 if (ndump == 0) ··· 2951 2945 state, task_thread_info(tsk)->cpu, 2952 2946 tsk->comm); 2953 2947 } 2948 + 2949 + #ifdef CONFIG_PPC_BOOK3S_64 2950 + void format_pte(void *ptep, unsigned long pte) 2951 + { 2952 + printf("ptep @ 0x%016lx = 0x%016lx\n", (unsigned long)ptep, pte); 2953 + printf("Maps physical address = 0x%016lx\n", pte & PTE_RPN_MASK); 2954 + 2955 + printf("Flags = %s%s%s%s%s\n", 2956 + (pte & _PAGE_ACCESSED) ? "Accessed " : "", 2957 + (pte & _PAGE_DIRTY) ? "Dirty " : "", 2958 + (pte & _PAGE_READ) ? "Read " : "", 2959 + (pte & _PAGE_WRITE) ? "Write " : "", 2960 + (pte & _PAGE_EXEC) ? "Exec " : ""); 2961 + } 2962 + 2963 + static void show_pte(unsigned long addr) 2964 + { 2965 + unsigned long tskv = 0; 2966 + struct task_struct *tsk = NULL; 2967 + struct mm_struct *mm; 2968 + pgd_t *pgdp, *pgdir; 2969 + pud_t *pudp; 2970 + pmd_t *pmdp; 2971 + pte_t *ptep; 2972 + 2973 + if (!scanhex(&tskv)) 2974 + mm = &init_mm; 2975 + else 2976 + tsk = (struct task_struct *)tskv; 2977 + 2978 + if (tsk == NULL) 2979 + mm = &init_mm; 2980 + else 2981 + mm = tsk->active_mm; 2982 + 2983 + if (setjmp(bus_error_jmp) != 0) { 2984 + catch_memory_errors = 0; 2985 + printf("*** Error dumping pte for task %p\n", tsk); 2986 + return; 2987 + } 2988 + 2989 + catch_memory_errors = 1; 2990 + sync(); 2991 + 2992 + if (mm == &init_mm) { 2993 + pgdp = pgd_offset_k(addr); 2994 + pgdir = pgd_offset_k(0); 2995 + } else { 2996 + pgdp = pgd_offset(mm, addr); 2997 + pgdir = pgd_offset(mm, 0); 2998 + } 2999 + 3000 + if (pgd_none(*pgdp)) { 3001 + printf("no linux page table for address\n"); 3002 + return; 3003 + } 3004 + 3005 + printf("pgd @ 0x%016lx\n", pgdir); 3006 + 3007 + if (pgd_huge(*pgdp)) { 3008 + format_pte(pgdp, pgd_val(*pgdp)); 3009 + return; 3010 + } 3011 + printf("pgdp @ 0x%016lx = 0x%016lx\n", pgdp, pgd_val(*pgdp)); 3012 + 3013 + pudp = pud_offset(pgdp, addr); 3014 + 3015 + if (pud_none(*pudp)) { 3016 + printf("No valid PUD\n"); 3017 + return; 3018 + } 3019 + 3020 + if (pud_huge(*pudp)) { 3021 + format_pte(pudp, pud_val(*pudp)); 3022 + return; 3023 + } 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 + if (pmd_huge(*pmdp)) { 3035 + format_pte(pmdp, pmd_val(*pmdp)); 3036 + return; 3037 + } 3038 + printf("pmdp @ 0x%016lx = 0x%016lx\n", pmdp, pmd_val(*pmdp)); 3039 + 3040 + ptep = pte_offset_map(pmdp, addr); 3041 + if (pte_none(*ptep)) { 3042 + printf("no valid PTE\n"); 3043 + return; 3044 + } 3045 + 3046 + format_pte(ptep, pte_val(*ptep)); 3047 + 3048 + sync(); 3049 + __delay(200); 3050 + catch_memory_errors = 0; 3051 + } 3052 + #else 3053 + static void show_pte(unsigned long addr) 3054 + { 3055 + printf("show_pte not yet implemented\n"); 3056 + } 3057 + #endif /* CONFIG_PPC_BOOK3S_64 */ 2954 3058 2955 3059 static void show_tasks(void) 2956 3060 {