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(a)in.ibm.com>
---
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) {