|
[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
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |