[edk2-devel] [PATCH v3 05/35] OvmfPkg/OvmfXen: Creating an ELF header

Anthony PERARD anthony.perard at citrix.com
Thu Jul 4 14:42:03 UTC 2019


This patch changes the flash device image of OvmfXen to make it look
like it's an ELF. For this, we replace the empty embedded variable store
by a binary array, which is a ELF file header.

The ELF header explain to a loader to load the binary at the address
1MB, then jump to the PVH entry point which will be created in a later
patch. The header also includes a Xen ELF note that is part of the
PVH ABI.

That patch include OvmfXenElfHeaderGenerator.c which can be use to
regenerate the ELF header, but this will be a manual step.

Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=1689
Signed-off-by: Anthony PERARD <anthony.perard at citrix.com>
---

Notes:
    v3:
    - added license to generate_elf_header.c
      which is renamed to OvmfPkg/OvmfXenElfHeaderGenerator.c
    - added an ELF NOTE into the header

 OvmfPkg/OvmfXen.fdf                 | 101 +++++++++++++++++++-
 OvmfPkg/OvmfXenElfHeaderGenerator.c | 140 ++++++++++++++++++++++++++++
 2 files changed, 238 insertions(+), 3 deletions(-)
 create mode 100644 OvmfPkg/OvmfXenElfHeaderGenerator.c

diff --git a/OvmfPkg/OvmfXen.fdf b/OvmfPkg/OvmfXen.fdf
index 2ceff7baa2..43c268f6cb 100644
--- a/OvmfPkg/OvmfXen.fdf
+++ b/OvmfPkg/OvmfXen.fdf
@@ -15,8 +15,8 @@ [Defines]
 !include OvmfPkg.fdf.inc

 

 #

-# Build the variable store and the firmware code as one unified flash device

-# image.

+# This will allow the flash device image to be recognize as an ELF, with first

+# an ELF headers, then the firmware code.

 #

 [FD.OVMF]

 BaseAddress   = $(FW_BASE_ADDRESS)

@@ -25,7 +25,102 @@ [FD.OVMF]
 BlockSize     = $(BLOCK_SIZE)

 NumBlocks     = $(FW_BLOCKS)

 

-!include VarStore.fdf.inc

+!if ($(FD_SIZE_IN_KB) == 1024) || ($(FD_SIZE_IN_KB) == 2048)

+0x00000000|0x0000e000

+!endif

+!if $(FD_SIZE_IN_KB) == 4096

+0x00000000|0x00040000

+!endif

+DATA = {

+  #

+  # This hex array have been generated by OvmfPkg/OvmfXenElfHeaderGenerator.c

+  # and copied manually.

+  #

+  # ELF file header

+  0x7f, 0x45, 0x4c, 0x46, # e_ident[0..3]: Magic number

+  0x01, # File class: 32-bit objects

+  0x01, # Data encoding: 2's complement, little endian

+  0x01, # File version

+  0x03, # OS ABI identification: Object uses GNU ELF extensions

+  0x00, # ABI version

+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  # e_ident[EI_PAD...]

+  0x02, 0x00, # e_type = Executable file

+  0x03, 0x00, # e_machine = Intel 80386

+  0x01, 0x00, 0x00, 0x00, # e_version

+  0xd0, 0xff, 0x2f, 0x00, # e_entry: Entry point virtual address

+  0x34, 0x00, 0x00, 0x00, # e_phoff: Program header table file offset

+  0x00, 0x00, 0x00, 0x00, # e_shoff: Section header table file offset

+  0x00, 0x00, 0x00, 0x00, # e_flags: Processor-specific flags

+  0x34, 0x00, #    e_ehsize: ELF header size

+  0x20, 0x00, # e_phentsize: Program header table entry size

+  0x02, 0x00, #     e_phnum: Program header table entry count

+  0x00, 0x00, # e_shentsize: Section header table entry size

+  0x00, 0x00, #     e_shnum: Section header table entry count

+  0x00, 0x00, # e_shstrndx

+

+  # ELF Program segment headers

+  # - Load segment

+  0x01, 0x00, 0x00, 0x00, # p_type = Loadable program segment

+  0x00, 0x00, 0x00, 0x00, # p_offset

+  0x00, 0x00, 0x10, 0x00, # p_vaddr: Segment virtual address

+  0x00, 0x00, 0x10, 0x00, # p_paddr: Segment physical address

+  0x00, 0x00, 0x20, 0x00, # p_filesz: Segment size in file

+  0x00, 0x00, 0x20, 0x00, # p_memsz: Segment size in memory

+  0x07, 0x00, 0x00, 0x00, # p_flags = Segment is executable | writable | readable

+  0x00, 0x00, 0x00, 0x00, # p_align

+  # - ELFNOTE segment

+  0x04, 0x00, 0x00, 0x00, # p_type = PT_NOTE

+  0x74, 0x00, 0x00, 0x00, # p_offset = point to XEN_ELFNOTE_PHYS32_ENTRY below

+  0x74, 0x00, 0x10, 0x00,

+  0x74, 0x00, 0x10, 0x00,

+  0x14, 0x00, 0x00, 0x00,

+  0x14, 0x00, 0x00, 0x00,

+  0x04, 0x00, 0x00, 0x00, # p_flags = Segment is readable

+  0x00, 0x00, 0x00, 0x00,

+

+  # XEN_ELFNOTE_PHYS32_ENTRY

+  0x04, 0x00, 0x00, 0x00, # name size

+  0x04, 0x00, 0x00, 0x00, # desc size

+  0x12, 0x00, 0x00, 0x00, # type = XEN_ELFNOTE_PHYS32_ENTRY

+  0x58, 0x65, 0x6e, 0x00, # name = "Xen"

+  0xd0, 0xff, 0x2f, 0x00, # desc: PVH entry point

+  0x00

+}

+

+!if ($(FD_SIZE_IN_KB) == 1024) || ($(FD_SIZE_IN_KB) == 2048)

+0x0000e000|0x00001000

+!endif

+!if $(FD_SIZE_IN_KB) == 4096

+0x00040000|0x00001000

+!endif

+#NV_EVENT_LOG

+

+!if ($(FD_SIZE_IN_KB) == 1024) || ($(FD_SIZE_IN_KB) == 2048)

+0x0000f000|0x00001000

+!endif

+!if $(FD_SIZE_IN_KB) == 4096

+0x00041000|0x00001000

+!endif

+#NV_FTW_WORKING

+DATA = {

+  # EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER->Signature = gEdkiiWorkingBlockSignatureGuid         =

+  #  { 0x9e58292b, 0x7c68, 0x497d, { 0xa0, 0xce, 0x65,  0x0, 0xfd, 0x9f, 0x1b, 0x95 }}

+  0x2b, 0x29, 0x58, 0x9e, 0x68, 0x7c, 0x7d, 0x49,

+  0xa0, 0xce, 0x65,  0x0, 0xfd, 0x9f, 0x1b, 0x95,

+  # Crc:UINT32            #WorkingBlockValid:1, WorkingBlockInvalid:1, Reserved

+  0x2c, 0xaf, 0x2c, 0x64, 0xFE, 0xFF, 0xFF, 0xFF,

+  # WriteQueueSize: UINT64

+  0xE0, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00

+}

+

+!if ($(FD_SIZE_IN_KB) == 1024) || ($(FD_SIZE_IN_KB) == 2048)

+0x00010000|0x00010000

+!endif

+!if $(FD_SIZE_IN_KB) == 4096

+0x00042000|0x00042000

+!endif

+#NV_FTW_SPARE

+

 

 $(VARS_SIZE)|$(FVMAIN_SIZE)

 FV = FVMAIN_COMPACT

diff --git a/OvmfPkg/OvmfXenElfHeaderGenerator.c b/OvmfPkg/OvmfXenElfHeaderGenerator.c
new file mode 100644
index 0000000000..6cbad8fbf7
--- /dev/null
+++ b/OvmfPkg/OvmfXenElfHeaderGenerator.c
@@ -0,0 +1,140 @@
+/*

+ * @file

+ * This program generates a hex array to be manually coppied into

+ * OvmfXen.fdf.

+ * The purpose is for the flash device image to be recognize as an ELF.

+ *

+ * Copyright (c) 2019, Citrix Systems, Inc.

+ *

+ * SPDX-License-Identifier: BSD-2-Clause-Patent

+ */

+

+#include "elf.h"

+#include "stdio.h"

+#include "stddef.h"

+

+void print_hdr(void *s, size_t size)

+{

+  char *c = s;

+

+  while (size--) {

+    printf("0x%02hhx, ", *(c++));

+  }

+}

+

+/* Format for the XEN_ELFNOTE_PHYS32_ENTRY program segment */

+#define XEN_ELFNOTE_PHYS32_ENTRY 18

+typedef struct {

+  uint32_t name_size;

+  uint32_t desc_size;

+  uint32_t type;

+  char name[4];

+  uint32_t desc;

+} xen_elfnote_phys32_entry;

+

+int main(void)

+{

+  /* FW_SIZE */

+  size_t ovmf_blob_size = 0x00200000;

+  /* Load OVMF at 1MB when running as PVH guest */

+  uint32_t ovmf_base_address = 0x00100000;

+  /* Xen PVH entry point */

+  uint32_t ovmfxen_pvh_entry_point = ovmf_base_address + ovmf_blob_size - 0x30;

+  size_t offset_into_file = 0;

+

+  /* ELF file header */

+  Elf32_Ehdr hdr = {

+    .e_ident = ELFMAG,

+    .e_type = ET_EXEC,

+    .e_machine = EM_386,

+    .e_version = EV_CURRENT,

+    .e_entry = ovmfxen_pvh_entry_point,

+    .e_flags = R_386_NONE,

+    .e_ehsize = sizeof (hdr),

+    .e_phentsize = sizeof (Elf32_Phdr),

+  };

+  offset_into_file += sizeof (hdr);

+

+  hdr.e_ident[EI_CLASS] = ELFCLASS32;

+  hdr.e_ident[EI_DATA] = ELFDATA2LSB;

+  hdr.e_ident[EI_VERSION] = EV_CURRENT;

+  hdr.e_ident[EI_OSABI] = ELFOSABI_LINUX;

+  /* Placing program headers just after hdr */

+  hdr.e_phoff = sizeof (hdr);

+

+  /* program header */

+  Elf32_Phdr phdr_load = {

+    .p_type = PT_LOAD,

+    .p_offset = 0, /* load everything */

+    .p_paddr = ovmf_base_address,

+    .p_filesz = ovmf_blob_size,

+    .p_memsz = ovmf_blob_size,

+    .p_flags = PF_X | PF_W | PF_R,

+    .p_align = 0,

+  };

+  phdr_load.p_vaddr = phdr_load.p_paddr;

+  hdr.e_phnum += 1;

+  offset_into_file += sizeof (phdr_load);

+

+  /* Xen ELF Note. */

+

+  xen_elfnote_phys32_entry xen_elf_note = {

+    .type = XEN_ELFNOTE_PHYS32_ENTRY,

+    .name = "Xen",

+    .desc = ovmfxen_pvh_entry_point,

+    .name_size =

+      offsetof (xen_elfnote_phys32_entry, desc) -

+      offsetof (xen_elfnote_phys32_entry, name),

+    .desc_size =

+      sizeof (xen_elfnote_phys32_entry) -

+      offsetof (xen_elfnote_phys32_entry, desc),

+  };

+  Elf32_Phdr phdr_note = {

+    .p_type = PT_NOTE,

+    .p_filesz = sizeof (xen_elf_note),

+    .p_memsz = sizeof (xen_elf_note),

+    .p_flags = PF_R,

+    .p_align = 0,

+  };

+  hdr.e_phnum += 1;

+  offset_into_file += sizeof (phdr_note);

+  phdr_note.p_offset = offset_into_file;

+  phdr_note.p_paddr = ovmf_base_address + phdr_note.p_offset;

+  phdr_note.p_vaddr = phdr_note.p_paddr;

+

+

+  /*

+   * print elf header

+   */

+

+  size_t i;

+  size_t hdr_size = sizeof (hdr);

+  size_t entry_off = offsetof(typeof(hdr), e_entry);

+

+  printf("# ELF file header\n");

+  print_hdr(&hdr, entry_off);

+  printf("\n");

+  print_hdr(&hdr.e_entry, sizeof (hdr.e_entry));

+  printf(" # hdr.e_entry\n");

+  print_hdr(&hdr.e_entry + 1, hdr_size - entry_off - sizeof (hdr.e_entry));

+

+  printf("\n\n# ELF Program segment headers\n");

+  printf("# - Load segment\n");

+  for (i = 0; i < sizeof (phdr_load); i += 4) {

+    print_hdr(((char*)&phdr_load) + i, 4);

+    printf("\n");

+  }

+  printf("# - ELFNOTE segment\n");

+  for (i = 0; i < sizeof (phdr_note); i += 4) {

+    print_hdr(((char*)&phdr_note) + i, 4);

+    printf("\n");

+  }

+

+  printf("\n# XEN_ELFNOTE_PHYS32_ENTRY\n");

+  for (i = 0; i < sizeof (xen_elf_note); i += 4) {

+    print_hdr(((char*)&xen_elf_note) + i, 4);

+    printf("\n");

+  }

+

+  return 0;

+}

-- 
Anthony PERARD


-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.

View/Reply Online (#43281): https://edk2.groups.io/g/devel/message/43281
Mute This Topic: https://groups.io/mt/32308566/1813853
Group Owner: devel+owner at edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub  [edk2-devel-archive at redhat.com]
-=-=-=-=-=-=-=-=-=-=-=-





More information about the edk2-devel-archive mailing list