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