[Crash-utility] [PATCH 2/2] ARM: add support for the new page table format introduced in 2.6.38

Mika Westerberg ext-mika.1.westerberg at nokia.com
Fri Jan 28 08:17:04 UTC 2011


Starting from 2.6.38 ARM hardware and Linux page tables switched place. There
were also some smaller changes to the PTE bits.  This patch makes crash to cope
with those changes.

Signed-off-by: Mika Westerberg <ext-mika.1.westerberg at nokia.com>
---
Dave,

Are you interested in having a reference vmlinux/vmcore pair for .38 ARM
kernels? I can try to arrange such if needed and provide download url in
a private email.

Regards,
MW


 arm.c  |   63 ++++++++++++++++++++++++++++++++++++++++++++++++++++++---------
 defs.h |    1 +
 2 files changed, 55 insertions(+), 9 deletions(-)

diff --git a/arm.c b/arm.c
index 1752f62..0347166 100644
--- a/arm.c
+++ b/arm.c
@@ -6,7 +6,7 @@
  *   Jan Karlsson <jan.karlsson at sonyericsson.com>
  *   Mika Westerberg <ext-mika.1.westerberg at nokia.com>
  *
- * Copyright (C) 2010 Nokia Corporation
+ * Copyright (C) 2010-2011 Nokia Corporation
  * Copyright (C) 2010 Sony Ericsson. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
@@ -88,8 +88,12 @@ pmd_page_addr(ulong pmd)
 {
 	ulong ptr;
 
-	ptr = pmd & ~(PTRS_PER_PTE * sizeof(void *) - 1);
-	ptr += PTRS_PER_PTE * sizeof(void *);
+	if (machdep->flags & PGTABLE_V2) {
+		ptr = PAGEBASE(pmd);
+	} else {
+		ptr = pmd & ~(PTRS_PER_PTE * sizeof(void *) - 1);
+		ptr += PTRS_PER_PTE * sizeof(void *);
+	}
 
 	return (ulong *)ptr;
 }
@@ -102,16 +106,21 @@ pmd_page_addr(ulong pmd)
 #define L_PTE_FILE		(1 << 2)
 #define L_PTE_DIRTY		(1 << 6)
 #define L_PTE_WRITE		(1 << 7)
+#define L_PTE_RDONLY		L_PTE_WRITE
 #define L_PTE_USER		(1 << 8)
 #define L_PTE_EXEC		(1 << 9)
+#define L_PTE_XN		L_PTE_EXEC
 #define L_PTE_SHARED		(1 << 10)
 
 #define pte_val(pte)		(pte)
 
 #define pte_present(pte)	(pte_val(pte) & L_PTE_PRESENT)
 #define pte_write(pte)		(pte_val(pte) & L_PTE_WRITE)
+#define pte_rdonly(pte)		(pte_val(pte) & L_PTE_RDONLY)
 #define pte_dirty(pte)		(pte_val(pte) & L_PTE_DIRTY)
 #define pte_young(pte)		(pte_val(pte) & L_PTE_YOUNG)
+#define pte_exec(pte)		(pte_val(pte) & L_PTE_EXEC)
+#define pte_xn(pte)		(pte_val(pte) & L_PTE_XN)
 
 /*
  * Following stuff is taken directly from the kernel sources. These are used in
@@ -241,6 +250,16 @@ arm_init(int when)
 		break;
 
 	case POST_GDB:
+		/*
+		 * Starting from 2.6.38 hardware and Linux page tables
+		 * were reordered. See also mainline kernel commit
+		 * d30e45eeabe (ARM: pgtable: switch order of Linux vs
+		 * hardware page tables).
+		 */
+		if (THIS_KERNEL_VERSION > LINUX(2,6,37) ||
+		    STRUCT_EXISTS("pteval_t"))
+			machdep->flags |= PGTABLE_V2;
+
 		if (symbol_exists("irq_desc"))
 			ARRAY_LENGTH_INIT(machdep->nr_irqs, irq_desc,
 					  "irq_desc", NULL, 0);
@@ -313,6 +332,8 @@ arm_dump_machdep_table(ulong arg)
 		fprintf(fp, "%sKSYMS_START", others++ ? "|" : "");
 	if (machdep->flags & PHYS_BASE)
 		fprintf(fp, "%sPHYS_BASE", others++ ? "|" : "");
+	if (machdep->flags & PGTABLE_V2)
+		fprintf(fp, "%sPGTABLE_V2", others++ ? "|" : "");
         fprintf(fp, ")\n");
 
 	fprintf(fp, "             kvbase: %lx\n", machdep->kvbase);
@@ -823,12 +844,21 @@ arm_translate_pte(ulong pte, void *physaddr, ulonglong pae_pte)
 	if (pte) {
 		if (pte_present(pte))
 			fprintf(fp, "%sPRESENT", others++ ? "|" : "");
-		if (pte_write(pte))
-			fprintf(fp, "%sWRITE", others++ ? "|" : "");
 		if (pte_dirty(pte))
 			fprintf(fp, "%sDIRTY", others++ ? "|" : "");
 		if (pte_young(pte))
 			fprintf(fp, "%sYOUNG", others++ ? "|" : "");
+		if (machdep->flags & PGTABLE_V2) {
+			if (!pte_rdonly(pte))
+				fprintf(fp, "%sWRITE", others++ ? "|" : "");
+			if (!pte_xn(pte))
+				fprintf(fp, "%sEXEC", others++ ? "|" : "");
+		} else {
+			if (pte_write(pte))
+				fprintf(fp, "%sWRITE", others++ ? "|" : "");
+			if (pte_exec(pte))
+				fprintf(fp, "%sEXEC", others++ ? "|" : "");
+		}
 	} else {
 		fprintf(fp, "no mapping");
 	}
@@ -863,6 +893,8 @@ arm_vtop(ulong vaddr, ulong *pgd, physaddr_t *paddr, int verbose)
 	 * that in ARM Linux we have following setup (see also
 	 * arch/arm/include/asm/pgtable.h)
 	 *
+	 * Before 2.6.38
+	 *
 	 *     PGD                   PTE
 	 * +---------+
 	 * |         | 0  ---->  +------------+
@@ -875,15 +907,28 @@ arm_vtop(ulong vaddr, ulong *pgd, physaddr_t *paddr, int verbose)
 	 * |         | 4095      | Linux pt 1 |
 	 * +---------+           +------------+ +4096
 	 *
+	 * Starting from 2.6.38
+	 *
+	 *     PGD                   PTE
+	 * +---------+
+	 * |         | 0  ---->  +------------+
+	 * +- - - - -+           | Linux pt 0 |
+	 * |         | 4  ---->  +------------+ +1024
+	 * +- - - - -+           | Linux pt 1 |
+	 * .         .           +------------+ +2048
+	 * .         .           | h/w pt 0   |
+	 * .         .           +------------+ +3072
+	 * |         | 4095      | h/w pt 1   |
+	 * +---------+           +------------+ +4096
+	 *
 	 * So in Linux implementation we have two hardware pointers to second
-	 * level page tables. After these come "Linux" versions of the page
-	 * tables.
+	 * level page tables. Depending on the kernel version, the "Linux" page
+	 * tables either follow or precede the hardware tables.
 	 *
 	 * Linux PT entries contain bits that are not supported on hardware, for
 	 * example "young" and "dirty" flags.
 	 *
-	 * Our translation scheme only uses Linux PTEs here. Hardware entries
-	 * are 1024 bytes below Linux versions.
+	 * Our translation scheme only uses Linux PTEs here.
 	 */
 
 	if (verbose)
diff --git a/defs.h b/defs.h
index 22f876b..e1b7d01 100755
--- a/defs.h
+++ b/defs.h
@@ -4097,6 +4097,7 @@ struct arm_pt_regs {
 
 #define KSYMS_START	(0x1)
 #define PHYS_BASE	(0x2)
+#define PGTABLE_V2	(0x4)
 
 struct machine_specific {
 	ulong phys_base;
-- 
1.7.3.2




More information about the Crash-utility mailing list