[Crash-utility] [PATCH] IA-64 4-level page table support

Troy Heber troy.heber at hp.com
Tue Aug 1 16:10:48 UTC 2006


Attached is a patch that adds 4-level page table support to the IA-64
architecture. I followed the way PPC used the machdep command line
argument to force it. Since this is truly a CONFIG option on IA-64, I
have also added a routine to parse the required information out of
IKCONFIG if it's available. I'm thinking about requiring IKCONFIG for
LKCD, because it just makes life easer.

As a side note, I decided I hate how everything is piled into defs.h
and separated by ifdefs. Dave, how do you feel about breaking defs.h
up into a header for each arch, i.e. ia64_defs.h, ppc_def.h, etc, and
a small common defs.h?

Thanks,

Troy
-------------- next part --------------
diff -urpN -urN -X /root/dontdiff orig/defs.h crash-4.0-2.33/defs.h
--- orig/defs.h	2006-07-13 12:51:50.000000000 -0600
+++ crash-4.0-2.33/defs.h	2006-08-01 09:04:01.000000000 -0600
@@ -701,9 +701,11 @@ struct machdep_table {
         	char **file;
 	} *line_number_hooks;
 	ulong last_pgd_read;
+	ulong last_pud_read;
 	ulong last_pmd_read;
 	ulong last_ptbl_read;
 	char *pgd;
+	char *pud;
  	char *pmd;	
 	char *ptbl;
 	int ptrs_per_pgd;
@@ -717,6 +719,7 @@ struct machdep_table {
 	void (*get_xendump_regs)(struct xendump_data *, struct bt_info *, ulong *, ulong *);
 	void (*clear_machdep_cache)(void);
 	int (*xen_kdump_p2m_create)(struct xen_kdump_data *);
+	int nr_cpus;
 };
 
 /*
@@ -735,6 +738,7 @@ extern struct machdep_table *machdep;
 #define IS_LAST_PGD_READ(pgd)     ((ulong)(pgd) == machdep->last_pgd_read)
 #define IS_LAST_PMD_READ(pmd)     ((ulong)(pmd) == machdep->last_pmd_read)
 #define IS_LAST_PTBL_READ(ptbl)   ((ulong)(ptbl) == machdep->last_ptbl_read)
+#define IS_LAST_PUD_READ(pud)     ((ulong)(pud) == machdep->last_pud_read)
 
 #define FILL_PGD(PGD, TYPE, SIZE) 					    \
     if (!IS_LAST_PGD_READ(PGD)) {                                           \
@@ -743,6 +747,13 @@ extern struct machdep_table *machdep;
             machdep->last_pgd_read = (ulong)(PGD);                          \
     }								            
 
+#define FILL_PUD(PUD, TYPE, SIZE) 					    \
+    if (!IS_LAST_PUD_READ(PUD)) {                                           \
+            readmem((ulonglong)((ulong)(PUD)), TYPE, machdep->pud,          \
+                    SIZE, "pud page", FAULT_ON_ERROR);                      \
+            machdep->last_pud_read = (ulong)(PUD);                          \
+    }
+
 #define FILL_PMD(PMD, TYPE, SIZE)			                    \
     if (!IS_LAST_PMD_READ(PMD)) {                                           \
             readmem((ulonglong)(PMD), TYPE, machdep->pmd,                   \
@@ -2117,16 +2128,57 @@ struct load_module {
 
 #define SWITCH_STACK_ADDR(X)  (ia64_get_switch_stack((ulong)(X)))
 
-#define PGDIR_SHIFT     (PAGESHIFT() + 2*(PAGESHIFT()-3))
-#define PMD_SHIFT       (PAGESHIFT() + (PAGESHIFT()-3))
-#define PTRS_PER_PGD    (((ulong)(1)) << (PAGESHIFT()-3))
-#define PTRS_PER_PMD    (((ulong)(1)) << (PAGESHIFT()-3))
-#define PTRS_PER_PTE    (((ulong)(1)) << (PAGESHIFT()-3))
-#define PTRS_PER_PAGE   (((ulong)(1)) << (PAGESHIFT()-3))
 #define __IA64_UL(x)           ((unsigned long)(x))
 #define IA64_MAX_PHYS_BITS  (50)  /* max # of phys address bits (architected) */
 
 /*
+ * How many pointers will a page table level hold expressed in shift 
+ */
+#define PTRS_PER_PTD_SHIFT	(PAGESHIFT()-3)
+
+/*
+ * Definitions for fourth level:
+ */
+#define PTRS_PER_PTE	(__IA64_UL(1) << (PTRS_PER_PTD_SHIFT))
+
+/*
+ * Definitions for third level:
+ *
+ * PMD_SHIFT determines the size of the area a third-level page table
+ * can map.
+ */
+#define PMD_SHIFT	(PAGESHIFT() + (PTRS_PER_PTD_SHIFT))
+#define PMD_SIZE	(1UL << PMD_SHIFT)
+#define PMD_MASK	(~(PMD_SIZE-1))
+#define PTRS_PER_PMD	(1UL << (PTRS_PER_PTD_SHIFT))
+
+/*
+ * PUD_SHIFT determines the size of the area a second-level page table
+ * can map
+ */
+#define PUD_SHIFT	(PMD_SHIFT + (PTRS_PER_PTD_SHIFT))
+#define PUD_SIZE	(1UL << PUD_SHIFT)
+#define PUD_MASK	(~(PUD_SIZE-1))
+#define PTRS_PER_PUD	(1UL << (PTRS_PER_PTD_SHIFT))
+
+/*
+ * Definitions for first level:
+ *
+ * PGDIR_SHIFT determines what a first-level page table entry can map.
+ */
+
+#define PGDIR_SHIFT_4L		(PUD_SHIFT + (PTRS_PER_PTD_SHIFT))
+#define PGDIR_SHIFT_3L		(PMD_SHIFT + (PTRS_PER_PTD_SHIFT))
+/* Turns out 4L & 3L PGDIR_SHIFT are the same (for now) */
+#define PGDIR_SHIFT		PGDIR_SHIFT_4L
+#define PGDIR_SIZE		(__IA64_UL(1) << PGDIR_SHIFT)
+#define PGDIR_MASK		(~(PGDIR_SIZE-1))
+#define PTRS_PER_PGD_SHIFT	PTRS_PER_PTD_SHIFT
+#define PTRS_PER_PGD		(1UL << PTRS_PER_PGD_SHIFT)
+#define USER_PTRS_PER_PGD	(5*PTRS_PER_PGD/8)	/* regions 0-4 are user regions */
+#define FIRST_USER_ADDRESS	0
+
+/*
  * First, define the various bits in a PTE.  Note that the PTE format
  * matches the VHPT short format, the firt doubleword of the VHPD long
  * format, and the first doubleword of the TLB insertion format.
@@ -2178,6 +2230,9 @@ struct load_module {
 #define __DIRTY_BITS		_PAGE_ED | __DIRTY_BITS_NO_ED
 
 #define EFI_PAGE_SHIFT  (12)
+
+#define VM_4_LEVEL 	(0x4)
+
 /*
  * NOTE: #include'ing <asm/efi.h> creates too many compiler problems, so
  * this stuff is hardwired here; it's probably etched in stone somewhere.
@@ -3588,6 +3643,12 @@ int ia64_in_init_stack(ulong addr);
 #define IA64_RBS_OFFSET   ((SIZE(task_struct) + 15) & ~15)
 #define IA64_STK_OFFSET   (STACKSIZE())
 
+#define MAGIC_START	"IKCFG_ST"
+#define MAGIC_END	"IKCFG_ED"
+#define MAGIC_SIZE (sizeof(MAGIC_START) - 1)
+#define LIST_SIZE 2
+
+
 struct machine_specific {
 	ulong cpu_data_address;
         ulong unimpl_va_mask;
diff -urpN -urN -X /root/dontdiff orig/ia64.c crash-4.0-2.33/ia64.c
--- orig/ia64.c	2006-07-13 12:51:50.000000000 -0600
+++ crash-4.0-2.33/ia64.c	2006-08-01 08:25:37.000000000 -0600
@@ -25,6 +25,8 @@ static void ia64_old_unwind_init(void);
 static void try_old_unwind(struct bt_info *);
 static void ia64_dump_irq(int);
 static ulong ia64_processor_speed(void);
+static int ia64_vtop_4l(ulong vaddr, physaddr_t *paddr, ulong *pgd, int verbose, int usr);
+static int ia64_vtop(ulong vaddr, physaddr_t *paddr, ulong *pgd, int verbose, int usr);
 static int ia64_uvtop(struct task_context *, ulong, physaddr_t *, int);
 static int ia64_kvtop(struct task_context *, ulong, physaddr_t *, int);
 static ulong ia64_get_task_pgd(ulong);
@@ -63,6 +65,9 @@ static ulong rse_read_reg(struct unw_fra
 static void rse_function_params(struct unw_frame_info *, char *);
 
 
+static void read_config(void);
+static void read_config_err(int e, char *msg);
+
 struct machine_specific ia64_machine_specific = { 0 };
 
 void
@@ -101,11 +106,14 @@ ia64_init(int when)
 		}
                 if ((machdep->pgd = (char *)malloc(PAGESIZE())) == NULL)
                         error(FATAL, "cannot malloc pgd space.");
+		if ((machdep->pud = (char *)malloc(PAGESIZE())) == NULL)
+			error(FATAL, "cannot malloc pud space.");
                 if ((machdep->pmd = (char *)malloc(PAGESIZE())) == NULL)
                         error(FATAL, "cannot malloc pmd space.");
                 if ((machdep->ptbl = (char *)malloc(PAGESIZE())) == NULL)
                         error(FATAL, "cannot malloc ptbl space.");
                 machdep->last_pgd_read = 0;
+                machdep->last_pud_read = 0;
                 machdep->last_pmd_read = 0;
                 machdep->last_ptbl_read = 0;
 		machdep->verify_paddr = ia64_verify_paddr;
@@ -118,14 +126,17 @@ ia64_init(int when)
                 break;     
 
         case PRE_GDB:
+
 		if (pc->flags & KERNEL_DEBUG_QUERY)
 			return;
+		
 		/*
 		 * Until the kernel core dump and va_server library code
 		 * do the right thing with respect to the configured page size,
 		 * try to recognize a fatal inequity between the compiled-in 
 		 * page size and the page size used by the kernel.
 		 */ 
+		
 
 		if ((sp = symbol_search("empty_zero_page")) &&
 		    (spn = next_symbol(NULL, sp)) && 
@@ -179,6 +190,7 @@ ia64_init(int when)
                 break;
 
         case POST_GDB:
+		read_config();
 		STRUCT_SIZE_INIT(cpuinfo_ia64, "cpuinfo_ia64");
 		STRUCT_SIZE_INIT(switch_stack, "switch_stack");
 		MEMBER_OFFSET_INIT(thread_struct_fph, "thread_struct", "fph");
@@ -215,6 +227,235 @@ ia64_init(int when)
 	}
 }
 
+void
+read_config_err(int e, char *msg)
+{
+	error(WARNING, "zlib could not %s\n", msg);
+	switch (e) {
+		case Z_OK:
+			fprintf(fp, "Z_OK\n");
+			break;
+
+		case Z_STREAM_END:
+			fprintf(fp, "Z_STREAM_END\n");
+			break;
+
+		case Z_NEED_DICT:
+			fprintf(fp, "Z_NEED_DICT\n");
+			break;
+		
+		case Z_ERRNO:
+			fprintf(fp, "Z_ERNO\n");
+			break;
+
+		case Z_STREAM_ERROR:
+			fprintf(fp, "Z_STREAM\n");
+			break;
+
+		case Z_DATA_ERROR: 
+			fprintf(fp, "Z_DATA_ERROR\n");
+			break;
+
+		case Z_MEM_ERROR: /* out of memory */
+			fprintf(fp, "Z_MEM_ERROR\n");
+			break;
+
+		case Z_BUF_ERROR: /* not enough room in output buf */
+			fprintf(fp, "Z_BUF_ERROR\n");
+			break;
+		
+		case Z_VERSION_ERROR:
+			fprintf(fp, "Z_VERSION_ERROR\n");
+			break;
+
+		default: 
+			fprintf(fp, "UNKNOWN ERROR: %d\n", e);
+			break;
+	}
+}
+
+void
+read_config(void)
+{
+	struct syment *sp;
+	ulong kr;
+	int ii, jj, len, ret=0, found=0;
+	unsigned long size, bufsz;
+	char *pos, *ln, *buf, *head, *tail, *val, *uncomp;
+	char line[512];
+	z_stream stream;
+
+	if (!symbol_exists("kernel_config_data"))
+		return;
+		
+	if ((sp = symbol_search("kernel_config_data")) != NULL) 
+			kr = sp->value;
+	else
+		return;
+	
+	error(NOTE, "Using IKCONFIG (In Kernel Config)\n");
+
+	/* we don't know how large IKCONFIG is, so we start with 
+	 * 32k, if we can't find MAGIC_END assume we didn't read 
+	 * enough, double it and try again
+	 */
+	ii = 32;
+
+again:
+	size = ii * 1024;
+
+	if ((buf = (char *)malloc(size)) == NULL){
+		error(WARNING, "cannot malloc ia64_memmap\n");
+		return;
+	}
+	
+        readmem(kr, KVADDR, buf, size,
+                "kernel_config_data", RETURN_ON_ERROR);
+		
+	/* Find the start */
+	if (strstr(buf, MAGIC_START))
+		head = buf + MAGIC_SIZE + 10; /* skip past MAGIC_START and gzip header */
+	else{
+		error(WARNING, "could not find MAGIC_START!\n");
+		goto out2;
+	}
+
+	tail = head;
+
+	/* Find the end*/
+	while(tail < (buf + (size - 1))){
+		
+		if (strncmp(tail, MAGIC_END, strlen(MAGIC_END))==0){
+			found = 1;
+			break;
+		}
+		tail++;
+	}
+
+	if (found){
+		bufsz = tail - head;
+		size = 10 * bufsz;
+		if ((uncomp = (char *)malloc(size)) == NULL){
+			error(WARNING, "cannot malloc ia64_memmap\n");
+			goto out2;
+		}
+	} else {
+		if (ii > 512){
+			error(WARNING, "could not find MAGIC_END!\n");
+			goto out2;
+		} else {
+			free(buf);
+			ii *= 2;
+			goto again;
+		}
+	}
+
+
+	/* initialize zlib */
+	stream.next_in = (Bytef*)head;
+	stream.avail_in = (uInt) bufsz;
+
+	stream.next_out = uncomp;
+	stream.avail_out = (uInt) size;
+
+	stream.zalloc = NULL;
+	stream.zfree = NULL;
+	stream.opaque = NULL;
+
+	ret = inflateInit2(&stream, -MAX_WBITS);
+	if (ret != Z_OK){
+		read_config_err(ret, "initialize");
+		goto out1;
+	}
+
+	ret = inflate(&stream, Z_FINISH);
+
+	if (ret != Z_STREAM_END) {
+		inflateEnd(&stream);
+		if (ret == Z_NEED_DICT || 
+		   (ret == Z_BUF_ERROR && stream.avail_in == 0)){
+			read_config_err(Z_DATA_ERROR, "uncompress");
+			goto out1;
+		}
+		read_config_err(ret, "uncompress");
+		goto out1;
+	}
+	size = stream.total_out;
+
+	ret = inflateEnd(&stream);
+
+	pos = uncomp;
+
+	do{
+		ret = sscanf(pos, "%[^\n]\n%n", line, &ii); 
+		if (ret > 0){
+			pos += ii;
+
+			ln = line;
+				
+			/* skip leading whitespace */
+			while(isblank(*ln) != 0)
+				ln++;
+
+			/* skip comments */
+			if ((head = strchr(ln, '#')) != NULL)
+				continue;
+
+			/* Find '=' */
+			if ((head = strchr(ln, '=')) != NULL){
+				*head = '\0';
+				val = head + 1;
+
+				head--;
+
+				/* skip trailing whitespace */
+				while(isblank(*head) != 0){
+					*head = '\0';
+					head--;
+				}
+
+				/* skip whitespace */
+				while(isblank(*val) != 0)
+					val++;
+
+			} else /* Bad line, skip it */
+				continue;
+
+			for (jj=0; jj < LIST_SIZE; jj++){
+				/* keep the parse list here to make it obvious */
+				char *parse[LIST_SIZE] = {"CONFIG_NR_CPUS",
+							  "CONFIG_PGTABLE_4"
+				};
+
+				if (strncmp(ln, parse[jj], strlen(parse[jj]))==0){
+					switch (jj)
+					{
+						/* FIXME: nr_cpus currently
+						 * unused, it would be nice to
+						 * use the real config value
+						 */
+						case 0: /* CONFIG_NR_CPUS */
+							machdep->nr_cpus = atoi(val);
+							break;
+						case 1: /* CONFIG_PGTABLE_4 */
+							machdep->flags |= VM_4_LEVEL;
+							break;
+					}
+				}
+			}
+
+		}
+
+	} while (ret > 0);
+
+out1:
+	free(uncomp);
+out2:
+	free(buf);
+	return;
+
+}
+
 /*
  *  --machdep <addr> defaults to the physical start location.
  *
@@ -287,11 +528,34 @@ parse_cmdline_arg(void)
 					continue;
 				}
 			}
+		} else if (STRNEQ(arglist[i], "vm=")) {
+			p = arglist[i] + strlen("vm=");
+			if (strlen(p)) {
+				if (STREQ(p, "4l")) {
+					machdep->flags |= VM_4_LEVEL;
+					continue;
+				}
+			}
 		}
 
 		error(WARNING, "ignoring --machdep option: %s\n", arglist[i]);
 	} 
 
+	switch (machdep->flags & (VM_4_LEVEL))
+	{
+		case VM_4_LEVEL:
+			error(NOTE, "using 4-level pagetable\n");
+			c++;
+			break;
+			
+		default:
+			error(WARNING, "Invalid vm= option\n");
+			c++;
+			machdep->flags &= ~(VM_4_LEVEL);
+			break;
+	} 
+
+
 	if (c)
 		fprintf(fp, "\n");
 }
@@ -451,6 +715,7 @@ ia64_dump_machdep_table(ulong arg)
 	fprintf(fp, "    value_to_symbol: generic_machdep_value_to_symbol()\n");
         fprintf(fp, "  line_number_hooks: ia64_line_number_hooks\n");
         fprintf(fp, "      last_pgd_read: %lx\n", machdep->last_pgd_read);
+        fprintf(fp, "      last_pud_read: %lx\n", machdep->last_pud_read);
         fprintf(fp, "      last_pmd_read: %lx\n", machdep->last_pmd_read);
         fprintf(fp, "     last_ptbl_read: %lx\n", machdep->last_ptbl_read);
         fprintf(fp, "                pgd: %lx\n", (ulong)machdep->pgd);
@@ -667,75 +932,152 @@ ia64_processor_speed(void)
 
 	return (machdep->mhz = mhz);
 }
-
-
-/*
- *  Translates a user virtual address to its physical address.  cmd_vtop()
- *  sets the verbose flag so that the pte translation gets displayed; all
- *  other callers quietly accept the translation.
- *
- *  This routine can also take mapped kernel virtual addresses if the -u flag
- *  was passed to cmd_vtop().  If so, it makes the translation using the
- *  swapper_pg_dir, making it irrelevant in this processor's case.
+/* Generic abstraction to translate user or kernel virtual
+ * addresses to physical using a 4 level page table.
  */
 static int
-ia64_uvtop(struct task_context *tc, ulong uvaddr, physaddr_t *paddr, int verbose)
+ia64_vtop_4l(ulong vaddr, physaddr_t *paddr, ulong *pgd, int verbose, int usr)
 {
-	ulong mm;
-	ulong *pgd;
 	ulong *page_dir;
+	ulong *page_upper;
 	ulong *page_middle;
 	ulong *page_table;
 	ulong pgd_pte;
+	ulong pud_pte;
 	ulong pmd_pte;
 	ulong pte;
 	ulong region, offset;
 
-	if (!tc)
-		error(FATAL, "current context invalid\n");
-
-	*paddr = 0;
-       	region = VADDR_REGION(uvaddr);
+	if(usr){
+		region = VADDR_REGION(vaddr);
+		offset = (vaddr >> PGDIR_SHIFT) & ((PTRS_PER_PGD >> 3) - 1);
+		offset |= (region << (PAGESHIFT() - 6));
+		page_dir = pgd + offset;
+	}else{
+		pgd = (ulong *)vt->kernel_pgd[0];
+		page_dir = pgd + ((vaddr >> PGDIR_SHIFT) & (PTRS_PER_PGD - 1));
+	}
 
-	if (IS_KVADDR(uvaddr))
-		return ia64_kvtop(tc, uvaddr, paddr, verbose);
+	if (verbose) 
+		fprintf(fp, "PAGE DIRECTORY: %lx\n", (ulong)pgd);
 
-	if ((mm = task_mm(tc->task, TRUE)))
-        	pgd = ULONG_PTR(tt->mm_struct + OFFSET(mm_struct_pgd));
-	else
-		readmem(tc->mm_struct + OFFSET(mm_struct_pgd), KVADDR, &pgd,
-			sizeof(long), "mm_struct pgd", FAULT_ON_ERROR);
+	FILL_PGD(PAGEBASE(pgd), KVADDR, PAGESIZE());
+	pgd_pte = ULONG(machdep->pgd + PAGEOFFSET(page_dir));
+	
+        if (verbose) 
+                fprintf(fp, "   PGD: %lx => %lx\n", (ulong)page_dir, pgd_pte);
 
+        if (!(pgd_pte))
+		return FALSE;
+	
+	offset = (vaddr >> PUD_SHIFT) & (PTRS_PER_PUD - 1);
+	page_upper = (ulong *)(PTOV(pgd_pte & _PFN_MASK)) + offset; 
+	
+	FILL_PUD(PAGEBASE(page_upper), KVADDR, PAGESIZE());
+	pud_pte = ULONG(machdep->pud + PAGEOFFSET(page_upper));
+        
 	if (verbose) 
+                fprintf(fp, "   PUD: %lx => %lx\n", (ulong)page_upper, pud_pte);
+        
+	if (!(pud_pte))
+		return FALSE;
+
+	offset = (vaddr >> PMD_SHIFT) & (PTRS_PER_PMD - 1);
+	page_middle = (ulong *)(PTOV(pud_pte & _PFN_MASK)) + offset; 
+
+	FILL_PMD(PAGEBASE(page_middle), KVADDR, PAGESIZE());
+	pmd_pte = ULONG(machdep->pmd + PAGEOFFSET(page_middle));
+
+        if (verbose)
+                fprintf(fp, "   PMD: %lx => %lx\n", (ulong)page_middle, pmd_pte);
+
+        if (!(pmd_pte))
+		return FALSE;
+
+        offset = (vaddr >> PAGESHIFT()) & (PTRS_PER_PTE - 1);
+        page_table = (ulong *)(PTOV(pmd_pte & _PFN_MASK)) + offset;
+
+	FILL_PTBL(PAGEBASE(page_table), KVADDR, PAGESIZE());
+	pte = ULONG(machdep->ptbl + PAGEOFFSET(page_table));
+
+        if (verbose)
+                fprintf(fp, "   PTE: %lx => %lx\n", (ulong)page_table, pte);
+
+        if (!(pte & (_PAGE_P))) {
+		if(usr)
+		  *paddr = pte;
+		if (pte && verbose) {
+			fprintf(fp, "\n");
+			ia64_translate_pte(pte, 0, 0);
+		}
+		return FALSE;
+        }
+
+        *paddr = (pte & _PFN_MASK) + PAGEOFFSET(vaddr);
+
+        if (verbose) {
+                fprintf(fp, "  PAGE: %lx\n\n", PAGEBASE(*paddr));
+		ia64_translate_pte(pte, 0, 0);
+	}
+
+	return TRUE;
+
+
+
+}
+
+/* Generic abstraction to translate user or kernel virtual
+ * addresses to physical using a 3 level page table.
+ */
+static int
+ia64_vtop(ulong vaddr, physaddr_t *paddr, ulong *pgd, int verbose, int usr)
+{
+	ulong *page_dir;
+	ulong *page_middle;
+	ulong *page_table;
+	ulong pgd_pte;
+	ulong pmd_pte;
+	ulong pte;
+	ulong region, offset;
+
+	if(usr){
+		region = VADDR_REGION(vaddr);
+		offset = (vaddr >> PGDIR_SHIFT) & ((PTRS_PER_PGD >> 3) - 1);
+		offset |= (region << (PAGESHIFT() - 6));
+		page_dir = pgd + offset;
+	}else{
+		pgd = (ulong *)vt->kernel_pgd[0];
+		page_dir = pgd + ((vaddr >> PGDIR_SHIFT) & (PTRS_PER_PGD - 1));
+	}
+
+	if (verbose)
 		fprintf(fp, "PAGE DIRECTORY: %lx\n", (ulong)pgd);
+	
 
-        offset = (uvaddr >> PGDIR_SHIFT) & ((PTRS_PER_PGD >> 3) - 1);
-        offset |= (region << (PAGESHIFT() - 6));
-        page_dir = pgd + offset;
 
 	FILL_PGD(PAGEBASE(pgd), KVADDR, PAGESIZE());
 	pgd_pte = ULONG(machdep->pgd + PAGEOFFSET(page_dir));
 	
-        if (verbose) {
+        if (verbose) 
                 fprintf(fp, "   PGD: %lx => %lx\n", (ulong)page_dir, pgd_pte);
-        }
+
 
         if (!(pgd_pte))
-                goto no_upage;
+		return FALSE;
 
-	offset = (uvaddr >> PMD_SHIFT) & (PTRS_PER_PMD - 1);
+	offset = (vaddr >> PMD_SHIFT) & (PTRS_PER_PMD - 1);
 	page_middle = (ulong *)(PTOV(pgd_pte & _PFN_MASK)) + offset; 
 
 	FILL_PMD(PAGEBASE(page_middle), KVADDR, PAGESIZE());
 	pmd_pte = ULONG(machdep->pmd + PAGEOFFSET(page_middle));
 
         if (verbose)
-                fprintf(fp, "   PMD: %lx => %lx\n", (ulong)page_middle,pmd_pte);
+                fprintf(fp, "   PMD: %lx => %lx\n", (ulong)page_middle, pmd_pte);
 
         if (!(pmd_pte))
-                goto no_upage;
+		return FALSE;
 
-        offset = (uvaddr >> PAGESHIFT()) & (PTRS_PER_PTE - 1);
+        offset = (vaddr >> PAGESHIFT()) & (PTRS_PER_PTE - 1);
         page_table = (ulong *)(PTOV(pmd_pte & _PFN_MASK)) + offset;
 
 	FILL_PTBL(PAGEBASE(page_table), KVADDR, PAGESIZE());
@@ -745,15 +1087,16 @@ ia64_uvtop(struct task_context *tc, ulon
                 fprintf(fp, "   PTE: %lx => %lx\n", (ulong)page_table, pte);
 
         if (!(pte & (_PAGE_P))) {
-		*paddr = pte;
+		if(usr)
+		  *paddr = pte;
 		if (pte && verbose) {
 			fprintf(fp, "\n");
 			ia64_translate_pte(pte, 0, 0);
 		}
-                goto no_upage;
+		return FALSE;
         }
 
-        *paddr = (pte & _PFN_MASK) + PAGEOFFSET(uvaddr);
+        *paddr = (pte & _PFN_MASK) + PAGEOFFSET(vaddr);
 
         if (verbose) {
                 fprintf(fp, "  PAGE: %lx\n\n", PAGEBASE(*paddr));
@@ -762,9 +1105,50 @@ ia64_uvtop(struct task_context *tc, ulon
 
 	return TRUE;
 
-no_upage:
+}
 
-	return FALSE;
+
+/*
+ *  Translates a user virtual address to its physical address.  cmd_vtop()
+ *  sets the verbose flag so that the pte translation gets displayed; all
+ *  other callers quietly accept the translation.
+ *
+ *  This routine can also take mapped kernel virtual addresses if the -u flag
+ *  was passed to cmd_vtop().  If so, it makes the translation using the
+ *  swapper_pg_dir, making it irrelevant in this processor's case.
+ */
+static int
+ia64_uvtop(struct task_context *tc, ulong uvaddr, physaddr_t *paddr, int verbose)
+{
+	ulong mm;
+	ulong *pgd;
+	ulong *page_dir;
+	ulong *page_middle;
+	ulong *page_table;
+	ulong pgd_pte;
+	ulong pmd_pte;
+	ulong pte;
+	ulong offset;
+
+	if (!tc)
+		error(FATAL, "current context invalid\n");
+
+	*paddr = 0;
+
+	if (IS_KVADDR(uvaddr))
+		return ia64_kvtop(tc, uvaddr, paddr, verbose);
+
+	if ((mm = task_mm(tc->task, TRUE)))
+        	pgd = ULONG_PTR(tt->mm_struct + OFFSET(mm_struct_pgd));
+	else
+		readmem(tc->mm_struct + OFFSET(mm_struct_pgd), KVADDR, &pgd,
+			sizeof(long), "mm_struct pgd", FAULT_ON_ERROR);
+
+	if (machdep->flags & VM_4_LEVEL)
+		return ia64_vtop_4l(uvaddr, paddr, pgd, verbose, 1);
+	else
+		return ia64_vtop(uvaddr, paddr, pgd, verbose, 1);
+	
 }
 
 
@@ -818,64 +1202,11 @@ ia64_kvtop(struct task_context *tc, ulon
 
         pgd = (ulong *)vt->kernel_pgd[0];
 
-        if (verbose) {
-                fprintf(fp, "PAGE DIRECTORY: %lx\n", (ulong)pgd);
-	}
-
-	page_dir = pgd + ((kvaddr >> PGDIR_SHIFT) & (PTRS_PER_PGD - 1)); 
-
-        FILL_PGD(PAGEBASE(pgd), KVADDR, PAGESIZE());
-        pgd_pte = ULONG(machdep->pgd + PAGEOFFSET(page_dir));
-
-        if (verbose) {
-                fprintf(fp, "   PGD: %lx => %lx\n", (ulong)page_dir, pgd_pte);
-	}
-
-        if (!(pgd_pte))
-                goto no_kpage;
-
-	offset = (kvaddr >> PMD_SHIFT) & (PTRS_PER_PMD - 1);
-	page_middle = (ulong *)(PTOV(pgd_pte & _PFN_MASK)) + offset; 
-
-        FILL_PMD(PAGEBASE(page_middle), KVADDR, PAGESIZE());
-        pmd_pte = ULONG(machdep->pmd + PAGEOFFSET(page_middle));
-
-        if (verbose)
-                fprintf(fp, "   PMD: %lx => %lx\n", (ulong)page_middle, 
-			pmd_pte);
-
-        if (!(pmd_pte))
-                goto no_kpage;
-
-        offset = (kvaddr >> PAGESHIFT()) & (PTRS_PER_PTE - 1);
-        page_table = (ulong *)(PTOV(pmd_pte & _PFN_MASK)) + offset;
-
-        FILL_PTBL(PAGEBASE(page_table), KVADDR, PAGESIZE());
-        pte = ULONG(machdep->ptbl + PAGEOFFSET(page_table));
-
-        if (verbose)
-                fprintf(fp, "   PTE: %lx => %lx\n", (ulong)page_table, pte);
-
-        if (!(pte & (_PAGE_P))) {
-		if (pte && verbose) {
-			fprintf(fp, "\n");
-			ia64_translate_pte(pte, 0, 0);
-		}
-                goto no_kpage;
-        }
-
-        *paddr = (pte & _PFN_MASK) + PAGEOFFSET(kvaddr);
-
-        if (verbose) {
-                fprintf(fp, "  PAGE: %lx\n\n", PAGEBASE(*paddr));
-		ia64_translate_pte(pte, 0, 0);
-	}
-
-	return TRUE;
-
-no_kpage:
+	if (machdep->flags & VM_4_LEVEL)
+		return ia64_vtop_4l(kvaddr, paddr, pgd, verbose, 0);
+	else
+		return ia64_vtop(kvaddr, paddr, pgd, verbose, 0);
 
-	return FALSE;
 }
 
 /*


More information about the Crash-utility mailing list