Hari,
Thanks for looking into this. I'm currently on vacation and
and so I'll check out this patch next week.
Thanks,
Dave Anderson
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(a)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
------------------------------
--
Crash-utility mailing list
Crash-utility(a)redhat.com
https://www.redhat.com/mailman/listinfo/crash-utility
End of Crash-utility Digest, Vol 95, Issue 3
********************************************