diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c
index 5809489..192241a 100644
--- a/xen/arch/arm/domain_build.c
+++ b/xen/arch/arm/domain_build.c
@@ -484,6 +484,7 @@ static int prepare_dtb(struct domain *d, struct kernel_info *kinfo)
     void *fdt;
     int new_size;
     int ret;
+    paddr_t end;
 
     kinfo->unassigned_mem = dom0_mem;
 
@@ -509,17 +510,26 @@ static int prepare_dtb(struct domain *d, struct kernel_info *kinfo)
         goto err;
 
     /*
-     * Put the device tree at the beginning of the first bank.  It
-     * must be below 4 GiB.
+     * DTB must be load below 4GiB and far enough from linux (Linux uses
+     * the space after it to decompress)
+     * Load the DTB at the end of the first bank, while ensuring it is
+     * also below 4G
      */
-    kinfo->dtb_paddr = kinfo->mem.bank[0].start + 0x100;
-    if ( kinfo->dtb_paddr + fdt_totalsize(kinfo->fdt) > (1ull << 32) )
+    end = kinfo->mem.bank[0].start + kinfo->mem.bank[0].size;
+    end = MIN(1ull << 32, end);
+    kinfo->dtb_paddr = end - fdt_totalsize(kinfo->fdt);
+    /* Align the address to 2Mb. Linux only requires 4 byte alignment */
+    kinfo->dtb_paddr &= ~((2 << 20) - 1);
+
+    if ( fdt_totalsize(kinfo->fdt) > end )
     {
-        printk("Not enough memory below 4 GiB for the device tree.");
+        printk(XENLOG_ERR "Not enough memory in the first bank for "
+               "the device tree.");
         ret = -FDT_ERR_XEN(EINVAL);
         goto err;
     }
 
+
     return 0;
 
   err:
@@ -532,6 +542,9 @@ static void dtb_load(struct kernel_info *kinfo)
 {
     void * __user dtb_virt = (void * __user)(register_t)kinfo->dtb_paddr;
 
+    printk("Loading dom0 DTB to 0x%"PRIpaddr"-0x%"PRIpaddr"\n",
+           kinfo->dtb_paddr, kinfo->dtb_paddr + fdt_totalsize(kinfo->fdt));
+
     raw_copy_to_guest(dtb_virt, kinfo->fdt, fdt_totalsize(kinfo->fdt));
     xfree(kinfo->fdt);
 }
@@ -566,10 +579,12 @@ int construct_dom0(struct domain *d)
     if ( rc < 0 )
         return rc;
 
+    if ( kinfo.check_overlap )
+        kinfo.check_overlap(&kinfo);
+
     /* The following loads use the domain's p2m */
     p2m_load_VTTBR(d);
 
-    kinfo.dtb_paddr = kinfo.zimage.load_addr + kinfo.zimage.len;
     kernel_load(&kinfo);
     dtb_load(&kinfo);
 
diff --git a/xen/arch/arm/kernel.c b/xen/arch/arm/kernel.c
index aba5441..3953f0f 100644
--- a/xen/arch/arm/kernel.c
+++ b/xen/arch/arm/kernel.c
@@ -12,6 +12,7 @@
 #include <xen/sched.h>
 #include <asm/byteorder.h>
 #include <asm/setup.h>
+#include <xen/libfdt/libfdt.h>
 
 #include "kernel.h"
 
@@ -64,6 +65,21 @@ void copy_from_paddr(void *dst, paddr_t paddr, unsigned long len, int attrindx)
     clear_fixmap(FIXMAP_MISC);
 }
 
+static void kernel_zimage_check_overlap(struct kernel_info *info)
+{
+    paddr_t zimage_start = info->zimage.load_addr;
+    paddr_t zimage_end = info->zimage.load_addr + info->zimage.len;
+    paddr_t dtb_start = info->dtb_paddr;
+    paddr_t dtb_end = info->dtb_paddr + fdt_totalsize(info->fdt);
+
+    if ( (dtb_start > zimage_end) || (dtb_end < zimage_start) )
+        return;
+
+    panic(XENLOG_ERR "The kernel(0x%"PRIpaddr"-0x%"PRIpaddr
+          ") is overlapping the DTB(0x%"PRIpaddr"-0x%"PRIpaddr")\n",
+          zimage_start, zimage_end, dtb_start, dtb_end);
+}
+
 static void kernel_zimage_load(struct kernel_info *info)
 {
     paddr_t load_addr = info->zimage.load_addr;
@@ -152,6 +168,7 @@ static int kernel_try_zimage_prepare(struct kernel_info *info,
 
     info->entry = info->zimage.load_addr;
     info->load = kernel_zimage_load;
+    info->check_overlap = kernel_zimage_check_overlap;
 
     return 0;
 }
@@ -197,6 +214,7 @@ static int kernel_try_elf_prepare(struct kernel_info *info,
      */
     info->entry = info->elf.parms.virt_entry;
     info->load = kernel_elf_load;
+    info->check_overlap = NULL;
 
     if ( elf_check_broken(&info->elf.elf) )
         printk("Xen: warning: ELF kernel broken: %s\n",
diff --git a/xen/arch/arm/kernel.h b/xen/arch/arm/kernel.h
index 1776a4d..c900e74 100644
--- a/xen/arch/arm/kernel.h
+++ b/xen/arch/arm/kernel.h
@@ -38,6 +38,8 @@ struct kernel_info {
     };
 
     void (*load)(struct kernel_info *info);
+    /* Callback to check overlap between the kernel and the device tree */
+    void (*check_overlap)(struct kernel_info *kinfo);
     int load_attr;
 };
 
