]> nv-tegra.nvidia Code Review - linux-3.10.git/blobdiff - arch/x86/xen/mmu.c
x86, mm: Patch out arch_flush_lazy_mmu_mode() when running on bare metal
[linux-3.10.git] / arch / x86 / xen / mmu.c
index b5f776f60b1b1dcfb26d3b96ba1f6cbaaa5920cf..2f5d6875555eaacd2accc2024ba3345ab7ea1202 100644 (file)
@@ -47,6 +47,9 @@
 #include <linux/gfp.h>
 #include <linux/memblock.h>
 #include <linux/seq_file.h>
+#include <linux/crash_dump.h>
+
+#include <trace/events/xen.h>
 
 #include <asm/pgtable.h>
 #include <asm/tlbflush.h>
@@ -59,6 +62,7 @@
 #include <asm/page.h>
 #include <asm/init.h>
 #include <asm/pat.h>
+#include <asm/smp.h>
 
 #include <asm/xen/hypercall.h>
 #include <asm/xen/hypervisor.h>
 #include "mmu.h"
 #include "debugfs.h"
 
-#define MMU_UPDATE_HISTO       30
-
 /*
  * Protects atomic reservation decrease/increase against concurrent increases.
  * Also protects non-atomic updates of current_pages and balloon lists.
  */
 DEFINE_SPINLOCK(xen_reservation_lock);
 
-#ifdef CONFIG_XEN_DEBUG_FS
-
-static struct {
-       u32 pgd_update;
-       u32 pgd_update_pinned;
-       u32 pgd_update_batched;
-
-       u32 pud_update;
-       u32 pud_update_pinned;
-       u32 pud_update_batched;
-
-       u32 pmd_update;
-       u32 pmd_update_pinned;
-       u32 pmd_update_batched;
-
-       u32 pte_update;
-       u32 pte_update_pinned;
-       u32 pte_update_batched;
-
-       u32 mmu_update;
-       u32 mmu_update_extended;
-       u32 mmu_update_histo[MMU_UPDATE_HISTO];
-
-       u32 prot_commit;
-       u32 prot_commit_batched;
-
-       u32 set_pte_at;
-       u32 set_pte_at_batched;
-       u32 set_pte_at_pinned;
-       u32 set_pte_at_current;
-       u32 set_pte_at_kernel;
-} mmu_stats;
-
-static u8 zero_stats;
-
-static inline void check_zero(void)
-{
-       if (unlikely(zero_stats)) {
-               memset(&mmu_stats, 0, sizeof(mmu_stats));
-               zero_stats = 0;
-       }
-}
-
-#define ADD_STATS(elem, val)                   \
-       do { check_zero(); mmu_stats.elem += (val); } while(0)
-
-#else  /* !CONFIG_XEN_DEBUG_FS */
-
-#define ADD_STATS(elem, val)   do { (void)(val); } while(0)
-
-#endif /* CONFIG_XEN_DEBUG_FS */
-
-
+#ifdef CONFIG_X86_32
 /*
  * Identity map, in addition to plain kernel map.  This needs to be
  * large enough to allocate page table pages to allocate the rest.
@@ -143,7 +93,7 @@ static inline void check_zero(void)
  */
 #define LEVEL1_IDENT_ENTRIES   (PTRS_PER_PTE * 4)
 static RESERVE_BRK_ARRAY(pte_t, level1_ident_pgt, LEVEL1_IDENT_ENTRIES);
-
+#endif
 #ifdef CONFIG_X86_64
 /* l3 pud for userspace vsyscall mapping */
 static pud_t level3_user_vsyscall[PTRS_PER_PUD] __page_aligned_bss;
@@ -243,21 +193,18 @@ static bool xen_page_pinned(void *ptr)
        return PagePinned(page);
 }
 
-static bool xen_iomap_pte(pte_t pte)
-{
-       return pte_flags(pte) & _PAGE_IOMAP;
-}
-
 void xen_set_domain_pte(pte_t *ptep, pte_t pteval, unsigned domid)
 {
        struct multicall_space mcs;
        struct mmu_update *u;
 
+       trace_xen_mmu_set_domain_pte(ptep, pteval, domid);
+
        mcs = xen_mc_entry(sizeof(*u));
        u = mcs.args;
 
        /* ptep might be kmapped when using 32-bit HIGHPTE */
-       u->ptr = arbitrary_virt_to_machine(ptep).maddr;
+       u->ptr = virt_to_machine(ptep).maddr;
        u->val = pte_val_ma(pteval);
 
        MULTI_mmu_update(mcs.mc, mcs.args, 1, NULL, domid);
@@ -266,11 +213,6 @@ void xen_set_domain_pte(pte_t *ptep, pte_t pteval, unsigned domid)
 }
 EXPORT_SYMBOL_GPL(xen_set_domain_pte);
 
-static void xen_set_iomap_pte(pte_t *ptep, pte_t pteval)
-{
-       xen_set_domain_pte(ptep, pteval, DOMID_IO);
-}
-
 static void xen_extend_mmu_update(const struct mmu_update *update)
 {
        struct multicall_space mcs;
@@ -279,27 +221,35 @@ static void xen_extend_mmu_update(const struct mmu_update *update)
        mcs = xen_mc_extend_args(__HYPERVISOR_mmu_update, sizeof(*u));
 
        if (mcs.mc != NULL) {
-               ADD_STATS(mmu_update_extended, 1);
-               ADD_STATS(mmu_update_histo[mcs.mc->args[1]], -1);
-
                mcs.mc->args[1]++;
-
-               if (mcs.mc->args[1] < MMU_UPDATE_HISTO)
-                       ADD_STATS(mmu_update_histo[mcs.mc->args[1]], 1);
-               else
-                       ADD_STATS(mmu_update_histo[0], 1);
        } else {
-               ADD_STATS(mmu_update, 1);
                mcs = __xen_mc_entry(sizeof(*u));
                MULTI_mmu_update(mcs.mc, mcs.args, 1, NULL, DOMID_SELF);
-               ADD_STATS(mmu_update_histo[1], 1);
        }
 
        u = mcs.args;
        *u = *update;
 }
 
-void xen_set_pmd_hyper(pmd_t *ptr, pmd_t val)
+static void xen_extend_mmuext_op(const struct mmuext_op *op)
+{
+       struct multicall_space mcs;
+       struct mmuext_op *u;
+
+       mcs = xen_mc_extend_args(__HYPERVISOR_mmuext_op, sizeof(*u));
+
+       if (mcs.mc != NULL) {
+               mcs.mc->args[1]++;
+       } else {
+               mcs = __xen_mc_entry(sizeof(*u));
+               MULTI_mmuext_op(mcs.mc, mcs.args, 1, NULL, DOMID_SELF);
+       }
+
+       u = mcs.args;
+       *u = *op;
+}
+
+static void xen_set_pmd_hyper(pmd_t *ptr, pmd_t val)
 {
        struct mmu_update u;
 
@@ -312,16 +262,14 @@ void xen_set_pmd_hyper(pmd_t *ptr, pmd_t val)
        u.val = pmd_val_ma(val);
        xen_extend_mmu_update(&u);
 
-       ADD_STATS(pmd_update_batched, paravirt_get_lazy_mode() == PARAVIRT_LAZY_MMU);
-
        xen_mc_issue(PARAVIRT_LAZY_MMU);
 
        preempt_enable();
 }
 
-void xen_set_pmd(pmd_t *ptr, pmd_t val)
+static void xen_set_pmd(pmd_t *ptr, pmd_t val)
 {
-       ADD_STATS(pmd_update, 1);
+       trace_xen_mmu_set_pmd(ptr, val);
 
        /* If page is not pinned, we can just update the entry
           directly */
@@ -330,8 +278,6 @@ void xen_set_pmd(pmd_t *ptr, pmd_t val)
                return;
        }
 
-       ADD_STATS(pmd_update_pinned, 1);
-
        xen_set_pmd_hyper(ptr, val);
 }
 
@@ -344,41 +290,60 @@ void set_pte_mfn(unsigned long vaddr, unsigned long mfn, pgprot_t flags)
        set_pte_vaddr(vaddr, mfn_pte(mfn, flags));
 }
 
-void xen_set_pte_at(struct mm_struct *mm, unsigned long addr,
-                   pte_t *ptep, pte_t pteval)
+static bool xen_batched_set_pte(pte_t *ptep, pte_t pteval)
 {
-       if (xen_iomap_pte(pteval)) {
-               xen_set_iomap_pte(ptep, pteval);
-               goto out;
-       }
+       struct mmu_update u;
 
-       ADD_STATS(set_pte_at, 1);
-//     ADD_STATS(set_pte_at_pinned, xen_page_pinned(ptep));
-       ADD_STATS(set_pte_at_current, mm == current->mm);
-       ADD_STATS(set_pte_at_kernel, mm == &init_mm);
+       if (paravirt_get_lazy_mode() != PARAVIRT_LAZY_MMU)
+               return false;
 
-       if (mm == current->mm || mm == &init_mm) {
-               if (paravirt_get_lazy_mode() == PARAVIRT_LAZY_MMU) {
-                       struct multicall_space mcs;
-                       mcs = xen_mc_entry(0);
+       xen_mc_batch();
 
-                       MULTI_update_va_mapping(mcs.mc, addr, pteval, 0);
-                       ADD_STATS(set_pte_at_batched, 1);
-                       xen_mc_issue(PARAVIRT_LAZY_MMU);
-                       goto out;
-               } else
-                       if (HYPERVISOR_update_va_mapping(addr, pteval, 0) == 0)
-                               goto out;
+       u.ptr = virt_to_machine(ptep).maddr | MMU_NORMAL_PT_UPDATE;
+       u.val = pte_val_ma(pteval);
+       xen_extend_mmu_update(&u);
+
+       xen_mc_issue(PARAVIRT_LAZY_MMU);
+
+       return true;
+}
+
+static inline void __xen_set_pte(pte_t *ptep, pte_t pteval)
+{
+       if (!xen_batched_set_pte(ptep, pteval)) {
+               /*
+                * Could call native_set_pte() here and trap and
+                * emulate the PTE write but with 32-bit guests this
+                * needs two traps (one for each of the two 32-bit
+                * words in the PTE) so do one hypercall directly
+                * instead.
+                */
+               struct mmu_update u;
+
+               u.ptr = virt_to_machine(ptep).maddr | MMU_NORMAL_PT_UPDATE;
+               u.val = pte_val_ma(pteval);
+               HYPERVISOR_mmu_update(&u, 1, NULL, DOMID_SELF);
        }
-       xen_set_pte(ptep, pteval);
+}
 
-out:   return;
+static void xen_set_pte(pte_t *ptep, pte_t pteval)
+{
+       trace_xen_mmu_set_pte(ptep, pteval);
+       __xen_set_pte(ptep, pteval);
+}
+
+static void xen_set_pte_at(struct mm_struct *mm, unsigned long addr,
+                   pte_t *ptep, pte_t pteval)
+{
+       trace_xen_mmu_set_pte_at(mm, addr, ptep, pteval);
+       __xen_set_pte(ptep, pteval);
 }
 
 pte_t xen_ptep_modify_prot_start(struct mm_struct *mm,
                                 unsigned long addr, pte_t *ptep)
 {
        /* Just return the pte as-is.  We preserve the bits on commit */
+       trace_xen_mmu_ptep_modify_prot_start(mm, addr, ptep, *ptep);
        return *ptep;
 }
 
@@ -387,15 +352,13 @@ void xen_ptep_modify_prot_commit(struct mm_struct *mm, unsigned long addr,
 {
        struct mmu_update u;
 
+       trace_xen_mmu_ptep_modify_prot_commit(mm, addr, ptep, pte);
        xen_mc_batch();
 
-       u.ptr = arbitrary_virt_to_machine(ptep).maddr | MMU_PT_UPDATE_PRESERVE_AD;
+       u.ptr = virt_to_machine(ptep).maddr | MMU_PT_UPDATE_PRESERVE_AD;
        u.val = pte_val_ma(pte);
        xen_extend_mmu_update(&u);
 
-       ADD_STATS(prot_commit, 1);
-       ADD_STATS(prot_commit_batched, paravirt_get_lazy_mode() == PARAVIRT_LAZY_MMU);
-
        xen_mc_issue(PARAVIRT_LAZY_MMU);
 }
 
@@ -404,8 +367,13 @@ static pteval_t pte_mfn_to_pfn(pteval_t val)
 {
        if (val & _PAGE_PRESENT) {
                unsigned long mfn = (val & PTE_PFN_MASK) >> PAGE_SHIFT;
+               unsigned long pfn = mfn_to_pfn(mfn);
+
                pteval_t flags = val & PTE_FLAGS_MASK;
-               val = ((pteval_t)mfn_to_pfn(mfn) << PAGE_SHIFT) | flags;
+               if (unlikely(pfn == ~0))
+                       val = flags & ~_PAGE_PRESENT;
+               else
+                       val = ((pteval_t)pfn << PAGE_SHIFT) | flags;
        }
 
        return val;
@@ -463,16 +431,16 @@ static pteval_t iomap_pte(pteval_t val)
        return val;
 }
 
-pteval_t xen_pte_val(pte_t pte)
+static pteval_t xen_pte_val(pte_t pte)
 {
        pteval_t pteval = pte.pte;
-
+#if 0
        /* If this is a WC pte, convert back from Xen WC to Linux WC */
        if ((pteval & (_PAGE_PAT | _PAGE_PCD | _PAGE_PWT)) == _PAGE_PAT) {
                WARN_ON(!pat_enabled);
                pteval = (pteval & ~_PAGE_PAT) | _PAGE_PWT;
        }
-
+#endif
        if (xen_initial_domain() && (pteval & _PAGE_IOMAP))
                return pteval;
 
@@ -480,7 +448,7 @@ pteval_t xen_pte_val(pte_t pte)
 }
 PV_CALLEE_SAVE_REGS_THUNK(xen_pte_val);
 
-pgdval_t xen_pgd_val(pgd_t pgd)
+static pgdval_t xen_pgd_val(pgd_t pgd)
 {
        return pte_mfn_to_pfn(pgd.pgd);
 }
@@ -511,10 +479,10 @@ void xen_set_pat(u64 pat)
        WARN_ON(pat != 0x0007010600070106ull);
 }
 
-pte_t xen_make_pte(pteval_t pte)
+static pte_t xen_make_pte(pteval_t pte)
 {
        phys_addr_t addr = (pte & PTE_PFN_MASK);
-
+#if 0
        /* If Linux is trying to set a WC pte, then map to the Xen WC.
         * If _PAGE_PAT is set, then it probably means it is really
         * _PAGE_PSE, so avoid fiddling with the PAT mapping and hope
@@ -527,7 +495,7 @@ pte_t xen_make_pte(pteval_t pte)
                if ((pte & (_PAGE_PCD | _PAGE_PWT)) == _PAGE_PWT)
                        pte = (pte & ~(_PAGE_PCD | _PAGE_PWT)) | _PAGE_PAT;
        }
-
+#endif
        /*
         * Unprivileged domains are allowed to do IOMAPpings for
         * PCI passthrough, but not map ISA space.  The ISA
@@ -546,55 +514,20 @@ pte_t xen_make_pte(pteval_t pte)
 }
 PV_CALLEE_SAVE_REGS_THUNK(xen_make_pte);
 
-#ifdef CONFIG_XEN_DEBUG
-pte_t xen_make_pte_debug(pteval_t pte)
-{
-       phys_addr_t addr = (pte & PTE_PFN_MASK);
-       phys_addr_t other_addr;
-       bool io_page = false;
-       pte_t _pte;
-
-       if (pte & _PAGE_IOMAP)
-               io_page = true;
-
-       _pte = xen_make_pte(pte);
-
-       if (!addr)
-               return _pte;
-
-       if (io_page &&
-           (xen_initial_domain() || addr >= ISA_END_ADDRESS)) {
-               other_addr = pfn_to_mfn(addr >> PAGE_SHIFT) << PAGE_SHIFT;
-               WARN_ONCE(addr != other_addr,
-                       "0x%lx is using VM_IO, but it is 0x%lx!\n",
-                       (unsigned long)addr, (unsigned long)other_addr);
-       } else {
-               pteval_t iomap_set = (_pte.pte & PTE_FLAGS_MASK) & _PAGE_IOMAP;
-               other_addr = (_pte.pte & PTE_PFN_MASK);
-               WARN_ONCE((addr == other_addr) && (!io_page) && (!iomap_set),
-                       "0x%lx is missing VM_IO (and wasn't fixed)!\n",
-                       (unsigned long)addr);
-       }
-
-       return _pte;
-}
-PV_CALLEE_SAVE_REGS_THUNK(xen_make_pte_debug);
-#endif
-
-pgd_t xen_make_pgd(pgdval_t pgd)
+static pgd_t xen_make_pgd(pgdval_t pgd)
 {
        pgd = pte_pfn_to_mfn(pgd);
        return native_make_pgd(pgd);
 }
 PV_CALLEE_SAVE_REGS_THUNK(xen_make_pgd);
 
-pmdval_t xen_pmd_val(pmd_t pmd)
+static pmdval_t xen_pmd_val(pmd_t pmd)
 {
        return pte_mfn_to_pfn(pmd.pmd);
 }
 PV_CALLEE_SAVE_REGS_THUNK(xen_pmd_val);
 
-void xen_set_pud_hyper(pud_t *ptr, pud_t val)
+static void xen_set_pud_hyper(pud_t *ptr, pud_t val)
 {
        struct mmu_update u;
 
@@ -607,16 +540,14 @@ void xen_set_pud_hyper(pud_t *ptr, pud_t val)
        u.val = pud_val_ma(val);
        xen_extend_mmu_update(&u);
 
-       ADD_STATS(pud_update_batched, paravirt_get_lazy_mode() == PARAVIRT_LAZY_MMU);
-
        xen_mc_issue(PARAVIRT_LAZY_MMU);
 
        preempt_enable();
 }
 
-void xen_set_pud(pud_t *ptr, pud_t val)
+static void xen_set_pud(pud_t *ptr, pud_t val)
 {
-       ADD_STATS(pud_update, 1);
+       trace_xen_mmu_set_pud(ptr, val);
 
        /* If page is not pinned, we can just update the entry
           directly */
@@ -625,56 +556,31 @@ void xen_set_pud(pud_t *ptr, pud_t val)
                return;
        }
 
-       ADD_STATS(pud_update_pinned, 1);
-
        xen_set_pud_hyper(ptr, val);
 }
 
-void xen_set_pte(pte_t *ptep, pte_t pte)
-{
-       if (xen_iomap_pte(pte)) {
-               xen_set_iomap_pte(ptep, pte);
-               return;
-       }
-
-       ADD_STATS(pte_update, 1);
-//     ADD_STATS(pte_update_pinned, xen_page_pinned(ptep));
-       ADD_STATS(pte_update_batched, paravirt_get_lazy_mode() == PARAVIRT_LAZY_MMU);
-
-#ifdef CONFIG_X86_PAE
-       ptep->pte_high = pte.pte_high;
-       smp_wmb();
-       ptep->pte_low = pte.pte_low;
-#else
-       *ptep = pte;
-#endif
-}
-
 #ifdef CONFIG_X86_PAE
-void xen_set_pte_atomic(pte_t *ptep, pte_t pte)
+static void xen_set_pte_atomic(pte_t *ptep, pte_t pte)
 {
-       if (xen_iomap_pte(pte)) {
-               xen_set_iomap_pte(ptep, pte);
-               return;
-       }
-
+       trace_xen_mmu_set_pte_atomic(ptep, pte);
        set_64bit((u64 *)ptep, native_pte_val(pte));
 }
 
-void xen_pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
+static void xen_pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
 {
-       ptep->pte_low = 0;
-       smp_wmb();              /* make sure low gets written first */
-       ptep->pte_high = 0;
+       trace_xen_mmu_pte_clear(mm, addr, ptep);
+       if (!xen_batched_set_pte(ptep, native_make_pte(0)))
+               native_pte_clear(mm, addr, ptep);
 }
 
-void xen_pmd_clear(pmd_t *pmdp)
+static void xen_pmd_clear(pmd_t *pmdp)
 {
+       trace_xen_mmu_pmd_clear(pmdp);
        set_pmd(pmdp, __pmd(0));
 }
 #endif /* CONFIG_X86_PAE */
 
-pmd_t xen_make_pmd(pmdval_t pmd)
+static pmd_t xen_make_pmd(pmdval_t pmd)
 {
        pmd = pte_pfn_to_mfn(pmd);
        return native_make_pmd(pmd);
@@ -682,13 +588,13 @@ pmd_t xen_make_pmd(pmdval_t pmd)
 PV_CALLEE_SAVE_REGS_THUNK(xen_make_pmd);
 
 #if PAGETABLE_LEVELS == 4
-pudval_t xen_pud_val(pud_t pud)
+static pudval_t xen_pud_val(pud_t pud)
 {
        return pte_mfn_to_pfn(pud.pud);
 }
 PV_CALLEE_SAVE_REGS_THUNK(xen_pud_val);
 
-pud_t xen_make_pud(pudval_t pud)
+static pud_t xen_make_pud(pudval_t pud)
 {
        pud = pte_pfn_to_mfn(pud);
 
@@ -696,7 +602,7 @@ pud_t xen_make_pud(pudval_t pud)
 }
 PV_CALLEE_SAVE_REGS_THUNK(xen_make_pud);
 
-pgd_t *xen_get_user_pgd(pgd_t *pgd)
+static pgd_t *xen_get_user_pgd(pgd_t *pgd)
 {
        pgd_t *pgd_page = (pgd_t *)(((unsigned long)pgd) & PAGE_MASK);
        unsigned offset = pgd - pgd_page;
@@ -728,7 +634,7 @@ static void __xen_set_pgd_hyper(pgd_t *ptr, pgd_t val)
  *  2. It is always pinned
  *  3. It has no user pagetable attached to it
  */
-void __init xen_set_pgd_hyper(pgd_t *ptr, pgd_t val)
+static void __init xen_set_pgd_hyper(pgd_t *ptr, pgd_t val)
 {
        preempt_disable();
 
@@ -741,11 +647,11 @@ void __init xen_set_pgd_hyper(pgd_t *ptr, pgd_t val)
        preempt_enable();
 }
 
-void xen_set_pgd(pgd_t *ptr, pgd_t val)
+static void xen_set_pgd(pgd_t *ptr, pgd_t val)
 {
        pgd_t *user_ptr = xen_get_user_pgd(ptr);
 
-       ADD_STATS(pgd_update, 1);
+       trace_xen_mmu_set_pgd(ptr, user_ptr, val);
 
        /* If page is not pinned, we can just update the entry
           directly */
@@ -758,9 +664,6 @@ void xen_set_pgd(pgd_t *ptr, pgd_t val)
                return;
        }
 
-       ADD_STATS(pgd_update_pinned, 1);
-       ADD_STATS(pgd_update_batched, paravirt_get_lazy_mode() == PARAVIRT_LAZY_MMU);
-
        /* If it's pinned, then we can at least batch the kernel and
           user updates together. */
        xen_mc_batch();
@@ -909,14 +812,12 @@ static void xen_pte_unlock(void *v)
 
 static void xen_do_pin(unsigned level, unsigned long pfn)
 {
-       struct mmuext_op *op;
-       struct multicall_space mcs;
+       struct mmuext_op op;
 
-       mcs = __xen_mc_entry(sizeof(*op));
-       op = mcs.args;
-       op->cmd = level;
-       op->arg1.mfn = pfn_to_mfn(pfn);
-       MULTI_mmuext_op(mcs.mc, op, 1, NULL, DOMID_SELF);
+       op.cmd = level;
+       op.arg1.mfn = pfn_to_mfn(pfn);
+
+       xen_extend_mmuext_op(&op);
 }
 
 static int xen_pin_page(struct mm_struct *mm, struct page *page,
@@ -984,6 +885,8 @@ static int xen_pin_page(struct mm_struct *mm, struct page *page,
    read-only, and can be pinned. */
 static void __xen_pgd_pin(struct mm_struct *mm, pgd_t *pgd)
 {
+       trace_xen_mmu_pgd_pin(mm, pgd);
+
        xen_mc_batch();
 
        if (__xen_pgd_walk(mm, pgd, xen_pin_page, USER_LIMIT)) {
@@ -1109,6 +1012,8 @@ static int xen_unpin_page(struct mm_struct *mm, struct page *page,
 /* Release a pagetables pages back as normal RW */
 static void __xen_pgd_unpin(struct mm_struct *mm, pgd_t *pgd)
 {
+       trace_xen_mmu_pgd_unpin(mm, pgd);
+
        xen_mc_batch();
 
        xen_do_pin(MMUEXT_UNPIN_TABLE, PFN_DOWN(__pa(pgd)));
@@ -1162,14 +1067,14 @@ void xen_mm_unpin_all(void)
        spin_unlock(&pgd_lock);
 }
 
-void xen_activate_mm(struct mm_struct *prev, struct mm_struct *next)
+static void xen_activate_mm(struct mm_struct *prev, struct mm_struct *next)
 {
        spin_lock(&next->page_table_lock);
        xen_pgd_pin(next);
        spin_unlock(&next->page_table_lock);
 }
 
-void xen_dup_mmap(struct mm_struct *oldmm, struct mm_struct *mm)
+static void xen_dup_mmap(struct mm_struct *oldmm, struct mm_struct *mm)
 {
        spin_lock(&mm->page_table_lock);
        xen_pgd_pin(mm);
@@ -1185,14 +1090,14 @@ static void drop_other_mm_ref(void *info)
        struct mm_struct *mm = info;
        struct mm_struct *active_mm;
 
-       active_mm = percpu_read(cpu_tlbstate.active_mm);
+       active_mm = this_cpu_read(cpu_tlbstate.active_mm);
 
-       if (active_mm == mm)
+       if (active_mm == mm && this_cpu_read(cpu_tlbstate.state) != TLBSTATE_OK)
                leave_mm(smp_processor_id());
 
        /* If this cpu still has a stale cr3 reference, then make sure
           it has been flushed. */
-       if (percpu_read(xen_current_cr3) == __pa(mm->pgd))
+       if (this_cpu_read(xen_current_cr3) == __pa(mm->pgd))
                load_cr3(swapper_pg_dir);
 }
 
@@ -1256,7 +1161,7 @@ static void xen_drop_mm_ref(struct mm_struct *mm)
  * pagetable because of lazy tlb flushing.  This means we need need to
  * switch all CPUs off this pagetable before we can unpin it.
  */
-void xen_exit_mmap(struct mm_struct *mm)
+static void xen_exit_mmap(struct mm_struct *mm)
 {
        get_cpu();              /* make sure we don't move around */
        xen_drop_mm_ref(mm);
@@ -1271,52 +1176,130 @@ void xen_exit_mmap(struct mm_struct *mm)
        spin_unlock(&mm->page_table_lock);
 }
 
-static void __init xen_pagetable_setup_start(pgd_t *base)
-{
-}
+static void xen_post_allocator_init(void);
 
-static __init void xen_mapping_pagetable_reserve(u64 start, u64 end)
+#ifdef CONFIG_X86_64
+static void __init xen_cleanhighmap(unsigned long vaddr,
+                                   unsigned long vaddr_end)
 {
-       /* reserve the range used */
-       native_pagetable_reserve(start, end);
+       unsigned long kernel_end = roundup((unsigned long)_brk_end, PMD_SIZE) - 1;
+       pmd_t *pmd = level2_kernel_pgt + pmd_index(vaddr);
 
-       /* set as RW the rest */
-       printk(KERN_DEBUG "xen: setting RW the range %llx - %llx\n", end,
-                       PFN_PHYS(pgt_buf_top));
-       while (end < PFN_PHYS(pgt_buf_top)) {
-               make_lowmem_page_readwrite(__va(end));
-               end += PAGE_SIZE;
+       /* NOTE: The loop is more greedy than the cleanup_highmap variant.
+        * We include the PMD passed in on _both_ boundaries. */
+       for (; vaddr <= vaddr_end && (pmd < (level2_kernel_pgt + PAGE_SIZE));
+                       pmd++, vaddr += PMD_SIZE) {
+               if (pmd_none(*pmd))
+                       continue;
+               if (vaddr < (unsigned long) _text || vaddr > kernel_end)
+                       set_pmd(pmd, __pmd(0));
        }
+       /* In case we did something silly, we should crash in this function
+        * instead of somewhere later and be confusing. */
+       xen_mc_flush();
 }
-
-static void xen_post_allocator_init(void);
-
-static void __init xen_pagetable_setup_done(pgd_t *base)
+#endif
+static void __init xen_pagetable_init(void)
 {
+#ifdef CONFIG_X86_64
+       unsigned long size;
+       unsigned long addr;
+#endif
+       paging_init();
        xen_setup_shared_info();
+#ifdef CONFIG_X86_64
+       if (!xen_feature(XENFEAT_auto_translated_physmap)) {
+               unsigned long new_mfn_list;
+
+               size = PAGE_ALIGN(xen_start_info->nr_pages * sizeof(unsigned long));
+
+               /* On 32-bit, we get zero so this never gets executed. */
+               new_mfn_list = xen_revector_p2m_tree();
+               if (new_mfn_list && new_mfn_list != xen_start_info->mfn_list) {
+                       /* using __ka address and sticking INVALID_P2M_ENTRY! */
+                       memset((void *)xen_start_info->mfn_list, 0xff, size);
+
+                       /* We should be in __ka space. */
+                       BUG_ON(xen_start_info->mfn_list < __START_KERNEL_map);
+                       addr = xen_start_info->mfn_list;
+                       /* We roundup to the PMD, which means that if anybody at this stage is
+                        * using the __ka address of xen_start_info or xen_start_info->shared_info
+                        * they are in going to crash. Fortunatly we have already revectored
+                        * in xen_setup_kernel_pagetable and in xen_setup_shared_info. */
+                       size = roundup(size, PMD_SIZE);
+                       xen_cleanhighmap(addr, addr + size);
+
+                       size = PAGE_ALIGN(xen_start_info->nr_pages * sizeof(unsigned long));
+                       memblock_free(__pa(xen_start_info->mfn_list), size);
+                       /* And revector! Bye bye old array */
+                       xen_start_info->mfn_list = new_mfn_list;
+               } else
+                       goto skip;
+       }
+       /* At this stage, cleanup_highmap has already cleaned __ka space
+        * from _brk_limit way up to the max_pfn_mapped (which is the end of
+        * the ramdisk). We continue on, erasing PMD entries that point to page
+        * tables - do note that they are accessible at this stage via __va.
+        * For good measure we also round up to the PMD - which means that if
+        * anybody is using __ka address to the initial boot-stack - and try
+        * to use it - they are going to crash. The xen_start_info has been
+        * taken care of already in xen_setup_kernel_pagetable. */
+       addr = xen_start_info->pt_base;
+       size = roundup(xen_start_info->nr_pt_frames * PAGE_SIZE, PMD_SIZE);
+
+       xen_cleanhighmap(addr, addr + size);
+       xen_start_info->pt_base = (unsigned long)__va(__pa(xen_start_info->pt_base));
+#ifdef DEBUG
+       /* This is superflous and is not neccessary, but you know what
+        * lets do it. The MODULES_VADDR -> MODULES_END should be clear of
+        * anything at this stage. */
+       xen_cleanhighmap(MODULES_VADDR, roundup(MODULES_VADDR, PUD_SIZE) - 1);
+#endif
+skip:
+#endif
        xen_post_allocator_init();
 }
-
 static void xen_write_cr2(unsigned long cr2)
 {
-       percpu_read(xen_vcpu)->arch.cr2 = cr2;
+       this_cpu_read(xen_vcpu)->arch.cr2 = cr2;
 }
 
 static unsigned long xen_read_cr2(void)
 {
-       return percpu_read(xen_vcpu)->arch.cr2;
+       return this_cpu_read(xen_vcpu)->arch.cr2;
 }
 
 unsigned long xen_read_cr2_direct(void)
 {
-       return percpu_read(xen_vcpu_info.arch.cr2);
+       return this_cpu_read(xen_vcpu_info.arch.cr2);
 }
 
+void xen_flush_tlb_all(void)
+{
+       struct mmuext_op *op;
+       struct multicall_space mcs;
+
+       trace_xen_mmu_flush_tlb_all(0);
+
+       preempt_disable();
+
+       mcs = xen_mc_entry(sizeof(*op));
+
+       op = mcs.args;
+       op->cmd = MMUEXT_TLB_FLUSH_ALL;
+       MULTI_mmuext_op(mcs.mc, op, 1, NULL, DOMID_SELF);
+
+       xen_mc_issue(PARAVIRT_LAZY_MMU);
+
+       preempt_enable();
+}
 static void xen_flush_tlb(void)
 {
        struct mmuext_op *op;
        struct multicall_space mcs;
 
+       trace_xen_mmu_flush_tlb(0);
+
        preempt_disable();
 
        mcs = xen_mc_entry(sizeof(*op));
@@ -1335,6 +1318,8 @@ static void xen_flush_tlb_single(unsigned long addr)
        struct mmuext_op *op;
        struct multicall_space mcs;
 
+       trace_xen_mmu_flush_tlb_single(addr);
+
        preempt_disable();
 
        mcs = xen_mc_entry(sizeof(*op));
@@ -1349,14 +1334,21 @@ static void xen_flush_tlb_single(unsigned long addr)
 }
 
 static void xen_flush_tlb_others(const struct cpumask *cpus,
-                                struct mm_struct *mm, unsigned long va)
+                                struct mm_struct *mm, unsigned long start,
+                                unsigned long end)
 {
        struct {
                struct mmuext_op op;
+#ifdef CONFIG_SMP
+               DECLARE_BITMAP(mask, num_processors);
+#else
                DECLARE_BITMAP(mask, NR_CPUS);
+#endif
        } *args;
        struct multicall_space mcs;
 
+       trace_xen_mmu_flush_tlb_others(cpus, mm, start, end);
+
        if (cpumask_empty(cpus))
                return;         /* nothing to do */
 
@@ -1368,11 +1360,10 @@ static void xen_flush_tlb_others(const struct cpumask *cpus,
        cpumask_and(to_cpumask(args->mask), cpus, cpu_online_mask);
        cpumask_clear_cpu(smp_processor_id(), to_cpumask(args->mask));
 
-       if (va == TLB_FLUSH_ALL) {
-               args->op.cmd = MMUEXT_TLB_FLUSH_MULTI;
-       } else {
+       args->op.cmd = MMUEXT_TLB_FLUSH_MULTI;
+       if (end != TLB_FLUSH_ALL && (end - start) <= PAGE_SIZE) {
                args->op.cmd = MMUEXT_INVLPG_MULTI;
-               args->op.arg1.linear_addr = va;
+               args->op.arg1.linear_addr = start;
        }
 
        MULTI_mmuext_op(mcs.mc, &args->op, 1, NULL, DOMID_SELF);
@@ -1382,20 +1373,21 @@ static void xen_flush_tlb_others(const struct cpumask *cpus,
 
 static unsigned long xen_read_cr3(void)
 {
-       return percpu_read(xen_cr3);
+       return this_cpu_read(xen_cr3);
 }
 
 static void set_current_cr3(void *v)
 {
-       percpu_write(xen_current_cr3, (unsigned long)v);
+       this_cpu_write(xen_current_cr3, (unsigned long)v);
 }
 
 static void __xen_write_cr3(bool kernel, unsigned long cr3)
 {
-       struct mmuext_op *op;
-       struct multicall_space mcs;
+       struct mmuext_op op;
        unsigned long mfn;
 
+       trace_xen_mmu_write_cr3(kernel, cr3);
+
        if (cr3)
                mfn = pfn_to_mfn(PFN_DOWN(cr3));
        else
@@ -1403,23 +1395,19 @@ static void __xen_write_cr3(bool kernel, unsigned long cr3)
 
        WARN_ON(mfn == 0 && kernel);
 
-       mcs = __xen_mc_entry(sizeof(*op));
+       op.cmd = kernel ? MMUEXT_NEW_BASEPTR : MMUEXT_NEW_USER_BASEPTR;
+       op.arg1.mfn = mfn;
 
-       op = mcs.args;
-       op->cmd = kernel ? MMUEXT_NEW_BASEPTR : MMUEXT_NEW_USER_BASEPTR;
-       op->arg1.mfn = mfn;
-
-       MULTI_mmuext_op(mcs.mc, op, 1, NULL, DOMID_SELF);
+       xen_extend_mmuext_op(&op);
 
        if (kernel) {
-               percpu_write(xen_cr3, cr3);
+               this_cpu_write(xen_cr3, cr3);
 
                /* Update xen_current_cr3 once the batch has actually
                   been submitted. */
                xen_mc_callback(set_current_cr3, (void *)cr3);
        }
 }
-
 static void xen_write_cr3(unsigned long cr3)
 {
        BUG_ON(preemptible());
@@ -1428,7 +1416,7 @@ static void xen_write_cr3(unsigned long cr3)
 
        /* Update while interrupts are disabled, so its atomic with
           respect to ipis */
-       percpu_write(xen_cr3, cr3);
+       this_cpu_write(xen_cr3, cr3);
 
        __xen_write_cr3(true, cr3);
 
@@ -1445,6 +1433,43 @@ static void xen_write_cr3(unsigned long cr3)
        xen_mc_issue(PARAVIRT_LAZY_CPU);  /* interrupts restored */
 }
 
+#ifdef CONFIG_X86_64
+/*
+ * At the start of the day - when Xen launches a guest, it has already
+ * built pagetables for the guest. We diligently look over them
+ * in xen_setup_kernel_pagetable and graft as appropiate them in the
+ * init_level4_pgt and its friends. Then when we are happy we load
+ * the new init_level4_pgt - and continue on.
+ *
+ * The generic code starts (start_kernel) and 'init_mem_mapping' sets
+ * up the rest of the pagetables. When it has completed it loads the cr3.
+ * N.B. that baremetal would start at 'start_kernel' (and the early
+ * #PF handler would create bootstrap pagetables) - so we are running
+ * with the same assumptions as what to do when write_cr3 is executed
+ * at this point.
+ *
+ * Since there are no user-page tables at all, we have two variants
+ * of xen_write_cr3 - the early bootup (this one), and the late one
+ * (xen_write_cr3). The reason we have to do that is that in 64-bit
+ * the Linux kernel and user-space are both in ring 3 while the
+ * hypervisor is in ring 0.
+ */
+static void __init xen_write_cr3_init(unsigned long cr3)
+{
+       BUG_ON(preemptible());
+
+       xen_mc_batch();  /* disables interrupts */
+
+       /* Update while interrupts are disabled, so its atomic with
+          respect to ipis */
+       this_cpu_write(xen_cr3, cr3);
+
+       __xen_write_cr3(true, cr3);
+
+       xen_mc_issue(PARAVIRT_LAZY_CPU);  /* interrupts restored */
+}
+#endif
+
 static int xen_pgd_alloc(struct mm_struct *mm)
 {
        pgd_t *pgd = mm->pgd;
@@ -1500,30 +1525,32 @@ static pte_t __init mask_rw_pte(pte_t *ptep, pte_t pte)
 #else /* CONFIG_X86_64 */
 static pte_t __init mask_rw_pte(pte_t *ptep, pte_t pte)
 {
-       unsigned long pfn = pte_pfn(pte);
-
-       /*
-        * If the new pfn is within the range of the newly allocated
-        * kernel pagetable, and it isn't being mapped into an
-        * early_ioremap fixmap slot as a freshly allocated page, make sure
-        * it is RO.
-        */
-       if (((!is_early_ioremap_ptep(ptep) &&
-                       pfn >= pgt_buf_start && pfn < pgt_buf_top)) ||
-                       (is_early_ioremap_ptep(ptep) && pfn != (pgt_buf_end - 1)))
-               pte = pte_wrprotect(pte);
-
        return pte;
 }
 #endif /* CONFIG_X86_64 */
 
-/* Init-time set_pte while constructing initial pagetables, which
-   doesn't allow RO pagetable pages to be remapped RW */
+/*
+ * Init-time set_pte while constructing initial pagetables, which
+ * doesn't allow RO page table pages to be remapped RW.
+ *
+ * If there is no MFN for this PFN then this page is initially
+ * ballooned out so clear the PTE (as in decrease_reservation() in
+ * drivers/xen/balloon.c).
+ *
+ * Many of these PTE updates are done on unpinned and writable pages
+ * and doing a hypercall for these is unnecessary and expensive.  At
+ * this point it is not possible to tell if a page is pinned or not,
+ * so always write the PTE directly and rely on Xen trapping and
+ * emulating any updates as necessary.
+ */
 static void __init xen_set_pte_init(pte_t *ptep, pte_t pte)
 {
-       pte = mask_rw_pte(ptep, pte);
+       if (pte_mfn(pte) != INVALID_P2M_ENTRY)
+               pte = mask_rw_pte(ptep, pte);
+       else
+               pte = __pte_ma(0);
 
-       xen_set_pte(ptep, pte);
+       native_set_pte(ptep, pte);
 }
 
 static void pin_pagetable_pfn(unsigned cmd, unsigned long pfn)
@@ -1568,19 +1595,52 @@ static void __init xen_release_pmd_init(unsigned long pfn)
        make_lowmem_page_readwrite(__va(PFN_PHYS(pfn)));
 }
 
+static inline void __pin_pagetable_pfn(unsigned cmd, unsigned long pfn)
+{
+       struct multicall_space mcs;
+       struct mmuext_op *op;
+
+       mcs = __xen_mc_entry(sizeof(*op));
+       op = mcs.args;
+       op->cmd = cmd;
+       op->arg1.mfn = pfn_to_mfn(pfn);
+
+       MULTI_mmuext_op(mcs.mc, mcs.args, 1, NULL, DOMID_SELF);
+}
+
+static inline void __set_pfn_prot(unsigned long pfn, pgprot_t prot)
+{
+       struct multicall_space mcs;
+       unsigned long addr = (unsigned long)__va(pfn << PAGE_SHIFT);
+
+       mcs = __xen_mc_entry(0);
+       MULTI_update_va_mapping(mcs.mc, (unsigned long)addr,
+                               pfn_pte(pfn, prot), 0);
+}
+
 /* This needs to make sure the new pte page is pinned iff its being
    attached to a pinned pagetable. */
-static void xen_alloc_ptpage(struct mm_struct *mm, unsigned long pfn, unsigned level)
+static inline void xen_alloc_ptpage(struct mm_struct *mm, unsigned long pfn,
+                                   unsigned level)
 {
-       struct page *page = pfn_to_page(pfn);
+       bool pinned = PagePinned(virt_to_page(mm->pgd));
+
+       trace_xen_mmu_alloc_ptpage(mm, pfn, level, pinned);
+
+       if (pinned) {
+               struct page *page = pfn_to_page(pfn);
 
-       if (PagePinned(virt_to_page(mm->pgd))) {
                SetPagePinned(page);
 
                if (!PageHighMem(page)) {
-                       make_lowmem_page_readonly(__va(PFN_PHYS((unsigned long)pfn)));
+                       xen_mc_batch();
+
+                       __set_pfn_prot(pfn, PAGE_KERNEL_RO);
+
                        if (level == PT_PTE && USE_SPLIT_PTLOCKS)
-                               pin_pagetable_pfn(MMUEXT_PIN_L1_TABLE, pfn);
+                               __pin_pagetable_pfn(MMUEXT_PIN_L1_TABLE, pfn);
+
+                       xen_mc_issue(PARAVIRT_LAZY_MMU);
                } else {
                        /* make sure there are no stray mappings of
                           this page */
@@ -1600,15 +1660,23 @@ static void xen_alloc_pmd(struct mm_struct *mm, unsigned long pfn)
 }
 
 /* This should never happen until we're OK to use struct page */
-static void xen_release_ptpage(unsigned long pfn, unsigned level)
+static inline void xen_release_ptpage(unsigned long pfn, unsigned level)
 {
        struct page *page = pfn_to_page(pfn);
+       bool pinned = PagePinned(page);
 
-       if (PagePinned(page)) {
+       trace_xen_mmu_release_ptpage(pfn, level, pinned);
+
+       if (pinned) {
                if (!PageHighMem(page)) {
+                       xen_mc_batch();
+
                        if (level == PT_PTE && USE_SPLIT_PTLOCKS)
-                               pin_pagetable_pfn(MMUEXT_UNPIN_TABLE, pfn);
-                       make_lowmem_page_readwrite(__va(PFN_PHYS(pfn)));
+                               __pin_pagetable_pfn(MMUEXT_UNPIN_TABLE, pfn);
+
+                       __set_pfn_prot(pfn, PAGE_KERNEL);
+
+                       xen_mc_issue(PARAVIRT_LAZY_MMU);
                }
                ClearPagePinned(page);
        }
@@ -1688,7 +1756,7 @@ static void set_page_prot(void *addr, pgprot_t prot)
        if (HYPERVISOR_update_va_mapping((unsigned long)addr, pte, 0))
                BUG();
 }
-
+#ifdef CONFIG_X86_32
 static void __init xen_map_identity_early(pmd_t *pmd, unsigned long max_pfn)
 {
        unsigned pmdidx, pteidx;
@@ -1721,6 +1789,11 @@ static void __init xen_map_identity_early(pmd_t *pmd, unsigned long max_pfn)
                for (pteidx = 0; pteidx < PTRS_PER_PTE; pteidx++, pfn++) {
                        pte_t pte;
 
+#ifdef CONFIG_X86_32
+                       if (pfn > max_pfn_mapped)
+                               max_pfn_mapped = pfn;
+#endif
+
                        if (!pte_none(pte_page[pteidx]))
                                continue;
 
@@ -1734,19 +1807,21 @@ static void __init xen_map_identity_early(pmd_t *pmd, unsigned long max_pfn)
 
        set_page_prot(pmd, PAGE_KERNEL_RO);
 }
-
+#endif
 void __init xen_setup_machphys_mapping(void)
 {
        struct xen_machphys_mapping mapping;
-       unsigned long machine_to_phys_nr_ents;
 
        if (HYPERVISOR_memory_op(XENMEM_machphys_mapping, &mapping) == 0) {
                machine_to_phys_mapping = (unsigned long *)mapping.v_start;
-               machine_to_phys_nr_ents = mapping.max_mfn + 1;
+               machine_to_phys_nr = mapping.max_mfn + 1;
        } else {
-               machine_to_phys_nr_ents = MACH2PHYS_NR_ENTRIES;
+               machine_to_phys_nr = MACH2PHYS_NR_ENTRIES;
        }
-       machine_to_phys_order = fls(machine_to_phys_nr_ents - 1);
+#ifdef CONFIG_X86_32
+       WARN_ON((machine_to_phys_mapping + (machine_to_phys_nr - 1))
+               < machine_to_phys_mapping);
+#endif
 }
 
 #ifdef CONFIG_X86_64
@@ -1760,7 +1835,20 @@ static void convert_pfn_mfn(void *v)
        for (i = 0; i < PTRS_PER_PTE; i++)
                pte[i] = xen_make_pte(pte[i].pte);
 }
-
+static void __init check_pt_base(unsigned long *pt_base, unsigned long *pt_end,
+                                unsigned long addr)
+{
+       if (*pt_base == PFN_DOWN(__pa(addr))) {
+               set_page_prot((void *)addr, PAGE_KERNEL);
+               clear_page((void *)addr);
+               (*pt_base)++;
+       }
+       if (*pt_end == PFN_DOWN(__pa(addr))) {
+               set_page_prot((void *)addr, PAGE_KERNEL);
+               clear_page((void *)addr);
+               (*pt_end)--;
+       }
+}
 /*
  * Set up the initial kernel pagetable.
  *
@@ -1772,11 +1860,13 @@ static void convert_pfn_mfn(void *v)
  * of the physical mapping once some sort of allocator has been set
  * up.
  */
-pgd_t * __init xen_setup_kernel_pagetable(pgd_t *pgd,
-                                        unsigned long max_pfn)
+void __init xen_setup_kernel_pagetable(pgd_t *pgd, unsigned long max_pfn)
 {
        pud_t *l3;
        pmd_t *l2;
+       unsigned long addr[3];
+       unsigned long pt_base, pt_end;
+       unsigned i;
 
        /* max_pfn_mapped is the last pfn mapped in the initial memory
         * mappings. Considering that on Xen after the kernel mappings we
@@ -1784,32 +1874,53 @@ pgd_t * __init xen_setup_kernel_pagetable(pgd_t *pgd,
         * set max_pfn_mapped to the last real pfn mapped. */
        max_pfn_mapped = PFN_DOWN(__pa(xen_start_info->mfn_list));
 
+       pt_base = PFN_DOWN(__pa(xen_start_info->pt_base));
+       pt_end = pt_base + xen_start_info->nr_pt_frames;
+
        /* Zap identity mapping */
        init_level4_pgt[0] = __pgd(0);
 
        /* Pre-constructed entries are in pfn, so convert to mfn */
+       /* L4[272] -> level3_ident_pgt
+        * L4[511] -> level3_kernel_pgt */
        convert_pfn_mfn(init_level4_pgt);
+
+       /* L3_i[0] -> level2_ident_pgt */
        convert_pfn_mfn(level3_ident_pgt);
+       /* L3_k[510] -> level2_kernel_pgt
+        * L3_i[511] -> level2_fixmap_pgt */
        convert_pfn_mfn(level3_kernel_pgt);
 
+       /* We get [511][511] and have Xen's version of level2_kernel_pgt */
        l3 = m2v(pgd[pgd_index(__START_KERNEL_map)].pgd);
        l2 = m2v(l3[pud_index(__START_KERNEL_map)].pud);
 
-       memcpy(level2_ident_pgt, l2, sizeof(pmd_t) * PTRS_PER_PMD);
-       memcpy(level2_kernel_pgt, l2, sizeof(pmd_t) * PTRS_PER_PMD);
-
+       addr[0] = (unsigned long)pgd;
+       addr[1] = (unsigned long)l3;
+       addr[2] = (unsigned long)l2;
+       /* Graft it onto L4[272][0]. Note that we creating an aliasing problem:
+        * Both L4[272][0] and L4[511][511] have entries that point to the same
+        * L2 (PMD) tables. Meaning that if you modify it in __va space
+        * it will be also modified in the __ka space! (But if you just
+        * modify the PMD table to point to other PTE's or none, then you
+        * are OK - which is what cleanup_highmap does) */
+       copy_page(level2_ident_pgt, l2);
+       /* Graft it onto L4[511][511] */
+       copy_page(level2_kernel_pgt, l2);
+
+       /* Get [511][510] and graft that in level2_fixmap_pgt */
        l3 = m2v(pgd[pgd_index(__START_KERNEL_map + PMD_SIZE)].pgd);
        l2 = m2v(l3[pud_index(__START_KERNEL_map + PMD_SIZE)].pud);
-       memcpy(level2_fixmap_pgt, l2, sizeof(pmd_t) * PTRS_PER_PMD);
-
-       /* Set up identity map */
-       xen_map_identity_early(level2_ident_pgt, max_pfn);
+       copy_page(level2_fixmap_pgt, l2);
+       /* Note that we don't do anything with level1_fixmap_pgt which
+        * we don't need. */
 
        /* Make pagetable pieces RO */
        set_page_prot(init_level4_pgt, PAGE_KERNEL_RO);
        set_page_prot(level3_ident_pgt, PAGE_KERNEL_RO);
        set_page_prot(level3_kernel_pgt, PAGE_KERNEL_RO);
        set_page_prot(level3_user_vsyscall, PAGE_KERNEL_RO);
+       set_page_prot(level2_ident_pgt, PAGE_KERNEL_RO);
        set_page_prot(level2_kernel_pgt, PAGE_KERNEL_RO);
        set_page_prot(level2_fixmap_pgt, PAGE_KERNEL_RO);
 
@@ -1820,24 +1931,28 @@ pgd_t * __init xen_setup_kernel_pagetable(pgd_t *pgd,
        /* Unpin Xen-provided one */
        pin_pagetable_pfn(MMUEXT_UNPIN_TABLE, PFN_DOWN(__pa(pgd)));
 
-       /* Switch over */
-       pgd = init_level4_pgt;
-
        /*
         * At this stage there can be no user pgd, and no page
         * structure to attach it to, so make sure we just set kernel
         * pgd.
         */
        xen_mc_batch();
-       __xen_write_cr3(true, __pa(pgd));
+       __xen_write_cr3(true, __pa(init_level4_pgt));
        xen_mc_issue(PARAVIRT_LAZY_CPU);
 
-       memblock_x86_reserve_range(__pa(xen_start_info->pt_base),
-                     __pa(xen_start_info->pt_base +
-                          xen_start_info->nr_pt_frames * PAGE_SIZE),
-                     "XEN PAGETABLES");
+       /* We can't that easily rip out L3 and L2, as the Xen pagetables are
+        * set out this way: [L4], [L1], [L2], [L3], [L1], [L1] ...  for
+        * the initial domain. For guests using the toolstack, they are in:
+        * [L4], [L3], [L2], [L1], [L1], order .. So for dom0 we can only
+        * rip out the [L4] (pgd), but for guests we shave off three pages.
+        */
+       for (i = 0; i < ARRAY_SIZE(addr); i++)
+               check_pt_base(&pt_base, &pt_end, addr[i]);
 
-       return pgd;
+       /* Our (by three pages) smaller Xen pagetable that we are using */
+       memblock_reserve(PFN_PHYS(pt_base), (pt_end - pt_base) * PAGE_SIZE);
+       /* Revector the xen_start_info */
+       xen_start_info = (struct start_info *)__va(__pa(xen_start_info));
 }
 #else  /* !CONFIG_X86_64 */
 static RESERVE_BRK_ARRAY(pmd_t, initial_kernel_pmd, PTRS_PER_PMD);
@@ -1862,8 +1977,7 @@ static void __init xen_write_cr3_init(unsigned long cr3)
         */
        swapper_kernel_pmd =
                extend_brk(sizeof(pmd_t) * PTRS_PER_PMD, PAGE_SIZE);
-       memcpy(swapper_kernel_pmd, initial_kernel_pmd,
-              sizeof(pmd_t) * PTRS_PER_PMD);
+       copy_page(swapper_kernel_pmd, initial_kernel_pmd);
        swapper_pg_dir[KERNEL_PGD_BOUNDARY] =
                __pgd(__pa(swapper_kernel_pmd) | _PAGE_PRESENT);
        set_page_prot(swapper_kernel_pmd, PAGE_KERNEL_RO);
@@ -1880,22 +1994,23 @@ static void __init xen_write_cr3_init(unsigned long cr3)
        pv_mmu_ops.write_cr3 = &xen_write_cr3;
 }
 
-pgd_t * __init xen_setup_kernel_pagetable(pgd_t *pgd,
-                                        unsigned long max_pfn)
+void __init xen_setup_kernel_pagetable(pgd_t *pgd, unsigned long max_pfn)
 {
        pmd_t *kernel_pmd;
 
        initial_kernel_pmd =
                extend_brk(sizeof(pmd_t) * PTRS_PER_PMD, PAGE_SIZE);
 
-       max_pfn_mapped = PFN_DOWN(__pa(xen_start_info->mfn_list));
+       max_pfn_mapped = PFN_DOWN(__pa(xen_start_info->pt_base) +
+                                 xen_start_info->nr_pt_frames * PAGE_SIZE +
+                                 512*1024);
 
        kernel_pmd = m2v(pgd[KERNEL_PGD_BOUNDARY].pgd);
-       memcpy(initial_kernel_pmd, kernel_pmd, sizeof(pmd_t) * PTRS_PER_PMD);
+       copy_page(initial_kernel_pmd, kernel_pmd);
 
        xen_map_identity_early(initial_kernel_pmd, max_pfn);
 
-       memcpy(initial_page_table, pgd, sizeof(pgd_t) * PTRS_PER_PGD);
+       copy_page(initial_page_table, pgd);
        initial_page_table[KERNEL_PGD_BOUNDARY] =
                __pgd(__pa(initial_kernel_pmd) | _PAGE_PRESENT);
 
@@ -1909,12 +2024,8 @@ pgd_t * __init xen_setup_kernel_pagetable(pgd_t *pgd,
                          PFN_DOWN(__pa(initial_page_table)));
        xen_write_cr3(__pa(initial_page_table));
 
-       memblock_x86_reserve_range(__pa(xen_start_info->pt_base),
-                     __pa(xen_start_info->pt_base +
-                          xen_start_info->nr_pt_frames * PAGE_SIZE),
-                     "XEN PAGETABLES");
-
-       return initial_page_table;
+       memblock_reserve(__pa(xen_start_info->pt_base),
+                        xen_start_info->nr_pt_frames * PAGE_SIZE);
 }
 #endif /* CONFIG_X86_64 */
 
@@ -1939,6 +2050,7 @@ static void xen_set_fixmap(unsigned idx, phys_addr_t phys, pgprot_t prot)
 # endif
 #else
        case VSYSCALL_LAST_PAGE ... VSYSCALL_FIRST_PAGE:
+       case VVAR_PAGE:
 #endif
        case FIX_TEXT_POKE0:
        case FIX_TEXT_POKE1:
@@ -1979,41 +2091,16 @@ static void xen_set_fixmap(unsigned idx, phys_addr_t phys, pgprot_t prot)
 #ifdef CONFIG_X86_64
        /* Replicate changes to map the vsyscall page into the user
           pagetable vsyscall mapping. */
-       if (idx >= VSYSCALL_LAST_PAGE && idx <= VSYSCALL_FIRST_PAGE) {
+       if ((idx >= VSYSCALL_LAST_PAGE && idx <= VSYSCALL_FIRST_PAGE) ||
+           idx == VVAR_PAGE) {
                unsigned long vaddr = __fix_to_virt(idx);
                set_pte_vaddr_pud(level3_user_vsyscall, vaddr, pte);
        }
 #endif
 }
 
-void __init xen_ident_map_ISA(void)
-{
-       unsigned long pa;
-
-       /*
-        * If we're dom0, then linear map the ISA machine addresses into
-        * the kernel's address space.
-        */
-       if (!xen_initial_domain())
-               return;
-
-       xen_raw_printk("Xen: setup ISA identity maps\n");
-
-       for (pa = ISA_START_ADDRESS; pa < ISA_END_ADDRESS; pa += PAGE_SIZE) {
-               pte_t pte = mfn_pte(PFN_DOWN(pa), PAGE_KERNEL_IO);
-
-               if (HYPERVISOR_update_va_mapping(PAGE_OFFSET + pa, pte, 0))
-                       BUG();
-       }
-
-       xen_flush_tlb();
-}
-
 static void __init xen_post_allocator_init(void)
 {
-#ifdef CONFIG_XEN_DEBUG
-       pv_mmu_ops.make_pte = PV_CALLEE_SAVE(xen_make_pte_debug);
-#endif
        pv_mmu_ops.set_pte = xen_set_pte;
        pv_mmu_ops.set_pmd = xen_set_pmd;
        pv_mmu_ops.set_pud = xen_set_pud;
@@ -2033,6 +2120,7 @@ static void __init xen_post_allocator_init(void)
 #endif
 
 #ifdef CONFIG_X86_64
+       pv_mmu_ops.write_cr3 = &xen_write_cr3;
        SetPagePinned(virt_to_page(level3_user_vsyscall));
 #endif
        xen_mark_init_mm_pinned();
@@ -2051,11 +2139,7 @@ static const struct pv_mmu_ops xen_mmu_ops __initconst = {
        .write_cr2 = xen_write_cr2,
 
        .read_cr3 = xen_read_cr3,
-#ifdef CONFIG_X86_32
        .write_cr3 = xen_write_cr3_init,
-#else
-       .write_cr3 = xen_write_cr3,
-#endif
 
        .flush_tlb_user = xen_flush_tlb,
        .flush_tlb_kernel = xen_flush_tlb,
@@ -2112,6 +2196,7 @@ static const struct pv_mmu_ops xen_mmu_ops __initconst = {
        .lazy_mode = {
                .enter = paravirt_enter_lazy_mmu,
                .leave = xen_leave_lazy_mmu,
+               .flush = paravirt_flush_lazy_mmu,
        },
 
        .set_fixmap = xen_set_fixmap,
@@ -2119,9 +2204,7 @@ static const struct pv_mmu_ops xen_mmu_ops __initconst = {
 
 void __init xen_init_mmu_ops(void)
 {
-       x86_init.mapping.pagetable_reserve = xen_mapping_pagetable_reserve;
-       x86_init.paging.pagetable_setup_start = xen_pagetable_setup_start;
-       x86_init.paging.pagetable_setup_done = xen_pagetable_setup_done;
+       x86_init.paging.pagetable_init = xen_pagetable_init;
        pv_mmu_ops = xen_mmu_ops;
 
        memset(dummy_mapping, 0xff, PAGE_SIZE);
@@ -2324,6 +2407,43 @@ void xen_destroy_contiguous_region(unsigned long vstart, unsigned int order)
 EXPORT_SYMBOL_GPL(xen_destroy_contiguous_region);
 
 #ifdef CONFIG_XEN_PVHVM
+#ifdef CONFIG_PROC_VMCORE
+/*
+ * This function is used in two contexts:
+ * - the kdump kernel has to check whether a pfn of the crashed kernel
+ *   was a ballooned page. vmcore is using this function to decide
+ *   whether to access a pfn of the crashed kernel.
+ * - the kexec kernel has to check whether a pfn was ballooned by the
+ *   previous kernel. If the pfn is ballooned, handle it properly.
+ * Returns 0 if the pfn is not backed by a RAM page, the caller may
+ * handle the pfn special in this case.
+ */
+static int xen_oldmem_pfn_is_ram(unsigned long pfn)
+{
+       struct xen_hvm_get_mem_type a = {
+               .domid = DOMID_SELF,
+               .pfn = pfn,
+       };
+       int ram;
+
+       if (HYPERVISOR_hvm_op(HVMOP_get_mem_type, &a))
+               return -ENXIO;
+
+       switch (a.mem_type) {
+               case HVMMEM_mmio_dm:
+                       ram = 0;
+                       break;
+               case HVMMEM_ram_rw:
+               case HVMMEM_ram_ro:
+               default:
+                       ram = 1;
+                       break;
+       }
+
+       return ram;
+}
+#endif
+
 static void xen_hvm_exit_mmap(struct mm_struct *mm)
 {
        struct xen_hvm_pagetable_dying a;
@@ -2354,6 +2474,9 @@ void __init xen_hvm_init_mmu_ops(void)
 {
        if (is_pagetable_dying_supported())
                pv_mmu_ops.exit_mmap = xen_hvm_exit_mmap;
+#ifdef CONFIG_PROC_VMCORE
+       register_oldmem_pfn_is_ram(&xen_oldmem_pfn_is_ram);
+#endif
 }
 #endif
 
@@ -2371,7 +2494,7 @@ static int remap_area_mfn_pte_fn(pte_t *ptep, pgtable_t token,
        struct remap_data *rmd = data;
        pte_t pte = pte_mkspecial(pfn_pte(rmd->mfn++, rmd->prot));
 
-       rmd->mmu_update->ptr = arbitrary_virt_to_machine(ptep).maddr;
+       rmd->mmu_update->ptr = virt_to_machine(ptep).maddr;
        rmd->mmu_update->val = pte_val_ma(pte);
        rmd->mmu_update++;
 
@@ -2380,8 +2503,10 @@ static int remap_area_mfn_pte_fn(pte_t *ptep, pgtable_t token,
 
 int xen_remap_domain_mfn_range(struct vm_area_struct *vma,
                               unsigned long addr,
-                              unsigned long mfn, int nr,
-                              pgprot_t prot, unsigned domid)
+                              xen_pfn_t mfn, int nr,
+                              pgprot_t prot, unsigned domid,
+                              struct page **pages)
+
 {
        struct remap_data rmd;
        struct mmu_update mmu_update[REMAP_BATCH_SIZE];
@@ -2389,10 +2514,12 @@ int xen_remap_domain_mfn_range(struct vm_area_struct *vma,
        unsigned long range;
        int err = 0;
 
+       if (xen_feature(XENFEAT_auto_translated_physmap))
+               return -EINVAL;
+
        prot = __pgprot(pgprot_val(prot) | _PAGE_IOMAP);
 
-       BUG_ON(!((vma->vm_flags & (VM_PFNMAP | VM_RESERVED | VM_IO)) ==
-                               (VM_PFNMAP | VM_RESERVED | VM_IO)));
+       BUG_ON(!((vma->vm_flags & (VM_PFNMAP | VM_IO)) == (VM_PFNMAP | VM_IO)));
 
        rmd.mfn = mfn;
        rmd.prot = prot;
@@ -2407,8 +2534,8 @@ int xen_remap_domain_mfn_range(struct vm_area_struct *vma,
                if (err)
                        goto out;
 
-               err = -EFAULT;
-               if (HYPERVISOR_mmu_update(mmu_update, batch, NULL, domid) < 0)
+               err = HYPERVISOR_mmu_update(mmu_update, batch, NULL, domid);
+               if (err < 0)
                        goto out;
 
                nr -= batch;
@@ -2418,84 +2545,19 @@ int xen_remap_domain_mfn_range(struct vm_area_struct *vma,
        err = 0;
 out:
 
-       flush_tlb_all();
+       xen_flush_tlb_all();
 
        return err;
 }
 EXPORT_SYMBOL_GPL(xen_remap_domain_mfn_range);
 
-#ifdef CONFIG_XEN_DEBUG_FS
-
-static int p2m_dump_open(struct inode *inode, struct file *filp)
-{
-       return single_open(filp, p2m_dump_show, NULL);
-}
-
-static const struct file_operations p2m_dump_fops = {
-       .open           = p2m_dump_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = single_release,
-};
-
-static struct dentry *d_mmu_debug;
-
-static int __init xen_mmu_debugfs(void)
+/* Returns: 0 success */
+int xen_unmap_domain_mfn_range(struct vm_area_struct *vma,
+                              int numpgs, struct page **pages)
 {
-       struct dentry *d_xen = xen_init_debugfs();
-
-       if (d_xen == NULL)
-               return -ENOMEM;
+       if (!pages || !xen_feature(XENFEAT_auto_translated_physmap))
+               return 0;
 
-       d_mmu_debug = debugfs_create_dir("mmu", d_xen);
-
-       debugfs_create_u8("zero_stats", 0644, d_mmu_debug, &zero_stats);
-
-       debugfs_create_u32("pgd_update", 0444, d_mmu_debug, &mmu_stats.pgd_update);
-       debugfs_create_u32("pgd_update_pinned", 0444, d_mmu_debug,
-                          &mmu_stats.pgd_update_pinned);
-       debugfs_create_u32("pgd_update_batched", 0444, d_mmu_debug,
-                          &mmu_stats.pgd_update_pinned);
-
-       debugfs_create_u32("pud_update", 0444, d_mmu_debug, &mmu_stats.pud_update);
-       debugfs_create_u32("pud_update_pinned", 0444, d_mmu_debug,
-                          &mmu_stats.pud_update_pinned);
-       debugfs_create_u32("pud_update_batched", 0444, d_mmu_debug,
-                          &mmu_stats.pud_update_pinned);
-
-       debugfs_create_u32("pmd_update", 0444, d_mmu_debug, &mmu_stats.pmd_update);
-       debugfs_create_u32("pmd_update_pinned", 0444, d_mmu_debug,
-                          &mmu_stats.pmd_update_pinned);
-       debugfs_create_u32("pmd_update_batched", 0444, d_mmu_debug,
-                          &mmu_stats.pmd_update_pinned);
-
-       debugfs_create_u32("pte_update", 0444, d_mmu_debug, &mmu_stats.pte_update);
-//     debugfs_create_u32("pte_update_pinned", 0444, d_mmu_debug,
-//                        &mmu_stats.pte_update_pinned);
-       debugfs_create_u32("pte_update_batched", 0444, d_mmu_debug,
-                          &mmu_stats.pte_update_pinned);
-
-       debugfs_create_u32("mmu_update", 0444, d_mmu_debug, &mmu_stats.mmu_update);
-       debugfs_create_u32("mmu_update_extended", 0444, d_mmu_debug,
-                          &mmu_stats.mmu_update_extended);
-       xen_debugfs_create_u32_array("mmu_update_histo", 0444, d_mmu_debug,
-                                    mmu_stats.mmu_update_histo, 20);
-
-       debugfs_create_u32("set_pte_at", 0444, d_mmu_debug, &mmu_stats.set_pte_at);
-       debugfs_create_u32("set_pte_at_batched", 0444, d_mmu_debug,
-                          &mmu_stats.set_pte_at_batched);
-       debugfs_create_u32("set_pte_at_current", 0444, d_mmu_debug,
-                          &mmu_stats.set_pte_at_current);
-       debugfs_create_u32("set_pte_at_kernel", 0444, d_mmu_debug,
-                          &mmu_stats.set_pte_at_kernel);
-
-       debugfs_create_u32("prot_commit", 0444, d_mmu_debug, &mmu_stats.prot_commit);
-       debugfs_create_u32("prot_commit_batched", 0444, d_mmu_debug,
-                          &mmu_stats.prot_commit_batched);
-
-       debugfs_create_file("p2m", 0600, d_mmu_debug, NULL, &p2m_dump_fops);
-       return 0;
+       return -EINVAL;
 }
-fs_initcall(xen_mmu_debugfs);
-
-#endif /* CONFIG_XEN_DEBUG_FS */
+EXPORT_SYMBOL_GPL(xen_unmap_domain_mfn_range);