Running make check-tcg-x86_64 on a big-endian host (e.g., s390x) fails due
to problems reading/parsing the ELF data:

  qemu-system-x86_64: Error loading uncompressed kernel without PVH ELF Note

There already exists logic in include/hw/elf_ops.h.inc to handle byte-swaps
where necessary, but it does not perform this logic for ELF notes itself.

Fixing that improves matters, but yields other errors: most of the tests
timeout while some generate confusing assertions. Both appear to be related
to the data addresses in those notes, which are incorrect when running on a
big-endian host.

Adding tswap wrappers, which will conditionally swap if the host and target
endianness don't match, fixes that such that check-tcg-x86_64 runs cleanly
on an s390 host.

Acked-by: Pierrick Bouvier <[email protected]>
Signed-off-by: Eric Farman <[email protected]>
---
 hw/i386/x86-common.c     |  6 ++++--
 include/hw/elf_ops.h.inc | 20 ++++++++++++++++++--
 2 files changed, 22 insertions(+), 4 deletions(-)

diff --git a/hw/i386/x86-common.c b/hw/i386/x86-common.c
index fa18bf1aece..dcd4fa8eb79 100644
--- a/hw/i386/x86-common.c
+++ b/hw/i386/x86-common.c
@@ -45,6 +45,8 @@
 #include "kvm/kvm_i386.h"
 #include "kvm/tdx.h"
 
+#include "exec/tswap.h"
+
 #ifdef CONFIG_XEN_EMU
 #include "hw/xen/xen.h"
 #include "hw/i386/kvm/xen_evtchn.h"
@@ -573,7 +575,7 @@ static uint64_t read_pvh_start_addr(void *arg1, void *arg2, 
bool is64)
             ((void *)nhdr64) + nhdr_size64 +
             QEMU_ALIGN_UP(nhdr_namesz, phdr_align);
 
-        pvh_start_addr = *elf_note_data_addr;
+        pvh_start_addr = tswap64(*elf_note_data_addr);
     } else {
         struct elf32_note *nhdr32 = (struct elf32_note *)arg1;
         uint32_t nhdr_size32 = sizeof(struct elf32_note);
@@ -584,7 +586,7 @@ static uint64_t read_pvh_start_addr(void *arg1, void *arg2, 
bool is64)
             ((void *)nhdr32) + nhdr_size32 +
             QEMU_ALIGN_UP(nhdr_namesz, phdr_align);
 
-        pvh_start_addr = *(uint32_t *)elf_note_data_addr;
+        pvh_start_addr = tswap32(*(uint32_t *)elf_note_data_addr);
     }
 
     return pvh_start_addr;
diff --git a/include/hw/elf_ops.h.inc b/include/hw/elf_ops.h.inc
index 044e72de2a2..b4fc0b146f0 100644
--- a/include/hw/elf_ops.h.inc
+++ b/include/hw/elf_ops.h.inc
@@ -56,6 +56,13 @@ static void glue(bswap_rela, SZ)(struct elf_rela *rela)
     bswapSZs((elf_word *)&rela->r_addend);
 }
 
+static void glue(bswap_note, SZ)(struct elf_note *note)
+{
+    bswap32s(&note->n_namesz);
+    bswap32s(&note->n_descsz);
+    bswap32s(&note->n_type);
+}
+
 static struct elf_shdr *glue(find_section, SZ)(struct elf_shdr *shdr_table,
                                                int n, int type)
 {
@@ -275,7 +282,8 @@ fail:
 static struct elf_note *glue(get_elf_note_type, SZ)(struct elf_note *nhdr,
                                                     elf_word note_size,
                                                     elf_word phdr_align,
-                                                    elf_word elf_note_type)
+                                                    elf_word elf_note_type,
+                                                    int must_swab)
 {
     elf_word nhdr_size = sizeof(struct elf_note);
     elf_word elf_note_entry_offset = 0;
@@ -287,6 +295,10 @@ static struct elf_note *glue(get_elf_note_type, SZ)(struct 
elf_note *nhdr,
         return NULL;
     }
 
+    if (must_swab) {
+        glue(bswap_note, SZ)(nhdr);
+    }
+
     note_type = nhdr->n_type;
     while (note_type != elf_note_type) {
         nhdr_namesz = nhdr->n_namesz;
@@ -306,6 +318,9 @@ static struct elf_note *glue(get_elf_note_type, SZ)(struct 
elf_note *nhdr,
 
         /* skip to the next ELF Note entry */
         nhdr = (void *)nhdr + elf_note_entry_offset;
+        if (must_swab) {
+            glue(bswap_note, SZ)(nhdr);
+        }
         note_type = nhdr->n_type;
     }
 
@@ -608,7 +623,8 @@ static ssize_t glue(load_elf, SZ)(const char *name, int fd,
             nhdr = (struct elf_note *)data;
             assert(translate_opaque != NULL);
             nhdr = glue(get_elf_note_type, SZ)(nhdr, file_size, ph->p_align,
-                                               *(uint64_t *)translate_opaque);
+                                               *(uint64_t *)translate_opaque,
+                                               must_swab);
             if (nhdr != NULL) {
                 elf_note_fn((void *)nhdr, (void *)&ph->p_align, SZ == 64);
             }
-- 
2.53.0


Reply via email to