[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] [PATCH v2 3/8] xen/x86: manually build xen.mb.efi binary



This patch introduces xen.mb.efi which contains PE header build manually.
The code executed by it is almost the same like the code executed by
currently existing xen.efi. However, the file layout is simpler and
completely different. This way we have better control on PE image. Hence,
it allow us to play tricks which are not feasible in xen.efi.

This is the first step to get:
  - one binary which can be loaded by the UEFI loader, Multiboot and
    Multiboot2 protocols,
  - UEFI secure boot support when Xen is loaded via Multiboot2 protocol,
  - if we wish, in the future we can drop xen/xen.gz and build
    xen.mb.efi only,
  - crash dumps generated by the xen.mb.efi loaded from the EFI loader
    can be analyzed by crash tool,
  - simpler code,
  - simpler build,
  - Xen build will no longer depend on ld i386pep support.

Signed-off-by: Daniel Kiper <daniel.kiper@xxxxxxxxxx>
---
v2 - suggestions/fixes:
   - align __pe_SizeOfImage at 16 MiB
     (suggested by Jan Beulich),
   - use GLOBAL() instead of ENTRY() for EFI PE header labels
     (suggested by Boris Ostrovsky),
   - improve comments
     (suggested by Konrad Rzeszutek Wilk).

Not done:
   - ASM PE header conversion to C; not feasible,
   - DOS stub code reduction; experiments showed that DOS stub code size
     cannot be changed due to some bugs in applications playing with PE
     files, e.g. objdump (more about the issue can be found in the patch
     itself); so, I think that if it is not possible to reduce the size
     of code then it does make sens change the code itself; hence, it
     pays to leave common DOS stub code as is.
---
 xen/Makefile                |    6 +-
 xen/arch/x86/Makefile       |    3 +
 xen/arch/x86/Rules.mk       |    2 +
 xen/arch/x86/boot/head.S    |  150 +++++++++++++++++++++++++++++++++++++++++++
 xen/arch/x86/efi/efi-boot.h |   22 ++++++-
 xen/arch/x86/efi/stub.c     |   12 +++-
 xen/arch/x86/xen.lds.S      |   28 ++++++++
 xen/include/xen/efi.h       |    1 +
 8 files changed, 221 insertions(+), 3 deletions(-)

diff --git a/xen/Makefile b/xen/Makefile
index 1bed339..a49b9b7 100644
--- a/xen/Makefile
+++ b/xen/Makefile
@@ -61,6 +61,10 @@ _install: $(TARGET)$(CONFIG_XEN_INSTALL_SUFFIX)
        ln -f -s $(T)-$(XEN_FULLVERSION)$(Z) 
$(D)$(BOOT_DIR)/$(T)-$(XEN_VERSION).$(XEN_SUBVERSION)$(Z)
        ln -f -s $(T)-$(XEN_FULLVERSION)$(Z) 
$(D)$(BOOT_DIR)/$(T)-$(XEN_VERSION)$(Z)
        ln -f -s $(T)-$(XEN_FULLVERSION)$(Z) $(D)$(BOOT_DIR)/$(T)$(Z)
+       $(INSTALL_DATA) $(TARGET).mb.efi 
$(D)$(BOOT_DIR)/$(T)-$(XEN_FULLVERSION).mb.efi
+       ln -f -s $(T)-$(XEN_FULLVERSION).mb.efi 
$(D)$(BOOT_DIR)/$(T)-$(XEN_VERSION).$(XEN_SUBVERSION).mb.efi
+       ln -f -s $(T)-$(XEN_FULLVERSION).mb.efi 
$(D)$(BOOT_DIR)/$(T)-$(XEN_VERSION).mb.efi
+       ln -f -s $(T)-$(XEN_FULLVERSION).mb.efi $(D)$(BOOT_DIR)/$(T).mb.efi
        [ -d "$(D)$(DEBUG_DIR)" ] || $(INSTALL_DIR) $(D)$(DEBUG_DIR)
        $(INSTALL_DATA) $(TARGET)-syms 
$(D)$(DEBUG_DIR)/$(T)-syms-$(XEN_FULLVERSION)
        $(INSTALL_DATA) $(TARGET)-syms.map 
$(D)$(DEBUG_DIR)/$(T)-syms-$(XEN_FULLVERSION).map
@@ -121,7 +125,7 @@ _clean: delete-unfresh-files
        $(MAKE) -f $(BASEDIR)/Rules.mk -C test clean
        $(MAKE) -f $(BASEDIR)/tools/kconfig/Makefile.kconfig ARCH=$(ARCH) 
SRCARCH=$(SRCARCH) clean
        find . \( -name "*.o" -o -name ".*.d" -o -name "*.gcno" \) -exec rm -f 
{} \;
-       rm -f include/asm $(TARGET) $(TARGET).gz $(TARGET).efi 
$(TARGET).efi.map $(TARGET)-syms $(TARGET)-syms.map *~ core
+       rm -f include/asm $(TARGET) $(TARGET).gz $(TARGET).efi $(TARGET).mb.efi 
$(TARGET).efi.map $(TARGET)-syms $(TARGET)-syms.map *~ core
        rm -f include/asm-*/asm-offsets.h
        rm -f .banner
 
diff --git a/xen/arch/x86/Makefile b/xen/arch/x86/Makefile
index 5563c81..ef3fb51 100644
--- a/xen/arch/x86/Makefile
+++ b/xen/arch/x86/Makefile
@@ -101,6 +101,9 @@ syms-warn-dup-$(CONFIG_SUPPRESS_DUPLICATE_SYMBOL_WARNINGS) 
:=
 $(TARGET): $(TARGET)-syms $(efi-y) boot/mkelf32
        ./boot/mkelf32 $(notes_phdrs) $(TARGET)-syms $(TARGET) 
$(XEN_IMG_OFFSET) \
                       `$(NM) $(TARGET)-syms | sed -ne 's/^\([^ ]*\) . 
__2M_rwdata_end$$/0x\1/p'`
+       $(OBJCOPY) -O binary -S --change-section-address \
+               ".efi.pe.header-`$(NM) $(TARGET)-syms | sed -ne 's/^\([^ ]*\) . 
__image_base__$$/0x\1/p'`" \
+               $(TARGET)-syms $(TARGET).mb.efi
 
 ALL_OBJS := $(BASEDIR)/arch/x86/boot/built_in.o 
$(BASEDIR)/arch/x86/efi/built_in.o $(ALL_OBJS)
 
diff --git a/xen/arch/x86/Rules.mk b/xen/arch/x86/Rules.mk
index ac585a3..51331bf 100644
--- a/xen/arch/x86/Rules.mk
+++ b/xen/arch/x86/Rules.mk
@@ -7,6 +7,8 @@ CFLAGS += -I$(BASEDIR)/include
 CFLAGS += -I$(BASEDIR)/include/asm-x86/mach-generic
 CFLAGS += -I$(BASEDIR)/include/asm-x86/mach-default
 CFLAGS += -DXEN_IMG_OFFSET=$(XEN_IMG_OFFSET)
+CFLAGS += -DXEN_LOAD_ALIGN=XEN_IMG_OFFSET
+CFLAGS += -DXEN_FILE_ALIGN=0x20
 CFLAGS += '-D__OBJECT_LABEL__=$(subst /,$$,$(subst -,_,$(subst 
$(BASEDIR)/,,$(CURDIR))/$@))'
 
 # Prevent floating-point variables from creeping into Xen.
diff --git a/xen/arch/x86/boot/head.S b/xen/arch/x86/boot/head.S
index db19ac6..47f254d 100644
--- a/xen/arch/x86/boot/head.S
+++ b/xen/arch/x86/boot/head.S
@@ -1,3 +1,4 @@
+#include <xen/compile.h>
 #include <xen/multiboot.h>
 #include <xen/multiboot2.h>
 #include <public/xen.h>
@@ -45,6 +46,155 @@
 .Lmb2ht_init_end\@:
         .endm
 
+        .section .efi.pe.header, "a", @progbits
+
+GLOBAL(efi_pe_head)
+        /*
+         * Legacy EXE header.
+         *
+         * Most of it is copied from binutils package, version 2.30,
+         * include/coff/pe.h:struct external_PEI_filehdr and
+         * bfd/peXXigen.c:_bfd_XXi_only_swap_filehdr_out().
+         *
+         * Page is equal 512 bytes here.
+         * Paragraph is equal 16 bytes here.
+         */
+        .short  0x5a4d                               /* EXE magic number. */
+        .short  0x90                                 /* Bytes on last page of 
file. */
+        .short  0x3                                  /* Pages in file. */
+        .short  0                                    /* Relocations. */
+        .short  0x4                                  /* Size of header in 
paragraphs. */
+        .short  0                                    /* Minimum extra 
paragraphs needed. */
+        .short  0xffff                               /* Maximum extra 
paragraphs needed. */
+        .short  0                                    /* Initial (relative) SS 
value. */
+        .short  0xb8                                 /* Initial SP value. */
+        .short  0                                    /* Checksum. */
+        .short  0                                    /* Initial IP value. */
+        .short  0                                    /* Initial (relative) CS 
value. */
+        .short  0x40                                 /* File address of 
relocation table. */
+        .short  0                                    /* Overlay number. */
+        .fill   4, 2, 0                              /* Reserved words. */
+        .short  0                                    /* OEM identifier. */
+        .short  0                                    /* OEM information. */
+        .fill   10, 2, 0                             /* Reserved words. */
+        .long   pe_header - efi_pe_head              /* File address of the PE 
header. */
+
+        /*
+         * Standard/Minimal DOS code/data.
+         *
+         * It is copied from binutils package, version 2.30,
+         * include/coff/pe.h:struct external_PEI_filehdr and
+         * bfd/peXXigen.c:_bfd_XXi_only_swap_filehdr_out().
+         *
+         * Do not change DOS code/data size!!! Some buggy applications
+         * ignore PE header address from EXE header and look for PE header
+         * at 0x80 file offset. The size of this code assures that it is
+         * found at exactly that address.
+         */
+        .long   0x0eba1f0e
+        .long   0xcd09b400
+        .long   0x4c01b821
+        .long   0x685421cd
+        .long   0x70207369
+        .long   0x72676f72
+        .long   0x63206d61
+        .long   0x6f6e6e61
+        .long   0x65622074
+        .long   0x6e757220
+        .long   0x206e6920
+        .long   0x20534f44
+        .long   0x65646f6d
+        .long   0x0a0d0d2e
+        .long   0x24
+        .long   0
+
+        /*
+         * PE/COFF header.
+         *
+         * The PE/COFF format is defined by Microsoft, and is available from
+         * http://www.microsoft.com/whdc/system/platform/firmware/PECOFF.mspx
+         *
+         * Some ideas are taken from Linux kernel and Xen ARM64.
+         */
+
+pe_header:
+        .ascii  "PE\0\0"                             /* PE signature. */
+        .short  0x8664                               /* Machine: 
IMAGE_FILE_MACHINE_AMD64 */
+        .short  1                                    /* NumberOfSections. */
+        .long   XEN_COMPILE_POSIX_TIME               /* TimeDateStamp. */
+        .long   0                                    /* PointerToSymbolTable. 
*/
+        .long   0                                    /* NumberOfSymbols. */
+        .short  section_table - optional_header      /* SizeOfOptionalHeader. 
*/
+        .short  0x226                                /* Characteristics:
+                                                      *   
IMAGE_FILE_EXECUTABLE_IMAGE |
+                                                      *   
IMAGE_FILE_LARGE_ADDRESS_AWARE |
+                                                      *   
IMAGE_FILE_DEBUG_STRIPPED |
+                                                      *   
IMAGE_FILE_LINE_NUMS_STRIPPED
+                                                      */
+
+optional_header:
+        .short  0x20b                                /* PE format: PE32+ */
+        .byte   0x02                                 /* MajorLinkerVersion. */
+        .byte   0x1e                                 /* MinorLinkerVersion. */
+        .long   __2M_rwdata_end - efi_pe_head_end    /* SizeOfCode. */
+        .long   0                                    /* SizeOfInitializedData. 
*/
+        .long   0                                    /* 
SizeOfUninitializedData. */
+        .long   sym_offs(efi_mb_start)               /* AddressOfEntryPoint. */
+        .long   sym_offs(start)                      /* BaseOfCode. */
+        .quad   sym_offs(__image_base__)             /* ImageBase. */
+        .long   XEN_LOAD_ALIGN                       /* SectionAlignment. */
+        .long   XEN_FILE_ALIGN                       /* FileAlignment. */
+        .short  2                                    /* 
MajorOperatingSystemVersion. */
+        .short  0                                    /* 
MinorOperatingSystemVersion. */
+        .short  XEN_VERSION                          /* MajorImageVersion. */
+        .short  XEN_SUBVERSION                       /* MinorImageVersion. */
+        .short  2                                    /* MajorSubsystemVersion. 
*/
+        .short  0                                    /* MinorSubsystemVersion. 
*/
+        .long   0                                    /* Win32VersionValue. */
+        .long   __pe_SizeOfImage                     /* SizeOfImage. */
+        .long   efi_pe_head_end - efi_pe_head        /* SizeOfHeaders. */
+        .long   0                                    /* CheckSum. */
+        .short  0xa                                  /* Subsystem: EFI 
application. */
+        .short  0                                    /* DllCharacteristics. */
+        .quad   0                                    /* SizeOfStackReserve. */
+        .quad   0                                    /* SizeOfStackCommit. */
+        .quad   0                                    /* SizeOfHeapReserve. */
+        .quad   0                                    /* SizeOfHeapCommit. */
+        .long   0                                    /* LoaderFlags. */
+        .long   0x6                                  /* NumberOfRvaAndSizes. */
+
+        /* Data Directories. */
+        .quad   0                                    /* Export Table. */
+        .quad   0                                    /* Import Table. */
+        .quad   0                                    /* Resource Table. */
+        .quad   0                                    /* Exception Table. */
+        .quad   0                                    /* Certificate Table. */
+        .quad   0                                    /* Base Relocation Table. 
*/
+
+section_table:
+        .ascii  ".text\0\0\0"                        /* Name. */
+        .long   __2M_rwdata_end - efi_pe_head_end    /* VirtualSize. */
+        .long   sym_offs(start)                      /* VirtualAddress. */
+        .long   __pe_text_raw_end - efi_pe_head_end  /* SizeOfRawData. */
+        .long   efi_pe_head_end - efi_pe_head        /* PointerToRawData. */
+        .long   0                                    /* PointerToRelocations. 
*/
+        .long   0                                    /* PointerToLinenumbers. 
*/
+        .short  0                                    /* NumberOfRelocations. */
+        .short  0                                    /* NumberOfLinenumbers. */
+        .long   0xe0500020                           /* Characteristics:
+                                                      *   IMAGE_SCN_CNT_CODE |
+                                                      *   
IMAGE_SCN_ALIGN_16BYTES |
+                                                      *   
IMAGE_SCN_MEM_EXECUTE |
+                                                      *   IMAGE_SCN_MEM_READ |
+                                                      *   IMAGE_SCN_MEM_WRITE
+                                                      */
+
+        .align XEN_FILE_ALIGN
+GLOBAL(efi_pe_head_end)
+
+        .text
+        .code32
+
 ENTRY(start)
         jmp     __start
 
diff --git a/xen/arch/x86/efi/efi-boot.h b/xen/arch/x86/efi/efi-boot.h
index 5789d2c..5f0e821 100644
--- a/xen/arch/x86/efi/efi-boot.h
+++ b/xen/arch/x86/efi/efi-boot.h
@@ -31,7 +31,8 @@ static void __init edd_put_string(u8 *dst, size_t n, const 
char *src)
 }
 #define edd_put_string(d, s) edd_put_string(d, ARRAY_SIZE(d), s)
 
-extern const intpte_t __page_tables_start[], __page_tables_end[];
+extern intpte_t __page_tables_start[], __page_tables_end[];
+
 #define in_page_tables(v) ((intpte_t *)(v) >= __page_tables_start && \
                            (intpte_t *)(v) < __page_tables_end)
 
@@ -49,6 +50,9 @@ static void __init efi_arch_relocate_image(unsigned long 
delta)
 {
     const struct pe_base_relocs *base_relocs;
 
+    if ( efi_enabled(EFI_MB_LOADER) )
+        return;
+
     for ( base_relocs = __base_relocs_start; base_relocs < __base_relocs_end; )
     {
         unsigned int i = 0, n;
@@ -558,6 +562,7 @@ static void __init 
efi_arch_video_init(EFI_GRAPHICS_OUTPUT_PROTOCOL *gop,
 
 static void __init efi_arch_memory_setup(void)
 {
+    intpte_t *pte;
     unsigned int i;
     EFI_STATUS status;
 
@@ -582,6 +587,12 @@ static void __init efi_arch_memory_setup(void)
     if ( !efi_enabled(EFI_LOADER) )
         return;
 
+    if ( efi_enabled(EFI_MB_LOADER) )
+        for ( pte = __page_tables_start; pte < __page_tables_end;
+              pte += ( pte != (intpte_t *)l2_identmap ) ? 1 : 4 * 
L2_PAGETABLE_ENTRIES )
+            if ( get_pte_flags(*pte) & _PAGE_PRESENT )
+                *pte += xen_phys_start;
+
     /* Initialise L2 identity-map and boot-map page table entries (16MB). */
     for ( i = 0; i < 8; ++i )
     {
@@ -674,6 +685,15 @@ static bool __init 
efi_arch_use_config_file(EFI_SYSTEM_TABLE *SystemTable)
 
 static void __init efi_arch_flush_dcache_area(const void *vaddr, UINTN size) { 
}
 
+void EFIAPI efi_start(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable);
+
+void EFIAPI __init noreturn
+efi_mb_start(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable)
+{
+    __set_bit(EFI_MB_LOADER, &efi_flags);
+    efi_start(ImageHandle, SystemTable);
+}
+
 void __init efi_multiboot2(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE 
*SystemTable)
 {
     EFI_GRAPHICS_OUTPUT_PROTOCOL *gop;
diff --git a/xen/arch/x86/efi/stub.c b/xen/arch/x86/efi/stub.c
index 0c481e3..2142932 100644
--- a/xen/arch/x86/efi/stub.c
+++ b/xen/arch/x86/efi/stub.c
@@ -14,9 +14,19 @@
  * Here we are in EFI stub. EFI calls are not supported due to lack
  * of relevant functionality in compiler and/or linker.
  *
- * efi_multiboot2() is an exception. Please look below for more details.
+ * efi_mb_start() and efi_multiboot2() are the exceptions.
+ * Please look below for more details.
  */
 
+asm (
+    "    .text                         \n"
+    "    .globl efi_mb_start           \n"
+    "efi_mb_start:                     \n"
+    "    mov    %rcx,%rdi              \n"
+    "    mov    %rdx,%rsi              \n"
+    "    call   efi_multiboot2         \n"
+    );
+
 void __init noreturn efi_multiboot2(EFI_HANDLE ImageHandle,
                                     EFI_SYSTEM_TABLE *SystemTable)
 {
diff --git a/xen/arch/x86/xen.lds.S b/xen/arch/x86/xen.lds.S
index 70afedd..1e5233a 100644
--- a/xen/arch/x86/xen.lds.S
+++ b/xen/arch/x86/xen.lds.S
@@ -60,7 +60,20 @@ SECTIONS
 
   start_pa = ABSOLUTE(start - __XEN_VIRT_START);
 
+#ifdef EFI
   . = __XEN_VIRT_START + XEN_IMG_OFFSET;
+#else
+  /*
+   * The PE header must be followed by .text section which
+   * starts at __XEN_VIRT_START + XEN_IMG_OFFSET address.
+   */
+  . = __XEN_VIRT_START + XEN_IMG_OFFSET - efi_pe_head_end + efi_pe_head;
+
+  DECL_SECTION(.efi.pe.header) {
+       *(.efi.pe.header)
+  } :NONE
+#endif
+
   _start = .;
   DECL_SECTION(.text) {
         _stext = .;            /* Text and read-only data */
@@ -271,6 +284,9 @@ SECTIONS
        *(.data.rel)
        *(.data.rel.*)
        CONSTRUCTORS
+       /* PE file must end at XEN_FILE_ALIGN boundary. */
+       . = ALIGN(XEN_FILE_ALIGN);
+       __pe_text_raw_end = .;
   } :text
 
   DECL_SECTION(.bss) {
@@ -292,6 +308,8 @@ SECTIONS
   . = ALIGN(SECTION_ALIGN);
   __2M_rwdata_end = .;
 
+  __pe_SizeOfImage = ALIGN(. - __image_base__, MB(16));
+
 #ifdef EFI
   . = ALIGN(4);
   .reloc : {
@@ -315,6 +333,7 @@ SECTIONS
        *(.discard.*)
        *(.eh_frame)
 #ifdef EFI
+       *(.efi.pe.header)
        *(.comment)
        *(.comment.*)
        *(.note.Xen)
@@ -361,3 +380,12 @@ ASSERT((trampoline_end - trampoline_start) < 
TRAMPOLINE_SPACE - MBI_SPACE_MIN,
     "not enough room for trampoline and mbi data")
 ASSERT((wakeup_stack - wakeup_stack_start) >= WAKEUP_STACK_MIN,
     "wakeup stack too small")
+
+#ifndef EFI
+ASSERT(efi_pe_head_end == _start, "PE header does not end at the beginning of 
.text section")
+ASSERT(_start == __XEN_VIRT_START + XEN_IMG_OFFSET, ".text section begins at 
wrong address")
+ASSERT(IS_ALIGNED(_start,      XEN_FILE_ALIGN), "_start misaligned")
+ASSERT(IS_ALIGNED(__bss_start, XEN_FILE_ALIGN), "__bss_start misaligned")
+ASSERT(IS_ALIGNED(__pe_SizeOfImage, XEN_LOAD_ALIGN), "__pe_SizeOfImage is not 
multiple of XEN_LOAD_ALIGN")
+ASSERT(XEN_LOAD_ALIGN >= XEN_FILE_ALIGN, "XEN_LOAD_ALIGN < XEN_FILE_ALIGN")
+#endif
diff --git a/xen/include/xen/efi.h b/xen/include/xen/efi.h
index 44b7d3e..73f83c1 100644
--- a/xen/include/xen/efi.h
+++ b/xen/include/xen/efi.h
@@ -11,6 +11,7 @@ extern unsigned int efi_flags;
 #define EFI_BOOT       0       /* Were we booted from EFI? */
 #define EFI_LOADER     1       /* Were we booted directly from EFI loader? */
 #define EFI_RS         2       /* Can we use runtime services? */
+#define EFI_MB_LOADER  4       /* xen.mb.efi booted directly from EFI loader? 
*/
 
 /* Add fields here only if they need to be referenced from non-EFI code. */
 struct efi {
-- 
1.7.10.4


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/mailman/listinfo/xen-devel

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.