diff --git a/tools/libxc/xc_dom.h b/tools/libxc/xc_dom.h
index 7099cee..313fd65 100644
--- a/tools/libxc/xc_dom.h
+++ b/tools/libxc/xc_dom.h
@@ -68,6 +68,14 @@ struct xc_dom_image {
 
     /* memory layout */
     struct xc_dom_seg kernel_seg;
+    /* If ramdisk_seg.vstart is non zero then the ramdisk will be
+     * loaded at that address, otherwise it will automatically placed.
+     *
+     * If automatic placement is used and the ramdisk is gzip
+     * compressed then it will be decompressed as it is loaded. If the
+     * ramdisk has been explicitly placed then it is loaded as is
+     * itherwise decompressing risks undoing the manual placement.
+     */
     struct xc_dom_seg ramdisk_seg;
     struct xc_dom_seg p2m_seg;
     struct xc_dom_seg pgtables_seg;
diff --git a/tools/libxc/xc_dom_arm.c b/tools/libxc/xc_dom_arm.c
index a40e04d..3330f12 100644
--- a/tools/libxc/xc_dom_arm.c
+++ b/tools/libxc/xc_dom_arm.c
@@ -249,6 +249,18 @@ int arch_setup_meminit(struct xc_dom_image *dom)
 {
     int rc;
     xen_pfn_t pfn, allocsz, i;
+    uint64_t modbase;
+
+    /* Convenient */
+    const uint64_t rambase = dom->rambase_pfn << XC_PAGE_SHIFT;
+    const uint64_t ramend = rambase + ( dom->total_pages << XC_PAGE_SHIFT );
+    const uint64_t kernend = ROUNDUP(dom->kernel_seg.vend, 21/*2MB*/);
+    const uint64_t dtb_size = dom->devicetree_blob ?
+        ROUNDUP(dom->devicetree_size, XC_PAGE_SHIFT) : 0;
+    const uint64_t ramdisk_size = dom->ramdisk_blob ?
+        ROUNDUP(dom->ramdisk_size, XC_PAGE_SHIFT) : 0;
+    const uint64_t modsize = dtb_size + ramdisk_size;
+    const uint64_t ram128mb = rambase + (128<<20);
 
     rc = set_mode(dom->xch, dom->guest_domid, dom->guest_type);
     if ( rc )
@@ -278,23 +290,49 @@ int arch_setup_meminit(struct xc_dom_image *dom)
             0, 0, &dom->p2m_host[i]);
     }
 
-    if ( dom->devicetree_blob )
+
+    /*
+     * Place boot modules at 128MB into RAM if there is enough RAM and
+     * the kernel does not overlap. Otherwise place them immediately
+     * after the kernel. If there is no space after the kernel then
+     * there is insufficient RAM and we fail.
+     */
+    if ( ramend >= ram128mb + modsize && kernend < ram128mb )
+        modbase = ram128mb;
+    else if ( ramend >= kernend + modsize )
+        modbase = kernend;
+    else
+        return -1;
+
+    DOMPRINTF("%s: placing boot modules at 0x%" PRIx64, __FUNCTION__, modbase);
+
+    /*
+     * Must map DTB *after* initrd, to satisfy order of calls to
+     * xc_dom_alloc_segment in xc_dom_build_image, which must map
+     * things at monotonolically increasing addresses.
+     */
+    if ( ramdisk_size )
     {
-        const uint64_t rambase = dom->rambase_pfn << XC_PAGE_SHIFT;
-        const uint64_t ramend = rambase + ( dom->total_pages << XC_PAGE_SHIFT );
-        const uint64_t dtbsize = ROUNDUP(dom->devicetree_size, XC_PAGE_SHIFT);
-
-        /* Place at 128MB if there is sufficient RAM */
-        if ( ramend >= rambase + 128*1024*1024 + dtbsize )
-            dom->devicetree_seg.vstart = rambase + 128*1024*1024;
-        else /* otherwise at top of RAM */
-            dom->devicetree_seg.vstart = ramend - dtbsize;
-
-        dom->devicetree_seg.vend =
-            dom->devicetree_seg.vstart + dom->devicetree_size;
+        dom->ramdisk_seg.vstart = modbase;
+        dom->ramdisk_seg.vend = modbase + ramdisk_size;
+
+        DOMPRINTF("%s: ramdisk: 0x%" PRIx64 " -> 0x%" PRIx64 "",
+                  __FUNCTION__,
+                  dom->ramdisk_seg.vstart, dom->ramdisk_seg.vend);
+
+        modbase += ramdisk_size;
+    }
+
+    if ( dtb_size )
+    {
+        dom->devicetree_seg.vstart = modbase;
+        dom->devicetree_seg.vend = modbase + dtb_size;
+
         DOMPRINTF("%s: devicetree: 0x%" PRIx64 " -> 0x%" PRIx64 "",
                   __FUNCTION__,
                   dom->devicetree_seg.vstart, dom->devicetree_seg.vend);
+
+        modbase += dtb_size;
     }
 
     return 0;
@@ -326,7 +364,6 @@ int xc_dom_feature_translated(struct xc_dom_image *dom)
  * mode: C
  * c-file-style: "BSD"
  * c-basic-offset: 4
- * tab-width: 4
  * indent-tabs-mode: nil
  * End:
  */
diff --git a/tools/libxc/xc_dom_core.c b/tools/libxc/xc_dom_core.c
index b9d1015..baa62a1 100644
--- a/tools/libxc/xc_dom_core.c
+++ b/tools/libxc/xc_dom_core.c
@@ -955,13 +955,20 @@ int xc_dom_build_image(struct xc_dom_image *dom)
         size_t unziplen, ramdisklen;
         void *ramdiskmap;
 
-        unziplen = xc_dom_check_gzip(dom->xch, dom->ramdisk_blob, dom->ramdisk_size);
-        if ( xc_dom_ramdisk_check_size(dom, unziplen) != 0 )
+        if ( !dom->ramdisk_seg.vstart )
+        {
+            unziplen = xc_dom_check_gzip(dom->xch,
+                                         dom->ramdisk_blob, dom->ramdisk_size);
+            if ( xc_dom_ramdisk_check_size(dom, unziplen) != 0 )
+                unziplen = 0;
+        }
+        else
             unziplen = 0;
 
         ramdisklen = unziplen ? unziplen : dom->ramdisk_size;
 
-        if ( xc_dom_alloc_segment(dom, &dom->ramdisk_seg, "ramdisk", 0,
+        if ( xc_dom_alloc_segment(dom, &dom->ramdisk_seg, "ramdisk",
+                                  dom->ramdisk_seg.vstart,
                                   ramdisklen) != 0 )
             goto err;
         ramdiskmap = xc_dom_seg_to_ptr(dom, &dom->ramdisk_seg);
diff --git a/tools/libxl/libxl_arch.h b/tools/libxl/libxl_arch.h
index aee0a91..d3bc136 100644
--- a/tools/libxl/libxl_arch.h
+++ b/tools/libxl/libxl_arch.h
@@ -19,7 +19,12 @@
 int libxl__arch_domain_create(libxl__gc *gc, libxl_domain_config *d_config,
                uint32_t domid);
 
-int libxl__arch_domain_configure(libxl__gc *gc,
-                                 libxl_domain_build_info *info,
-                                 struct xc_dom_image *dom);
+/* setup arch specific hardware description, i.e. DTB on ARM */
+int libxl__arch_domain_init_hw_description(libxl__gc *gc,
+                                           libxl_domain_build_info *info,
+                                           struct xc_dom_image *dom);
+/* finalize arch specific hardware description. */
+int libxl__arch_domain_finalise_hw_description(libxl__gc *gc,
+                                      libxl_domain_build_info *info,
+                                      struct xc_dom_image *dom);
 #endif
diff --git a/tools/libxl/libxl_arm.c b/tools/libxl/libxl_arm.c
index 0cfd0cf..4f0f0e2 100644
--- a/tools/libxl/libxl_arm.c
+++ b/tools/libxl/libxl_arm.c
@@ -2,6 +2,7 @@
 #include "libxl_arch.h"
 
 #include <xc_dom.h>
+#include <stdbool.h>
 #include <libfdt.h>
 #include <assert.h>
 
@@ -31,6 +32,9 @@ typedef be32 gic_interrupt[3];
 #define ROOT_ADDRESS_CELLS 2
 #define ROOT_SIZE_CELLS 2
 
+#define PROP_INITRD_START "linux,initrd-start"
+#define PROP_INITRD_END "linux,initrd-end"
+
 static void set_cell(be32 **cellp, int size, uint64_t val)
 {
     int cells = size;
@@ -155,7 +159,7 @@ static int make_root_properties(libxl__gc *gc,
     return 0;
 }
 
-static int make_chosen_node(libxl__gc *gc, void *fdt,
+static int make_chosen_node(libxl__gc *gc, void *fdt, bool ramdisk,
                             const libxl_domain_build_info *info)
 {
     int res;
@@ -169,6 +173,15 @@ static int make_chosen_node(libxl__gc *gc, void *fdt,
         if (res) return res;
     }
 
+    if (ramdisk) {
+        uint64_t dummy = 0;
+        LOG(DEBUG, "/chosen adding placeholder linux,initrd properties");
+        res = fdt_property(fdt, PROP_INITRD_START, &dummy, sizeof(dummy));
+        if (res) return res;
+        res = fdt_property(fdt, PROP_INITRD_END, &dummy, sizeof(dummy));
+        if (res) return res;
+    }
+
     res = fdt_end_node(fdt);
     if (res) return res;
 
@@ -412,9 +425,9 @@ out:
 
 #define FDT_MAX_SIZE (1<<20)
 
-int libxl__arch_domain_configure(libxl__gc *gc,
-                                 libxl_domain_build_info *info,
-                                 struct xc_dom_image *dom)
+int libxl__arch_domain_init_hw_description(libxl__gc *gc,
+                                           libxl_domain_build_info *info,
+                                           struct xc_dom_image *dom)
 {
     void *fdt = NULL;
     int rc, res;
@@ -475,7 +488,7 @@ next_resize:
         FDT( fdt_begin_node(fdt, "") );
 
         FDT( make_root_properties(gc, vers, fdt) );
-        FDT( make_chosen_node(gc, fdt, info) );
+        FDT( make_chosen_node(gc, fdt, !!dom->ramdisk_blob, info) );
         FDT( make_cpus_node(gc, fdt, info->max_vcpus, ainfo) );
         FDT( make_psci_node(gc, fdt) );
 
@@ -505,10 +518,49 @@ next_resize:
         goto out;
     }
 
-    debug_dump_fdt(gc, fdt);
-
     rc = 0;
 
 out:
     return rc;
 }
+
+int libxl__arch_domain_finalise_hw_description(libxl__gc *gc,
+                                               libxl_domain_build_info *info,
+                                               struct xc_dom_image *dom)
+{
+    void *fdt = dom->devicetree_blob;
+
+    const struct xc_dom_seg *ramdisk = dom->ramdisk_blob ?
+        &dom->ramdisk_seg : NULL;
+
+    if (ramdisk) {
+        int chosen, res;
+        uint64_t val;
+
+        /* Neither the fdt_path_offset() nor either of the
+         * fdt_setprop_inplace() calls can fail. If they do then
+         * make_chosen_node() (see above) has got something very
+         * wrong.
+         */
+        chosen = fdt_path_offset(fdt, "/chosen");
+        assert(chosen > 0);
+
+        LOG(DEBUG, "/chosen updating initrd properties to cover "
+            "%"PRIx64"-%"PRIx64,
+            ramdisk->vstart, ramdisk->vend);
+
+        val = cpu_to_fdt64(ramdisk->vstart);
+        res = fdt_setprop_inplace(fdt, chosen, PROP_INITRD_START,
+                                  &val, sizeof(val));
+        assert(!res);
+
+        val = cpu_to_fdt64(ramdisk->vend);
+        res = fdt_setprop_inplace(fdt, chosen,PROP_INITRD_END,
+                                  &val, sizeof(val));
+        assert(!res);
+    }
+
+    debug_dump_fdt(gc, fdt);
+
+    return 0;
+}
diff --git a/tools/libxl/libxl_dom.c b/tools/libxl/libxl_dom.c
index 36e70b5..c3fa439 100644
--- a/tools/libxl/libxl_dom.c
+++ b/tools/libxl/libxl_dom.c
@@ -407,8 +407,8 @@ int libxl__build_pv(libxl__gc *gc, uint32_t domid,
         LOGE(ERROR, "xc_dom_parse_image failed");
         goto out;
     }
-    if ( (ret = libxl__arch_domain_configure(gc, info, dom)) != 0 ) {
-        LOGE(ERROR, "libxl__arch_domain_configure failed");
+    if ( (ret = libxl__arch_domain_init_hw_description(gc, info, dom)) != 0 ) {
+        LOGE(ERROR, "libxl__arch_domain_init_hw_description failed");
         goto out;
     }
     if ( (ret = xc_dom_mem_init(dom, info->target_memkb / 1024)) != 0 ) {
@@ -419,6 +419,10 @@ int libxl__build_pv(libxl__gc *gc, uint32_t domid,
         LOGE(ERROR, "xc_dom_boot_mem_init failed");
         goto out;
     }
+    if ( (ret = libxl__arch_domain_finalise_hw_description(gc, info, dom)) != 0 ) {
+        LOGE(ERROR, "libxl__arch_domain_finalise_hw_description failed");
+        goto out;
+    }
     if ( (ret = xc_dom_build_image(dom)) != 0 ) {
         LOGE(ERROR, "xc_dom_build_image failed");
         goto out;
diff --git a/tools/libxl/libxl_x86.c b/tools/libxl/libxl_x86.c
index b11d036..7589060 100644
--- a/tools/libxl/libxl_x86.c
+++ b/tools/libxl/libxl_x86.c
@@ -311,9 +311,16 @@ int libxl__arch_domain_create(libxl__gc *gc, libxl_domain_config *d_config,
     return ret;
 }
 
-int libxl__arch_domain_configure(libxl__gc *gc,
-                                 libxl_domain_build_info *info,
-                                 struct xc_dom_image *dom)
+int libxl__arch_domain_init_hw_description(libxl__gc *gc,
+                                           libxl_domain_build_info *info,
+                                           struct xc_dom_image *dom)
+{
+    return 0;
+}
+
+int libxl__arch_domain_finalise_hw_description(libxl__gc *gc,
+                                               libxl_domain_build_info *info,
+                                               struct xc_dom_image *dom)
 {
     return 0;
 }
