diff --git a/xen/arch/x86/boot/edd.S b/xen/arch/x86/boot/edd.S
index 434bbbd960..138d04c964 100644
--- a/xen/arch/x86/boot/edd.S
+++ b/xen/arch/x86/boot/edd.S
@@ -163,6 +163,7 @@ edd_done:
 .Ledd_mbr_sig_skip:
         ret
 
+        .pushsection .data.boot16, "aw", @progbits
 GLOBAL(boot_edd_info_nr)
         .byte   0
 GLOBAL(boot_mbr_signature_nr)
@@ -171,3 +172,4 @@ GLOBAL(boot_mbr_signature)
         .fill   EDD_MBR_SIG_MAX*8,1,0
 GLOBAL(boot_edd_info)
         .fill   EDD_INFO_MAX * (EDDEXTSIZE + EDDPARMSIZE), 1, 0
+        .popsection
diff --git a/xen/arch/x86/boot/head.S b/xen/arch/x86/boot/head.S
index 556dab127f..104eb0eb3c 100644
--- a/xen/arch/x86/boot/head.S
+++ b/xen/arch/x86/boot/head.S
@@ -733,6 +733,17 @@ trampoline_setup:
         cmp     $sym_offs(__bootsym_seg_stop),%edi
         jb      1b
 
+        /* Relocations for the boot data section. */
+        mov     sym_fs(trampoline_phys),%edx
+        add     $(boot_trampoline_end - boot_trampoline_start),%edx
+        mov     $sym_offs(__bootdatasym_rel_start),%edi
+1:
+        mov     %fs:(%edi),%eax
+        add     %edx,%fs:(%edi,%eax)
+        add     $4,%edi
+        cmp     $sym_offs(__bootdatasym_rel_stop),%edi
+        jb      1b
+
         /* Do not parse command line on EFI platform here. */
         cmpb    $0,sym_fs(efi_platform)
         jnz     1f
@@ -770,6 +781,11 @@ trampoline_setup:
         mov     $((boot_trampoline_end - boot_trampoline_start) / 4),%ecx
         rep movsl %fs:(%esi),%es:(%edi)
 
+        /* Copy boot data template to low memory. */
+        mov     $sym_offs(bootdata_start),%esi
+        mov     $((bootdata_end - bootdata_start + 3) / 4),%ecx
+        rep movsl %fs:(%esi),%es:(%edi)
+
         /* Jump into the relocated trampoline. */
         lret
 
diff --git a/xen/arch/x86/boot/mem.S b/xen/arch/x86/boot/mem.S
index aa39608442..86f0fa9af7 100644
--- a/xen/arch/x86/boot/mem.S
+++ b/xen/arch/x86/boot/mem.S
@@ -67,6 +67,7 @@ get_memory_map:
         ret
 
         .align  4
+        .pushsection .data.boot16, "aw", @progbits
 GLOBAL(bios_e820map)
         .fill   E820_BIOS_MAX*20,1,0
 GLOBAL(bios_e820nr)
@@ -75,3 +76,4 @@ GLOBAL(lowmem_kb)
         .long   0
 GLOBAL(highmem_kb)
         .long   0
+	.popsection
diff --git a/xen/arch/x86/boot/trampoline.S b/xen/arch/x86/boot/trampoline.S
index 26af9c6beb..b5517a44bb 100644
--- a/xen/arch/x86/boot/trampoline.S
+++ b/xen/arch/x86/boot/trampoline.S
@@ -47,11 +47,15 @@
         .long 111b - (off) - .;            \
         .popsection
 
-#define bootdatasym(s) ((s)-boot_trampoline_start)
+        .pushsection .data.boot16, "aw", @progbits
+GLOBAL(bootdata_start)
+        .popsection
+
+#define bootdatasym(s) ((s)-bootdata_start+(boot_trampoline_end-boot_trampoline_start))
 #define bootdatasym_rel(sym, off, opnd...) \
         bootdatasym(sym),##opnd;           \
 111:;                                      \
-        .pushsection .bootdatasym_rel, "a";\
+        .pushsection .bootsym_rel, "a";\
         .long 111b - (off) - .;            \
         .popsection
 
@@ -227,7 +231,7 @@ start64:
         .word   0
 idt_48: .word   0, 0, 0 # base = limit = 0
         .word   0
-gdt_48: .word   6*8-1
+gdt_48: .word   7*8-1
         .long   tramp32sym_rel(trampoline_gdt,4)
 
 /* The first page of trampoline is permanent, the rest boot-time only. */
@@ -318,6 +322,23 @@ trampoline_boot_cpu_entry:
         mov     %eax,%gs
         mov     %eax,%ss
 
+        /*
+         * Copy locally-gathered data back up into the Xen physical image
+         */
+        mov     $BOOT_FS,%eax
+        mov     %eax,%es
+
+        mov     $sym_offs(bootdata_end),%ecx
+        mov     $sym_offs(bootdata_start),%edi
+        sub     %edi,%ecx
+        mov     $bootdatasym_rel(bootdata_start,4,%esi)
+        rep movsb %ds:(%esi),%es:(%edi)
+
+        /*
+         * %es still points to BOOT_FS but trampoline_protmode_entry
+         * reloads it anyway.
+         */
+
         /* EBX == 0 indicates we are the BP (Boot Processor). */
         xor     %ebx,%ebx
 
@@ -345,8 +366,10 @@ vesa_size:
         .word   0,0,0                           /* width x depth x height */
 #endif
 
+        .pushsection .data.boot16, "aw", @progbits
 GLOBAL(kbd_shift_flags)
         .byte   0
+        .popsection
 
 rm_idt: .word   256*4-1, 0, 0
 
@@ -355,3 +378,7 @@ rm_idt: .word   256*4-1, 0, 0
 #ifdef CONFIG_VIDEO
 #include "video.S"
 #endif
+
+        .pushsection .data.boot16, "aw", @progbits
+GLOBAL(bootdata_end)
+        .popsection
diff --git a/xen/arch/x86/boot/video.S b/xen/arch/x86/boot/video.S
index 5087c6a4d5..4608464b77 100644
--- a/xen/arch/x86/boot/video.S
+++ b/xen/arch/x86/boot/video.S
@@ -15,10 +15,10 @@
 
 #include "video.h"
 
-/* Scratch space layout: boot_trampoline_end to boot_trampoline_end+0x1000. */
-#define modelist       bootsym(boot_trampoline_end)   /* 2kB (256 entries) */
-#define vesa_glob_info (modelist + 0x800)        /* 1kB */
-#define vesa_mode_info (vesa_glob_info + 0x400)  /* 1kB */
+/* Scratch space layout: bootdata_end to bootdata_end+0x1000. */
+#define modelist(t)       bootdatasym_rel(bootdata_end,2,t)         /* 2KiB (256 entries) */
+#define vesa_glob_info(t) bootdatasym_rel((bootdata_end+0x800),2,t) /* 1KiB */
+#define vesa_mode_info(t) bootdatasym_rel((bootdata_end+0xc00),2,t) /* 1KiB */
 
 /* Retrieve Extended Display Identification Data. */
 #define CONFIG_FIRMWARE_EDID
@@ -113,7 +113,7 @@ mopar2: movb    %al, _param(PARAM_VIDEO_LINES)
 
 # Fetching of VESA frame buffer parameters
 mopar_gr:
-        leaw    vesa_mode_info, %di
+        leaw    vesa_mode_info(%di)
         movb    $0x23, _param(PARAM_HAVE_VGA)
         movw    16(%di), %ax
         movw    %ax, _param(PARAM_LFB_LINELENGTH)
@@ -134,7 +134,7 @@ mopar_gr:
         movw    %ax, _param(PARAM_VESA_ATTRIB)
 
 # get video mem size
-        leaw    vesa_glob_info, %di
+        leaw    vesa_glob_info(%di)
         xorl    %eax, %eax
         movw    18(%di), %ax
         movl    %eax, _param(PARAM_LFB_SIZE)
@@ -226,7 +226,7 @@ an1:    call    prtstr
         leaw    bootsym(listhdr), %si   # Table header
         call    prtstr
         movb    $0x30, %dl              # DL holds mode number
-        leaw    modelist, %si
+        leaw    modelist(%si)
 lm1:    cmpw    $ASK_VGA, (%si)         # End?
         jz      lm2
 
@@ -435,13 +435,13 @@ setmenu:
         jmp     mode_set
 
 check_vesa:
-        leaw    vesa_glob_info, %di
+        leaw    vesa_glob_info(%di)
         movw    $0x4f00, %ax
         int     $0x10
         cmpw    $0x004f, %ax
         jnz     setbad
 
-        leaw    vesa_mode_info, %di
+        leaw    vesa_mode_info(%di)
         subb    $VIDEO_FIRST_VESA>>8, %bh
         movw    %bx, %cx                # Get mode information structure
         movw    $0x4f01, %ax
@@ -509,7 +509,7 @@ inidx:  outb    %al, %dx                # Read from indexed VGA register
 
 setvesabysize:
         call    mode_table
-        leaw    modelist,%si
+        leaw    modelist(%si)
 1:      add     $8,%si
         cmpw    $ASK_VGA,-8(%si)        # End?
         je      _setbad
@@ -669,7 +669,7 @@ mode_table:
         orw     %di, %di
         jnz     mtab1
 
-        leaw    modelist, %di           # Store standard modes:
+        leaw    modelist(%di)           # Store standard modes:
         movw    $VIDEO_80x25,(%di)      # The 80x25 mode (ALL)
         movw    $0x50,2(%di)
         movw    $0x19,4(%di)
@@ -684,7 +684,7 @@ mode_table:
 
         movw    $ASK_VGA, (%di)         # End marker
         movw    %di, bootsym(mt_end)
-mtab1:  leaw    modelist, %si           # SI=mode list, DI=list end
+mtab1:  leaw    modelist(%si)           # SI=mode list, DI=list end
 ret0:   ret
 
 # Modes usable on all standard VGAs
@@ -700,7 +700,7 @@ vga_modes_end:
 # Detect VESA modes.
 vesa_modes:
         movw    %di, %bp                # BP=original mode table end
-        leaw    vesa_glob_info, %di
+        leaw    vesa_glob_info(%di)
         movw    $0x4f00, %ax            # VESA Get card info call
         int     $0x10
         movw    %di, %si
@@ -897,7 +897,7 @@ store_edid:
         cmpb    $1, bootsym(opt_edid)   # EDID disabled on cmdline (edid=no)?
         je      .Lno_edid
 
-        leaw    vesa_glob_info, %di
+        leaw    vesa_glob_info(%di)
         movw    $0x4f00, %ax
         int     $0x10
         cmpw    $0x004f, %ax
@@ -990,6 +990,7 @@ name_bann:      .asciz  "Video adapter: "
 
 force_size:     .word   0       # Use this size instead of the one in BIOS vars
 
+        .pushsection .data.boot16, "aw", @progbits
 GLOBAL(boot_vid_info)
         .byte   0, 0    /* orig_x, orig_y */
         .byte   3       /* text mode 3    */
@@ -1001,3 +1002,4 @@ GLOBAL(boot_edid_info)
         .fill   128,1,0x13
 GLOBAL(boot_edid_caps)
         .word   0x1313
+        .popsection
diff --git a/xen/arch/x86/platform_hypercall.c b/xen/arch/x86/platform_hypercall.c
index b19f6ec4ed..9a56bd8f84 100644
--- a/xen/arch/x86/platform_hypercall.c
+++ b/xen/arch/x86/platform_hypercall.c
@@ -318,10 +318,10 @@ ret_t do_platform_op(XEN_GUEST_HANDLE_PARAM(xen_platform_op_t) u_xenpf_op)
             u16 length;
 
             ret = -ESRCH;
-            if ( op->u.firmware_info.index >= bootsym(boot_edd_info_nr) )
+            if ( op->u.firmware_info.index >= boot_edd_info_nr )
                 break;
 
-            info = bootsym(boot_edd_info) + op->u.firmware_info.index;
+            info = boot_edd_info + op->u.firmware_info.index;
 
             /* Transfer the EDD info block. */
             ret = -EFAULT;
@@ -357,10 +357,10 @@ ret_t do_platform_op(XEN_GUEST_HANDLE_PARAM(xen_platform_op_t) u_xenpf_op)
             const struct mbr_signature *sig;
 
             ret = -ESRCH;
-            if ( op->u.firmware_info.index >= bootsym(boot_mbr_signature_nr) )
+            if ( op->u.firmware_info.index >= boot_mbr_signature_nr )
                 break;
 
-            sig = bootsym(boot_mbr_signature) + op->u.firmware_info.index;
+            sig = boot_mbr_signature + op->u.firmware_info.index;
 
             op->u.firmware_info.u.disk_mbr_signature.device = sig->device;
             op->u.firmware_info.u.disk_mbr_signature.mbr_signature =
@@ -376,13 +376,13 @@ ret_t do_platform_op(XEN_GUEST_HANDLE_PARAM(xen_platform_op_t) u_xenpf_op)
 #ifdef CONFIG_VIDEO
             if ( op->u.firmware_info.index != 0 )
                 break;
-            if ( *(u32 *)bootsym(boot_edid_info) == 0x13131313 )
+            if ( *(u32 *)boot_edid_info == 0x13131313 )
                 break;
 
             op->u.firmware_info.u.vbeddc_info.capabilities =
-                bootsym(boot_edid_caps);
+                boot_edid_caps;
             op->u.firmware_info.u.vbeddc_info.edid_transfer_time =
-                bootsym(boot_edid_caps) >> 8;
+                boot_edid_caps >> 8;
 
             ret = 0;
             if ( __copy_field_to_guest(u_xenpf_op, op, u.firmware_info.
@@ -390,7 +390,7 @@ ret_t do_platform_op(XEN_GUEST_HANDLE_PARAM(xen_platform_op_t) u_xenpf_op)
                  __copy_field_to_guest(u_xenpf_op, op, u.firmware_info.
                                        u.vbeddc_info.edid_transfer_time) ||
                  copy_to_compat(op->u.firmware_info.u.vbeddc_info.edid,
-                                bootsym(boot_edid_info), 128) )
+                                boot_edid_info, 128) )
                 ret = -EFAULT;
 #endif
             break;
@@ -407,7 +407,7 @@ ret_t do_platform_op(XEN_GUEST_HANDLE_PARAM(xen_platform_op_t) u_xenpf_op)
             if ( op->u.firmware_info.index != 0 )
                 break;
 
-            op->u.firmware_info.u.kbd_shift_flags = bootsym(kbd_shift_flags);
+            op->u.firmware_info.u.kbd_shift_flags = kbd_shift_flags;
 
             ret = 0;
             if ( __copy_field_to_guest(u_xenpf_op, op,
diff --git a/xen/arch/x86/setup.c b/xen/arch/x86/setup.c
index 06e779368c..101c9dd272 100644
--- a/xen/arch/x86/setup.c
+++ b/xen/arch/x86/setup.c
@@ -509,7 +509,7 @@ extern struct boot_video_info boot_vid_info;
 static void __init parse_video_info(void)
 {
 #ifdef CONFIG_VIDEO
-    struct boot_video_info *bvi = &bootsym(boot_vid_info);
+    struct boot_video_info *bvi = &boot_vid_info;
 
     /* vga_console_info is filled directly on EFI platform. */
     if ( efi_enabled(EFI_BOOT) )
@@ -674,10 +674,10 @@ static char * __init cmdline_cook(char *p, const char *loader_name)
 
 static unsigned int __init copy_bios_e820(struct e820entry *map, unsigned int limit)
 {
-    unsigned int n = min(bootsym(bios_e820nr), limit);
+    unsigned int n = min(bios_e820nr, limit);
 
     if ( n )
-        memcpy(map, bootsym(bios_e820map), sizeof(*map) * n);
+        memcpy(map, bios_e820map, sizeof(*map) * n);
 
     return n;
 }
@@ -818,15 +818,15 @@ void __init noreturn __start_xen(unsigned long mbi_p)
     }
 
     /* Print VBE/DDC EDID information. */
-    if ( bootsym(boot_edid_caps) != 0x1313 )
+    if ( boot_edid_caps != 0x1313 )
     {
-        u16 caps = bootsym(boot_edid_caps);
+        u16 caps = boot_edid_caps;
         printk(" VBE/DDC methods:%s%s%s; ",
                (caps & 1) ? " V1" : "",
                (caps & 2) ? " V2" : "",
                !(caps & 3) ? " none" : "");
         printk("EDID transfer time: %d seconds\n", caps >> 8);
-        if ( *(u32 *)bootsym(boot_edid_info) == 0x13131313 )
+        if ( *(u32 *)boot_edid_info == 0x13131313 )
         {
             printk(" EDID info not retrieved because ");
             if ( !(caps & 3) )
@@ -841,9 +841,9 @@ void __init noreturn __start_xen(unsigned long mbi_p)
 
     printk("Disc information:\n");
     printk(" Found %d MBR signatures\n",
-           bootsym(boot_mbr_signature_nr));
+           boot_mbr_signature_nr);
     printk(" Found %d EDD information structures\n",
-           bootsym(boot_edd_info_nr));
+           boot_edd_info_nr);
 
     /* Check that we have at least one Multiboot module. */
     if ( !(mbi->flags & MBI_MODULES) || (mbi->mods_count == 0) )
@@ -926,14 +926,14 @@ void __init noreturn __start_xen(unsigned long mbi_p)
             bytes += map->size + 4;
         }
     }
-    else if ( bootsym(lowmem_kb) )
+    else if ( lowmem_kb )
     {
         memmap_type = "Xen-e801";
         e820_raw.map[0].addr = 0;
-        e820_raw.map[0].size = bootsym(lowmem_kb) << 10;
+        e820_raw.map[0].size = lowmem_kb << 10;
         e820_raw.map[0].type = E820_RAM;
         e820_raw.map[1].addr = 0x100000;
-        e820_raw.map[1].size = bootsym(highmem_kb) << 10;
+        e820_raw.map[1].size = highmem_kb << 10;
         e820_raw.map[1].type = E820_RAM;
         e820_raw.nr_map = 2;
     }
diff --git a/xen/arch/x86/xen.lds.S b/xen/arch/x86/xen.lds.S
index 6968262a60..acc1e2d593 100644
--- a/xen/arch/x86/xen.lds.S
+++ b/xen/arch/x86/xen.lds.S
@@ -244,11 +244,13 @@ SECTIONS
        __trampoline32_rel_stop = .;
        __bootsym_rel_start = .;
        *(.bootsym_rel)
-       *(.bootdatasym_rel)
        __bootsym_rel_stop = .;
        __bootsym_seg_start = .;
        *(.bootsym_seg)
        __bootsym_seg_stop = .;
+       __bootdatasym_rel_start = .;
+       *(.bootdatasym_rel)
+       __bootdatasym_rel_stop = .;
        /*
         * struct alt_inst entries. From the header (alternative.h):
         * "Alternative instructions for different CPU types or capabilities"
@@ -291,6 +293,10 @@ SECTIONS
   DECL_SECTION(.data) {
        *(.data.page_aligned)
        *(.data)
+       . = ALIGN(16);
+       __bootdata_start = .;
+       *(.data.boot16)
+       __bootdata_end = .;
        *(.data.rel)
        *(.data.rel.*)
        CONSTRUCTORS
diff --git a/xen/include/asm-x86/edd.h b/xen/include/asm-x86/edd.h
index afaa23732a..a4d6b4d90e 100644
--- a/xen/include/asm-x86/edd.h
+++ b/xen/include/asm-x86/edd.h
@@ -143,7 +143,6 @@ struct __packed mbr_signature {
     u32 signature;
 };
 
-/* These all reside in the boot trampoline. Access via bootsym(). */
 extern struct mbr_signature boot_mbr_signature[];
 extern u8 boot_mbr_signature_nr;
 extern struct edd_info boot_edd_info[];
