Signed-off-by: Olivia Yin <hong-hua....@freescale.com> --- elf.h | 10 ++++++ hw/elf_ops.h | 101 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 111 insertions(+), 0 deletions(-)
diff --git a/elf.h b/elf.h index a21ea53..335f1af 100644 --- a/elf.h +++ b/elf.h @@ -1078,6 +1078,16 @@ typedef struct elf64_hdr { Elf64_Half e_shstrndx; } Elf64_Ehdr; +typedef struct ImageElf ImageElf; +struct ImageElf { + char *name; + uint64_t (*fn)(void *, uint64_t); + void *opaque; + int swab; + int machine; + int lsb; +}; + /* These constants define the permissions on sections in the program header, p_flags. */ #define PF_R 0x4 diff --git a/hw/elf_ops.h b/hw/elf_ops.h index 531a425..89654bb 100644 --- a/hw/elf_ops.h +++ b/hw/elf_ops.h @@ -187,6 +187,95 @@ static int glue(load_symbols, SZ)(struct elfhdr *ehdr, int fd, int must_swab, return -1; } +static void glue(elf_reset, SZ)(void *opaque) +{ + ImageElf *elf = opaque; + struct elfhdr ehdr; + struct elf_phdr *phdr = NULL, *ph; + int size, i, fd; + elf_word mem_size; + uint64_t addr; + uint8_t *data = NULL; + + fd = open(elf->name, O_RDONLY | O_BINARY); + if (read(fd, &ehdr, sizeof(ehdr)) != sizeof(ehdr)) + goto fail; + if (elf->swab) { + glue(bswap_ehdr, SZ)(&ehdr); + } + + switch (elf->machine) { + case EM_PPC64: + if (EM_PPC64 != ehdr.e_machine) + if (EM_PPC != ehdr.e_machine) + goto fail; + break; + case EM_X86_64: + if (EM_X86_64 != ehdr.e_machine) + if (EM_386 != ehdr.e_machine) + goto fail; + break; + case EM_MICROBLAZE: + if (EM_MICROBLAZE != ehdr.e_machine) + if (EM_MICROBLAZE_OLD != ehdr.e_machine) + goto fail; + break; + default: + if (elf->machine != ehdr.e_machine) + goto fail; + } + + glue(load_symbols, SZ)(&ehdr, fd, elf->swab, elf->lsb); + + size = ehdr.e_phnum * sizeof(phdr[0]); + lseek(fd, ehdr.e_phoff, SEEK_SET); + phdr = g_malloc0(size); + if (!phdr) + goto fail; + if (read(fd, phdr, size) != size) + goto fail; + if (elf->swab) { + for(i = 0; i < ehdr.e_phnum; i++) { + ph = &phdr[i]; + glue(bswap_phdr, SZ)(ph); + } + } + + for(i = 0; i < ehdr.e_phnum; i++) { + ph = &phdr[i]; + if (ph->p_type == PT_LOAD) { + mem_size = ph->p_memsz; + /* XXX: avoid allocating */ + data = g_malloc0(mem_size); + if (ph->p_filesz > 0) { + if (lseek(fd, ph->p_offset, SEEK_SET) < 0) + goto fail; + if (read(fd, data, ph->p_filesz) != ph->p_filesz) + goto fail; + } + /* address_offset is hack for kernel images that are + linked at the wrong physical address. */ + if (elf->fn) { + addr = elf->fn(elf->opaque, ph->p_paddr); + } else { + addr = ph->p_paddr; + } + + cpu_physical_memory_write(addr, data, mem_size); + + g_free(data); + data = NULL; + } + } + close(fd); + g_free(phdr); + phdr = NULL; + fail: + close(fd); + g_free(data); + g_free(phdr); +} + static int glue(load_elf, SZ)(const char *name, int fd, uint64_t (*translate_fn)(void *, uint64_t), void *translate_opaque, @@ -293,6 +382,18 @@ static int glue(load_elf, SZ)(const char *name, int fd, data = NULL; } } + + ImageElf *elf; + elf = g_malloc0(sizeof(*elf)); + elf->name = g_strdup(name); + elf->fn = translate_fn; + elf->opaque = translate_opaque; + elf->swab = must_swab; + elf->machine = elf_machine; + elf->lsb = clear_lsb; + + qemu_register_reset(glue(elf_reset, SZ), elf); + g_free(phdr); if (lowaddr) *lowaddr = (uint64_t)(elf_sword)low; -- 1.7.1