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, the size of a PTE and also the various Page flags.
This patch also changes the pte to ulonglong type.
mach command now displays the platform string read from the kernel.
crash> mach
MACHINE TYPE: ppc
PLATFORM: ppc440gp
MEMORY SIZE: 128 MB
...
Signed-off-by: Suzuki K. Poulose <suzuki(a)in.ibm.com>
---
defs.h | 82 ++++++++++++++++++++++++++++++++++---------
ppc.c | 123 +++++++++++++++++++++++++++++++++++++++++++++++++++++++---------
2 files changed, 171 insertions(+), 34 deletions(-)
diff --git a/defs.h b/defs.h
index a942dbb..0c5558e 100755
--- a/defs.h
+++ b/defs.h
@@ -2635,27 +2635,50 @@ struct load_module {
#define _32BIT_
#define MACHINE_TYPE "PPC"
-#define PAGEBASE(X) (((ulong)(X)) & (ulong)machdep->pagemask)
+#define PAGEBASE(X) ((X) & machdep->pagemask)
#define PTOV(X) ((unsigned long)(X)+(machdep->kvbase))
#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)
-
-#define _PAGE_PRESENT 0x001 /* software: pte contains a translation */
-#define _PAGE_USER 0x002 /* matches one of the PP bits */
-#define _PAGE_RW 0x004 /* software: user write access allowed */
-#define _PAGE_GUARDED 0x008
-#define _PAGE_COHERENT 0x010 /* M: enforce memory coherence (SMP systems) */
-#define _PAGE_NO_CACHE 0x020 /* I: cache inhibit */
-#define _PAGE_WRITETHRU 0x040 /* W: cache write-through */
-#define _PAGE_DIRTY 0x080 /* C: page changed */
-#define _PAGE_ACCESSED 0x100 /* R: page referenced */
-#define _PAGE_HWWRITE 0x200 /* software: _PAGE_RW & _PAGE_DIRTY */
-#define _PAGE_SHARED 0
+/* Page translation bits */
+#define PPC_PLATFORM (machdep->machspec->platform)
+#define PGDIR_SHIFT (machdep->machspec->pgdir_shift)
+#define PTRS_PER_PTE (machdep->machspec->ptrs_per_pte)
+#define PTRS_PER_PGD (machdep->machspec->ptrs_per_pgd)
+#define PTE_SIZE (machdep->machspec->pte_size)
+
+/* Default values for Page translation */
+#define DEFAULT_PGDIR_SHIFT (22)
+#define DEFAULT_PTRS_PER_PTE (1024)
+#define DEFAULT_PTRS_PER_PGD (1024)
+#define DEFAULT_PTE_SIZE sizeof(ulong)
+
+/* PAGE flags */
+#define _PAGE_PRESENT (machdep->machspec->_page_present) /* software: pte
contains a translation */
+#define _PAGE_USER (machdep->machspec->_page_user) /* matches one of the PP
bits */
+#define _PAGE_RW (machdep->machspec->_page_rw) /* software: user write
access allowed */
+#define _PAGE_GUARDED (machdep->machspec->_page_guarded)
+#define _PAGE_COHERENT (machdep->machspec->_page_coherent /* M: enforce memory
coherence (SMP systems) */)
+#define _PAGE_NO_CACHE (machdep->machspec->_page_no_cache) /* I: cache inhibit */
+#define _PAGE_WRITETHRU (machdep->machspec->_page_writethru) /* W: cache
write-through */
+#define _PAGE_DIRTY (machdep->machspec->_page_dirty) /* C: page changed */
+#define _PAGE_ACCESSED (machdep->machspec->_page_accessed) /* R: page referenced
*/
+#define _PAGE_HWWRITE (machdep->machspec->_page_hwwrite) /* software: _PAGE_RW
& _PAGE_DIRTY */
+#define _PAGE_SHARED (machdep->machspec->_page_shared)
+
+/* Default values for PAGE flags */
+#define DEFAULT_PAGE_PRESENT 0x001
+#define DEFAULT_PAGE_USER 0x002
+#define DEFAULT_PAGE_RW 0x004
+#define DEFAULT_PAGE_GUARDED 0x008
+#define DEFAULT_PAGE_COHERENT 0x010
+#define DEFAULT_PAGE_NO_CACHE 0x020
+#define DEFAULT_PAGE_WRITETHRU 0x040
+#define DEFAULT_PAGE_DIRTY 0x080
+#define DEFAULT_PAGE_ACCESSED 0x100
+#define DEFAULT_PAGE_HWWRITE 0x200
+#define DEFAULT_PAGE_SHARED 0
#define SWP_TYPE(entry) (((entry) >> 1) & 0x7f)
#define SWP_OFFSET(entry) ((entry) >> 8)
@@ -4533,6 +4556,33 @@ void ppc64_dump_machdep_table(ulong);
* ppc.c
*/
#ifdef PPC
+
+/* Holds the platform specific info for page translation */
+struct machine_specific {
+
+ char *platform;
+
+ /* page address translation bits */
+ int pgdir_shift;
+ int ptrs_per_pgd;
+ int ptrs_per_pte;
+ int pte_size;
+
+ /* page flags */
+ ulong _page_present;
+ ulong _page_user;
+ ulong _page_rw;
+ ulong _page_guarded;
+ ulong _page_coherent;
+ ulong _page_no_cache;
+ ulong _page_writethru;
+ ulong _page_dirty;
+ ulong _page_accessed;
+ ulong _page_hwwrite;
+ ulong _page_shared;
+
+};
+
void ppc_init(int);
void ppc_dump_machdep_table(ulong);
#define display_idt_table() \
diff --git a/ppc.c b/ppc.c
index 3834e7f..9f765b6 100755
--- a/ppc.c
+++ b/ppc.c
@@ -17,6 +17,9 @@
#ifdef PPC
#include "defs.h"
+
+#define MAX_PLATFORM_LEN 32 /* length for platform string */
+
/*
* This structure was copied from kernel source
* in include/asm-ppc/ptrace.h
@@ -67,6 +70,71 @@ static void ppc_display_machine_stats(void);
static void ppc_dump_line_number(ulong);
static struct line_number_hook ppc_line_number_hooks[];
+
+static struct machine_specific ppc_machine_specific = { 0 };
+static int probe_default_platform(char *);
+static void ppc_probe_base_platform(void);
+
+typedef int (*probe_func_t) (char *);
+
+probe_func_t probe_platforms[] = {
+ probe_default_platform, /* This should be at the end */
+ NULL
+};
+
+static int
+probe_default_platform(char *name)
+{
+ struct machine_specific *machspec = machdep->machspec;
+
+ /* Use the default definitions */
+ machspec->platform = strdup(name);
+
+ machspec->pgdir_shift = DEFAULT_PGDIR_SHIFT;
+ machspec->ptrs_per_pgd = DEFAULT_PTRS_PER_PGD;
+ machspec->ptrs_per_pte = DEFAULT_PTRS_PER_PTE;
+ machspec->pte_size = DEFAULT_PTE_SIZE;
+
+ machspec->_page_present = DEFAULT_PAGE_PRESENT;
+ machspec->_page_user = DEFAULT_PAGE_USER;
+ machspec->_page_rw = DEFAULT_PAGE_RW;
+ machspec->_page_guarded = DEFAULT_PAGE_GUARDED;
+ machspec->_page_coherent = DEFAULT_PAGE_COHERENT;
+ machspec->_page_no_cache = DEFAULT_PAGE_NO_CACHE;
+ machspec->_page_writethru = DEFAULT_PAGE_WRITETHRU;
+ machspec->_page_dirty = DEFAULT_PAGE_DIRTY;
+ machspec->_page_accessed = DEFAULT_PAGE_ACCESSED;
+ machspec->_page_hwwrite = DEFAULT_PAGE_HWWRITE;
+ machspec->_page_shared = DEFAULT_PAGE_SHARED;
+
+
+ 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))
+ break;
+ }
+}
+
/*
* Do all necessary machine-specific setup here. This is called twice,
* before and after GDB has been initialized.
@@ -80,6 +148,7 @@ ppc_init(int when)
switch (when)
{
case SETUP_ENV:
+ machdep->machspec = &ppc_machine_specific;
machdep->process_elf_notes = process_elf32_notes;
break;
@@ -101,7 +170,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 +195,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:
@@ -201,6 +274,7 @@ ppc_dump_machdep_table(ulong arg)
int others;
others = 0;
+ fprintf(fp, " platform: %s\n", PPC_PLATFORM);
fprintf(fp, " flags: %lx (", machdep->flags);
if (machdep->flags & KSYMS_START)
fprintf(fp, "%sKSYMS_START", others++ ? "|" : "");
@@ -212,6 +286,10 @@ ppc_dump_machdep_table(ulong arg)
fprintf(fp, " pageshift: %d\n", machdep->pageshift);
fprintf(fp, " pagemask: %llx\n", machdep->pagemask);
fprintf(fp, " pageoffset: %lx\n", machdep->pageoffset);
+ fprintf(fp, " pgdir_shift: %d\n", PGDIR_SHIFT);
+ fprintf(fp, " ptrs_per_pgd: %d\n", PTRS_PER_PGD);
+ fprintf(fp, " ptrs_per_pte: %d\n", PTRS_PER_PTE);
+ fprintf(fp, " pte_size: %d\n", PTE_SIZE);
fprintf(fp, " stacksize: %ld\n", machdep->stacksize);
fprintf(fp, " hz: %d\n", machdep->hz);
fprintf(fp, " mhz: %ld\n", machdep->mhz);
@@ -252,7 +330,6 @@ ppc_dump_machdep_table(ulong arg)
fprintf(fp, " pgd: %lx\n", (ulong)machdep->pgd);
fprintf(fp, " pmd: %lx\n", (ulong)machdep->pmd);
fprintf(fp, " ptbl: %lx\n", (ulong)machdep->ptbl);
- fprintf(fp, " ptrs_per_pgd: %d\n", machdep->ptrs_per_pgd);
fprintf(fp, " section_size_bits: %ld\n",
machdep->section_size_bits);
fprintf(fp, " max_physmem_bits: %ld\n",
machdep->max_physmem_bits);
fprintf(fp, " sections_per_root: %ld\n",
machdep->sections_per_root);
@@ -266,15 +343,20 @@ 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, "PAGE DIRECTORY: %lx\n", (ulong)pgd);
page_dir = pgd + (vaddr >> PGDIR_SHIFT);
- FILL_PGD(PAGEBASE(pgd), KVADDR, PAGESIZE());
- pgd_pte = ULONG(machdep->pgd + PAGEOFFSET(page_dir));
+ /*
+ * 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((ulong)page_dir), KVADDR, PAGESIZE());
+ pgd_pte = ULONG(machdep->pgd + PAGEOFFSET((ulong)page_dir));
if (verbose)
fprintf(fp, " PGD: %lx => %lx\n", (ulong)page_dir, pgd_pte);
@@ -285,33 +367,37 @@ 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)
fprintf(fp, " PMD: %lx => %lx\n", (ulong)page_middle,
(ulong)page_table);
- FILL_PTBL(PAGEBASE(page_table), KVADDR, PAGESIZE());
- pte = ULONG(machdep->ptbl + PAGEOFFSET(page_table));
+ FILL_PTBL(PAGEBASE((ulong)page_table), KVADDR, PAGESIZE());
+ if (PTE_SIZE == sizeof(ulonglong))
+ pte = ULONGLONG(machdep->ptbl + PAGEOFFSET((ulong)page_table));
+
+ else /* Defaults to ulong */
+ pte = ULONG(machdep->ptbl + PAGEOFFSET((ulong)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) {
fprintf(fp, "\n");
- ppc_translate_pte(pte, 0, 0);
+ ppc_translate_pte(0, 0, pte);
}
goto no_page;
}
if (verbose) {
- fprintf(fp, " PAGE: %lx\n\n", PAGEBASE(pte));
- ppc_translate_pte(pte, 0, 0);
+ fprintf(fp, " PAGE: %llx\n\n", PAGEBASE(pte));
+ ppc_translate_pte(0, 0, pte);
}
*paddr = PAGEBASE(pte) + PAGEOFFSET(vaddr);
@@ -623,7 +709,7 @@ ppc_get_task_pgd(ulong task)
* If a physaddr pointer is passed in, don't print anything.
*/
static int
-ppc_translate_pte(ulong pte, void *physaddr, ulonglong unused)
+ppc_translate_pte(ulong unused, void *physaddr, ulonglong pte)
{
int c, len1, len2, len3, others, page_present;
char buf[BUFSIZE];
@@ -632,7 +718,7 @@ ppc_translate_pte(ulong pte, void *physaddr, ulonglong unused)
char ptebuf[BUFSIZE];
char physbuf[BUFSIZE];
char *arglist[MAXARGS];
- ulong paddr;
+ ulonglong paddr;
paddr = PAGEBASE(pte);
page_present = (pte & _PAGE_PRESENT);
@@ -642,7 +728,7 @@ ppc_translate_pte(ulong pte, void *physaddr, ulonglong unused)
return page_present;
}
- sprintf(ptebuf, "%lx", pte);
+ sprintf(ptebuf, "%llx", pte);
len1 = MAX(strlen(ptebuf), strlen("PTE"));
fprintf(fp, "%s ", mkstring(buf, len1, CENTER|LJUST, "PTE"));
@@ -668,7 +754,7 @@ ppc_translate_pte(ulong pte, void *physaddr, ulonglong unused)
return page_present;
}
- sprintf(physbuf, "%lx", paddr);
+ sprintf(physbuf, "%llx", paddr);
len2 = MAX(strlen(physbuf), strlen("PHYSICAL"));
fprintf(fp, "%s ", mkstring(buf, len2, CENTER|LJUST, "PHYSICAL"));
@@ -1509,6 +1595,7 @@ ppc_display_machine_stats(void)
uts = &kt->utsname;
fprintf(fp, " MACHINE TYPE: %s\n", uts->machine);
+ fprintf(fp, " PLATFORM: %s\n", PPC_PLATFORM);
fprintf(fp, " MEMORY SIZE: %s\n", get_memory_size(buf));
fprintf(fp, " CPUS: %d\n", kt->cpus);
fprintf(fp, " PROCESSOR SPEED: ");