[PATCH v3] x86/efi: Use generic PE/COFF structures

Milan Djokic posted 1 patch 1 month, 4 weeks ago
Patches applied successfully (tree, apply log)
git fetch https://gitlab.com/xen-project/patchew/xen tags/patchew/5dfa21dd5f8e968bf38fda5690964e0f1d957ccc.1727113391.git.milandjokic1995@gmail.com
xen/arch/x86/Makefile      |   2 +
xen/arch/x86/efi/mkreloc.c | 134 +++++++++++--------------------------
xen/common/efi/pe.c        |  92 ++++++-------------------
3 files changed, 61 insertions(+), 167 deletions(-)
[PATCH v3] x86/efi: Use generic PE/COFF structures
Posted by Milan Djokic 1 month, 4 weeks ago
From: Nikola Jelic <nikola.jelic@rt-rk.com>

Adapted x86 efi parser and mkreloc utility to use generic PE header
(efi/pe.h), instead of locally defined structures for each component.

Signed-off-by: Nikola Jelic <nikola.jelic@rt-rk.com>
Signed-off-by: Milan Djokic <milan.djokic@rt-rk.com>
---
Changes in V3:
  - Add xen/include among include dirs for mkreloc, instead of using
    relative path in code to include pe.h
Changes in V2:
  - Using pe header constants instead of hardcoded values (magic,
    machine)
---
 xen/arch/x86/Makefile      |   2 +
 xen/arch/x86/efi/mkreloc.c | 134 +++++++++++--------------------------
 xen/common/efi/pe.c        |  92 ++++++-------------------
 3 files changed, 61 insertions(+), 167 deletions(-)

diff --git a/xen/arch/x86/Makefile b/xen/arch/x86/Makefile
index 286c003ec3..b1c8afbf03 100644
--- a/xen/arch/x86/Makefile
+++ b/xen/arch/x86/Makefile
@@ -88,6 +88,8 @@ extra-y += xen.lds
 hostprogs-y += boot/mkelf32
 hostprogs-y += efi/mkreloc
 
+$(obj)/efi/mkreloc:HOSTCFLAGS += -I$(srctree)/include
+
 # Allows usercopy.c to include itself
 $(obj)/usercopy.o: CFLAGS-y += -iquote .
 
diff --git a/xen/arch/x86/efi/mkreloc.c b/xen/arch/x86/efi/mkreloc.c
index 083740ab8a..7c9aac49ed 100644
--- a/xen/arch/x86/efi/mkreloc.c
+++ b/xen/arch/x86/efi/mkreloc.c
@@ -9,45 +9,7 @@
 #include <sys/mman.h>
 #include <unistd.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 pe_hdr {
-    uint32_t signature;
-#define PE_SIGNATURE 0x00004550
-    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;
-    struct {
-        uint16_t magic;
-#define PE_MAGIC_EXE32     0x010b
-#define PE_MAGIC_EXE32PLUS 0x020b
-        uint8_t linker_major, linker_minor;
-        uint32_t code_size, data_size, bss_size;
-        uint32_t entry_rva, code_rva, data_rva;
-    } opt_hdr;
-};
+#include <efi/pe.h>
 
 #define PE_PAGE_SIZE 0x1000
 
@@ -55,22 +17,6 @@ struct pe_hdr {
 #define PE_BASE_RELOC_HIGHLOW  3
 #define PE_BASE_RELOC_DIR64   10
 
-struct coff_section {
-    char name[8];
-    uint32_t size;
-    uint32_t rva;
-    uint32_t file_size;
-    uint32_t file_offset;
-    uint32_t relocation_file_offset;
-    uint32_t line_number_file_offset;
-    uint16_t relocation_count;
-    uint16_t line_number_count;
-    uint32_t flags;
-#define COFF_SECTION_BSS         0x00000080U
-#define COFF_SECTION_DISCARDABLE 0x02000000U
-#define COFF_SECTION_WRITEABLE   0x80000000U
-};
-
 static void usage(const char *cmd, int rc)
 {
     fprintf(rc ? stderr : stdout,
@@ -80,7 +26,7 @@ static void usage(const char *cmd, int rc)
 }
 
 static unsigned int load(const char *name, int *handle,
-                         struct coff_section **sections,
+                         struct section_header **sections,
                          uint_fast64_t *image_base,
                          uint32_t *image_size,
                          unsigned int *width)
@@ -88,6 +34,7 @@ static unsigned int load(const char *name, int *handle,
     int in = open(name, O_RDONLY);
     struct mz_hdr mz_hdr;
     struct pe_hdr pe_hdr;
+    struct pe32_opt_hdr pe32_opt_hdr;
     uint32_t base;
 
     if ( in < 0 ||
@@ -96,16 +43,17 @@ static unsigned int load(const char *name, int *handle,
         perror(name);
         exit(2);
     }
-    if ( mz_hdr.signature != MZ_SIGNATURE ||
-         mz_hdr.relocations < sizeof(mz_hdr) ||
-         !mz_hdr.extended_header_base )
+    if ( mz_hdr.magic != MZ_MAGIC ||
+         mz_hdr.reloc_table_offset < sizeof(mz_hdr) ||
+         !mz_hdr.peaddr )
     {
         fprintf(stderr, "%s: Wrong DOS file format\n", name);
         exit(2);
     }
 
-    if ( lseek(in, mz_hdr.extended_header_base, SEEK_SET) < 0 ||
+    if ( lseek(in, mz_hdr.peaddr, SEEK_SET) < 0 ||
          read(in, &pe_hdr, sizeof(pe_hdr)) != sizeof(pe_hdr) ||
+         read(in, &pe32_opt_hdr, sizeof(pe32_opt_hdr)) != sizeof(pe32_opt_hdr) ||
          read(in, &base, sizeof(base)) != sizeof(base) ||
          /*
           * Luckily the image size field lives at the
@@ -117,35 +65,33 @@ static unsigned int load(const char *name, int *handle,
         perror(name);
         exit(3);
     }
-    switch ( (pe_hdr.signature == PE_SIGNATURE &&
-              pe_hdr.opt_hdr_size > sizeof(pe_hdr.opt_hdr)) *
-             pe_hdr.opt_hdr.magic )
+    switch ( (pe_hdr.magic == PE_MAGIC &&
+              pe_hdr.opt_hdr_size > sizeof(pe32_opt_hdr)) *
+              pe32_opt_hdr.magic )
     {
-    case PE_MAGIC_EXE32:
+    case PE_OPT_MAGIC_PE32:
         *width = 32;
         *image_base = base;
         break;
-    case PE_MAGIC_EXE32PLUS:
+    case PE_OPT_MAGIC_PE32PLUS:
         *width = 64;
-        *image_base = ((uint64_t)base << 32) | pe_hdr.opt_hdr.data_rva;
+        *image_base = ((uint64_t)base << 32) | pe32_opt_hdr.data_base;
         break;
     default:
         fprintf(stderr, "%s: Wrong PE file format\n", name);
         exit(3);
     }
 
-    *sections = malloc(pe_hdr.section_count * sizeof(**sections));
+    *sections = malloc(pe_hdr.sections * sizeof(**sections));
     if ( !*sections )
     {
         perror(NULL);
         exit(4);
     }
-    if ( lseek(in,
-               mz_hdr.extended_header_base + offsetof(struct pe_hdr, opt_hdr) +
-                  pe_hdr.opt_hdr_size,
+    if ( lseek(in, mz_hdr.peaddr + sizeof(pe_hdr) + pe_hdr.opt_hdr_size,
                SEEK_SET) < 0 ||
-         read(in, *sections, pe_hdr.section_count * sizeof(**sections)) !=
-             pe_hdr.section_count * sizeof(**sections) )
+         read(in, *sections, pe_hdr.sections * sizeof(**sections)) !=
+             pe_hdr.sections * sizeof(**sections) )
     {
         perror(name);
         exit(4);
@@ -153,12 +99,12 @@ static unsigned int load(const char *name, int *handle,
 
     *handle = in;
 
-    return pe_hdr.section_count;
+    return pe_hdr.sections;
 }
 
 static long page_size;
 
-static const void *map_section(const struct coff_section *sec, int in,
+static const void *map_section(const struct section_header *sec, int in,
                                const char *name)
 {
     const char *ptr;
@@ -166,10 +112,10 @@ static const void *map_section(const struct coff_section *sec, int in,
 
     if ( !page_size )
         page_size = sysconf(_SC_PAGESIZE);
-    offs = sec->file_offset & (page_size - 1);
+    offs = sec->data_addr & (page_size - 1);
 
-    ptr = mmap(0, offs + sec->file_size, PROT_READ, MAP_PRIVATE, in,
-               sec->file_offset - offs);
+    ptr = mmap(0, offs + sec->raw_data_size, PROT_READ, MAP_PRIVATE, in,
+               sec->data_addr - offs);
     if ( ptr == MAP_FAILED )
     {
         perror(name);
@@ -179,15 +125,15 @@ static const void *map_section(const struct coff_section *sec, int in,
     return ptr + offs;
 }
 
-static void unmap_section(const void *ptr, const struct coff_section *sec)
+static void unmap_section(const void *ptr, const struct section_header *sec)
 {
-    unsigned long offs = sec->file_offset & (page_size - 1);
+    unsigned long offs = sec->data_addr & (page_size - 1);
 
-    munmap((char *)ptr - offs, offs + sec->file_size);
+    munmap((char *)ptr - offs, offs + sec->raw_data_size);
 }
 
 static void diff_sections(const unsigned char *ptr1, const unsigned char *ptr2,
-                          const struct coff_section *sec,
+                          const struct section_header *sec,
                           int_fast64_t diff, unsigned int width,
                           uint_fast64_t base, uint_fast64_t end)
 {
@@ -208,7 +154,7 @@ static void diff_sections(const unsigned char *ptr1, const unsigned char *ptr2,
     while ( !(diff & (((int_fast64_t)1 << ((disp + 1) * CHAR_BIT)) - 1)) )
         ++disp;
 
-    for ( i = 0; i < sec->file_size; ++i )
+    for ( i = 0; i < sec->raw_data_size; ++i )
     {
         uint_fast32_t rva;
         union {
@@ -222,7 +168,7 @@ static void diff_sections(const unsigned char *ptr1, const unsigned char *ptr2,
         if ( ptr1[i] == ptr2[i] )
             continue;
 
-        if ( i < disp || i + width - disp > sec->file_size )
+        if ( i < disp || i + width - disp > sec->raw_data_size )
         {
             fprintf(stderr,
                     "Bogus difference at %.8s:%08" PRIxFAST32 "\n",
@@ -250,11 +196,11 @@ static void diff_sections(const unsigned char *ptr1, const unsigned char *ptr2,
             reloc_size += reloc_size & 2;
             if ( reloc_size )
                 printf("\t.equ rva_%08" PRIxFAST32 "_relocs,"
-                             " %#08" PRIxFAST32 "\n",
+                       " %#08" PRIxFAST32 "\n",
                        cur_rva, reloc_size);
             printf("\t.balign 4\n"
                    "\t.long %#08" PRIxFAST32 ","
-                          " rva_%08" PRIxFAST32 "_relocs\n",
+                   " rva_%08" PRIxFAST32 "_relocs\n",
                    rva, rva);
             cur_rva = rva;
             reloc_size = 8;
@@ -267,7 +213,7 @@ static void diff_sections(const unsigned char *ptr1, const unsigned char *ptr2,
             exit(3);
         }
 
-        if ( !(sec->flags & COFF_SECTION_WRITEABLE) )
+        if ( !(sec->flags & IMAGE_SCN_MEM_WRITE) )
             fprintf(stderr,
                     "Warning: relocation to r/o section %.8s:%08" PRIxFAST32 "\n",
                     sec->name, i - disp);
@@ -285,7 +231,7 @@ int main(int argc, char *argv[])
     unsigned int i, nsec, width1, width2;
     uint_fast64_t base1, base2;
     uint32_t size1, size2;
-    struct coff_section *sec1, *sec2;
+    struct section_header *sec1, *sec2;
 
     if ( argc == 1 ||
          !strcmp(argv[1], "-?") ||
@@ -328,16 +274,16 @@ int main(int argc, char *argv[])
 
         if ( memcmp(sec1[i].name, sec2[i].name, sizeof(sec1[i].name)) ||
              sec1[i].rva != sec2[i].rva ||
-             sec1[i].size != sec2[i].size ||
-             sec1[i].file_size != sec2[i].file_size ||
+             sec1[i].virtual_size != sec2[i].virtual_size ||
+             sec1[i].raw_data_size != sec2[i].raw_data_size ||
              sec1[i].flags != sec2[i].flags )
         {
             fprintf(stderr, "Mismatched section %u parameters\n", i);
             return 5;
         }
 
-        if ( !sec1[i].size ||
-             (sec1[i].flags & (COFF_SECTION_DISCARDABLE|COFF_SECTION_BSS)) )
+        if ( !sec1[i].virtual_size ||
+             (sec1[i].flags & (IMAGE_SCN_MEM_DISCARDABLE | IMAGE_SCN_CNT_UNINITIALIZED_DATA)) )
             continue;
 
         /*
@@ -354,10 +300,10 @@ int main(int argc, char *argv[])
             return 3;
         }
 
-        if ( sec1[i].file_size > sec1[i].size )
+        if ( sec1[i].raw_data_size > sec1[i].virtual_size )
         {
-            sec1[i].file_size = sec1[i].size;
-            sec2[i].file_size = sec2[i].size;
+            sec1[i].raw_data_size = sec1[i].virtual_size;
+            sec2[i].raw_data_size = sec2[i].virtual_size;
         }
         ptr1 = map_section(sec1 + i, in1, argv[1]);
         ptr2 = map_section(sec2 + i, in2, argv[2]);
diff --git a/xen/common/efi/pe.c b/xen/common/efi/pe.c
index ef8a2543e0..edaa37006d 100644
--- a/xen/common/efi/pe.c
+++ b/xen/common/efi/pe.c
@@ -20,32 +20,10 @@
  * Lesser General Public License for more details.
  */
 
-
 #include "efi.h"
+#include "efi/pe.h"
 
-struct DosFileHeader {
-    UINT8   Magic[2];
-    UINT16  LastSize;
-    UINT16  nBlocks;
-    UINT16  nReloc;
-    UINT16  HdrSize;
-    UINT16  MinAlloc;
-    UINT16  MaxAlloc;
-    UINT16  ss;
-    UINT16  sp;
-    UINT16  Checksum;
-    UINT16  ip;
-    UINT16  cs;
-    UINT16  RelocPos;
-    UINT16  nOverlay;
-    UINT16  reserved[4];
-    UINT16  OEMId;
-    UINT16  OEMInfo;
-    UINT16  reserved2[10];
-    UINT32  ExeHeader;
-};
-
-#if defined(__arm__) || defined (__aarch64__)
+#if defined(__arm__) || defined(__aarch64__)
 #define PE_HEADER_MACHINE 0xaa64
 #elif defined(__x86_64__)
 #define PE_HEADER_MACHINE 0x8664
@@ -53,45 +31,17 @@ struct DosFileHeader {
 #error "Unknown architecture"
 #endif
 
-struct PeFileHeader {
-    UINT16  Machine;
-    UINT16  NumberOfSections;
-    UINT32  TimeDateStamp;
-    UINT32  PointerToSymbolTable;
-    UINT32  NumberOfSymbols;
-    UINT16  SizeOfOptionalHeader;
-    UINT16  Characteristics;
-};
-
-struct PeHeader {
-    UINT8   Magic[4];
-    struct PeFileHeader FileHeader;
-};
-
-struct PeSectionHeader {
-    CHAR8   Name[8];
-    UINT32  VirtualSize;
-    UINT32  VirtualAddress;
-    UINT32  SizeOfRawData;
-    UINT32  PointerToRawData;
-    UINT32  PointerToRelocations;
-    UINT32  PointerToLinenumbers;
-    UINT16  NumberOfRelocations;
-    UINT16  NumberOfLinenumbers;
-    UINT32  Characteristics;
-};
-
-static bool __init pe_name_compare(const struct PeSectionHeader *sect,
+static bool __init pe_name_compare(const struct section_header *sect,
                                    const CHAR16 *name)
 {
     size_t i;
 
-    if ( sect->Name[0] != '.' )
+    if ( sect->name[0] != '.' )
         return false;
 
-    for ( i = 1; i < sizeof(sect->Name); i++ )
+    for ( i = 1; i < sizeof(sect->name); i++ )
     {
-        const char c = sect->Name[i];
+        const char c = sect->name[i];
 
         if ( c != name[i - 1] )
             return false;
@@ -105,33 +55,29 @@ static bool __init pe_name_compare(const struct PeSectionHeader *sect,
 const void *__init pe_find_section(const void *image, const UINTN image_size,
                                    const CHAR16 *section_name, UINTN *size_out)
 {
-    const struct DosFileHeader *dos = image;
-    const struct PeHeader *pe;
-    const struct PeSectionHeader *sect;
+    const struct mz_hdr *mz = image;
+    const struct pe_hdr *pe;
+    const struct section_header *sect;
     UINTN offset, i;
 
-    if ( image_size < sizeof(*dos) ||
-         dos->Magic[0] != 'M' ||
-         dos->Magic[1] != 'Z' )
+    if ( image_size < sizeof(*mz) ||
+         mz->magic != MZ_MAGIC )
         return NULL;
 
-    offset = dos->ExeHeader;
+    offset = mz->peaddr;
     pe = image + offset;
 
     offset += sizeof(*pe);
     if ( image_size < offset ||
-         pe->Magic[0] != 'P' ||
-         pe->Magic[1] != 'E' ||
-         pe->Magic[2] != '\0' ||
-         pe->Magic[3] != '\0' )
+         pe->magic != PE_MAGIC )
         return NULL;
 
-    if ( pe->FileHeader.Machine != PE_HEADER_MACHINE )
+    if ( pe->machine != PE_HEADER_MACHINE )
         return NULL;
 
-    offset += pe->FileHeader.SizeOfOptionalHeader;
+    offset += pe->opt_hdr_size;
 
-    for ( i = 0; i < pe->FileHeader.NumberOfSections; i++ )
+    for ( i = 0; i < pe->sections; i++ )
     {
         sect = image + offset;
         if ( image_size < offset + sizeof(*sect) )
@@ -143,13 +89,13 @@ const void *__init pe_find_section(const void *image, const UINTN image_size,
             continue;
         }
 
-        if ( image_size < sect->VirtualSize + sect->VirtualAddress )
+        if ( image_size < sect->virtual_size + sect->rva )
             blexit(L"PE invalid section size + address");
 
         if ( size_out )
-            *size_out = sect->VirtualSize;
+            *size_out = sect->virtual_size;
 
-        return image + sect->VirtualAddress;
+        return image + sect->rva;
     }
 
     return NULL;
-- 
2.25.1
Re: [PATCH v3] x86/efi: Use generic PE/COFF structures
Posted by Daniel P. Smith 1 month, 4 weeks ago
On 9/23/24 13:50, Milan Djokic wrote:
> From: Nikola Jelic <nikola.jelic@rt-rk.com>
> 
> Adapted x86 efi parser and mkreloc utility to use generic PE header
> (efi/pe.h), instead of locally defined structures for each component.
> 
> Signed-off-by: Nikola Jelic <nikola.jelic@rt-rk.com>
> Signed-off-by: Milan Djokic <milan.djokic@rt-rk.com>
> ---

Looks good to me.

Acked-by: Daniel P. Smith <dpsmith@apertussolutions.com>
Re: [PATCH v3] x86/efi: Use generic PE/COFF structures
Posted by Andrew Cooper 1 month, 4 weeks ago
On 24/09/2024 11:07 am, Daniel P. Smith wrote:
> On 9/23/24 13:50, Milan Djokic wrote:
>> From: Nikola Jelic <nikola.jelic@rt-rk.com>
>>
>> Adapted x86 efi parser and mkreloc utility to use generic PE header
>> (efi/pe.h), instead of locally defined structures for each component.
>>
>> Signed-off-by: Nikola Jelic <nikola.jelic@rt-rk.com>
>> Signed-off-by: Milan Djokic <milan.djokic@rt-rk.com>
>> ---
>
> Looks good to me.
>
> Acked-by: Daniel P. Smith <dpsmith@apertussolutions.com>

Committed, with the aformentioned minor space corrections.

~Andrew
Re: [PATCH v3] x86/efi: Use generic PE/COFF structures
Posted by Jan Beulich 1 month, 4 weeks ago
On 23.09.2024 19:50, Milan Djokic wrote:
> --- a/xen/arch/x86/Makefile
> +++ b/xen/arch/x86/Makefile
> @@ -88,6 +88,8 @@ extra-y += xen.lds
>  hostprogs-y += boot/mkelf32
>  hostprogs-y += efi/mkreloc
>  
> +$(obj)/efi/mkreloc:HOSTCFLAGS += -I$(srctree)/include

Nit: Blank please after colon, just like it is e.g. ...

>  # Allows usercopy.c to include itself
>  $(obj)/usercopy.o: CFLAGS-y += -iquote .

... here. Could surely be taken care of while committing.

Jan
Re: [PATCH v3] x86/efi: Use generic PE/COFF structures
Posted by Andrew Cooper 1 month, 4 weeks ago
On 24/09/2024 9:22 am, Jan Beulich wrote:
> On 23.09.2024 19:50, Milan Djokic wrote:
>> --- a/xen/arch/x86/Makefile
>> +++ b/xen/arch/x86/Makefile
>> @@ -88,6 +88,8 @@ extra-y += xen.lds
>>  hostprogs-y += boot/mkelf32
>>  hostprogs-y += efi/mkreloc
>>  
>> +$(obj)/efi/mkreloc:HOSTCFLAGS += -I$(srctree)/include
> Nit: Blank please after colon, just like it is e.g. ...
>
>>  # Allows usercopy.c to include itself
>>  $(obj)/usercopy.o: CFLAGS-y += -iquote .
> ... here. Could surely be taken care of while committing.

There were two others I'd spotted, which I was intending on tweaking on
commit.

~Andrew
Re: [PATCH v3] x86/efi: Use generic PE/COFF structures
Posted by Andrew Cooper 1 month, 4 weeks ago
On 23/09/2024 6:50 pm, Milan Djokic wrote:
> From: Nikola Jelic <nikola.jelic@rt-rk.com>
>
> Adapted x86 efi parser and mkreloc utility to use generic PE header
> (efi/pe.h), instead of locally defined structures for each component.
>
> Signed-off-by: Nikola Jelic <nikola.jelic@rt-rk.com>
> Signed-off-by: Milan Djokic <milan.djokic@rt-rk.com>

Acked-by: Andrew Cooper <andrew.cooper3@citrix.com>