[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