[PATCH v2 6/6] x86_64: Fix the misusage of PGDIR_SHIFT

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Due to the backwards compatibility, we should setup machdep->machspec->pgdir_shift
correctly in x86_64_init() for all versions of linux. this patch set the default
4-level for each versions, and add a new function named x86_64_upgd_offset_legacy()
for old linuxes to get the user page global directory entry.

Signed-off-by: Dou Liyang <douly.fnst@xxxxxxxxxxxxxx>
---
 defs.h   | 15 +++++++--------
 sadump.c |  4 ++--
 x86_64.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++----------
 3 files changed, 55 insertions(+), 20 deletions(-)

diff --git a/defs.h b/defs.h
index c055e48..ee24acb 100644
--- a/defs.h
+++ b/defs.h
@@ -3330,19 +3330,18 @@ struct arm64_stackframe {
 #define VTOP(X)               x86_64_VTOP((ulong)(X))
 #define IS_VMALLOC_ADDR(X)    x86_64_IS_VMALLOC_ADDR((ulong)(X))
 
-/* origin level page */
-#define PGDIR_SHIFT     30
+/*
+ * the default page table level for x86_64:
+ *    4 level page tables
+ */
+#define PGDIR_SHIFT     39
 #define PTRS_PER_PGD    512
+#define PUD_SHIFT       30
+#define PTRS_PER_PUD    512
 #define PMD_SHIFT       21
 #define PTRS_PER_PMD    512
 #define PTRS_PER_PTE    512
 
-/* 4 level page */
-#define PGDIR_SHIFT_4LEVEL    39
-#define PTRS_PER_PGD_4LEVEL  512
-#define PUD_SHIFT       30
-#define PTRS_PER_PUD    512
-
 /* 5 level page */
 #define PGDIR_SHIFT_5LEVEL    48
 #define PTRS_PER_PGD_5LEVEL  512
diff --git a/sadump.c b/sadump.c
index a189c2d..1743e63 100644
--- a/sadump.c
+++ b/sadump.c
@@ -2053,8 +2053,8 @@ sadump_calc_kaslr_offset(ulong *kaslr_offset)
 	vt->kernel_pgd[0] = cr3;
 	machdep->last_pgd_read = vt->kernel_pgd[0];
 	machdep->machspec->physical_mask_shift = __PHYSICAL_MASK_SHIFT_2_6;
-	machdep->machspec->pgdir_shift = PGDIR_SHIFT_4LEVEL;
-	machdep->machspec->ptrs_per_pgd = PTRS_PER_PGD_4LEVEL;
+	machdep->machspec->pgdir_shift = PGDIR_SHIFT;
+	machdep->machspec->ptrs_per_pgd = PTRS_PER_PGD;
 	if (!readmem(cr3, PHYSADDR, machdep->pgd, PAGESIZE(),
 			"cr3", RETURN_ON_ERROR))
 		goto quit;
diff --git a/x86_64.c b/x86_64.c
index 944c7ee..95a1791 100644
--- a/x86_64.c
+++ b/x86_64.c
@@ -78,6 +78,7 @@ static int x86_64_is_kvaddr(ulong);
 static int x86_64_is_uvaddr(ulong, struct task_context *);
 static ulong *x86_64_kpgd_offset(ulong, int, int);
 static ulong x86_64_upgd_offset(struct task_context *, ulong, int, int);
+static ulong x86_64_upgd_offset_legacy(struct task_context *, ulong, int, int);
 static ulong x86_64_p4d_offset(ulong, ulong, int, int);
 static ulong x86_64_pud_offset(ulong, ulong, int, int);
 static ulong x86_64_pmd_offset(ulong, ulong, int, int);
@@ -258,8 +259,8 @@ x86_64_init(int when)
 
 			machdep->uvtop = x86_64_uvtop_level4;
 			machdep->machspec->physical_mask_shift = __PHYSICAL_MASK_SHIFT_2_6;
-			machdep->machspec->pgdir_shift = PGDIR_SHIFT_4LEVEL;
-			machdep->machspec->ptrs_per_pgd = PTRS_PER_PGD_4LEVEL;
+			machdep->machspec->pgdir_shift = PGDIR_SHIFT;
+			machdep->machspec->ptrs_per_pgd = PTRS_PER_PGD;
 			break;
 
                 case VM_XEN:
@@ -271,6 +272,8 @@ x86_64_init(int when)
                         machdep->machspec->modules_vaddr = MODULES_VADDR_XEN;
                         machdep->machspec->modules_end = MODULES_END_XEN;
 			machdep->machspec->physical_mask_shift = __PHYSICAL_MASK_SHIFT_XEN;
+			machdep->machspec->pgdir_shift = PGDIR_SHIFT;
+			machdep->machspec->ptrs_per_pgd = PTRS_PER_PGD;
                         break;
 
 		case VM_XEN_RHEL4:
@@ -282,6 +285,8 @@ x86_64_init(int when)
                         machdep->machspec->modules_vaddr = MODULES_VADDR_XEN_RHEL4;
                         machdep->machspec->modules_end = MODULES_END_XEN_RHEL4;
 			machdep->machspec->physical_mask_shift = __PHYSICAL_MASK_SHIFT_XEN;
+			machdep->machspec->pgdir_shift = PGDIR_SHIFT;
+			machdep->machspec->ptrs_per_pgd = PTRS_PER_PGD;
 			break;
 
 		case VM_5LEVEL:
@@ -625,20 +630,14 @@ x86_64_init(int when)
 				case VM_XEN: 
 				case VM_2_6_11:
                         		machdep->uvtop = x86_64_uvtop_level4_xen_wpt;
-					machdep->machspec->pgdir_shift = PGDIR_SHIFT_4LEVEL;
-					machdep->machspec->ptrs_per_pgd = PTRS_PER_PGD_4LEVEL;
 					break;
 				case VM_XEN_RHEL4:
                         		machdep->uvtop = x86_64_uvtop_level4_rhel4_xen_wpt;
-					machdep->machspec->pgdir_shift = PGDIR_SHIFT;
-					machdep->machspec->ptrs_per_pgd = PTRS_PER_PGD;
 					break;
 				}
 				machdep->machspec->physical_mask_shift = __PHYSICAL_MASK_SHIFT_XEN;
 			} else {
 				machdep->uvtop = x86_64_uvtop_level4;
-				machdep->machspec->pgdir_shift = PGDIR_SHIFT_4LEVEL;
-				machdep->machspec->ptrs_per_pgd = PTRS_PER_PGD_4LEVEL;
 			}
                         MEMBER_OFFSET_INIT(vcpu_guest_context_user_regs,
                                 "vcpu_guest_context", "user_regs");
@@ -1581,6 +1580,43 @@ x86_64_kpgd_offset(ulong kvaddr, int verbose , int IS_XEN)
 	return pgd;
 }
 
+/*
+ * In x86 64 bit system, Linux uses the 4-level page table as the default both
+ * in Kernel page tables and user page tables.
+ *
+ * But in some old versions(pre-2.6.11), the 3-level page table is used for
+ * user page tables.
+ *
+ * So reuse the PUD and find the user pgd entry for this older version Linux..
+ * pgd = pgd_offset(mm, address);
+ */
+static ulong
+x86_64_upgd_offset_legacy(struct task_context *tc, ulong uvaddr, int verbose , int IS_XEN)
+{
+	ulong *pud;
+	ulong pud_paddr;
+	ulong pud_pte;
+
+        if (task_mm(tc->task, TRUE))
+                pud = ULONG_PTR(tt->mm_struct + OFFSET(mm_struct_pgd));
+        else
+                readmem(tc->mm_struct + OFFSET(mm_struct_pgd), KVADDR, &pud,
+                        sizeof(long), "mm_struct pgd", FAULT_ON_ERROR);
+
+        pud_paddr = x86_64_VTOP((ulong)pud);
+        FILL_PUD(pud_paddr, PHYSADDR, PAGESIZE());
+	pud = ((ulong *)pud_paddr) + pud_index(uvaddr);
+	pud_pte = ULONG(machdep->pud + PAGEOFFSET(pud));
+        if (verbose) {
+		if(IS_XEN)
+			fprintf(fp, "   PGD: %lx => %lx [machine]\n", (ulong)pud, pud_pte);
+		else
+			fprintf(fp, "   PGD: %lx => %lx\n", (ulong)pud, pud_pte);
+        }
+
+	return pud_pte;
+}
+
 /*
  * Find the user pgd entry..
  * pgd = pgd_offset(mm, address);
@@ -1961,7 +1997,7 @@ x86_64_uvtop_level4_rhel4_xen_wpt(struct task_context *tc, ulong uvaddr, physadd
 	if (IS_KVADDR(uvaddr))
 		return x86_64_kvtop(tc, uvaddr, paddr, verbose);
 
-	pgd_pte = x86_64_upgd_offset(tc, uvaddr, verbose, TRUE);
+	pgd_pte = x86_64_upgd_offset_legacy(tc, uvaddr, verbose, TRUE);
 	if (!(pgd_pte & _PAGE_PRESENT))
 		goto no_upage;
 
@@ -2058,7 +2094,7 @@ x86_64_uvtop(struct task_context *tc, ulong uvaddr, physaddr_t *paddr, int verbo
         /*
          *  pgd = pgd_offset(mm, address);
          */
-        pgd_pte = x86_64_upgd_offset(tc, uvaddr, verbose, FALSE);
+        pgd_pte = x86_64_upgd_offset_legacy(tc, uvaddr, verbose, FALSE);
 	if (!(pgd_pte & _PAGE_PRESENT))
 		goto no_upage;
 
-- 
2.14.3



--
Crash-utility mailing list
Crash-utility@xxxxxxxxxx
https://www.redhat.com/mailman/listinfo/crash-utility



[Index of Archives]     [Fedora Development]     [Fedora Desktop]     [Fedora SELinux]     [Yosemite News]     [KDE Users]     [Fedora Tools]

 

Powered by Linux