diff --git a/xen/arch/x86/mm.c b/xen/arch/x86/mm.c
index f8a8f97f81..1dcd4289d1 100644
--- a/xen/arch/x86/mm.c
+++ b/xen/arch/x86/mm.c
@@ -4896,45 +4896,70 @@ void free_xen_pagetable_new(mfn_t mfn)
 
 static DEFINE_SPINLOCK(map_pgdir_lock);
 
+/*
+ * Given a virtual address, return a pointer to xen's L3 entry. Caller
+ * needs to unmap the pointer.
+ */
 static l3_pgentry_t *virt_to_xen_l3e(unsigned long v)
 {
     l4_pgentry_t *pl4e;
+    l3_pgentry_t *pl3e = NULL;
 
     pl4e = &idle_pg_table[l4_table_offset(v)];
     if ( !(l4e_get_flags(*pl4e) & _PAGE_PRESENT) )
     {
         bool locking = system_state > SYS_STATE_boot;
-        l3_pgentry_t *l3t = alloc_xen_pagetable();
+        l3_pgentry_t *l3t;
+        mfn_t mfn;
+
+        mfn = alloc_xen_pagetable_new();
+        if ( mfn_eq(mfn, INVALID_MFN) )
+            goto out;
+
+        l3t = map_xen_pagetable_new(mfn);
 
-        if ( !l3t )
-            return NULL;
         if ( locking )
             spin_lock(&map_pgdir_lock);
         if ( !(l4e_get_flags(*pl4e) & _PAGE_PRESENT) )
         {
-            l4_pgentry_t l4e = l4e_from_paddr(__pa(l3t), __PAGE_HYPERVISOR);
+            l4_pgentry_t l4e = l4e_from_mfn(mfn, __PAGE_HYPERVISOR);
 
             clear_page(l3t);
             l4e_write(pl4e, l4e);
             efi_update_l4_pgtable(l4_table_offset(v), l4e);
+            pl3e = l3t + l3_table_offset(v);
             l3t = NULL;
         }
         if ( locking )
             spin_unlock(&map_pgdir_lock);
         if ( l3t )
-            free_xen_pagetable(l3t);
+        {
+            ASSERT(!pl3e);
+            ASSERT(!mfn_eq(mfn, INVALID_MFN));
+            UNMAP_XEN_PAGETABLE_NEW(l3t);
+            free_xen_pagetable_new(mfn);
+        }
+    }
+
+    if ( !pl3e )
+    {
+        ASSERT(l4e_get_flags(*pl4e) & _PAGE_PRESENT);
+        pl3e = (l3_pgentry_t *)map_xen_pagetable_new(l4e_get_mfn(*pl4e))
+            + l3_table_offset(v);
     }
 
-    return l4e_to_l3e(*pl4e) + l3_table_offset(v);
+ out:
+    return pl3e;
 }
 
 static l2_pgentry_t *virt_to_xen_l2e(unsigned long v)
 {
     l3_pgentry_t *pl3e;
+    l2_pgentry_t *pl2e = NULL;
 
     pl3e = virt_to_xen_l3e(v);
     if ( !pl3e )
-        return NULL;
+        goto out;
 
     if ( !(l3e_get_flags(*pl3e) & _PAGE_PRESENT) )
     {
@@ -4942,7 +4967,8 @@ static l2_pgentry_t *virt_to_xen_l2e(unsigned long v)
         l2_pgentry_t *l2t = alloc_xen_pagetable();
 
         if ( !l2t )
-            return NULL;
+            goto out;
+
         if ( locking )
             spin_lock(&map_pgdir_lock);
         if ( !(l3e_get_flags(*pl3e) & _PAGE_PRESENT) )
@@ -4958,7 +4984,11 @@ static l2_pgentry_t *virt_to_xen_l2e(unsigned long v)
     }
 
     BUG_ON(l3e_get_flags(*pl3e) & _PAGE_PSE);
-    return l3e_to_l2e(*pl3e) + l2_table_offset(v);
+    pl2e = l3e_to_l2e(*pl3e) + l2_table_offset(v);
+
+ out:
+    UNMAP_XEN_PAGETABLE_NEW(pl3e);
+    return pl2e;
 }
 
 l1_pgentry_t *virt_to_xen_l1e(unsigned long v)
@@ -5014,7 +5044,7 @@ int map_pages_to_xen(
     unsigned int flags)
 {
     bool locking = system_state > SYS_STATE_boot;
-    l3_pgentry_t *pl3e, ol3e;
+    l3_pgentry_t *pl3e = NULL, ol3e;
     l2_pgentry_t *pl2e, ol2e;
     l1_pgentry_t *pl1e, ol1e;
     unsigned int  i;
@@ -5390,7 +5420,8 @@ int map_pages_to_xen(
             else if ( locking )
                 spin_unlock(&map_pgdir_lock);
         }
-    end_of_loop:;
+    end_of_loop:
+        UNMAP_XEN_PAGETABLE_NEW(pl3e);
     }
 
 #undef flush_flags
@@ -5398,6 +5429,7 @@ int map_pages_to_xen(
     rc = 0;
 
  out:
+    UNMAP_XEN_PAGETABLE_NEW(pl3e);
     return rc;
 }
 
@@ -5421,6 +5453,7 @@ int populate_pt_range(unsigned long virt, unsigned long nr_mfns)
 int modify_xen_mappings(unsigned long s, unsigned long e, unsigned int nf)
 {
     bool locking = system_state > SYS_STATE_boot;
+    l3_pgentry_t *pl3e = NULL;
     l2_pgentry_t *pl2e;
     l1_pgentry_t *pl1e;
     unsigned int  i;
@@ -5436,7 +5469,7 @@ int modify_xen_mappings(unsigned long s, unsigned long e, unsigned int nf)
 
     while ( v < e )
     {
-        l3_pgentry_t *pl3e = virt_to_xen_l3e(v);
+        pl3e = virt_to_xen_l3e(v);
 
         if ( !pl3e || !(l3e_get_flags(*pl3e) & _PAGE_PRESENT) )
         {
@@ -5662,7 +5695,8 @@ int modify_xen_mappings(unsigned long s, unsigned long e, unsigned int nf)
             else if ( locking )
                 spin_unlock(&map_pgdir_lock);
         }
-    end_of_loop:;
+    end_of_loop:
+        UNMAP_XEN_PAGETABLE_NEW(pl3e);
     }
 
     flush_area(NULL, FLUSH_TLB_GLOBAL);
@@ -5671,6 +5705,7 @@ int modify_xen_mappings(unsigned long s, unsigned long e, unsigned int nf)
     rc = 0;
 
  out:
+    UNMAP_XEN_PAGETABLE_NEW(pl3e);
     return rc;
 }
 
