diff --git a/.gitignore b/.gitignore
index d8b57e32f888..e61acd574b44 100644
--- a/.gitignore
+++ b/.gitignore
@@ -256,6 +256,7 @@ xen/arch/x86/boot/*.lnk
 xen/arch/x86/efi.lds
 xen/arch/x86/efi/check.efi
 xen/arch/x86/efi/mkreloc
+xen/arch/x86/efi/modify-mbi-exe
 xen/arch/x86/include/asm/asm-macros.h
 xen/arch/*/xen.lds
 xen/arch/*/efi/boot.c
@@ -304,6 +305,7 @@ xen/suppression-list.txt
 xen/xen-syms
 xen/xen-syms.map
 xen/xen.*
+xen/xen-mbi.*
 LibVNCServer*
 
 tools/qemu-xen-dir-remote
diff --git a/xen/Makefile b/xen/Makefile
index 21832d640225..1955e1d687df 100644
--- a/xen/Makefile
+++ b/xen/Makefile
@@ -581,6 +581,7 @@ _clean:
 		-o -name ".*.cmd" -o -name "lib.a" \) -exec rm -f {} \;
 	rm -f include/asm $(TARGET) $(TARGET).gz $(TARGET)-syms $(TARGET)-syms.map
 	rm -f $(TARGET).efi $(TARGET).efi.map $(TARGET).efi.elf $(TARGET).efi.stripped
+	rm -f $(TARGET)-mbi.exe
 	rm -f asm-offsets.s arch/*/include/asm/asm-offsets.h
 	rm -f .banner .allconfig.tmp include/xen/compile.h
 	rm -rf $(objtree)/arch/*/include/generated
diff --git a/xen/arch/x86/Makefile b/xen/arch/x86/Makefile
index 26d87405297b..5b6b8911f1f8 100644
--- a/xen/arch/x86/Makefile
+++ b/xen/arch/x86/Makefile
@@ -86,6 +86,7 @@ extra-y += xen.lds
 
 hostprogs-y += boot/mkelf32
 hostprogs-y += efi/mkreloc
+hostprogs-y += efi/modify-mbi-exe
 
 # Allows usercopy.c to include itself
 $(obj)/usercopy.o: CFLAGS-y += -iquote .
@@ -96,7 +97,7 @@ endif
 
 efi-y := $(shell if [ ! -r $(objtree)/include/xen/compile.h -o \
                       -O $(objtree)/include/xen/compile.h ]; then \
-                         echo '$(TARGET).efi'; fi) \
+                         echo '$(TARGET).efi $(TARGET)-mbi.exe'; fi) \
          $(space)
 efi-$(CONFIG_PV_SHIM_EXCLUSIVE) :=
 
@@ -123,6 +124,19 @@ syms-warn-dup-$(CONFIG_ENFORCE_UNIQUE_SYMBOLS) := --error-dup
 
 orphan-handling-$(call ld-option,--orphan-handling=warn) += --orphan-handling=warn
 
+ifeq ($(XEN_BUILD_PE),y)
+$(TARGET)-mbi.exe: $(TARGET).efi $(obj)/efi/modify-mbi-exe
+	$(OBJCOPY) --remove-section=.reloc $< $@.tmp
+	$(obj)/efi/modify-mbi-exe $@.tmp
+	$(OBJCOPY) --set-start=0x$$($(NM) -pa $@.tmp | awk '/T start$$/{print $$1}') $@.tmp $@.tmp2
+	mv $@.tmp2 $@
+	rm -f $@.tmp
+else
+$(TARGET)-mb.exe: FORCE
+	rm -f $@
+	echo 'PE build not supported'
+endif
+
 $(TARGET): TMP = $(dot-target).elf32
 $(TARGET): $(TARGET)-syms $(efi-y) $(obj)/boot/mkelf32
 	$(obj)/boot/mkelf32 $(notes_phdrs) $(TARGET)-syms $(TMP) $(XEN_IMG_OFFSET) \
diff --git a/xen/arch/x86/efi/modify-mbi-exe.c b/xen/arch/x86/efi/modify-mbi-exe.c
new file mode 100644
index 000000000000..57af382cab4d
--- /dev/null
+++ b/xen/arch/x86/efi/modify-mbi-exe.c
@@ -0,0 +1,77 @@
+#include <stdio.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+struct mz_hdr {
+    uint16_t signature;
+#define MZ_SIGNATURE 0x5a4d
+    uint16_t last_page_size;
+    uint16_t page_count;
+    uint16_t relocation_count;
+    uint16_t header_paras;
+    uint16_t min_paras;
+    uint16_t max_paras;
+    uint16_t entry_ss;
+    uint16_t entry_sp;
+    uint16_t checksum;
+    uint16_t entry_ip;
+    uint16_t entry_cs;
+    uint16_t relocations;
+    uint16_t overlay;
+    uint8_t reserved[32];
+    uint32_t extended_header_base;
+};
+
+struct coff_hdr {
+    uint32_t signature;
+    uint16_t cpu;
+    uint16_t section_count;
+    int32_t timestamp;
+    uint32_t symbols_file_offset;
+    uint32_t symbol_count;
+    uint16_t opt_hdr_size;
+    uint16_t flags;
+};
+
+#define IMAGE_BASE_OFFSET 48
+#define NEW_IMAGE_BASE 0x0
+
+int main(int argc, char **argv)
+{
+    int fd;
+    struct mz_hdr mz_hdr;
+    const uint64_t base_addr = NEW_IMAGE_BASE;
+
+    if ( argc != 2 )
+    {
+        fprintf(stderr, "usage: %s <image>\n", argv[0]);
+        return 1;
+    }
+
+    fd = open(argv[1], O_RDWR);
+    if ( fd < 0 ||
+         read(fd, &mz_hdr, sizeof(mz_hdr)) != sizeof(mz_hdr) )
+    {
+        perror(argv[1]);
+        return 2;
+    }
+
+    if ( mz_hdr.signature != MZ_SIGNATURE ||
+         !mz_hdr.extended_header_base )
+    {
+        fprintf(stderr, "%s: Wrong DOS file format\n", argv[1]);
+        return 2;
+    }
+
+    if ( lseek(fd, mz_hdr.extended_header_base + IMAGE_BASE_OFFSET, SEEK_SET) < 0 ||
+         write(fd, &base_addr, sizeof(base_addr)) != sizeof(base_addr) )
+    {
+        perror(argv[1]);
+        return 3;
+    }
+
+    close(fd);
+
+    return 0;
+}
