[Crash-utility] [PATCH] PPC64: Support virtual to physical address translation (VTOP) for huge pages.

Hari Bathini hbathini at linux.vnet.ibm.com
Mon Aug 12 07:03:22 UTC 2013


Crash utility currently does not supporting virtual to physical address translation for huge pages on PPC64.
This patch tries to address this issue by providing address translation support for huge pages in 'vtop' command on PPC64.
Below are couple of outputs for address translation of huge pages on crash-7.0.1 (with Dave's patch for vtop issue on >=3.10 kernel)

#On kernel release 3.6.0-rc1

  crash> set 8149
    PID: 8149
COMMAND: "hugepage-mmap"
   TASK: c000000079ce49f0  [THREAD_INFO: c00000007795c000]
    CPU: 0
  STATE: TASK_INTERRUPTIBLE
crash> vtop 0xefff0000000
VIRTUAL           PHYSICAL
vtop: invalid kernel virtual address: 4000000079060000  type: "page table"
  crash>


#On kernel release 3.11.0-rc2

  crash> set 13011
    PID: 13011
COMMAND: "hugepage-mmap"
   TASK: c000000071600000  [THREAD_INFO: c000000078240000]
    CPU: 0
  STATE: TASK_INTERRUPTIBLE
crash> vtop 0x1efff0000000
VIRTUAL           PHYSICAL
1efff0000000      (not mapped)

PAGE DIRECTORY: c000000002770000
  L4: c000000002770df8 => 0

      VMA              START             END        FLAGS FILE
c000000024f13af0     1efff0000000     1f0000000000 4400fb /mnt/huge/hugepagefile

FILE: /mnt/huge/hugepagefile  OFFSET: 0

  crash>

In the two cases mentioned above, crash fails to convert huge pages to corresponding physical addresses.
Below are the outputs with this patch "applied"

#On kernel release 3.6.0-rc1

  crash> vtop 0xefff0000000
VIRTUAL           PHYSICAL
efff0000000       37000000

PAGE DIRECTORY: c00000007906f800
  L4: c00000007906f870 => c00000007c588000
  PMD: c00000007c58fff8 => 4000000079063798
 HUGE PAGE: 37000000

    PTE      PHYSICAL  FLAGS
dc008000393  37000000  (PRESENT|USER|COHERENT|DIRTY|ACCESSED)

      VMA              START             END        FLAGS FILE
c00000007bf3a140      efff0000000      f0000000000 4800fb /mnt/huge/hugepagefile

      PAGE       PHYSICAL      MAPPING       INDEX CNT FLAGS
c00000007f380000 37000000 c00000007af00e88        0  2 3701000004018
  crash>

#On kernel release 3.11.0-rc2

  crash> vtop 0x1efff0000000
VIRTUAL           PHYSICAL
1efff0000000      45000000

PAGE DIRECTORY: c000000002770000
  L4: c000000002773df8 => c00000007ab80000
  PMD: c00000007ab81f80 => 114008000393
 HUGE PAGE: 45000000

    PTE       PHYSICAL  FLAGS
114008000393  45000000  (PRESENT|USER|COHERENT|DIRTY|ACCESSED)

      VMA              START             END        FLAGS FILE
c000000024f13af0     1efff0000000     1f0000000000 4400fb /mnt/huge/hugepagefile

      PAGE       PHYSICAL      MAPPING       INDEX CNT FLAGS
c00000007f460000 45000000 c000000072ea0c70        0  2 1140400004018
  crash>

With the patch applied huge pages could be converted to corresponding physical pages
from huge pte in 3.11 kernel and from huge page directory on 3.6 kernel respectively.
Though, there are couple of things still to be taken up (see TODOs).
	1) Only base physical address is returned for a huge page as of now.
	2) Appropraite offset in huge page directory to get the actual physical page for a given huge page.

Signed-off-by: Hari Bathini <hbathini at linux.vnet.ibm.com>
---
 defs.h  |    6 +++-
 ppc64.c |   91 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
 2 files changed, 92 insertions(+), 5 deletions(-)

diff --git a/defs.h b/defs.h
index 275697b..7196bc9 100755
--- a/defs.h
+++ b/defs.h
@@ -3494,7 +3494,11 @@ struct efi_memory_desc_t {
 #define PTE_SHIFT_L4_BOOK3E_4K 24
 #define PMD_MASKED_BITS_64K  0x1ff
 
-#define L4_OFFSET(vaddr)  ((vaddr >> (machdep->machspec->l4_shift)) & 0x1ff)
+#define PD_HUGE           0x8000000000000000
+#define HUGE_PTE_MASK     0x03
+#define HUGEPD_SHIFT_MASK 0x3f
+#define L4_MASK           (THIS_KERNEL_VERSION >= LINUX(3,10,0) ? 0xfff : 0x1ff)
+#define L4_OFFSET(vaddr)  ((vaddr >> (machdep->machspec->l4_shift)) & L4_MASK)
 
 #define PGD_OFFSET_L4(vaddr)	\
 	((vaddr >> (machdep->machspec->l3_shift)) & (machdep->machspec->ptrs_per_l3 - 1))
diff --git a/ppc64.c b/ppc64.c
index 6f4f623..bf7def3 100755
--- a/ppc64.c
+++ b/ppc64.c
@@ -55,7 +55,51 @@ static int ppc64_get_cpu_map(void);
 static void ppc64_clear_machdep_cache(void);
 static void ppc64_vmemmap_init(void);
 static int ppc64_get_kvaddr_ranges(struct vaddr_range *);
+static uint get_ptetype(ulong pte);
+static int is_hugepage(ulong pte);
+static int is_hugepd(ulong pte);
+static ulong hugepage_dir(ulong pte);
 
+static inline uint get_ptetype(ulong pte)
+{
+	uint pte_type = 0; /* 0: regular entry; 1: huge pte; 2: huge pd */
+
+	if (is_hugepage(pte))
+		pte_type = 1;
+	else if (is_hugepd(pte))
+		pte_type = 2;
+
+	return pte_type;
+}
+
+static int is_hugepage(ulong pte)
+{
+	/*
+	 * leaf pte for huge page, bottom two bits != 00
+	 */
+	return ((pte & HUGE_PTE_MASK) != 0x0);
+}
+
+static inline int is_hugepd(ulong pte)
+{
+	if (THIS_KERNEL_VERSION >= LINUX(3,10,0)) {
+		/*
+		 * hugepd pointer, bottom two bits == 00 and next 4 bits
+		 * indicate size of table
+		*/
+		return (((pte & HUGE_PTE_MASK) == 0x0) &&
+			((pte & HUGEPD_SHIFT_MASK) != 0));
+	} else
+		return ((pte & PD_HUGE) == 0x0);
+}
+
+static inline ulong hugepage_dir(ulong pte)
+{
+	if (THIS_KERNEL_VERSION >= LINUX(3,10,0))
+		return (ulong)(pte & ~HUGEPD_SHIFT_MASK);
+	else
+		return (ulong)((pte & ~HUGEPD_SHIFT_MASK) | PD_HUGE);
+}
 
 static int book3e_is_kvaddr(ulong addr)
 {
@@ -637,6 +681,7 @@ ppc64_vtop_level4(ulong vaddr, ulong *level4, physaddr_t *paddr, int verbose)
 	ulong *page_table;
 	ulong level4_pte, pgd_pte, pmd_pte;
 	ulong pte;
+	uint  hugepage_type = 0; /* 0: regular entry; 1: huge pte; 2: huge pd */
 
 	if (verbose)
 		fprintf(fp, "PAGE DIRECTORY: %lx\n", (ulong)level4);
@@ -649,6 +694,12 @@ ppc64_vtop_level4(ulong vaddr, ulong *level4, physaddr_t *paddr, int verbose)
 	if (!level4_pte)
 		return FALSE;
 
+	hugepage_type = get_ptetype(level4_pte);
+	if (hugepage_type) {
+		pte = level4_pte;
+		goto out;
+	}
+
 	/* Sometimes we don't have level3 pagetable entries */
 	if (machdep->machspec->l3_index_size != 0) {
 		page_dir = (ulong *)((ulong *)level4_pte + PGD_OFFSET_L4(vaddr));
@@ -659,6 +710,12 @@ ppc64_vtop_level4(ulong vaddr, ulong *level4, physaddr_t *paddr, int verbose)
 			fprintf(fp, "  PGD: %lx => %lx\n", (ulong)page_dir, pgd_pte);
 		if (!pgd_pte)
 			return FALSE;
+
+		hugepage_type = get_ptetype(pgd_pte);
+		if (hugepage_type) {
+			pte = pgd_pte;
+			goto out;
+		}
 	} else {
 		pgd_pte = level4_pte;
 	}
@@ -673,6 +730,12 @@ ppc64_vtop_level4(ulong vaddr, ulong *level4, physaddr_t *paddr, int verbose)
 	if (!(pmd_pte))
 		return FALSE;
 
+	hugepage_type = get_ptetype(pmd_pte);
+	if (hugepage_type) {
+		pte = pmd_pte;
+		goto out;
+	}
+
 	page_table = (ulong *)(pmd_pte & ~(machdep->machspec->l2_masked_bits))
 			 + (BTOP(vaddr) & (machdep->machspec->ptrs_per_l1 - 1));
 	if (verbose)
@@ -696,17 +759,37 @@ ppc64_vtop_level4(ulong vaddr, ulong *level4, physaddr_t *paddr, int verbose)
 	if (!pte)
 		return FALSE;
 
-	*paddr = PAGEBASE(PTOB(pte >> machdep->machspec->pte_shift)) 
-			+ PAGEOFFSET(vaddr);
+out:
+	if (hugepage_type) {
+		if (hugepage_type == 2) {
+			/* TODO: Calculate the offset within the huge page
+			 * directory for this huge page to get corresponding
+			 * physical address. In the current form, it may
+			 * return the physical address of the first huge page
+			 * in this directory for all the huge pages
+			 * in this huge page directory.
+			 */
+			readmem(hugepage_dir(pte), KVADDR, &pte, sizeof(pte),
+				"hugepd_entry", RETURN_ON_ERROR);
+		}
+		/* TODO: get page offset for huge pages based on page size */
+		*paddr = PAGEBASE(PTOB(pte >> machdep->machspec->pte_shift));
+	} else {
+		*paddr = PAGEBASE(PTOB(pte >> machdep->machspec->pte_shift))
+				+ PAGEOFFSET(vaddr);
+	}
 
 	if (verbose) {
-		fprintf(fp, " PAGE: %lx\n\n", PAGEBASE(*paddr));
+		if (hugepage_type)
+			fprintf(fp, " HUGE PAGE: %lx\n\n", PAGEBASE(*paddr));
+		else
+			fprintf(fp, " PAGE: %lx\n\n", PAGEBASE(*paddr));
 		ppc64_translate_pte(pte, 0, machdep->machspec->pte_shift);
 	}
 
 	return TRUE;
 }
-	
+
 /*
  *  Translates a user virtual address to its physical address.  cmd_vtop()
  *  sets the verbose flag so that the pte translation gets displayed; all




More information about the Crash-utility mailing list