This patch adds infrastructure for defining Virtual address translation bits for each platform and use the specific definition for the platform depending on the 'powerpc_base_platform' variable. If a matching platform is not found, fallbacks to the default definition. Each platform can define a probe function which can identify the 'kernel platform string' to one of its variant. It can then update PGDIR_SHIFT, PTRS_PER_PGD, PTRS_PER_PTE and the size of a PTE. The patch also adds support 64bit ptes. Signed-off-by: Suzuki K. Poulose <suzuki@xxxxxxxxxx> --- defs.h | 14 ++++++++-- ppc.c | 93 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 96 insertions(+), 11 deletions(-) diff --git a/defs.h b/defs.h index a942dbb..603a583 100755 --- a/defs.h +++ b/defs.h @@ -2641,9 +2641,17 @@ struct load_module { #define VTOP(X) ((unsigned long)(X)-(machdep->kvbase)) #define IS_VMALLOC_ADDR(X) (vt->vmalloc_start && (ulong)(X) >= vt->vmalloc_start) -#define PGDIR_SHIFT (22) -#define PTRS_PER_PTE (1024) -#define PTRS_PER_PGD (1024) +/* Default values for PPC */ +#define DEFAULT_PGDIR_SHIFT (22) +#define DEFAULT_PTRS_PER_PTE (1024) +#define DEFAULT_PTRS_PER_PGD (1024) +#define DEFAULT_PTE_SIZE sizeof(ulong) + + +#define PGDIR_SHIFT (base_platform.pgdir_shift) +#define PTRS_PER_PTE (base_platform.ptrs_per_pte) +#define PTRS_PER_PGD (base_platform.ptrs_per_pgd) +#define PTE_SIZE (base_platform.pte_size) #define _PAGE_PRESENT 0x001 /* software: pte contains a translation */ #define _PAGE_USER 0x002 /* matches one of the PP bits */ diff --git a/ppc.c b/ppc.c index 3834e7f..0e934ca 100755 --- a/ppc.c +++ b/ppc.c @@ -17,6 +17,21 @@ #ifdef PPC #include "defs.h" + +#define MAX_PLATFORM_LEN 32 /* length for platform string */ + +/* + * The following struct would hold the page translation information + * for the platform determined at runtime by ppc_probe_base_platform(). + */ +struct platform { + char *name; + int pgdir_shift; + int ptrs_per_pgd; + int ptrs_per_pte; + int pte_size; +} base_platform; + /* * This structure was copied from kernel source * in include/asm-ppc/ptrace.h @@ -67,6 +82,53 @@ static void ppc_display_machine_stats(void); static void ppc_dump_line_number(ulong); static struct line_number_hook ppc_line_number_hooks[]; +static int probe_default_platform(char *, struct platform *); +static void ppc_probe_base_platform(void); + +typedef int (*probe_func_t) (char *, struct platform *); + +probe_func_t probe_platforms[] = { + probe_default_platform, /* This should be at the end */ + NULL +}; + +static int +probe_default_platform(char *name, struct platform *p) +{ + /* Use the default definitions */ + p->pgdir_shift = DEFAULT_PGDIR_SHIFT; + p->ptrs_per_pgd = DEFAULT_PTRS_PER_PGD; + p->ptrs_per_pte = DEFAULT_PTRS_PER_PTE; + p->pte_size = DEFAULT_PTE_SIZE; + p->name = strdup("default"); + + return TRUE; +} + +/* + * Find the platform of the crashing system and set the + * base_platform accordingly. + */ +void +ppc_probe_base_platform(void) +{ + probe_func_t probe; + char platform_name[MAX_PLATFORM_LEN]; + ulong ptr; + int i; + + if(!try_get_symbol_data("powerpc_base_platform", sizeof(ulong), &ptr) || + read_string(ptr, platform_name, MAX_PLATFORM_LEN - 1) == 0) + /* Let us fallback to default definitions */ + platform_name[0] = '\0'; + + for (i = 0; probe_platforms[i] != NULL; i++) { + probe = probe_platforms[i]; + if (probe(platform_name, &base_platform)) + break; + } +} + /* * Do all necessary machine-specific setup here. This is called twice, * before and after GDB has been initialized. @@ -101,7 +163,6 @@ ppc_init(int when) machdep->last_pmd_read = 0; machdep->last_ptbl_read = 0; machdep->verify_paddr = generic_verify_paddr; - machdep->ptrs_per_pgd = PTRS_PER_PGD; break; case PRE_GDB: @@ -127,6 +188,11 @@ ppc_init(int when) machdep->line_number_hooks = ppc_line_number_hooks; machdep->value_to_symbol = generic_machdep_value_to_symbol; machdep->init_kernel_pgd = NULL; + + /* Find the platform where we crashed */ + ppc_probe_base_platform(); + machdep->ptrs_per_pgd = PTRS_PER_PGD; + break; case POST_GDB: @@ -266,14 +332,21 @@ ppc_pgd_vtop(ulong *pgd, ulong vaddr, physaddr_t *paddr, int verbose) ulong *page_middle; ulong *page_table; ulong pgd_pte; - ulong pte; + ulonglong pte; - if (verbose) + if (verbose) { + fprintf(fp, "Using %s board definitions:\n", base_platform.name); fprintf(fp, "PAGE DIRECTORY: %lx\n", (ulong)pgd); + } page_dir = pgd + (vaddr >> PGDIR_SHIFT); - FILL_PGD(PAGEBASE(pgd), KVADDR, PAGESIZE()); + /* + * Size of a pgd could be more than a PAGE. + * So use PAGEBASE(page_dir), instead of + * PAGEBASE(pgd) for FILL_PGD() + */ + FILL_PGD(PAGEBASE(page_dir), KVADDR, PAGESIZE()); pgd_pte = ULONG(machdep->pgd + PAGEOFFSET(page_dir)); if (verbose) @@ -285,10 +358,10 @@ ppc_pgd_vtop(ulong *pgd, ulong vaddr, physaddr_t *paddr, int verbose) page_middle = (ulong *)pgd_pte; if (machdep->flags & CPU_BOOKE) - page_table = page_middle + (BTOP(vaddr) & (PTRS_PER_PTE - 1)); + page_table = (ulong *)((ulong)page_middle + ((ulong)BTOP(vaddr) & (PTRS_PER_PTE - 1)) * PTE_SIZE); else { page_table = (ulong *)((pgd_pte & (ulong)machdep->pagemask) + machdep->kvbase); - page_table += ((ulong)BTOP(vaddr) & (PTRS_PER_PTE-1)); + page_table = (ulong *)((ulong)page_table + ((ulong)BTOP(vaddr) & (PTRS_PER_PTE-1)) * PTE_SIZE); } if (verbose) @@ -296,10 +369,14 @@ ppc_pgd_vtop(ulong *pgd, ulong vaddr, physaddr_t *paddr, int verbose) (ulong)page_table); FILL_PTBL(PAGEBASE(page_table), KVADDR, PAGESIZE()); - pte = ULONG(machdep->ptbl + PAGEOFFSET(page_table)); + if (PTE_SIZE == sizeof(ulonglong)) + pte = ULONGLONG(machdep->ptbl + PAGEOFFSET(page_table)); + + else /* Defaults to ulong */ + pte = ULONG(machdep->ptbl + PAGEOFFSET(page_table)); if (verbose) - fprintf(fp, " PTE: %lx => %lx\n", (ulong)page_table, pte); + fprintf(fp, " PTE: %lx => %llx\n", (ulong)page_table, pte); if (!(pte & _PAGE_PRESENT)) { if (pte && verbose) { -- Crash-utility mailing list Crash-utility@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/crash-utility