[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [PATCH v3 2/5] xen/x86: manually build xen.mb.efi binary
From: Daniel Kiper <daniel.kiper@xxxxxxxxxx> This patch introduces xen.mb.efi which contains a manually built PE header. This allows us to support Xen on UEFI Secure Boot-enabled hosts via multiboot2. xen.mb.efi is a single binary that is loadable by a UEFI loader or via the Multiboot/Multiboot2 protocols. Signed-off-by: Daniel Kiper <daniel.kiper@xxxxxxxxxx> Signed-off-by: Bobby Eshleman <bobbyeshleman@xxxxxxxxx> --- xen/Makefile | 20 +++--- xen/arch/x86/Makefile | 7 +- xen/arch/x86/arch.mk | 2 + xen/arch/x86/boot/Makefile | 1 + xen/arch/x86/boot/head.S | 1 + xen/arch/x86/boot/pecoff.S | 123 ++++++++++++++++++++++++++++++++++++ xen/arch/x86/efi/efi-boot.h | 24 ++++++- xen/arch/x86/efi/stub.c | 12 +++- xen/arch/x86/xen.lds.S | 34 ++++++++++ xen/include/xen/efi.h | 1 + 10 files changed, 212 insertions(+), 13 deletions(-) create mode 100644 xen/arch/x86/boot/pecoff.S diff --git a/xen/Makefile b/xen/Makefile index 85f9b763a4..9c689c2095 100644 --- a/xen/Makefile +++ b/xen/Makefile @@ -266,29 +266,31 @@ endif .PHONY: _build _build: $(TARGET)$(CONFIG_XEN_INSTALL_SUFFIX) +define install_xen_links + $(INSTALL_DATA) $(TARGET)$1 $(D)$(BOOT_DIR)/$(T)-$(XEN_FULLVERSION)$1 + ln -f -s $(T)-$(XEN_FULLVERSION)$1 $(D)$(BOOT_DIR)/$(T)-$(XEN_VERSION).$(XEN_SUBVERSION)$1 + ln -f -s $(T)-$(XEN_FULLVERSION)$1 $(D)$(BOOT_DIR)/$(T)-$(XEN_VERSION)$1 + ln -f -s $(T)-$(XEN_FULLVERSION)$1 $(D)$(BOOT_DIR)/$(T)$1 +endef + .PHONY: _install _install: D=$(DESTDIR) _install: T=$(notdir $(TARGET)) _install: Z=$(CONFIG_XEN_INSTALL_SUFFIX) _install: $(TARGET)$(CONFIG_XEN_INSTALL_SUFFIX) [ -d $(D)$(BOOT_DIR) ] || $(INSTALL_DIR) $(D)$(BOOT_DIR) - $(INSTALL_DATA) $(TARGET)$(Z) $(D)$(BOOT_DIR)/$(T)-$(XEN_FULLVERSION)$(Z) - 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) + $(call install_xen_links,$(Z)) + $(call install_xen_links,.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 $(INSTALL_DATA) $(KCONFIG_CONFIG) $(D)$(BOOT_DIR)/$(T)-$(XEN_FULLVERSION).config if [ -r $(TARGET).efi -a -n '$(EFI_DIR)' ]; then \ [ -d $(D)$(EFI_DIR) ] || $(INSTALL_DIR) $(D)$(EFI_DIR); \ - $(INSTALL_DATA) $(TARGET).efi $(D)$(EFI_DIR)/$(T)-$(XEN_FULLVERSION).efi; \ if [ -e $(TARGET).efi.map ]; then \ $(INSTALL_DATA) $(TARGET).efi.map $(D)$(DEBUG_DIR)/$(T)-$(XEN_FULLVERSION).efi.map; \ fi; \ - ln -sf $(T)-$(XEN_FULLVERSION).efi $(D)$(EFI_DIR)/$(T)-$(XEN_VERSION).$(XEN_SUBVERSION).efi; \ - ln -sf $(T)-$(XEN_FULLVERSION).efi $(D)$(EFI_DIR)/$(T)-$(XEN_VERSION).efi; \ - ln -sf $(T)-$(XEN_FULLVERSION).efi $(D)$(EFI_DIR)/$(T).efi; \ + $(call install_xen_links,.efi)) \ if [ -n '$(EFI_MOUNTPOINT)' -a -n '$(EFI_VENDOR)' ]; then \ $(INSTALL_DATA) $(TARGET).efi $(D)$(EFI_MOUNTPOINT)/efi/$(EFI_VENDOR)/$(T)-$(XEN_FULLVERSION).efi; \ elif [ "$(D)" = "$(patsubst $(shell cd $(XEN_ROOT) && pwd)/%,%,$(D))" ]; then \ @@ -341,7 +343,7 @@ _clean: delete-unfresh-files $(MAKE) -f $(BASEDIR)/tools/kconfig/Makefile.kconfig ARCH=$(ARCH) SRCARCH=$(SRCARCH) clean find . \( -name "*.o" -o -name ".*.d" -o -name ".*.d2" \ -o -name "*.gcno" -o -name ".*.cmd" \) -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).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 7769bb40d7..49c61adabf 100644 --- a/xen/arch/x86/Makefile +++ b/xen/arch/x86/Makefile @@ -110,7 +110,7 @@ syms-warn-dup-$(CONFIG_SUPPRESS_DUPLICATE_SYMBOL_WARNINGS) := syms-warn-dup-$(CONFIG_ENFORCE_UNIQUE_SYMBOLS) := --error-dup $(TARGET): TMP = $(@D)/.$(@F).elf32 -$(TARGET): $(TARGET)-syms $(efi-y) boot/mkelf32 +$(TARGET): $(TARGET).mb.efi $(TARGET)-syms $(efi-y) boot/mkelf32 ./boot/mkelf32 $(notes_phdrs) $(TARGET)-syms $(TMP) $(XEN_IMG_OFFSET) \ `$(NM) $(TARGET)-syms | sed -ne 's/^\([^ ]*\) . __2M_rwdata_end$$/0x\1/p'` od -t x4 -N 8192 $(TMP) | grep 1badb002 > /dev/null || \ @@ -119,6 +119,11 @@ $(TARGET): $(TARGET)-syms $(efi-y) boot/mkelf32 { echo "No Multiboot2 header found" >&2; false; } mv $(TMP) $(TARGET) +$(TARGET).mb.efi: $(TARGET)-syms + $(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 + ifneq ($(efi-y),) # Check if the compiler supports the MS ABI. export XEN_BUILD_EFI := $(shell $(CC) $(XEN_CFLAGS) -c efi/check.c -o efi/check.o 2>/dev/null && echo y) diff --git a/xen/arch/x86/arch.mk b/xen/arch/x86/arch.mk index ce0c1a0e7f..073343d8ea 100644 --- a/xen/arch/x86/arch.mk +++ b/xen/arch/x86/arch.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 # Prevent floating-point variables from creeping into Xen. CFLAGS += -msoft-float diff --git a/xen/arch/x86/boot/Makefile b/xen/arch/x86/boot/Makefile index 9b31bfcbfb..a559a75e0b 100644 --- a/xen/arch/x86/boot/Makefile +++ b/xen/arch/x86/boot/Makefile @@ -1,4 +1,5 @@ obj-bin-y += head.o +obj-bin-y += pecoff.o DEFS_H_DEPS = defs.h $(BASEDIR)/include/xen/stdbool.h diff --git a/xen/arch/x86/boot/head.S b/xen/arch/x86/boot/head.S index 150f7f90a2..2987b4f03a 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> diff --git a/xen/arch/x86/boot/pecoff.S b/xen/arch/x86/boot/pecoff.S new file mode 100644 index 0000000000..fa821f42c1 --- /dev/null +++ b/xen/arch/x86/boot/pecoff.S @@ -0,0 +1,123 @@ +#include <xen/compile.h> +#include <asm/page.h> + +#define sym_offs(sym) ((sym) - __XEN_VIRT_START) + + .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 Lpe_header - efi_pe_head /* File address of the PE header. */ + +Lpe_header: + /* + * PE/COFF header. + * + * The PE/COFF format is defined by Microsoft, and is available from + * https://docs.microsoft.com/en-us/windows/win32/debug/pe-format + * + * Some ideas are taken from Linux kernel and Xen ARM64. + */ + .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 Lsection_table - Loptional_header /* SizeOfOptionalHeader. */ + .short 0x226 /* Characteristics: + * IMAGE_FILE_EXECUTABLE_IMAGE | + * IMAGE_FILE_LARGE_ADDRESS_AWARE | + * IMAGE_FILE_DEBUG_STRIPPED | + * IMAGE_FILE_LINE_NUMS_STRIPPED + */ + +Loptional_header: + .short 0x20b /* PE format: PE32+ */ + .byte 0 /* MajorLinkerVersion. */ + .byte 0 /* 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. */ + +Lsection_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 + diff --git a/xen/arch/x86/efi/efi-boot.h b/xen/arch/x86/efi/efi-boot.h index 2541ba1f32..f694a069c9 100644 --- a/xen/arch/x86/efi/efi-boot.h +++ b/xen/arch/x86/efi/efi-boot.h @@ -32,7 +32,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) @@ -568,6 +569,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; @@ -592,6 +594,13 @@ 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 += ARRAY_SIZE(l2_directmap) ) + /* Skip relocating the directmap because start_xen() does this for us when + * when it updates all superpage-aligned mappings. */ + if ( (pte != (intpte_t *)l2_directmap) && (get_pte_flags(*pte) & _PAGE_PRESENT) ) + *pte += xen_phys_start; + /* * Map Xen into the higher mappings, using 2M superpages. * @@ -724,7 +733,18 @@ 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 __init efi_multiboot2(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) +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, + multiboot2_tag_module_t *dom0_kernel) { EFI_GRAPHICS_OUTPUT_PROTOCOL *gop; UINTN cols, gop_mode = ~0, rows; diff --git a/xen/arch/x86/efi/stub.c b/xen/arch/x86/efi/stub.c index 9984932626..9bd6355ec3 100644 --- a/xen/arch/x86/efi/stub.c +++ b/xen/arch/x86/efi/stub.c @@ -15,9 +15,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 0273f79152..a58ae1e491 100644 --- a/xen/arch/x86/xen.lds.S +++ b/xen/arch/x86/xen.lds.S @@ -63,7 +63,22 @@ SECTIONS start_pa = ABSOLUTE(start - __XEN_VIRT_START); +#ifdef EFI . = __XEN_VIRT_START + XEN_IMG_OFFSET; +#else + /* + * Multiboot2 with an EFI PE/COFF header. + * + * 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 */ @@ -289,6 +304,13 @@ SECTIONS *(.data.rel) *(.data.rel.*) CONSTRUCTORS + /* + * A la the PE/COFF spec, the PE file data section must end at the + * alignment boundary equal to FileAlignment in the optional header, + * i.e., XEN_FILE_ALIGN. + */ + . = ALIGN(XEN_FILE_ALIGN); + __pe_text_raw_end = .; } :text DECL_SECTION(.bss) { @@ -312,6 +334,8 @@ SECTIONS . = ALIGN(SECTION_ALIGN); __2M_rwdata_end = .; + __pe_SizeOfImage = ALIGN(. - __image_base__, MB(16)); + #ifdef EFI . = ALIGN(4); DECL_SECTION(.reloc) { @@ -341,6 +365,7 @@ SECTIONS *(.discard.*) *(.eh_frame) #ifdef EFI + *(.efi.pe.header) *(.comment) *(.comment.*) *(.note.Xen) @@ -392,5 +417,14 @@ ASSERT((trampoline_end - trampoline_start) < TRAMPOLINE_SPACE - MBI_SPACE_MIN, 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 + /* Plenty of boot code assumes that Xen isn't larger than 16M. */ ASSERT(_end - _start <= MB(16), "Xen too large for early-boot assumptions") diff --git a/xen/include/xen/efi.h b/xen/include/xen/efi.h index 94a7e547f9..f7f92b4e3d 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 { -- 2.30.0
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |