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(a)cn.fujitsu.com>
---
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