diff --git a/hw/arm-misc.h b/hw/arm-misc.h
index 2f46e21..25f3da8 100644
--- a/hw/arm-misc.h
+++ b/hw/arm-misc.h
@@ -31,6 +31,14 @@ struct arm_boot_info {
     const char *initrd_filename;
     const char *dtb_filename;
     target_phys_addr_t loader_start;
+    /* where to place the initrd relative to loader start. A value of 0
+     * will select the default value of loader_start + 0xd00000.
+     */
+    target_phys_addr_t initrd_offset;
+    /* where to place the dtb relative to loader start. A value of 0 will
+     * place it immediately after the initrd (page aligned).
+     */
+    target_phys_addr_t dtb_offset;
     /* multicore boards that use the default secondary core boot functions
      * need to put the address of the secondary boot code, the boot reg,
      * and the GIC address in the next 3 values, respectively. boards that
diff --git a/hw/arm_boot.c b/hw/arm_boot.c
index 7447f5c..302bd17 100644
--- a/hw/arm_boot.c
+++ b/hw/arm_boot.c
@@ -18,7 +18,8 @@
 
 #define KERNEL_ARGS_ADDR 0x100
 #define KERNEL_LOAD_ADDR 0x00010000
-#define INITRD_LOAD_ADDR 0x00d00000
+
+#define DEFAULT_INITRD_OFFSET 0x00d00000
 
 /* The worlds second smallest bootloader.  Set r0-r2, then jump to kernel.  */
 static uint32_t bootloader[] = {
@@ -107,7 +108,7 @@ static void set_kernel_args(const struct arm_boot_info *info)
         /* ATAG_INITRD2 */
         WRITE_WORD(p, 4);
         WRITE_WORD(p, 0x54420005);
-        WRITE_WORD(p, info->loader_start + INITRD_LOAD_ADDR);
+        WRITE_WORD(p, info->loader_start + info->initrd_offset);
         WRITE_WORD(p, initrd_size);
     }
     if (info->kernel_cmdline && *info->kernel_cmdline) {
@@ -184,7 +185,7 @@ static void set_kernel_args_old(const struct arm_boot_info *info)
     WRITE_WORD(p, 0);
     /* initrd_start */
     if (initrd_size)
-        WRITE_WORD(p, info->loader_start + INITRD_LOAD_ADDR);
+        WRITE_WORD(p, info->loader_start + info->initrd_offset);
     else
         WRITE_WORD(p, 0);
     /* initrd_size */
@@ -211,7 +212,7 @@ static void set_kernel_args_old(const struct arm_boot_info *info)
     }
 }
 
-static int load_dtb(target_phys_addr_t addr, const struct arm_boot_info *binfo)
+static int load_dtb(const struct arm_boot_info *binfo)
 {
 #ifdef CONFIG_FDT
     uint32_t mem_reg_property[] = { cpu_to_be32(binfo->loader_start),
@@ -248,20 +249,21 @@ static int load_dtb(target_phys_addr_t addr, const struct arm_boot_info *binfo)
 
     if (binfo->initrd_size) {
         rc = qemu_devtree_setprop_cell(fdt, "/chosen", "linux,initrd-start",
-                binfo->loader_start + INITRD_LOAD_ADDR);
+                binfo->loader_start + binfo->initrd_offset);
         if (rc < 0) {
             fprintf(stderr, "couldn't set /chosen/linux,initrd-start\n");
         }
 
         rc = qemu_devtree_setprop_cell(fdt, "/chosen", "linux,initrd-end",
-                    binfo->loader_start + INITRD_LOAD_ADDR +
+                    binfo->loader_start + binfo->initrd_offset +
                     binfo->initrd_size);
         if (rc < 0) {
             fprintf(stderr, "couldn't set /chosen/linux,initrd-end\n");
         }
     }
 
-    cpu_physical_memory_write(addr, fdt, size);
+    cpu_physical_memory_write(binfo->loader_start + binfo->dtb_offset,
+                                                                fdt, size);
 
     return 0;
 
@@ -362,10 +364,13 @@ void arm_load_kernel(CPUARMState *env, struct arm_boot_info *info)
     info->entry = entry;
     if (is_linux) {
         if (info->initrd_filename) {
+            if (!info->initrd_offset) {
+                info->initrd_offset = DEFAULT_INITRD_OFFSET;
+            }
             initrd_size = load_image_targphys(info->initrd_filename,
                                               info->loader_start
-                                              + INITRD_LOAD_ADDR,
-                                              ram_size - INITRD_LOAD_ADDR);
+                                              + info->initrd_offset,
+                                              ram_size - info->initrd_offset);
             if (initrd_size < 0) {
                 fprintf(stderr, "qemu: could not load initrd '%s'\n",
                         info->initrd_filename);
@@ -382,14 +387,15 @@ void arm_load_kernel(CPUARMState *env, struct arm_boot_info *info)
          * we point to the kernel args.
          */
         if (info->dtb_filename) {
-            /* Place the DTB after the initrd in memory */
-            target_phys_addr_t dtb_start = TARGET_PAGE_ALIGN(info->loader_start
-                                                             + INITRD_LOAD_ADDR
+            if (!info->dtb_offset) {
+                /* Place the DTB after the initrd in memory */
+                info->dtb_offset = TARGET_PAGE_ALIGN(info->initrd_offset
                                                              + initrd_size);
-            if (load_dtb(dtb_start, info)) {
+            }
+            if (load_dtb(info)) {
                 exit(1);
             }
-            bootloader[5] = dtb_start;
+            bootloader[5] = info->loader_start + info->dtb_offset;
         } else {
             bootloader[5] = info->loader_start + KERNEL_ARGS_ADDR;
         }
