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(¬e->n_namesz); + bswap32s(¬e->n_descsz); + bswap32s(¬e->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
