Add the support for x86_64 5-level page tables. Squeeze the 5-level support
into the currently existing x86_64_kvtop() and x86_64_uvtop() functions instead
of using the new xxx_5level() function placeholders.
Signed-off-by: Dou Liyang <douly.fnst(a)cn.fujitsu.com>
---
x86_64.c | 90 +++++++++++++++++++++++++++++++++++++++++++++-------------------
1 file changed, 63 insertions(+), 27 deletions(-)
diff --git a/x86_64.c b/x86_64.c
index c8c6819..d3d5ab9 100644
--- a/x86_64.c
+++ b/x86_64.c
@@ -19,13 +19,11 @@
#ifdef X86_64
static int x86_64_kvtop(struct task_context *, ulong, physaddr_t *, int);
-static int x86_64_kvtop_5level(struct task_context *, ulong, physaddr_t *, int);
static int x86_64_kvtop_xen_wpt(struct task_context *, ulong, physaddr_t *, int);
static int x86_64_uvtop(struct task_context *, ulong, physaddr_t *, int);
static int x86_64_uvtop_level4(struct task_context *, ulong, physaddr_t *, int);
static int x86_64_uvtop_level4_xen_wpt(struct task_context *, ulong, physaddr_t *, int);
static int x86_64_uvtop_level4_rhel4_xen_wpt(struct task_context *, ulong, physaddr_t *,
int);
-static int x86_64_uvtop_5level(struct task_context *, ulong, physaddr_t *, int);
static int x86_64_task_uses_5level(struct task_context *);
static ulong x86_64_vmalloc_start(void);
static int x86_64_is_task_addr(ulong);
@@ -81,6 +79,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_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);
static ulong x86_64_pte_offset(ulong, ulong, int, int);
@@ -1649,6 +1648,31 @@ x86_64_upgd_offset(struct task_context *tc, ulong uvaddr, int
verbose, int IS_XE
return pgd_pte;
}
+/*
+ * Find an entry in the fourth-level page table..
+ * p4d = p4d_offset(pgd, address);
+ */
+static ulong
+x86_64_p4d_offset(ulong pgd_pte, ulong vaddr, int verbose, int IS_XEN)
+{
+ ulong *p4d;
+ ulong p4d_paddr;
+ ulong p4d_pte;
+
+ p4d_paddr = pgd_pte & PHYSICAL_PAGE_MASK;
+ FILL_P4D(p4d_paddr, PHYSADDR, PAGESIZE());
+ p4d = ((ulong *)p4d_paddr) + p4d_index(vaddr);
+ p4d_pte = ULONG(machdep->machspec->p4d + PAGEOFFSET(p4d));
+ if (verbose) {
+ if(IS_XEN)
+ fprintf(fp, " P4D: %lx => %lx [machine]\n", (ulong)p4d, p4d_pte);
+ else
+ fprintf(fp, " P4D: %lx => %lx\n", (ulong)p4d, p4d_pte);
+ }
+
+ return p4d_pte;
+}
+
/*
* Find an entry in the third-level page table..
* pud = pud_offset(pgd, address);
@@ -1770,17 +1794,30 @@ x86_64_uvtop_level4(struct task_context *tc, ulong uvaddr,
physaddr_t *paddr, in
if (IS_KVADDR(uvaddr))
return x86_64_kvtop(tc, uvaddr, paddr, verbose);
- if ((machdep->flags & VM_5LEVEL) && x86_64_task_uses_5level(tc))
- return x86_64_uvtop_5level(tc, uvaddr, paddr, verbose);
-
pgd_pte = x86_64_upgd_offset(tc, uvaddr, verbose, FALSE);
if (!(pgd_pte & _PAGE_PRESENT))
goto no_upage;
- /*
- * pud = pud_offset(pgd, address);
- */
- pud_pte = x86_64_pud_offset(pgd_pte, uvaddr, verbose, FALSE);
+ /* If the VM is in 5-level page table*/
+ if (machdep->flags & VM_5LEVEL && x86_64_task_uses_5level(tc)) {
+ ulong p4d_pte;
+ /*
+ * p4d = p4d_offset(pgd, address);
+ */
+ p4d_pte = x86_64_p4d_offset(pgd_pte, uvaddr, verbose, FALSE);
+ if (!(p4d_pte & _PAGE_PRESENT))
+ goto no_upage;
+ /*
+ * pud = pud_offset(p4d, address);
+ */
+ pud_pte = x86_64_pud_offset(p4d_pte, uvaddr, verbose, FALSE);
+ } else {
+ /*
+ * pud = pud_offset(pgd, address);
+ */
+ pud_pte = x86_64_pud_offset(pgd_pte, uvaddr, verbose, FALSE);
+ }
+
if (!(pud_pte & _PAGE_PRESENT))
goto no_upage;
@@ -1839,13 +1876,6 @@ x86_64_task_uses_5level(struct task_context *tc)
return FALSE;
}
-static int
-x86_64_uvtop_5level(struct task_context *tc, ulong uvaddr, physaddr_t *paddr, int
verbose)
-{
- error(INFO, "support for 5-level page tables TBD\n");
- return FALSE;
-}
-
static int
x86_64_uvtop_level4_xen_wpt(struct task_context *tc, ulong uvaddr, physaddr_t *paddr, int
verbose)
{
@@ -2175,9 +2205,6 @@ x86_64_kvtop(struct task_context *tc, ulong kvaddr, physaddr_t
*paddr, int verbo
if (XEN() && (kt->xen_flags & WRITABLE_PAGE_TABLES))
return (x86_64_kvtop_xen_wpt(tc, kvaddr, paddr, verbose));
- if (machdep->flags & VM_5LEVEL)
- return (x86_64_kvtop_5level(tc, kvaddr, paddr, verbose));
-
/*
* pgd = pgd_offset_k(addr);
*/
@@ -2188,7 +2215,23 @@ start_vtop_with_pagetable:
if (!(*pgd & _PAGE_PRESENT))
goto no_kpage;
- pud_pte = x86_64_pud_offset(*pgd, kvaddr, verbose, FALSE);
+ /* If the VM is in 5-level page table*/
+ if (machdep->flags & VM_5LEVEL) {
+ ulong p4d_pte;
+ /*
+ * p4d = p4d_offset(pgd, address);
+ */
+ p4d_pte = x86_64_p4d_offset(*pgd, kvaddr, verbose, FALSE);
+ if (!(p4d_pte & _PAGE_PRESENT))
+ goto no_kpage;
+ /*
+ * pud = pud_offset(p4d, address);
+ */
+ pud_pte = x86_64_pud_offset(p4d_pte, kvaddr, verbose, FALSE);
+ } else {
+ pud_pte = x86_64_pud_offset(*pgd, kvaddr, verbose, FALSE);
+ }
+
if (!(pud_pte & _PAGE_PRESENT))
goto no_kpage;
@@ -2238,13 +2281,6 @@ no_kpage:
return FALSE;
}
-static int
-x86_64_kvtop_5level(struct task_context *tc, ulong kvaddr, physaddr_t *paddr, int
verbose)
-{
- error(INFO, "support for 5-level page tables TBD\n");
- return FALSE;
-}
-
static int
x86_64_kvtop_xen_wpt(struct task_context *tc, ulong kvaddr, physaddr_t *paddr, int
verbose)
{
--
2.14.3