#include <asm/setup.h>
 #include <asm/arch_hooks.h>
 #include <asm/time.h>
+#include <asm/pgalloc.h>
 #include <asm/irq.h>
 #include <asm/delay.h>
 #include <asm/fixmap.h>
        .flush_tlb_single = native_flush_tlb_single,
        .flush_tlb_others = native_flush_tlb_others,
 
+       .pgd_alloc = __paravirt_pgd_alloc,
+       .pgd_free = paravirt_nop,
+
        .alloc_pte = paravirt_nop,
        .alloc_pmd = paravirt_nop,
        .alloc_pmd_clone = paravirt_nop,
 
 
        /* so that alloc_pmd can use it */
        mm->pgd = pgd;
-       if (pgd)
+       if (pgd) {
                pgd_ctor(pgd);
 
-       if (pgd && !pgd_prepopulate_pmd(mm, pgd)) {
-               pgd_dtor(pgd);
-               free_page((unsigned long)pgd);
-               pgd = NULL;
+               if (paravirt_pgd_alloc(mm) != 0 ||
+                   !pgd_prepopulate_pmd(mm, pgd)) {
+                       pgd_dtor(pgd);
+                       free_page((unsigned long)pgd);
+                       pgd = NULL;
+               }
        }
 
        return pgd;
 {
        pgd_mop_up_pmds(mm, pgd);
        pgd_dtor(pgd);
+       paravirt_pgd_free(mm, pgd);
        free_page((unsigned long)pgd);
 }
 
 
 #include <asm/pgtable.h>
 #include <asm/tlbflush.h>
 #include <asm/reboot.h>
+#include <asm/pgalloc.h>
 
 #include "xen-ops.h"
 #include "mmu.h"
        .pte_update = paravirt_nop,
        .pte_update_defer = paravirt_nop,
 
+       .pgd_alloc = __paravirt_pgd_alloc,
+       .pgd_free = paravirt_nop,
+
        .alloc_pte = xen_alloc_pte_init,
        .release_pte = xen_release_pte_init,
        .alloc_pmd = xen_alloc_pte_init,
 
        void (*flush_tlb_others)(const cpumask_t *cpus, struct mm_struct *mm,
                                 unsigned long va);
 
-       /* Hooks for allocating/releasing pagetable pages */
+       /* Hooks for allocating and freeing a pagetable top-level */
+       int  (*pgd_alloc)(struct mm_struct *mm);
+       void (*pgd_free)(struct mm_struct *mm, pgd_t *pgd);
+
+       /*
+        * Hooks for allocating/releasing pagetable pages when they're
+        * attached to a pagetable
+        */
        void (*alloc_pte)(struct mm_struct *mm, u32 pfn);
        void (*alloc_pmd)(struct mm_struct *mm, u32 pfn);
        void (*alloc_pmd_clone)(u32 pfn, u32 clonepfn, u32 start, u32 count);
        PVOP_VCALL3(pv_mmu_ops.flush_tlb_others, &cpumask, mm, va);
 }
 
+static inline int paravirt_pgd_alloc(struct mm_struct *mm)
+{
+       return PVOP_CALL1(int, pv_mmu_ops.pgd_alloc, mm);
+}
+
+static inline void paravirt_pgd_free(struct mm_struct *mm, pgd_t *pgd)
+{
+       PVOP_VCALL2(pv_mmu_ops.pgd_free, mm, pgd);
+}
+
 static inline void paravirt_alloc_pte(struct mm_struct *mm, unsigned pfn)
 {
        PVOP_VCALL2(pv_mmu_ops.alloc_pte, mm, pfn);
 
 #include <linux/mm.h>          /* for struct page */
 #include <linux/pagemap.h>
 
+static inline int  __paravirt_pgd_alloc(struct mm_struct *mm) { return 0; }
+
 #ifdef CONFIG_PARAVIRT
 #include <asm/paravirt.h>
 #else
+#define paravirt_pgd_alloc(mm) __paravirt_pgd_alloc(mm)
+static inline void paravirt_pgd_free(struct mm_struct *mm, pgd_t *pgd) {}
 static inline void paravirt_alloc_pte(struct mm_struct *mm, unsigned long pfn) {}
 static inline void paravirt_alloc_pmd(struct mm_struct *mm, unsigned long pfn) {}
 static inline void paravirt_alloc_pmd_clone(unsigned long pfn, unsigned long clonepfn,