diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c
index 085d88671e..d2a9c047ea 100644
--- a/xen/arch/arm/domain_build.c
+++ b/xen/arch/arm/domain_build.c
@@ -814,19 +814,21 @@ int __init make_memory_node(const struct domain *d,
     return res;
 }
 
-static int __init add_ext_regions(unsigned long s_gfn, unsigned long e_gfn,
-                                  void *data)
+static int __init add_regions(unsigned long s_gfn, unsigned long e_gfn,
+                              void *data)
 {
-    struct meminfo *ext_regions = data;
+    struct mem_unused_info *unused = data;
+    struct meminfo *regions = unused->regions;
+    paddr_t min_region_size = unused->min_region_size;
     paddr_t start, size;
     paddr_t s = pfn_to_paddr(s_gfn);
     paddr_t e = pfn_to_paddr(e_gfn);
 
-    if ( ext_regions->nr_banks >= ARRAY_SIZE(ext_regions->bank) )
+    if ( regions->nr_banks >= ARRAY_SIZE(regions->bank) )
         return 0;
 
     /*
-     * Both start and size of the extended region should be 2MB aligned to
+     * Both start and size of the region should be 2MB aligned to
      * potentially allow superpage mapping.
      */
     start = (s + SZ_2M - 1) & ~(SZ_2M - 1);
@@ -845,26 +847,27 @@ static int __init add_ext_regions(unsigned long s_gfn, unsigned long e_gfn,
      * not quite useful but increase bookkeeping and not too large
      * to skip a large proportion of unused address space.
      */
-    if ( size < MB(64) )
+    if ( size < min_region_size )
         return 0;
 
-    ext_regions->bank[ext_regions->nr_banks].start = start;
-    ext_regions->bank[ext_regions->nr_banks].size = size;
-    ext_regions->nr_banks++;
+    regions->bank[regions->nr_banks].start = start;
+    regions->bank[regions->nr_banks].size = size;
+    regions->nr_banks++;
 
     return 0;
 }
 
 /*
- * Find unused regions of Host address space which can be exposed to Dom0
- * as extended regions for the special memory mappings. In order to calculate
- * regions we exclude every region assigned to Dom0 from the Host RAM:
+ * Find unused regions of Host address space which can be exposed to
+ * direct-mapped domains as regions for the special memory mappings.
+ * In order to calculate regions we exclude every region assigned to
+ * direct-mapped domains from the Host RAM:
  * - domain RAM
  * - reserved-memory
  * - grant table space
  */
 static int __init find_unallocated_memory(const struct kernel_info *kinfo,
-                                          struct meminfo *ext_regions)
+                                          struct mem_unused_info *unused)
 {
     const struct meminfo *assign_mem = &kinfo->mem;
     struct rangeset *unalloc_mem;
@@ -893,7 +896,7 @@ static int __init find_unallocated_memory(const struct kernel_info *kinfo,
         }
     }
 
-    /* Remove RAM assigned to Dom0 */
+    /* Remove RAM assigned to domain */
     for ( i = 0; i < assign_mem->nr_banks; i++ )
     {
         start = assign_mem->bank[i].start;
@@ -942,10 +945,10 @@ static int __init find_unallocated_memory(const struct kernel_info *kinfo,
     start = 0;
     end = (1ULL << p2m_ipa_bits) - 1;
     res = rangeset_report_ranges(unalloc_mem, PFN_DOWN(start), PFN_DOWN(end),
-                                 add_ext_regions, ext_regions);
+                                 add_regions, unused);
     if ( res )
-        ext_regions->nr_banks = 0;
-    else if ( !ext_regions->nr_banks )
+        unused->regions->nr_banks = 0;
+    else if ( !unused->regions->nr_banks )
         res = -ENOENT;
 
 out:
@@ -982,16 +985,16 @@ static int __init handle_pci_range(const struct dt_device_node *dev,
 }
 
 /*
- * Find the holes in the Host DT which can be exposed to Dom0 as extended
- * regions for the special memory mappings. In order to calculate regions
- * we exclude every addressable memory region described by "reg" and "ranges"
+ * Find the holes in the Host DT which can be exposed to direct-mapped domains
+ * as regions for the special memory mappings. In order to calculate regions we
+ * exclude every addressable memory region described by "reg" and "ranges"
  * properties from the maximum possible addressable physical memory range:
  * - MMIO
  * - Host RAM
  * - PCI aperture
  */
 static int __init find_memory_holes(const struct kernel_info *kinfo,
-                                    struct meminfo *ext_regions)
+                                    struct mem_unused_info *unused)
 {
     struct dt_device_node *np;
     struct rangeset *mem_holes;
@@ -1068,10 +1071,10 @@ static int __init find_memory_holes(const struct kernel_info *kinfo,
     start = 0;
     end = (1ULL << p2m_ipa_bits) - 1;
     res = rangeset_report_ranges(mem_holes, PFN_DOWN(start), PFN_DOWN(end),
-                                 add_ext_regions,  ext_regions);
+                                 add_regions, unused);
     if ( res )
-        ext_regions->nr_banks = 0;
-    else if ( !ext_regions->nr_banks )
+        unused->regions->nr_banks = 0;
+    else if ( !unused->regions->nr_banks )
         res = -ENOENT;
 
 out:
@@ -1081,35 +1084,62 @@ out:
 }
 
 static int __init find_domU_holes(const struct kernel_info *kinfo,
-                                  struct meminfo *ext_regions)
+                                  struct mem_unused_info *unused)
 {
     unsigned int i;
     uint64_t bankend;
     const uint64_t bankbase[] = GUEST_RAM_BANK_BASES;
     const uint64_t banksize[] = GUEST_RAM_BANK_SIZES;
+    struct meminfo *regions = unused->regions;
+    paddr_t min_region_size = unused->min_region_size;
     int res = -ENOENT;
 
     for ( i = 0; i < GUEST_RAM_BANKS; i++ )
     {
-        struct membank *ext_bank = &(ext_regions->bank[ext_regions->nr_banks]);
+        struct membank *bank = &(regions->bank[regions->nr_banks]);
 
-        ext_bank->start = ROUNDUP(bankbase[i] + kinfo->mem.bank[i].size, SZ_2M);
+        bank->start = ROUNDUP(bankbase[i] + kinfo->mem.bank[i].size, SZ_2M);
 
         bankend = ~0ULL >> (64 - p2m_ipa_bits);
         bankend = min(bankend, bankbase[i] + banksize[i] - 1);
-        if ( bankend > ext_bank->start )
-            ext_bank->size = bankend - ext_bank->start + 1;
+        if ( bankend > bank->start )
+            bank->size = bankend - bank->start + 1;
 
-        /* 64MB is the minimum size of an extended region */
-        if ( ext_bank->size < MB(64) )
+        if ( bank->size < min_region_size )
             continue;
-        ext_regions->nr_banks++;
+        regions->nr_banks++;
         res = 0;
     }
 
     return res;
 }
 
+int __init find_unused_regions(struct domain *d,
+                               const struct kernel_info *kinfo,
+                               struct meminfo *regions,
+                               paddr_t min_region_size)
+{
+    int res;
+    struct mem_unused_info unused;
+
+    unused.regions = regions;
+    unused.min_region_size = min_region_size;
+
+    if ( is_domain_direct_mapped(d) )
+    {
+        if ( !is_iommu_enabled(d) )
+            res = find_unallocated_memory(kinfo, &unused);
+        else
+            res = find_memory_holes(kinfo, &unused);
+    }
+    else
+    {
+        res = find_domU_holes(kinfo, &unused);
+    }
+
+    return res;
+}
+
 int __init make_hypervisor_node(struct domain *d,
                                 const struct kernel_info *kinfo,
                                 int addrcells, int sizecells)
@@ -1161,18 +1191,7 @@ int __init make_hypervisor_node(struct domain *d,
         if ( !ext_regions )
             return -ENOMEM;
 
-        if ( is_domain_direct_mapped(d) )
-        {
-            if ( !is_iommu_enabled(d) )
-                res = find_unallocated_memory(kinfo, ext_regions);
-            else
-                res = find_memory_holes(kinfo, ext_regions);
-        }
-        else
-        {
-            res = find_domU_holes(kinfo, ext_regions);
-        }
-
+        res = find_unused_regions(d, kinfo, ext_regions, MB(64));
         if ( res )
             printk(XENLOG_WARNING "%pd: failed to allocate extended regions\n",
                    d);
diff --git a/xen/arch/arm/include/asm/domain_build.h b/xen/arch/arm/include/asm/domain_build.h
index da9e6025f3..74432123fe 100644
--- a/xen/arch/arm/include/asm/domain_build.h
+++ b/xen/arch/arm/include/asm/domain_build.h
@@ -10,6 +10,8 @@ bool allocate_bank_memory(struct domain *d, struct kernel_info *kinfo,
                           gfn_t sgfn, paddr_t tot_size);
 int construct_domain(struct domain *d, struct kernel_info *kinfo);
 int domain_fdt_begin_node(void *fdt, const char *name, uint64_t unit);
+int find_unused_regions(struct domain *d, const struct kernel_info *kinfo,
+                        struct meminfo *regions, paddr_t min_region_size);
 int make_chosen_node(const struct kernel_info *kinfo);
 int make_cpus_node(const struct domain *d, void *fdt);
 int make_hypervisor_node(struct domain *d, const struct kernel_info *kinfo,
diff --git a/xen/arch/arm/include/asm/setup.h b/xen/arch/arm/include/asm/setup.h
index d15a88d2e0..d24c6d31c8 100644
--- a/xen/arch/arm/include/asm/setup.h
+++ b/xen/arch/arm/include/asm/setup.h
@@ -61,6 +61,11 @@ struct meminfo {
     struct membank bank[NR_MEM_BANKS];
 };
 
+struct mem_unused_info {
+    struct meminfo *regions;
+    paddr_t min_region_size;
+};
+
 /*
  * The domU flag is set for kernels and ramdisks of "xen,domain" nodes.
  * The purpose of the domU flag is to avoid getting confused in
