qemu-commits
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-commits] [COMMIT ca20cf3] Compile loader only once


From: Anthony Liguori
Subject: [Qemu-commits] [COMMIT ca20cf3] Compile loader only once
Date: Sun, 20 Sep 2009 15:12:29 -0000

From: Blue Swirl <address@hidden>

Callers must pass ELF machine, byte swapping and symbol LSB clearing
information to ELF loader. A.out loader needs page size information, pass
that too as a parameter.

Extract prototypes to a separate file. Move loader.[ch] and elf_ops.h under hw.

Adjust callers. Also use target_phys_addr_t instead of target_ulong for
addresses: loader addresses aren't virtual.

Signed-off-by: Blue Swirl <address@hidden>

diff --git a/Makefile.hw b/Makefile.hw
index 11227bf..cb9c9a4 100644
--- a/Makefile.hw
+++ b/Makefile.hw
@@ -11,6 +11,7 @@ VPATH=$(SRC_PATH):$(SRC_PATH)/hw
 QEMU_CFLAGS+=-I.. -I$(SRC_PATH)/fpu
 
 obj-y =
+obj-y += loader.o
 obj-y += virtio.o
 obj-y += fw_cfg.o
 obj-y += watchdog.o
diff --git a/Makefile.target b/Makefile.target
index d9e98fe..bc3998a 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -155,7 +155,7 @@ endif
 # System emulator target
 ifdef CONFIG_SOFTMMU
 
-obj-y = vl.o monitor.o pci.o loader.o isa_mmio.o machine.o \
+obj-y = vl.o monitor.o pci.o isa_mmio.o machine.o \
         gdbstub.o gdbstub-xml.o msix.o ioport.o
 # virtio has to be here due to weird dependency between PCI and virtio-net.
 # need to fix this properly
diff --git a/disas.h b/disas.h
index 0789b57..06abab2 100644
--- a/disas.h
+++ b/disas.h
@@ -3,6 +3,7 @@
 
 #include "qemu-common.h"
 
+#ifdef NEED_CPU_H
 /* Disassemble this for me please... (debugging). */
 void disas(FILE *out, void *code, unsigned long size);
 void target_disas(FILE *out, target_ulong code, target_ulong size, int flags);
@@ -15,12 +16,13 @@ void monitor_disas(Monitor *mon, CPUState *env,
 
 /* Look up symbol for debugging purpose.  Returns "" if unknown. */
 const char *lookup_symbol(target_ulong orig_addr);
+#endif
 
 struct syminfo;
 struct elf32_sym;
 struct elf64_sym;
 
-typedef const char *(*lookup_symbol_t)(struct syminfo *s, target_ulong 
orig_addr);
+typedef const char *(*lookup_symbol_t)(struct syminfo *s, target_phys_addr_t 
orig_addr);
 
 struct syminfo {
     lookup_symbol_t lookup_symbol;
diff --git a/elf_ops.h b/elf_ops.h
deleted file mode 100644
index 15928cb..0000000
--- a/elf_ops.h
+++ /dev/null
@@ -1,271 +0,0 @@
-static void glue(bswap_ehdr, SZ)(struct elfhdr *ehdr)
-{
-    bswap16s(&ehdr->e_type);                   /* Object file type */
-    bswap16s(&ehdr->e_machine);                /* Architecture */
-    bswap32s(&ehdr->e_version);                /* Object file version */
-    bswapSZs(&ehdr->e_entry);          /* Entry point virtual address */
-    bswapSZs(&ehdr->e_phoff);          /* Program header table file offset */
-    bswapSZs(&ehdr->e_shoff);          /* Section header table file offset */
-    bswap32s(&ehdr->e_flags);          /* Processor-specific flags */
-    bswap16s(&ehdr->e_ehsize);         /* ELF header size in bytes */
-    bswap16s(&ehdr->e_phentsize);              /* Program header table entry 
size */
-    bswap16s(&ehdr->e_phnum);          /* Program header table entry count */
-    bswap16s(&ehdr->e_shentsize);              /* Section header table entry 
size */
-    bswap16s(&ehdr->e_shnum);          /* Section header table entry count */
-    bswap16s(&ehdr->e_shstrndx);               /* Section header string table 
index */
-}
-
-static void glue(bswap_phdr, SZ)(struct elf_phdr *phdr)
-{
-    bswap32s(&phdr->p_type);                   /* Segment type */
-    bswapSZs(&phdr->p_offset);         /* Segment file offset */
-    bswapSZs(&phdr->p_vaddr);          /* Segment virtual address */
-    bswapSZs(&phdr->p_paddr);          /* Segment physical address */
-    bswapSZs(&phdr->p_filesz);         /* Segment size in file */
-    bswapSZs(&phdr->p_memsz);          /* Segment size in memory */
-    bswap32s(&phdr->p_flags);          /* Segment flags */
-    bswapSZs(&phdr->p_align);          /* Segment alignment */
-}
-
-static void glue(bswap_shdr, SZ)(struct elf_shdr *shdr)
-{
-    bswap32s(&shdr->sh_name);
-    bswap32s(&shdr->sh_type);
-    bswapSZs(&shdr->sh_flags);
-    bswapSZs(&shdr->sh_addr);
-    bswapSZs(&shdr->sh_offset);
-    bswapSZs(&shdr->sh_size);
-    bswap32s(&shdr->sh_link);
-    bswap32s(&shdr->sh_info);
-    bswapSZs(&shdr->sh_addralign);
-    bswapSZs(&shdr->sh_entsize);
-}
-
-static void glue(bswap_sym, SZ)(struct elf_sym *sym)
-{
-    bswap32s(&sym->st_name);
-    bswapSZs(&sym->st_value);
-    bswapSZs(&sym->st_size);
-    bswap16s(&sym->st_shndx);
-}
-
-static struct elf_shdr *glue(find_section, SZ)(struct elf_shdr *shdr_table,
-                                               int n, int type)
-{
-    int i;
-    for(i=0;i<n;i++) {
-        if (shdr_table[i].sh_type == type)
-            return shdr_table + i;
-    }
-    return NULL;
-}
-
-static int glue(symfind, SZ)(const void *s0, const void *s1)
-{
-    struct elf_sym *key = (struct elf_sym *)s0;
-    struct elf_sym *sym = (struct elf_sym *)s1;
-    int result = 0;
-    if (key->st_value < sym->st_value) {
-        result = -1;
-    } else if (key->st_value >= sym->st_value + sym->st_size) {
-        result = 1;
-    }
-    return result;
-}
-
-static const char *glue(lookup_symbol, SZ)(struct syminfo *s, target_ulong 
orig_addr)
-{
-    struct elf_sym *syms = glue(s->disas_symtab.elf, SZ);
-    struct elf_sym key;
-    struct elf_sym *sym;
-
-    key.st_value = orig_addr;
-
-    sym = bsearch(&key, syms, s->disas_num_syms, sizeof(*syms), glue(symfind, 
SZ));
-    if (sym != NULL) {
-        return s->disas_strtab + sym->st_name;
-    }
-
-    return "";
-}
-
-static int glue(symcmp, SZ)(const void *s0, const void *s1)
-{
-    struct elf_sym *sym0 = (struct elf_sym *)s0;
-    struct elf_sym *sym1 = (struct elf_sym *)s1;
-    return (sym0->st_value < sym1->st_value)
-        ? -1
-        : ((sym0->st_value > sym1->st_value) ? 1 : 0);
-}
-
-static int glue(load_symbols, SZ)(struct elfhdr *ehdr, int fd, int must_swab)
-{
-    struct elf_shdr *symtab, *strtab, *shdr_table = NULL;
-    struct elf_sym *syms = NULL;
-    struct syminfo *s;
-    int nsyms, i;
-    char *str = NULL;
-
-    shdr_table = load_at(fd, ehdr->e_shoff,
-                         sizeof(struct elf_shdr) * ehdr->e_shnum);
-    if (!shdr_table)
-        return -1;
-
-    if (must_swab) {
-        for (i = 0; i < ehdr->e_shnum; i++) {
-            glue(bswap_shdr, SZ)(shdr_table + i);
-        }
-    }
-
-    symtab = glue(find_section, SZ)(shdr_table, ehdr->e_shnum, SHT_SYMTAB);
-    if (!symtab)
-        goto fail;
-    syms = load_at(fd, symtab->sh_offset, symtab->sh_size);
-    if (!syms)
-        goto fail;
-
-    nsyms = symtab->sh_size / sizeof(struct elf_sym);
-
-    i = 0;
-    while (i < nsyms) {
-        if (must_swab)
-            glue(bswap_sym, SZ)(&syms[i]);
-        /* We are only interested in function symbols.
-           Throw everything else away.  */
-        if (syms[i].st_shndx == SHN_UNDEF ||
-                syms[i].st_shndx >= SHN_LORESERVE ||
-                ELF_ST_TYPE(syms[i].st_info) != STT_FUNC) {
-            nsyms--;
-            if (i < nsyms) {
-                syms[i] = syms[nsyms];
-            }
-            continue;
-        }
-#if defined(TARGET_ARM) || defined (TARGET_MIPS)
-        /* The bottom address bit marks a Thumb or MIPS16 symbol.  */
-        syms[i].st_value &= ~(target_ulong)1;
-#endif
-        i++;
-    }
-    syms = qemu_realloc(syms, nsyms * sizeof(*syms));
-
-    qsort(syms, nsyms, sizeof(*syms), glue(symcmp, SZ));
-
-    /* String table */
-    if (symtab->sh_link >= ehdr->e_shnum)
-        goto fail;
-    strtab = &shdr_table[symtab->sh_link];
-
-    str = load_at(fd, strtab->sh_offset, strtab->sh_size);
-    if (!str)
-        goto fail;
-
-    /* Commit */
-    s = qemu_mallocz(sizeof(*s));
-    s->lookup_symbol = glue(lookup_symbol, SZ);
-    glue(s->disas_symtab.elf, SZ) = syms;
-    s->disas_num_syms = nsyms;
-    s->disas_strtab = str;
-    s->next = syminfos;
-    syminfos = s;
-    qemu_free(shdr_table);
-    return 0;
- fail:
-    qemu_free(syms);
-    qemu_free(str);
-    qemu_free(shdr_table);
-    return -1;
-}
-
-static int glue(load_elf, SZ)(int fd, int64_t address_offset,
-                              int must_swab, uint64_t *pentry,
-                              uint64_t *lowaddr, uint64_t *highaddr)
-{
-    struct elfhdr ehdr;
-    struct elf_phdr *phdr = NULL, *ph;
-    int size, i, total_size;
-    elf_word mem_size;
-    uint64_t addr, low = (uint64_t)-1, high = 0;
-    uint8_t *data = NULL;
-
-    if (read(fd, &ehdr, sizeof(ehdr)) != sizeof(ehdr))
-        goto fail;
-    if (must_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;
-        default:
-            if (ELF_MACHINE != ehdr.e_machine)
-                goto fail;
-    }
-
-    if (pentry)
-       *pentry = (uint64_t)(elf_sword)ehdr.e_entry;
-
-    glue(load_symbols, SZ)(&ehdr, fd, must_swab);
-
-    size = ehdr.e_phnum * sizeof(phdr[0]);
-    lseek(fd, ehdr.e_phoff, SEEK_SET);
-    phdr = qemu_mallocz(size);
-    if (!phdr)
-        goto fail;
-    if (read(fd, phdr, size) != size)
-        goto fail;
-    if (must_swab) {
-        for(i = 0; i < ehdr.e_phnum; i++) {
-            ph = &phdr[i];
-            glue(bswap_phdr, SZ)(ph);
-        }
-    }
-
-    total_size = 0;
-    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 = qemu_mallocz(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.  */
-            addr = ph->p_paddr + address_offset;
-
-            cpu_physical_memory_write_rom(addr, data, mem_size);
-
-            total_size += mem_size;
-            if (addr < low)
-                low = addr;
-            if ((addr + mem_size) > high)
-                high = addr + mem_size;
-
-            qemu_free(data);
-            data = NULL;
-        }
-    }
-    qemu_free(phdr);
-    if (lowaddr)
-        *lowaddr = (uint64_t)(elf_sword)low;
-    if (highaddr)
-        *highaddr = (uint64_t)(elf_sword)high;
-    return total_size;
- fail:
-    qemu_free(data);
-    qemu_free(phdr);
-    return -1;
-}
diff --git a/hw/an5206.c b/hw/an5206.c
index d417d92..a4b83b0 100644
--- a/hw/an5206.c
+++ b/hw/an5206.c
@@ -11,6 +11,8 @@
 #include "mcf.h"
 #include "sysemu.h"
 #include "boards.h"
+#include "loader.h"
+#include "elf.h"
 
 #define KERNEL_LOAD_ADDR 0x10000
 #define AN5206_MBAR_ADDR 0x10000000
@@ -35,7 +37,7 @@ static void an5206_init(ram_addr_t ram_size,
     CPUState *env;
     int kernel_size;
     uint64_t elf_entry;
-    target_ulong entry;
+    target_phys_addr_t entry;
 
     if (!cpu_model)
         cpu_model = "m5206";
@@ -66,7 +68,8 @@ static void an5206_init(ram_addr_t ram_size,
         exit(1);
     }
 
-    kernel_size = load_elf(kernel_filename, 0, &elf_entry, NULL, NULL);
+    kernel_size = load_elf(kernel_filename, 0, &elf_entry, NULL, NULL,
+                           1, ELF_MACHINE, 0);
     entry = elf_entry;
     if (kernel_size < 0) {
         kernel_size = load_uimage(kernel_filename, &entry, NULL, NULL);
diff --git a/hw/arm_boot.c b/hw/arm_boot.c
index 35f0130..a8a38c5 100644
--- a/hw/arm_boot.c
+++ b/hw/arm_boot.c
@@ -10,6 +10,8 @@
 #include "hw.h"
 #include "arm-misc.h"
 #include "sysemu.h"
+#include "loader.h"
+#include "elf.h"
 
 #define KERNEL_ARGS_ADDR 0x100
 #define KERNEL_LOAD_ADDR 0x00010000
@@ -191,7 +193,8 @@ void arm_load_kernel(CPUState *env, struct arm_boot_info 
*info)
     int n;
     int is_linux = 0;
     uint64_t elf_entry;
-    target_ulong entry;
+    target_phys_addr_t entry;
+    int big_endian;
 
     /* Load the kernel.  */
     if (!info->kernel_filename) {
@@ -206,8 +209,15 @@ void arm_load_kernel(CPUState *env, struct arm_boot_info 
*info)
         qemu_register_reset(main_cpu_reset, env);
     }
 
+#ifdef TARGET_WORDS_BIGENDIAN
+    big_endian = 1;
+#else
+    big_endian = 0;
+#endif
+
     /* Assume that raw images are linux kernels, and ELF images are not.  */
-    kernel_size = load_elf(info->kernel_filename, 0, &elf_entry, NULL, NULL);
+    kernel_size = load_elf(info->kernel_filename, 0, &elf_entry, NULL, NULL,
+                           big_endian, ELF_MACHINE, 1);
     entry = elf_entry;
     if (kernel_size < 0) {
         kernel_size = load_uimage(info->kernel_filename, &entry, NULL,
diff --git a/hw/armv7m.c b/hw/armv7m.c
index 059a356..a96288d 100644
--- a/hw/armv7m.c
+++ b/hw/armv7m.c
@@ -10,6 +10,8 @@
 #include "sysbus.h"
 #include "arm-misc.h"
 #include "sysemu.h"
+#include "loader.h"
+#include "elf.h"
 
 /* Bitbanded IO.  Each word corresponds to a single bit.  */
 
@@ -166,6 +168,7 @@ qemu_irq *armv7m_init(int flash_size, int sram_size,
     uint64_t entry;
     uint64_t lowaddr;
     int i;
+    int big_endian;
 
     flash_size *= 1024;
     sram_size *= 1024;
@@ -206,7 +209,14 @@ qemu_irq *armv7m_init(int flash_size, int sram_size,
         pic[i] = qdev_get_gpio_in(nvic, i);
     }
 
-    image_size = load_elf(kernel_filename, 0, &entry, &lowaddr, NULL);
+#ifdef TARGET_WORDS_BIGENDIAN
+    big_endian = 1;
+#else
+    big_endian = 0;
+#endif
+
+    image_size = load_elf(kernel_filename, 0, &entry, &lowaddr, NULL,
+                          big_endian, ELF_MACHINE, 1);
     if (image_size < 0) {
         image_size = load_image_targphys(kernel_filename, 0, flash_size);
        lowaddr = 0;
diff --git a/hw/axis_dev88.c b/hw/axis_dev88.c
index b5163b6..81a41c9 100644
--- a/hw/axis_dev88.c
+++ b/hw/axis_dev88.c
@@ -28,6 +28,8 @@
 #include "boards.h"
 #include "sysemu.h"
 #include "etraxfs.h"
+#include "loader.h"
+#include "elf.h"
 
 #define D(x)
 #define DNAND(x)
@@ -344,7 +346,7 @@ void axisdev88_init (ram_addr_t ram_size,
         /* Boots a kernel elf binary, os/linux-2.6/vmlinux from the axis 
            devboard SDK.  */
         kernel_size = load_elf(kernel_filename, -0x80000000LL,
-                               &entry, NULL, &high);
+                               &entry, NULL, &high, 0, ELF_MACHINE, 0);
         bootstrap_pc = entry;
         if (kernel_size < 0) {
             /* Takes a kimage from the axis devboard SDK.  */
diff --git a/hw/dummy_m68k.c b/hw/dummy_m68k.c
index 5718ab6..ce45a59 100644
--- a/hw/dummy_m68k.c
+++ b/hw/dummy_m68k.c
@@ -9,6 +9,8 @@
 #include "hw.h"
 #include "sysemu.h"
 #include "boards.h"
+#include "loader.h"
+#include "elf.h"
 
 #define KERNEL_LOAD_ADDR 0x10000
 
@@ -22,7 +24,7 @@ static void dummy_m68k_init(ram_addr_t ram_size,
     CPUState *env;
     int kernel_size;
     uint64_t elf_entry;
-    target_ulong entry;
+    target_phys_addr_t entry;
 
     if (!cpu_model)
         cpu_model = "cfv4e";
@@ -41,7 +43,8 @@ static void dummy_m68k_init(ram_addr_t ram_size,
 
     /* Load kernel.  */
     if (kernel_filename) {
-        kernel_size = load_elf(kernel_filename, 0, &elf_entry, NULL, NULL);
+        kernel_size = load_elf(kernel_filename, 0, &elf_entry, NULL, NULL,
+                               1, ELF_MACHINE, 0);
         entry = elf_entry;
         if (kernel_size < 0) {
             kernel_size = load_uimage(kernel_filename, &entry, NULL, NULL);
diff --git a/hw/elf_ops.h b/hw/elf_ops.h
new file mode 100644
index 0000000..8376465
--- /dev/null
+++ b/hw/elf_ops.h
@@ -0,0 +1,274 @@
+static void glue(bswap_ehdr, SZ)(struct elfhdr *ehdr)
+{
+    bswap16s(&ehdr->e_type);                   /* Object file type */
+    bswap16s(&ehdr->e_machine);                /* Architecture */
+    bswap32s(&ehdr->e_version);                /* Object file version */
+    bswapSZs(&ehdr->e_entry);          /* Entry point virtual address */
+    bswapSZs(&ehdr->e_phoff);          /* Program header table file offset */
+    bswapSZs(&ehdr->e_shoff);          /* Section header table file offset */
+    bswap32s(&ehdr->e_flags);          /* Processor-specific flags */
+    bswap16s(&ehdr->e_ehsize);         /* ELF header size in bytes */
+    bswap16s(&ehdr->e_phentsize);              /* Program header table entry 
size */
+    bswap16s(&ehdr->e_phnum);          /* Program header table entry count */
+    bswap16s(&ehdr->e_shentsize);              /* Section header table entry 
size */
+    bswap16s(&ehdr->e_shnum);          /* Section header table entry count */
+    bswap16s(&ehdr->e_shstrndx);               /* Section header string table 
index */
+}
+
+static void glue(bswap_phdr, SZ)(struct elf_phdr *phdr)
+{
+    bswap32s(&phdr->p_type);                   /* Segment type */
+    bswapSZs(&phdr->p_offset);         /* Segment file offset */
+    bswapSZs(&phdr->p_vaddr);          /* Segment virtual address */
+    bswapSZs(&phdr->p_paddr);          /* Segment physical address */
+    bswapSZs(&phdr->p_filesz);         /* Segment size in file */
+    bswapSZs(&phdr->p_memsz);          /* Segment size in memory */
+    bswap32s(&phdr->p_flags);          /* Segment flags */
+    bswapSZs(&phdr->p_align);          /* Segment alignment */
+}
+
+static void glue(bswap_shdr, SZ)(struct elf_shdr *shdr)
+{
+    bswap32s(&shdr->sh_name);
+    bswap32s(&shdr->sh_type);
+    bswapSZs(&shdr->sh_flags);
+    bswapSZs(&shdr->sh_addr);
+    bswapSZs(&shdr->sh_offset);
+    bswapSZs(&shdr->sh_size);
+    bswap32s(&shdr->sh_link);
+    bswap32s(&shdr->sh_info);
+    bswapSZs(&shdr->sh_addralign);
+    bswapSZs(&shdr->sh_entsize);
+}
+
+static void glue(bswap_sym, SZ)(struct elf_sym *sym)
+{
+    bswap32s(&sym->st_name);
+    bswapSZs(&sym->st_value);
+    bswapSZs(&sym->st_size);
+    bswap16s(&sym->st_shndx);
+}
+
+static struct elf_shdr *glue(find_section, SZ)(struct elf_shdr *shdr_table,
+                                               int n, int type)
+{
+    int i;
+    for(i=0;i<n;i++) {
+        if (shdr_table[i].sh_type == type)
+            return shdr_table + i;
+    }
+    return NULL;
+}
+
+static int glue(symfind, SZ)(const void *s0, const void *s1)
+{
+    struct elf_sym *key = (struct elf_sym *)s0;
+    struct elf_sym *sym = (struct elf_sym *)s1;
+    int result = 0;
+    if (key->st_value < sym->st_value) {
+        result = -1;
+    } else if (key->st_value >= sym->st_value + sym->st_size) {
+        result = 1;
+    }
+    return result;
+}
+
+static const char *glue(lookup_symbol, SZ)(struct syminfo *s,
+                                           target_phys_addr_t orig_addr)
+{
+    struct elf_sym *syms = glue(s->disas_symtab.elf, SZ);
+    struct elf_sym key;
+    struct elf_sym *sym;
+
+    key.st_value = orig_addr;
+
+    sym = bsearch(&key, syms, s->disas_num_syms, sizeof(*syms), glue(symfind, 
SZ));
+    if (sym != NULL) {
+        return s->disas_strtab + sym->st_name;
+    }
+
+    return "";
+}
+
+static int glue(symcmp, SZ)(const void *s0, const void *s1)
+{
+    struct elf_sym *sym0 = (struct elf_sym *)s0;
+    struct elf_sym *sym1 = (struct elf_sym *)s1;
+    return (sym0->st_value < sym1->st_value)
+        ? -1
+        : ((sym0->st_value > sym1->st_value) ? 1 : 0);
+}
+
+static int glue(load_symbols, SZ)(struct elfhdr *ehdr, int fd, int must_swab,
+                                  int clear_lsb)
+{
+    struct elf_shdr *symtab, *strtab, *shdr_table = NULL;
+    struct elf_sym *syms = NULL;
+    struct syminfo *s;
+    int nsyms, i;
+    char *str = NULL;
+
+    shdr_table = load_at(fd, ehdr->e_shoff,
+                         sizeof(struct elf_shdr) * ehdr->e_shnum);
+    if (!shdr_table)
+        return -1;
+
+    if (must_swab) {
+        for (i = 0; i < ehdr->e_shnum; i++) {
+            glue(bswap_shdr, SZ)(shdr_table + i);
+        }
+    }
+
+    symtab = glue(find_section, SZ)(shdr_table, ehdr->e_shnum, SHT_SYMTAB);
+    if (!symtab)
+        goto fail;
+    syms = load_at(fd, symtab->sh_offset, symtab->sh_size);
+    if (!syms)
+        goto fail;
+
+    nsyms = symtab->sh_size / sizeof(struct elf_sym);
+
+    i = 0;
+    while (i < nsyms) {
+        if (must_swab)
+            glue(bswap_sym, SZ)(&syms[i]);
+        /* We are only interested in function symbols.
+           Throw everything else away.  */
+        if (syms[i].st_shndx == SHN_UNDEF ||
+                syms[i].st_shndx >= SHN_LORESERVE ||
+                ELF_ST_TYPE(syms[i].st_info) != STT_FUNC) {
+            nsyms--;
+            if (i < nsyms) {
+                syms[i] = syms[nsyms];
+            }
+            continue;
+        }
+        if (clear_lsb) {
+            /* The bottom address bit marks a Thumb or MIPS16 symbol.  */
+            syms[i].st_value &= ~(glue(glue(Elf, SZ), _Addr))1;
+        }
+        i++;
+    }
+    syms = qemu_realloc(syms, nsyms * sizeof(*syms));
+
+    qsort(syms, nsyms, sizeof(*syms), glue(symcmp, SZ));
+
+    /* String table */
+    if (symtab->sh_link >= ehdr->e_shnum)
+        goto fail;
+    strtab = &shdr_table[symtab->sh_link];
+
+    str = load_at(fd, strtab->sh_offset, strtab->sh_size);
+    if (!str)
+        goto fail;
+
+    /* Commit */
+    s = qemu_mallocz(sizeof(*s));
+    s->lookup_symbol = glue(lookup_symbol, SZ);
+    glue(s->disas_symtab.elf, SZ) = syms;
+    s->disas_num_syms = nsyms;
+    s->disas_strtab = str;
+    s->next = syminfos;
+    syminfos = s;
+    qemu_free(shdr_table);
+    return 0;
+ fail:
+    qemu_free(syms);
+    qemu_free(str);
+    qemu_free(shdr_table);
+    return -1;
+}
+
+static int glue(load_elf, SZ)(int fd, int64_t address_offset,
+                              int must_swab, uint64_t *pentry,
+                              uint64_t *lowaddr, uint64_t *highaddr,
+                              int elf_machine, int clear_lsb)
+{
+    struct elfhdr ehdr;
+    struct elf_phdr *phdr = NULL, *ph;
+    int size, i, total_size;
+    elf_word mem_size;
+    uint64_t addr, low = (uint64_t)-1, high = 0;
+    uint8_t *data = NULL;
+
+    if (read(fd, &ehdr, sizeof(ehdr)) != sizeof(ehdr))
+        goto fail;
+    if (must_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;
+        default:
+            if (elf_machine != ehdr.e_machine)
+                goto fail;
+    }
+
+    if (pentry)
+       *pentry = (uint64_t)(elf_sword)ehdr.e_entry;
+
+    glue(load_symbols, SZ)(&ehdr, fd, must_swab, clear_lsb);
+
+    size = ehdr.e_phnum * sizeof(phdr[0]);
+    lseek(fd, ehdr.e_phoff, SEEK_SET);
+    phdr = qemu_mallocz(size);
+    if (!phdr)
+        goto fail;
+    if (read(fd, phdr, size) != size)
+        goto fail;
+    if (must_swab) {
+        for(i = 0; i < ehdr.e_phnum; i++) {
+            ph = &phdr[i];
+            glue(bswap_phdr, SZ)(ph);
+        }
+    }
+
+    total_size = 0;
+    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 = qemu_mallocz(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.  */
+            addr = ph->p_paddr + address_offset;
+
+            cpu_physical_memory_write_rom(addr, data, mem_size);
+
+            total_size += mem_size;
+            if (addr < low)
+                low = addr;
+            if ((addr + mem_size) > high)
+                high = addr + mem_size;
+
+            qemu_free(data);
+            data = NULL;
+        }
+    }
+    qemu_free(phdr);
+    if (lowaddr)
+        *lowaddr = (uint64_t)(elf_sword)low;
+    if (highaddr)
+        *highaddr = (uint64_t)(elf_sword)high;
+    return total_size;
+ fail:
+    qemu_free(data);
+    qemu_free(phdr);
+    return -1;
+}
diff --git a/hw/etraxfs.c b/hw/etraxfs.c
index ab6a3a3..4f451c5 100644
--- a/hw/etraxfs.c
+++ b/hw/etraxfs.c
@@ -28,6 +28,8 @@
 #include "net.h"
 #include "flash.h"
 #include "etraxfs.h"
+#include "loader.h"
+#include "elf.h"
 
 #define FLASH_SIZE 0x2000000
 #define INTMEM_SIZE (128 * 1024)
@@ -136,7 +138,7 @@ void bareetraxfs_init (ram_addr_t ram_size,
         /* Boots a kernel elf binary, os/linux-2.6/vmlinux from the axis 
            devboard SDK.  */
         kernel_size = load_elf(kernel_filename, -0x80000000LL,
-                               &entry, NULL, &high);
+                               &entry, NULL, &high, 0, ELF_MACHINE, 0);
         bootstrap_pc = entry;
         if (kernel_size < 0) {
             /* Takes a kimage from the axis devboard SDK.  */
diff --git a/hw/loader.c b/hw/loader.c
new file mode 100644
index 0000000..5d83a66
--- /dev/null
+++ b/hw/loader.c
@@ -0,0 +1,546 @@
+/*
+ * QEMU Executable loader
+ *
+ * Copyright (c) 2006 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to 
deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * Gunzip functionality in this file is derived from u-boot:
+ *
+ * (C) Copyright 2008 Semihalf
+ *
+ * (C) Copyright 2000-2005
+ * Wolfgang Denk, DENX Software Engineering, address@hidden
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "hw.h"
+#include "disas.h"
+#include "sysemu.h"
+#include "uboot_image.h"
+#include "loader.h"
+
+#include <zlib.h>
+
+/* return the size or -1 if error */
+int get_image_size(const char *filename)
+{
+    int fd, size;
+    fd = open(filename, O_RDONLY | O_BINARY);
+    if (fd < 0)
+        return -1;
+    size = lseek(fd, 0, SEEK_END);
+    close(fd);
+    return size;
+}
+
+/* return the size or -1 if error */
+/* deprecated, because caller does not specify buffer size! */
+int load_image(const char *filename, uint8_t *addr)
+{
+    int fd, size;
+    fd = open(filename, O_RDONLY | O_BINARY);
+    if (fd < 0)
+        return -1;
+    size = lseek(fd, 0, SEEK_END);
+    lseek(fd, 0, SEEK_SET);
+    if (read(fd, addr, size) != size) {
+        close(fd);
+        return -1;
+    }
+    close(fd);
+    return size;
+}
+
+/* return the amount read, just like fread.  0 may mean error or eof */
+int fread_targphys(target_phys_addr_t dst_addr, size_t nbytes, FILE *f)
+{
+    uint8_t buf[4096];
+    target_phys_addr_t dst_begin = dst_addr;
+    size_t want, did;
+
+    while (nbytes) {
+       want = nbytes > sizeof(buf) ? sizeof(buf) : nbytes;
+       did = fread(buf, 1, want, f);
+
+       cpu_physical_memory_write_rom(dst_addr, buf, did);
+       dst_addr += did;
+       nbytes -= did;
+       if (did != want)
+           break;
+    }
+    return dst_addr - dst_begin;
+}
+
+/* returns 0 on error, 1 if ok */
+int fread_targphys_ok(target_phys_addr_t dst_addr, size_t nbytes, FILE *f)
+{
+    return fread_targphys(dst_addr, nbytes, f) == nbytes;
+}
+
+/* read()-like version */
+int read_targphys(int fd, target_phys_addr_t dst_addr, size_t nbytes)
+{
+    uint8_t buf[4096];
+    target_phys_addr_t dst_begin = dst_addr;
+    size_t want, did;
+
+    while (nbytes) {
+       want = nbytes > sizeof(buf) ? sizeof(buf) : nbytes;
+       did = read(fd, buf, want);
+       if (did != want) break;
+
+       cpu_physical_memory_write_rom(dst_addr, buf, did);
+       dst_addr += did;
+       nbytes -= did;
+    }
+    return dst_addr - dst_begin;
+}
+
+/* return the size or -1 if error */
+int load_image_targphys(const char *filename,
+                       target_phys_addr_t addr, int max_sz)
+{
+    FILE *f;
+    size_t got;
+
+    f = fopen(filename, "rb");
+    if (!f) return -1;
+
+    got = fread_targphys(addr, max_sz, f);
+    if (ferror(f)) { fclose(f); return -1; }
+    fclose(f);
+
+    return got;
+}
+
+void pstrcpy_targphys(target_phys_addr_t dest, int buf_size,
+                      const char *source)
+{
+    static const uint8_t nul_byte = 0;
+    const char *nulp;
+
+    if (buf_size <= 0) return;
+    nulp = memchr(source, 0, buf_size);
+    if (nulp) {
+       cpu_physical_memory_write_rom(dest, (uint8_t *)source,
+                                      (nulp - source) + 1);
+    } else {
+       cpu_physical_memory_write_rom(dest, (uint8_t *)source, buf_size - 1);
+       cpu_physical_memory_write_rom(dest, &nul_byte, 1);
+    }
+}
+
+/* A.OUT loader */
+
+struct exec
+{
+  uint32_t a_info;   /* Use macros N_MAGIC, etc for access */
+  uint32_t a_text;   /* length of text, in bytes */
+  uint32_t a_data;   /* length of data, in bytes */
+  uint32_t a_bss;    /* length of uninitialized data area, in bytes */
+  uint32_t a_syms;   /* length of symbol table data in file, in bytes */
+  uint32_t a_entry;  /* start address */
+  uint32_t a_trsize; /* length of relocation info for text, in bytes */
+  uint32_t a_drsize; /* length of relocation info for data, in bytes */
+};
+
+static void bswap_ahdr(struct exec *e)
+{
+    bswap32s(&e->a_info);
+    bswap32s(&e->a_text);
+    bswap32s(&e->a_data);
+    bswap32s(&e->a_bss);
+    bswap32s(&e->a_syms);
+    bswap32s(&e->a_entry);
+    bswap32s(&e->a_trsize);
+    bswap32s(&e->a_drsize);
+}
+
+#define N_MAGIC(exec) ((exec).a_info & 0xffff)
+#define OMAGIC 0407
+#define NMAGIC 0410
+#define ZMAGIC 0413
+#define QMAGIC 0314
+#define _N_HDROFF(x) (1024 - sizeof (struct exec))
+#define N_TXTOFF(x)                                                    \
+    (N_MAGIC(x) == ZMAGIC ? _N_HDROFF((x)) + sizeof (struct exec) :    \
+     (N_MAGIC(x) == QMAGIC ? 0 : sizeof (struct exec)))
+#define N_TXTADDR(x, target_page_size) (N_MAGIC(x) == QMAGIC ? 
target_page_size : 0)
+#define _N_SEGMENT_ROUND(x, target_page_size) (((x) + target_page_size - 1) & 
~(target_page_size - 1))
+
+#define _N_TXTENDADDR(x, target_page_size) (N_TXTADDR(x, 
target_page_size)+(x).a_text)
+
+#define N_DATADDR(x, target_page_size) \
+    (N_MAGIC(x)==OMAGIC? (_N_TXTENDADDR(x, target_page_size)) \
+     : (_N_SEGMENT_ROUND (_N_TXTENDADDR(x, target_page_size), 
target_page_size)))
+
+
+int load_aout(const char *filename, target_phys_addr_t addr, int max_sz,
+              int bswap_needed, target_phys_addr_t target_page_size)
+{
+    int fd, size, ret;
+    struct exec e;
+    uint32_t magic;
+
+    fd = open(filename, O_RDONLY | O_BINARY);
+    if (fd < 0)
+        return -1;
+
+    size = read(fd, &e, sizeof(e));
+    if (size < 0)
+        goto fail;
+
+    if (bswap_needed) {
+        bswap_ahdr(&e);
+    }
+
+    magic = N_MAGIC(e);
+    switch (magic) {
+    case ZMAGIC:
+    case QMAGIC:
+    case OMAGIC:
+        if (e.a_text + e.a_data > max_sz)
+            goto fail;
+       lseek(fd, N_TXTOFF(e), SEEK_SET);
+       size = read_targphys(fd, addr, e.a_text + e.a_data);
+       if (size < 0)
+           goto fail;
+       break;
+    case NMAGIC:
+        if (N_DATADDR(e, target_page_size) + e.a_data > max_sz)
+            goto fail;
+       lseek(fd, N_TXTOFF(e), SEEK_SET);
+       size = read_targphys(fd, addr, e.a_text);
+       if (size < 0)
+           goto fail;
+        ret = read_targphys(fd, addr + N_DATADDR(e, target_page_size),
+                            e.a_data);
+       if (ret < 0)
+           goto fail;
+       size += ret;
+       break;
+    default:
+       goto fail;
+    }
+    close(fd);
+    return size;
+ fail:
+    close(fd);
+    return -1;
+}
+
+/* ELF loader */
+
+static void *load_at(int fd, int offset, int size)
+{
+    void *ptr;
+    if (lseek(fd, offset, SEEK_SET) < 0)
+        return NULL;
+    ptr = qemu_malloc(size);
+    if (read(fd, ptr, size) != size) {
+        qemu_free(ptr);
+        return NULL;
+    }
+    return ptr;
+}
+
+#ifdef ELF_CLASS
+#undef ELF_CLASS
+#endif
+
+#define ELF_CLASS   ELFCLASS32
+#include "elf.h"
+
+#define SZ             32
+#define elf_word        uint32_t
+#define elf_sword        int32_t
+#define bswapSZs       bswap32s
+#include "elf_ops.h"
+
+#undef elfhdr
+#undef elf_phdr
+#undef elf_shdr
+#undef elf_sym
+#undef elf_note
+#undef elf_word
+#undef elf_sword
+#undef bswapSZs
+#undef SZ
+#define elfhdr         elf64_hdr
+#define elf_phdr       elf64_phdr
+#define elf_note       elf64_note
+#define elf_shdr       elf64_shdr
+#define elf_sym                elf64_sym
+#define elf_word        uint64_t
+#define elf_sword        int64_t
+#define bswapSZs       bswap64s
+#define SZ             64
+#include "elf_ops.h"
+
+/* return < 0 if error, otherwise the number of bytes loaded in memory */
+int load_elf(const char *filename, int64_t address_offset,
+             uint64_t *pentry, uint64_t *lowaddr, uint64_t *highaddr,
+             int big_endian, int elf_machine, int clear_lsb)
+{
+    int fd, data_order, target_data_order, must_swab, ret;
+    uint8_t e_ident[EI_NIDENT];
+
+    fd = open(filename, O_RDONLY | O_BINARY);
+    if (fd < 0) {
+        perror(filename);
+        return -1;
+    }
+    if (read(fd, e_ident, sizeof(e_ident)) != sizeof(e_ident))
+        goto fail;
+    if (e_ident[0] != ELFMAG0 ||
+        e_ident[1] != ELFMAG1 ||
+        e_ident[2] != ELFMAG2 ||
+        e_ident[3] != ELFMAG3)
+        goto fail;
+#ifdef HOST_WORDS_BIGENDIAN
+    data_order = ELFDATA2MSB;
+#else
+    data_order = ELFDATA2LSB;
+#endif
+    must_swab = data_order != e_ident[EI_DATA];
+    if (big_endian) {
+        target_data_order = ELFDATA2MSB;
+    } else {
+        target_data_order = ELFDATA2LSB;
+    }
+
+    if (target_data_order != e_ident[EI_DATA])
+        return -1;
+
+    lseek(fd, 0, SEEK_SET);
+    if (e_ident[EI_CLASS] == ELFCLASS64) {
+        ret = load_elf64(fd, address_offset, must_swab, pentry,
+                         lowaddr, highaddr, elf_machine, clear_lsb);
+    } else {
+        ret = load_elf32(fd, address_offset, must_swab, pentry,
+                         lowaddr, highaddr, elf_machine, clear_lsb);
+    }
+
+    close(fd);
+    return ret;
+
+ fail:
+    close(fd);
+    return -1;
+}
+
+static void bswap_uboot_header(uboot_image_header_t *hdr)
+{
+#ifndef HOST_WORDS_BIGENDIAN
+    bswap32s(&hdr->ih_magic);
+    bswap32s(&hdr->ih_hcrc);
+    bswap32s(&hdr->ih_time);
+    bswap32s(&hdr->ih_size);
+    bswap32s(&hdr->ih_load);
+    bswap32s(&hdr->ih_ep);
+    bswap32s(&hdr->ih_dcrc);
+#endif
+}
+
+
+#define ZALLOC_ALIGNMENT       16
+
+static void *zalloc(void *x, unsigned items, unsigned size)
+{
+    void *p;
+
+    size *= items;
+    size = (size + ZALLOC_ALIGNMENT - 1) & ~(ZALLOC_ALIGNMENT - 1);
+
+    p = qemu_malloc(size);
+
+    return (p);
+}
+
+static void zfree(void *x, void *addr)
+{
+    qemu_free(addr);
+}
+
+
+#define HEAD_CRC       2
+#define EXTRA_FIELD    4
+#define ORIG_NAME      8
+#define COMMENT                0x10
+#define RESERVED       0xe0
+
+#define DEFLATED       8
+
+/* This is the maximum in uboot, so if a uImage overflows this, it would
+ * overflow on real hardware too. */
+#define UBOOT_MAX_GUNZIP_BYTES 0x800000
+
+static ssize_t gunzip(void *dst, size_t dstlen, uint8_t *src,
+                      size_t srclen)
+{
+    z_stream s;
+    ssize_t dstbytes;
+    int r, i, flags;
+
+    /* skip header */
+    i = 10;
+    flags = src[3];
+    if (src[2] != DEFLATED || (flags & RESERVED) != 0) {
+        puts ("Error: Bad gzipped data\n");
+        return -1;
+    }
+    if ((flags & EXTRA_FIELD) != 0)
+        i = 12 + src[10] + (src[11] << 8);
+    if ((flags & ORIG_NAME) != 0)
+        while (src[i++] != 0)
+            ;
+    if ((flags & COMMENT) != 0)
+        while (src[i++] != 0)
+            ;
+    if ((flags & HEAD_CRC) != 0)
+        i += 2;
+    if (i >= srclen) {
+        puts ("Error: gunzip out of data in header\n");
+        return -1;
+    }
+
+    s.zalloc = zalloc;
+    s.zfree = zfree;
+
+    r = inflateInit2(&s, -MAX_WBITS);
+    if (r != Z_OK) {
+        printf ("Error: inflateInit2() returned %d\n", r);
+        return (-1);
+    }
+    s.next_in = src + i;
+    s.avail_in = srclen - i;
+    s.next_out = dst;
+    s.avail_out = dstlen;
+    r = inflate(&s, Z_FINISH);
+    if (r != Z_OK && r != Z_STREAM_END) {
+        printf ("Error: inflate() returned %d\n", r);
+        return -1;
+    }
+    dstbytes = s.next_out - (unsigned char *) dst;
+    inflateEnd(&s);
+
+    return dstbytes;
+}
+
+/* Load a U-Boot image.  */
+int load_uimage(const char *filename, target_phys_addr_t *ep,
+                target_phys_addr_t *loadaddr, int *is_linux)
+{
+    int fd;
+    int size;
+    uboot_image_header_t h;
+    uboot_image_header_t *hdr = &h;
+    uint8_t *data = NULL;
+    int ret = -1;
+
+    fd = open(filename, O_RDONLY | O_BINARY);
+    if (fd < 0)
+        return -1;
+
+    size = read(fd, hdr, sizeof(uboot_image_header_t));
+    if (size < 0)
+        goto out;
+
+    bswap_uboot_header(hdr);
+
+    if (hdr->ih_magic != IH_MAGIC)
+        goto out;
+
+    /* TODO: Implement other image types.  */
+    if (hdr->ih_type != IH_TYPE_KERNEL) {
+        fprintf(stderr, "Can only load u-boot image type \"kernel\"\n");
+        goto out;
+    }
+
+    switch (hdr->ih_comp) {
+    case IH_COMP_NONE:
+    case IH_COMP_GZIP:
+        break;
+    default:
+        fprintf(stderr,
+                "Unable to load u-boot images with compression type %d\n",
+                hdr->ih_comp);
+        goto out;
+    }
+
+    /* TODO: Check CPU type.  */
+    if (is_linux) {
+        if (hdr->ih_os == IH_OS_LINUX)
+            *is_linux = 1;
+        else
+            *is_linux = 0;
+    }
+
+    *ep = hdr->ih_ep;
+    data = qemu_malloc(hdr->ih_size);
+
+    if (read(fd, data, hdr->ih_size) != hdr->ih_size) {
+        fprintf(stderr, "Error reading file\n");
+        goto out;
+    }
+
+    if (hdr->ih_comp == IH_COMP_GZIP) {
+        uint8_t *compressed_data;
+        size_t max_bytes;
+        ssize_t bytes;
+
+        compressed_data = data;
+        max_bytes = UBOOT_MAX_GUNZIP_BYTES;
+        data = qemu_malloc(max_bytes);
+
+        bytes = gunzip(data, max_bytes, compressed_data, hdr->ih_size);
+        qemu_free(compressed_data);
+        if (bytes < 0) {
+            fprintf(stderr, "Unable to decompress gzipped image!\n");
+            goto out;
+        }
+        hdr->ih_size = bytes;
+    }
+
+    cpu_physical_memory_write_rom(hdr->ih_load, data, hdr->ih_size);
+
+    if (loadaddr)
+        *loadaddr = hdr->ih_load;
+
+    ret = hdr->ih_size;
+
+out:
+    if (data)
+        qemu_free(data);
+    close(fd);
+    return ret;
+}
diff --git a/hw/loader.h b/hw/loader.h
new file mode 100644
index 0000000..3632008
--- /dev/null
+++ b/hw/loader.h
@@ -0,0 +1,21 @@
+#ifndef LOADER_H
+#define LOADER_H
+
+/* loader.c */
+int get_image_size(const char *filename);
+int load_image(const char *filename, uint8_t *addr); /* deprecated */
+int load_image_targphys(const char *filename, target_phys_addr_t, int max_sz);
+int load_elf(const char *filename, int64_t address_offset,
+             uint64_t *pentry, uint64_t *lowaddr, uint64_t *highaddr,
+             int big_endian, int elf_machine, int clear_lsb);
+int load_aout(const char *filename, target_phys_addr_t addr, int max_sz,
+              int bswap_needed, target_phys_addr_t target_page_size);
+int load_uimage(const char *filename, target_phys_addr_t *ep,
+                target_phys_addr_t *loadaddr, int *is_linux);
+
+int fread_targphys(target_phys_addr_t dst_addr, size_t nbytes, FILE *f);
+int fread_targphys_ok(target_phys_addr_t dst_addr, size_t nbytes, FILE *f);
+int read_targphys(int fd, target_phys_addr_t dst_addr, size_t nbytes);
+void pstrcpy_targphys(target_phys_addr_t dest, int buf_size,
+                      const char *source);
+#endif
diff --git a/hw/mcf5208.c b/hw/mcf5208.c
index 95a03fc..5598611 100644
--- a/hw/mcf5208.c
+++ b/hw/mcf5208.c
@@ -11,6 +11,8 @@
 #include "sysemu.h"
 #include "net.h"
 #include "boards.h"
+#include "loader.h"
+#include "elf.h"
 
 #define SYS_FREQ 66000000
 
@@ -201,7 +203,7 @@ static void mcf5208evb_init(ram_addr_t ram_size,
     CPUState *env;
     int kernel_size;
     uint64_t elf_entry;
-    target_ulong entry;
+    target_phys_addr_t entry;
     qemu_irq *pic;
 
     if (!cpu_model)
@@ -268,7 +270,8 @@ static void mcf5208evb_init(ram_addr_t ram_size,
         exit(1);
     }
 
-    kernel_size = load_elf(kernel_filename, 0, &elf_entry, NULL, NULL);
+    kernel_size = load_elf(kernel_filename, 0, &elf_entry, NULL, NULL,
+                           1, ELF_MACHINE, 0);
     entry = elf_entry;
     if (kernel_size < 0) {
         kernel_size = load_uimage(kernel_filename, &entry, NULL, NULL);
diff --git a/hw/mips_jazz.c b/hw/mips_jazz.c
index d62a584..1a499fa 100644
--- a/hw/mips_jazz.c
+++ b/hw/mips_jazz.c
@@ -33,6 +33,7 @@
 #include "net.h"
 #include "scsi.h"
 #include "mips-bios.h"
+#include "loader.h"
 
 enum jazz_model_e
 {
diff --git a/hw/mips_malta.c b/hw/mips_malta.c
index 0a6eaa4..4d72da8 100644
--- a/hw/mips_malta.c
+++ b/hw/mips_malta.c
@@ -39,6 +39,8 @@
 #include "qemu-log.h"
 #include "mips-bios.h"
 #include "ide.h"
+#include "loader.h"
+#include "elf.h"
 
 //#define DEBUG_BOARD_INIT
 
@@ -687,10 +689,17 @@ static int64_t load_kernel (CPUState *env)
     int index = 0;
     long initrd_size;
     ram_addr_t initrd_offset;
+    int big_endian;
+
+#ifdef TARGET_WORDS_BIGENDIAN
+    big_endian = 1;
+#else
+    big_endian = 0;
+#endif
 
     if (load_elf(loaderparams.kernel_filename, VIRT_TO_PHYS_ADDEND,
                  (uint64_t *)&kernel_entry, (uint64_t *)&kernel_low,
-                 (uint64_t *)&kernel_high) < 0) {
+                 (uint64_t *)&kernel_high, big_endian, ELF_MACHINE, 1) < 0) {
         fprintf(stderr, "qemu: could not load kernel '%s'\n",
                 loaderparams.kernel_filename);
         exit(1);
diff --git a/hw/mips_mipssim.c b/hw/mips_mipssim.c
index 6080dc8..9aed40e 100644
--- a/hw/mips_mipssim.c
+++ b/hw/mips_mipssim.c
@@ -32,6 +32,8 @@
 #include "sysemu.h"
 #include "boards.h"
 #include "mips-bios.h"
+#include "loader.h"
+#include "elf.h"
 
 #ifdef TARGET_MIPS64
 #define PHYS_TO_VIRT(x) ((x) | ~0x7fffffffULL)
@@ -54,10 +56,17 @@ static void load_kernel (CPUState *env)
     long kernel_size;
     long initrd_size;
     ram_addr_t initrd_offset;
+    int big_endian;
+
+#ifdef TARGET_WORDS_BIGENDIAN
+    big_endian = 1;
+#else
+    big_endian = 0;
+#endif
 
     kernel_size = load_elf(loaderparams.kernel_filename, VIRT_TO_PHYS_ADDEND,
                            (uint64_t *)&entry, (uint64_t *)&kernel_low,
-                           (uint64_t *)&kernel_high);
+                           (uint64_t *)&kernel_high, big_endian, ELF_MACHINE, 
1);
     if (kernel_size >= 0) {
         if ((entry & ~0x7fffffffULL) == 0x80000000)
             entry = (int32_t)entry;
diff --git a/hw/mips_r4k.c b/hw/mips_r4k.c
index fcc7fed..b3abc61 100644
--- a/hw/mips_r4k.c
+++ b/hw/mips_r4k.c
@@ -18,6 +18,8 @@
 #include "qemu-log.h"
 #include "mips-bios.h"
 #include "ide.h"
+#include "loader.h"
+#include "elf.h"
 
 #define PHYS_TO_VIRT(x) ((x) | ~(target_ulong)0x7fffffff)
 
@@ -77,10 +79,16 @@ static void load_kernel (CPUState *env)
     long kernel_size, initrd_size;
     ram_addr_t initrd_offset;
     int ret;
+    int big_endian;
 
+#ifdef TARGET_WORDS_BIGENDIAN
+    big_endian = 1;
+#else
+    big_endian = 0;
+#endif
     kernel_size = load_elf(loaderparams.kernel_filename, VIRT_TO_PHYS_ADDEND,
                            (uint64_t *)&entry, (uint64_t *)&kernel_low,
-                           (uint64_t *)&kernel_high);
+                           (uint64_t *)&kernel_high, big_endian, ELF_MACHINE, 
1);
     if (kernel_size >= 0) {
         if ((entry & ~0x7fffffffULL) == 0x80000000)
             entry = (int32_t)entry;
diff --git a/hw/nseries.c b/hw/nseries.c
index e9b68a7..066a0f9 100644
--- a/hw/nseries.c
+++ b/hw/nseries.c
@@ -30,6 +30,7 @@
 #include "flash.h"
 #include "hw.h"
 #include "bt.h"
+#include "loader.h"
 
 /* Nokia N8x0 support */
 struct n800_s {
diff --git a/hw/palm.c b/hw/palm.c
index bba9722..6d19167 100644
--- a/hw/palm.c
+++ b/hw/palm.c
@@ -24,6 +24,7 @@
 #include "boards.h"
 #include "arm-misc.h"
 #include "devices.h"
+#include "loader.h"
 
 static uint32_t static_readb(void *opaque, target_phys_addr_t offset)
 {
diff --git a/hw/pc.c b/hw/pc.c
index 58de372..bc2875e 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -37,6 +37,8 @@
 #include "watchdog.h"
 #include "smbios.h"
 #include "ide.h"
+#include "loader.h"
+#include "elf.h"
 
 /* output Bochs bios info messages */
 //#define DEBUG_BIOS
@@ -657,7 +659,8 @@ static int load_multiboot(void *fw_cfg,
         uint64_t elf_entry;
         int kernel_size;
         fclose(f);
-        kernel_size = load_elf(kernel_filename, 0, &elf_entry, NULL, NULL);
+        kernel_size = load_elf(kernel_filename, 0, &elf_entry, NULL, NULL,
+                               0, ELF_MACHINE, 0);
         if (kernel_size < 0) {
             fprintf(stderr, "Error while loading elf kernel\n");
             exit(1);
diff --git a/hw/petalogix_s3adsp1800_mmu.c b/hw/petalogix_s3adsp1800_mmu.c
index a04794d..f343dbf 100644
--- a/hw/petalogix_s3adsp1800_mmu.c
+++ b/hw/petalogix_s3adsp1800_mmu.c
@@ -32,6 +32,8 @@
 #include "boards.h"
 #include "device_tree.h"
 #include "xilinx.h"
+#include "loader.h"
+#include "elf.h"
 
 #define LMB_BRAM_SIZE  (128 * 1024)
 #define FLASH_SIZE     (16 * 1024 * 1024)
@@ -155,11 +157,13 @@ petalogix_s3adsp1800_init(ram_addr_t ram_size,
 
         /* Boots a kernel elf binary.  */
         kernel_size = load_elf(kernel_filename, 0,
-                               &entry, &low, &high);
+                               &entry, &low, &high,
+                               1, ELF_MACHINE, 0);
         base32 = entry;
         if (base32 == 0xc0000000) {
             kernel_size = load_elf(kernel_filename, -0x30000000LL,
-                                   &entry, NULL, NULL);
+                                   &entry, NULL, NULL,
+                                   1, ELF_MACHINE, 0);
         }
         /* Always boot into physical ram.  */
         bootstrap_pc = ddr_base + (entry & 0x0fffffff);
diff --git a/hw/ppc.c b/hw/ppc.c
index 2d66b9d..09ee2e4 100644
--- a/hw/ppc.c
+++ b/hw/ppc.c
@@ -27,6 +27,7 @@
 #include "sysemu.h"
 #include "nvram.h"
 #include "qemu-log.h"
+#include "loader.h"
 
 //#define PPC_DEBUG_IRQ
 //#define PPC_DEBUG_TB
diff --git a/hw/ppc405_boards.c b/hw/ppc405_boards.c
index 0d7860e..9aa99c1 100644
--- a/hw/ppc405_boards.c
+++ b/hw/ppc405_boards.c
@@ -30,6 +30,7 @@
 #include "block.h"
 #include "boards.h"
 #include "qemu-log.h"
+#include "loader.h"
 
 #define BIOS_FILENAME "ppc405_rom.bin"
 #define BIOS_SIZE (2048 * 1024)
diff --git a/hw/ppc440_bamboo.c b/hw/ppc440_bamboo.c
index 3c59f33..8a6b7ce 100644
--- a/hw/ppc440_bamboo.c
+++ b/hw/ppc440_bamboo.c
@@ -22,6 +22,8 @@
 #include "kvm.h"
 #include "kvm_ppc.h"
 #include "device_tree.h"
+#include "loader.h"
+#include "elf.h"
 
 #define BINARY_DEVICE_TREE_FILE "bamboo.dtb"
 
@@ -93,8 +95,8 @@ static void bamboo_init(ram_addr_t ram_size,
     CPUState *env;
     uint64_t elf_entry;
     uint64_t elf_lowaddr;
-    target_ulong entry = 0;
-    target_ulong loadaddr = 0;
+    target_phys_addr_t entry = 0;
+    target_phys_addr_t loadaddr = 0;
     target_long kernel_size = 0;
     target_ulong initrd_base = 0;
     target_long initrd_size = 0;
@@ -126,7 +128,7 @@ static void bamboo_init(ram_addr_t ram_size,
         kernel_size = load_uimage(kernel_filename, &entry, &loadaddr, NULL);
         if (kernel_size < 0) {
             kernel_size = load_elf(kernel_filename, 0, &elf_entry, 
&elf_lowaddr,
-                                   NULL);
+                                   NULL, 1, ELF_MACHINE, 0);
             entry = elf_entry;
             loadaddr = elf_lowaddr;
         }
diff --git a/hw/ppc_newworld.c b/hw/ppc_newworld.c
index 9a491eb..6bd5234 100644
--- a/hw/ppc_newworld.c
+++ b/hw/ppc_newworld.c
@@ -36,6 +36,8 @@
 #include "escc.h"
 #include "openpic.h"
 #include "ide.h"
+#include "loader.h"
+#include "elf.h"
 
 #define MAX_IDE_BUS 2
 #define VGA_BIOS_SIZE 65536
@@ -145,7 +147,8 @@ static void ppc_core99_init (ram_addr_t ram_size,
 
     /* Load OpenBIOS (ELF) */
     if (filename) {
-        bios_size = load_elf(filename, 0, NULL, NULL, NULL);
+        bios_size = load_elf(filename, 0, NULL, NULL, NULL, 1, ELF_MACHINE, 0);
+
         qemu_free(filename);
     } else {
         bios_size = -1;
@@ -187,19 +190,28 @@ static void ppc_core99_init (ram_addr_t ram_size,
 
     if (linux_boot) {
         uint64_t lowaddr = 0;
+        int bswap_needed;
+
+#ifdef BSWAP_NEEDED
+        bswap_needed = 1;
+#else
+        bswap_needed = 0;
+#endif
         kernel_base = KERNEL_LOAD_ADDR;
 
         /* Now we can load the kernel. The first step tries to load the kernel
            supposing PhysAddr = 0x00000000. If that was wrong the kernel is
            loaded again, the new PhysAddr being computed from lowaddr. */
-        kernel_size = load_elf(kernel_filename, kernel_base, NULL, &lowaddr, 
NULL);
+        kernel_size = load_elf(kernel_filename, kernel_base, NULL, &lowaddr, 
NULL,
+                               1, ELF_MACHINE, 0);
         if (kernel_size > 0 && lowaddr != KERNEL_LOAD_ADDR) {
             kernel_size = load_elf(kernel_filename, (2 * kernel_base) - 
lowaddr,
-                                   NULL, NULL, NULL);
+                                   NULL, NULL, NULL, 1, ELF_MACHINE, 0);
         }
         if (kernel_size < 0)
             kernel_size = load_aout(kernel_filename, kernel_base,
-                                    ram_size - kernel_base);
+                                    ram_size - kernel_base, bswap_needed,
+                                    TARGET_PAGE_SIZE);
         if (kernel_size < 0)
             kernel_size = load_image_targphys(kernel_filename,
                                               kernel_base,
diff --git a/hw/ppc_oldworld.c b/hw/ppc_oldworld.c
index 6933650..bb8c969 100644
--- a/hw/ppc_oldworld.c
+++ b/hw/ppc_oldworld.c
@@ -36,6 +36,8 @@
 #include "fw_cfg.h"
 #include "escc.h"
 #include "ide.h"
+#include "loader.h"
+#include "elf.h"
 
 #define MAX_IDE_BUS 2
 #define VGA_BIOS_SIZE 65536
@@ -180,7 +182,8 @@ static void ppc_heathrow_init (ram_addr_t ram_size,
 
     /* Load OpenBIOS (ELF) */
     if (filename) {
-        bios_size = load_elf(filename, 0, NULL, NULL, NULL);
+        bios_size = load_elf(filename, 0, NULL, NULL, NULL,
+                               1, ELF_MACHINE, 0);
         qemu_free(filename);
     } else {
         bios_size = -1;
@@ -222,18 +225,27 @@ static void ppc_heathrow_init (ram_addr_t ram_size,
 
     if (linux_boot) {
         uint64_t lowaddr = 0;
+        int bswap_needed;
+
+#ifdef BSWAP_NEEDED
+        bswap_needed = 1;
+#else
+        bswap_needed = 0;
+#endif
         kernel_base = KERNEL_LOAD_ADDR;
         /* Now we can load the kernel. The first step tries to load the kernel
            supposing PhysAddr = 0x00000000. If that was wrong the kernel is
            loaded again, the new PhysAddr being computed from lowaddr. */
-        kernel_size = load_elf(kernel_filename, kernel_base, NULL, &lowaddr, 
NULL);
+        kernel_size = load_elf(kernel_filename, kernel_base, NULL, &lowaddr, 
NULL,
+                               1, ELF_MACHINE, 0);
         if (kernel_size > 0 && lowaddr != KERNEL_LOAD_ADDR) {
             kernel_size = load_elf(kernel_filename, (2 * kernel_base) - 
lowaddr,
-                                   NULL, NULL, NULL);
+                                   NULL, NULL, NULL, 1, ELF_MACHINE, 0);
         }
         if (kernel_size < 0)
             kernel_size = load_aout(kernel_filename, kernel_base,
-                                    ram_size - kernel_base);
+                                    ram_size - kernel_base, bswap_needed,
+                                    TARGET_PAGE_SIZE);
         if (kernel_size < 0)
             kernel_size = load_image_targphys(kernel_filename,
                                               kernel_base,
diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c
index 5392072..eb281f8 100644
--- a/hw/ppc_prep.c
+++ b/hw/ppc_prep.c
@@ -33,6 +33,7 @@
 #include "boards.h"
 #include "qemu-log.h"
 #include "ide.h"
+#include "loader.h"
 
 //#define HARD_DEBUG_PPC_IO
 //#define DEBUG_PPC_IO
diff --git a/hw/ppce500_mpc8544ds.c b/hw/ppce500_mpc8544ds.c
index 5120821..5044194 100644
--- a/hw/ppce500_mpc8544ds.c
+++ b/hw/ppce500_mpc8544ds.c
@@ -29,6 +29,8 @@
 #include "device_tree.h"
 #include "openpic.h"
 #include "ppce500.h"
+#include "loader.h"
+#include "elf.h"
 
 #define BINARY_DEVICE_TREE_FILE    "mpc8544ds.dtb"
 #define UIMAGE_LOAD_BASE           0
@@ -160,8 +162,8 @@ static void mpc8544ds_init(ram_addr_t ram_size,
     CPUState *env;
     uint64_t elf_entry;
     uint64_t elf_lowaddr;
-    target_ulong entry=0;
-    target_ulong loadaddr=UIMAGE_LOAD_BASE;
+    target_phys_addr_t entry=0;
+    target_phys_addr_t loadaddr=UIMAGE_LOAD_BASE;
     target_long kernel_size=0;
     target_ulong dt_base=DTB_LOAD_BASE;
     target_ulong initrd_base=INITRD_LOAD_BASE;
@@ -226,7 +228,7 @@ static void mpc8544ds_init(ram_addr_t ram_size,
         kernel_size = load_uimage(kernel_filename, &entry, &loadaddr, NULL);
         if (kernel_size < 0) {
             kernel_size = load_elf(kernel_filename, 0, &elf_entry, 
&elf_lowaddr,
-                                   NULL);
+                                   NULL, 1, ELF_MACHINE, 0);
             entry = elf_entry;
             loadaddr = elf_lowaddr;
         }
diff --git a/hw/r2d.c b/hw/r2d.c
index ff514a4..ea19ff6 100644
--- a/hw/r2d.c
+++ b/hw/r2d.c
@@ -32,6 +32,7 @@
 #include "net.h"
 #include "sh7750_regs.h"
 #include "ide.h"
+#include "loader.h"
 
 #define SDRAM_BASE 0x0c000000 /* Physical location of SDRAM: Area 3 */
 #define SDRAM_SIZE 0x04000000
diff --git a/hw/shix.c b/hw/shix.c
index 19b0155..638bf16 100644
--- a/hw/shix.c
+++ b/hw/shix.c
@@ -32,6 +32,7 @@
 #include "sh.h"
 #include "sysemu.h"
 #include "boards.h"
+#include "loader.h"
 
 #define BIOS_FILENAME "shix_bios.bin"
 #define BIOS_ADDRESS 0xA0000000
diff --git a/hw/smbios.c b/hw/smbios.c
index e28beba..a3ae1de 100644
--- a/hw/smbios.c
+++ b/hw/smbios.c
@@ -13,6 +13,7 @@
 
 #include "sysemu.h"
 #include "smbios.h"
+#include "loader.h"
 
 /*
  * Structures shared with the BIOS
diff --git a/hw/sun4m.c b/hw/sun4m.c
index d970723..a869d15 100644
--- a/hw/sun4m.c
+++ b/hw/sun4m.c
@@ -37,6 +37,8 @@
 #include "fw_cfg.h"
 #include "escc.h"
 #include "qdev-addr.h"
+#include "loader.h"
+#include "elf.h"
 
 //#define DEBUG_IRQ
 
@@ -302,11 +304,19 @@ static unsigned long sun4m_load_kernel(const char 
*kernel_filename,
 
     kernel_size = 0;
     if (linux_boot) {
+        int bswap_needed;
+
+#ifdef BSWAP_NEEDED
+        bswap_needed = 1;
+#else
+        bswap_needed = 0;
+#endif
         kernel_size = load_elf(kernel_filename, -0xf0000000ULL, NULL, NULL,
-                               NULL);
+                               NULL, 1, ELF_MACHINE, 0);
         if (kernel_size < 0)
             kernel_size = load_aout(kernel_filename, KERNEL_LOAD_ADDR,
-                                    RAM_size - KERNEL_LOAD_ADDR);
+                                    RAM_size - KERNEL_LOAD_ADDR, bswap_needed,
+                                    TARGET_PAGE_SIZE);
         if (kernel_size < 0)
             kernel_size = load_image_targphys(kernel_filename,
                                               KERNEL_LOAD_ADDR,
@@ -608,7 +618,8 @@ static void prom_init(target_phys_addr_t addr, const char 
*bios_name)
     }
     filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
     if (filename) {
-        ret = load_elf(filename, addr - PROM_VADDR, NULL, NULL, NULL);
+        ret = load_elf(filename, addr - PROM_VADDR, NULL, NULL, NULL,
+                       1, ELF_MACHINE, 0);
         if (ret < 0 || ret > PROM_SIZE_MAX) {
             ret = load_image_targphys(filename, addr, PROM_SIZE_MAX);
         }
diff --git a/hw/sun4u.c b/hw/sun4u.c
index 427ee76..2c97d9d 100644
--- a/hw/sun4u.c
+++ b/hw/sun4u.c
@@ -34,6 +34,8 @@
 #include "fw_cfg.h"
 #include "sysbus.h"
 #include "ide.h"
+#include "loader.h"
+#include "elf.h"
 
 //#define DEBUG_IRQ
 
@@ -164,10 +166,19 @@ static unsigned long sun4u_load_kernel(const char 
*kernel_filename,
 
     kernel_size = 0;
     if (linux_boot) {
-        kernel_size = load_elf(kernel_filename, 0, NULL, NULL, NULL);
+        int bswap_needed;
+
+#ifdef BSWAP_NEEDED
+        bswap_needed = 1;
+#else
+        bswap_needed = 0;
+#endif
+        kernel_size = load_elf(kernel_filename, 0, NULL, NULL, NULL,
+                               1, ELF_MACHINE, 0);
         if (kernel_size < 0)
             kernel_size = load_aout(kernel_filename, KERNEL_LOAD_ADDR,
-                                    RAM_size - KERNEL_LOAD_ADDR);
+                                    RAM_size - KERNEL_LOAD_ADDR, bswap_needed,
+                                    TARGET_PAGE_SIZE);
         if (kernel_size < 0)
             kernel_size = load_image_targphys(kernel_filename,
                                               KERNEL_LOAD_ADDR,
@@ -418,7 +429,8 @@ static void prom_init(target_phys_addr_t addr, const char 
*bios_name)
     }
     filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
     if (filename) {
-        ret = load_elf(filename, addr - PROM_VADDR, NULL, NULL, NULL);
+        ret = load_elf(filename, addr - PROM_VADDR, NULL, NULL, NULL,
+                       1, ELF_MACHINE, 0);
         if (ret < 0 || ret > PROM_SIZE_MAX) {
             ret = load_image_targphys(filename, addr, PROM_SIZE_MAX);
         }
diff --git a/hw/tc58128.c b/hw/tc58128.c
index 21e8085..264aa02 100644
--- a/hw/tc58128.c
+++ b/hw/tc58128.c
@@ -1,6 +1,7 @@
 #include "hw.h"
 #include "sh.h"
 #include "sysemu.h"
+#include "loader.h"
 
 #define CE1  0x0100
 #define CE2  0x0200
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index 10d4781..7c8e771 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -1315,10 +1315,10 @@ static void load_symbols(struct elfhdr *hdr, int fd)
     s->disas_num_syms = nsyms;
 #if ELF_CLASS == ELFCLASS32
     s->disas_symtab.elf32 = syms;
-    s->lookup_symbol = lookup_symbolxx;
+    s->lookup_symbol = (lookup_symbol_t)lookup_symbolxx;
 #else
     s->disas_symtab.elf64 = syms;
-    s->lookup_symbol = lookup_symbolxx;
+    s->lookup_symbol = (lookup_symbol_t)lookup_symbolxx;
 #endif
     s->next = syminfos;
     syminfos = s;
diff --git a/loader.c b/loader.c
deleted file mode 100644
index 0cbcf9c..0000000
--- a/loader.c
+++ /dev/null
@@ -1,544 +0,0 @@
-/*
- * QEMU Executable loader
- *
- * Copyright (c) 2006 Fabrice Bellard
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to 
deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- *
- * Gunzip functionality in this file is derived from u-boot:
- *
- * (C) Copyright 2008 Semihalf
- *
- * (C) Copyright 2000-2005
- * Wolfgang Denk, DENX Software Engineering, address@hidden
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu-common.h"
-#include "disas.h"
-#include "sysemu.h"
-#include "uboot_image.h"
-
-#include <zlib.h>
-
-/* return the size or -1 if error */
-int get_image_size(const char *filename)
-{
-    int fd, size;
-    fd = open(filename, O_RDONLY | O_BINARY);
-    if (fd < 0)
-        return -1;
-    size = lseek(fd, 0, SEEK_END);
-    close(fd);
-    return size;
-}
-
-/* return the size or -1 if error */
-/* deprecated, because caller does not specify buffer size! */
-int load_image(const char *filename, uint8_t *addr)
-{
-    int fd, size;
-    fd = open(filename, O_RDONLY | O_BINARY);
-    if (fd < 0)
-        return -1;
-    size = lseek(fd, 0, SEEK_END);
-    lseek(fd, 0, SEEK_SET);
-    if (read(fd, addr, size) != size) {
-        close(fd);
-        return -1;
-    }
-    close(fd);
-    return size;
-}
-
-/* return the amount read, just like fread.  0 may mean error or eof */
-int fread_targphys(target_phys_addr_t dst_addr, size_t nbytes, FILE *f)
-{
-    uint8_t buf[4096];
-    target_phys_addr_t dst_begin = dst_addr;
-    size_t want, did;
-
-    while (nbytes) {
-       want = nbytes > sizeof(buf) ? sizeof(buf) : nbytes;
-       did = fread(buf, 1, want, f);
-
-       cpu_physical_memory_write_rom(dst_addr, buf, did);
-       dst_addr += did;
-       nbytes -= did;
-       if (did != want)
-           break;
-    }
-    return dst_addr - dst_begin;
-}
-
-/* returns 0 on error, 1 if ok */
-int fread_targphys_ok(target_phys_addr_t dst_addr, size_t nbytes, FILE *f)
-{
-    return fread_targphys(dst_addr, nbytes, f) == nbytes;
-}
-
-/* read()-like version */
-int read_targphys(int fd, target_phys_addr_t dst_addr, size_t nbytes)
-{
-    uint8_t buf[4096];
-    target_phys_addr_t dst_begin = dst_addr;
-    size_t want, did;
-
-    while (nbytes) {
-       want = nbytes > sizeof(buf) ? sizeof(buf) : nbytes;
-       did = read(fd, buf, want);
-       if (did != want) break;
-
-       cpu_physical_memory_write_rom(dst_addr, buf, did);
-       dst_addr += did;
-       nbytes -= did;
-    }
-    return dst_addr - dst_begin;
-}
-
-/* return the size or -1 if error */
-int load_image_targphys(const char *filename,
-                       target_phys_addr_t addr, int max_sz)
-{
-    FILE *f;
-    size_t got;
-
-    f = fopen(filename, "rb");
-    if (!f) return -1;
-
-    got = fread_targphys(addr, max_sz, f);
-    if (ferror(f)) { fclose(f); return -1; }
-    fclose(f);
-
-    return got;
-}
-
-void pstrcpy_targphys(target_phys_addr_t dest, int buf_size,
-                      const char *source)
-{
-    static const uint8_t nul_byte = 0;
-    const char *nulp;
-
-    if (buf_size <= 0) return;
-    nulp = memchr(source, 0, buf_size);
-    if (nulp) {
-       cpu_physical_memory_write_rom(dest, (uint8_t *)source,
-                                      (nulp - source) + 1);
-    } else {
-       cpu_physical_memory_write_rom(dest, (uint8_t *)source, buf_size - 1);
-       cpu_physical_memory_write_rom(dest, &nul_byte, 1);
-    }
-}
-
-/* A.OUT loader */
-
-struct exec
-{
-  uint32_t a_info;   /* Use macros N_MAGIC, etc for access */
-  uint32_t a_text;   /* length of text, in bytes */
-  uint32_t a_data;   /* length of data, in bytes */
-  uint32_t a_bss;    /* length of uninitialized data area, in bytes */
-  uint32_t a_syms;   /* length of symbol table data in file, in bytes */
-  uint32_t a_entry;  /* start address */
-  uint32_t a_trsize; /* length of relocation info for text, in bytes */
-  uint32_t a_drsize; /* length of relocation info for data, in bytes */
-};
-
-#ifdef BSWAP_NEEDED
-static void bswap_ahdr(struct exec *e)
-{
-    bswap32s(&e->a_info);
-    bswap32s(&e->a_text);
-    bswap32s(&e->a_data);
-    bswap32s(&e->a_bss);
-    bswap32s(&e->a_syms);
-    bswap32s(&e->a_entry);
-    bswap32s(&e->a_trsize);
-    bswap32s(&e->a_drsize);
-}
-#else
-#define bswap_ahdr(x) do { } while (0)
-#endif
-
-#define N_MAGIC(exec) ((exec).a_info & 0xffff)
-#define OMAGIC 0407
-#define NMAGIC 0410
-#define ZMAGIC 0413
-#define QMAGIC 0314
-#define _N_HDROFF(x) (1024 - sizeof (struct exec))
-#define N_TXTOFF(x)                                                    \
-    (N_MAGIC(x) == ZMAGIC ? _N_HDROFF((x)) + sizeof (struct exec) :    \
-     (N_MAGIC(x) == QMAGIC ? 0 : sizeof (struct exec)))
-#define N_TXTADDR(x) (N_MAGIC(x) == QMAGIC ? TARGET_PAGE_SIZE : 0)
-#define _N_SEGMENT_ROUND(x) (((x) + TARGET_PAGE_SIZE - 1) & ~(TARGET_PAGE_SIZE 
- 1))
-
-#define _N_TXTENDADDR(x) (N_TXTADDR(x)+(x).a_text)
-
-#define N_DATADDR(x) \
-    (N_MAGIC(x)==OMAGIC? (_N_TXTENDADDR(x)) \
-     : (_N_SEGMENT_ROUND (_N_TXTENDADDR(x))))
-
-
-int load_aout(const char *filename, target_phys_addr_t addr, int max_sz)
-{
-    int fd, size, ret;
-    struct exec e;
-    uint32_t magic;
-
-    fd = open(filename, O_RDONLY | O_BINARY);
-    if (fd < 0)
-        return -1;
-
-    size = read(fd, &e, sizeof(e));
-    if (size < 0)
-        goto fail;
-
-    bswap_ahdr(&e);
-
-    magic = N_MAGIC(e);
-    switch (magic) {
-    case ZMAGIC:
-    case QMAGIC:
-    case OMAGIC:
-        if (e.a_text + e.a_data > max_sz)
-            goto fail;
-       lseek(fd, N_TXTOFF(e), SEEK_SET);
-       size = read_targphys(fd, addr, e.a_text + e.a_data);
-       if (size < 0)
-           goto fail;
-       break;
-    case NMAGIC:
-        if (N_DATADDR(e) + e.a_data > max_sz)
-            goto fail;
-       lseek(fd, N_TXTOFF(e), SEEK_SET);
-       size = read_targphys(fd, addr, e.a_text);
-       if (size < 0)
-           goto fail;
-       ret = read_targphys(fd, addr + N_DATADDR(e), e.a_data);
-       if (ret < 0)
-           goto fail;
-       size += ret;
-       break;
-    default:
-       goto fail;
-    }
-    close(fd);
-    return size;
- fail:
-    close(fd);
-    return -1;
-}
-
-/* ELF loader */
-
-static void *load_at(int fd, int offset, int size)
-{
-    void *ptr;
-    if (lseek(fd, offset, SEEK_SET) < 0)
-        return NULL;
-    ptr = qemu_malloc(size);
-    if (read(fd, ptr, size) != size) {
-        qemu_free(ptr);
-        return NULL;
-    }
-    return ptr;
-}
-
-#ifdef ELF_CLASS
-#undef ELF_CLASS
-#endif
-
-#define ELF_CLASS   ELFCLASS32
-#include "elf.h"
-
-#define SZ             32
-#define elf_word        uint32_t
-#define elf_sword        int32_t
-#define bswapSZs       bswap32s
-#include "elf_ops.h"
-
-#undef elfhdr
-#undef elf_phdr
-#undef elf_shdr
-#undef elf_sym
-#undef elf_note
-#undef elf_word
-#undef elf_sword
-#undef bswapSZs
-#undef SZ
-#define elfhdr         elf64_hdr
-#define elf_phdr       elf64_phdr
-#define elf_note       elf64_note
-#define elf_shdr       elf64_shdr
-#define elf_sym                elf64_sym
-#define elf_word        uint64_t
-#define elf_sword        int64_t
-#define bswapSZs       bswap64s
-#define SZ             64
-#include "elf_ops.h"
-
-/* return < 0 if error, otherwise the number of bytes loaded in memory */
-int load_elf(const char *filename, int64_t address_offset,
-             uint64_t *pentry, uint64_t *lowaddr, uint64_t *highaddr)
-{
-    int fd, data_order, host_data_order, must_swab, ret;
-    uint8_t e_ident[EI_NIDENT];
-
-    fd = open(filename, O_RDONLY | O_BINARY);
-    if (fd < 0) {
-        perror(filename);
-        return -1;
-    }
-    if (read(fd, e_ident, sizeof(e_ident)) != sizeof(e_ident))
-        goto fail;
-    if (e_ident[0] != ELFMAG0 ||
-        e_ident[1] != ELFMAG1 ||
-        e_ident[2] != ELFMAG2 ||
-        e_ident[3] != ELFMAG3)
-        goto fail;
-#ifdef HOST_WORDS_BIGENDIAN
-    data_order = ELFDATA2MSB;
-#else
-    data_order = ELFDATA2LSB;
-#endif
-    must_swab = data_order != e_ident[EI_DATA];
-
-#ifdef TARGET_WORDS_BIGENDIAN
-    host_data_order = ELFDATA2MSB;
-#else
-    host_data_order = ELFDATA2LSB;
-#endif
-    if (host_data_order != e_ident[EI_DATA])
-        return -1;
-
-    lseek(fd, 0, SEEK_SET);
-    if (e_ident[EI_CLASS] == ELFCLASS64) {
-        ret = load_elf64(fd, address_offset, must_swab, pentry,
-                         lowaddr, highaddr);
-    } else {
-        ret = load_elf32(fd, address_offset, must_swab, pentry,
-                         lowaddr, highaddr);
-    }
-
-    close(fd);
-    return ret;
-
- fail:
-    close(fd);
-    return -1;
-}
-
-static void bswap_uboot_header(uboot_image_header_t *hdr)
-{
-#ifndef HOST_WORDS_BIGENDIAN
-    bswap32s(&hdr->ih_magic);
-    bswap32s(&hdr->ih_hcrc);
-    bswap32s(&hdr->ih_time);
-    bswap32s(&hdr->ih_size);
-    bswap32s(&hdr->ih_load);
-    bswap32s(&hdr->ih_ep);
-    bswap32s(&hdr->ih_dcrc);
-#endif
-}
-
-
-#define ZALLOC_ALIGNMENT       16
-
-static void *zalloc(void *x, unsigned items, unsigned size)
-{
-    void *p;
-
-    size *= items;
-    size = (size + ZALLOC_ALIGNMENT - 1) & ~(ZALLOC_ALIGNMENT - 1);
-
-    p = qemu_malloc(size);
-
-    return (p);
-}
-
-static void zfree(void *x, void *addr)
-{
-    qemu_free(addr);
-}
-
-
-#define HEAD_CRC       2
-#define EXTRA_FIELD    4
-#define ORIG_NAME      8
-#define COMMENT                0x10
-#define RESERVED       0xe0
-
-#define DEFLATED       8
-
-/* This is the maximum in uboot, so if a uImage overflows this, it would
- * overflow on real hardware too. */
-#define UBOOT_MAX_GUNZIP_BYTES 0x800000
-
-static ssize_t gunzip(void *dst, size_t dstlen, uint8_t *src,
-                      size_t srclen)
-{
-    z_stream s;
-    ssize_t dstbytes;
-    int r, i, flags;
-
-    /* skip header */
-    i = 10;
-    flags = src[3];
-    if (src[2] != DEFLATED || (flags & RESERVED) != 0) {
-        puts ("Error: Bad gzipped data\n");
-        return -1;
-    }
-    if ((flags & EXTRA_FIELD) != 0)
-        i = 12 + src[10] + (src[11] << 8);
-    if ((flags & ORIG_NAME) != 0)
-        while (src[i++] != 0)
-            ;
-    if ((flags & COMMENT) != 0)
-        while (src[i++] != 0)
-            ;
-    if ((flags & HEAD_CRC) != 0)
-        i += 2;
-    if (i >= srclen) {
-        puts ("Error: gunzip out of data in header\n");
-        return -1;
-    }
-
-    s.zalloc = zalloc;
-    s.zfree = zfree;
-
-    r = inflateInit2(&s, -MAX_WBITS);
-    if (r != Z_OK) {
-        printf ("Error: inflateInit2() returned %d\n", r);
-        return (-1);
-    }
-    s.next_in = src + i;
-    s.avail_in = srclen - i;
-    s.next_out = dst;
-    s.avail_out = dstlen;
-    r = inflate(&s, Z_FINISH);
-    if (r != Z_OK && r != Z_STREAM_END) {
-        printf ("Error: inflate() returned %d\n", r);
-        return -1;
-    }
-    dstbytes = s.next_out - (unsigned char *) dst;
-    inflateEnd(&s);
-
-    return dstbytes;
-}
-
-/* Load a U-Boot image.  */
-int load_uimage(const char *filename, target_ulong *ep, target_ulong *loadaddr,
-                int *is_linux)
-{
-    int fd;
-    int size;
-    uboot_image_header_t h;
-    uboot_image_header_t *hdr = &h;
-    uint8_t *data = NULL;
-    int ret = -1;
-
-    fd = open(filename, O_RDONLY | O_BINARY);
-    if (fd < 0)
-        return -1;
-
-    size = read(fd, hdr, sizeof(uboot_image_header_t));
-    if (size < 0)
-        goto out;
-
-    bswap_uboot_header(hdr);
-
-    if (hdr->ih_magic != IH_MAGIC)
-        goto out;
-
-    /* TODO: Implement other image types.  */
-    if (hdr->ih_type != IH_TYPE_KERNEL) {
-        fprintf(stderr, "Can only load u-boot image type \"kernel\"\n");
-        goto out;
-    }
-
-    switch (hdr->ih_comp) {
-    case IH_COMP_NONE:
-    case IH_COMP_GZIP:
-        break;
-    default:
-        fprintf(stderr,
-                "Unable to load u-boot images with compression type %d\n",
-                hdr->ih_comp);
-        goto out;
-    }
-
-    /* TODO: Check CPU type.  */
-    if (is_linux) {
-        if (hdr->ih_os == IH_OS_LINUX)
-            *is_linux = 1;
-        else
-            *is_linux = 0;
-    }
-
-    *ep = hdr->ih_ep;
-    data = qemu_malloc(hdr->ih_size);
-
-    if (read(fd, data, hdr->ih_size) != hdr->ih_size) {
-        fprintf(stderr, "Error reading file\n");
-        goto out;
-    }
-
-    if (hdr->ih_comp == IH_COMP_GZIP) {
-        uint8_t *compressed_data;
-        size_t max_bytes;
-        ssize_t bytes;
-
-        compressed_data = data;
-        max_bytes = UBOOT_MAX_GUNZIP_BYTES;
-        data = qemu_malloc(max_bytes);
-
-        bytes = gunzip(data, max_bytes, compressed_data, hdr->ih_size);
-        qemu_free(compressed_data);
-        if (bytes < 0) {
-            fprintf(stderr, "Unable to decompress gzipped image!\n");
-            goto out;
-        }
-        hdr->ih_size = bytes;
-    }
-
-    cpu_physical_memory_write_rom(hdr->ih_load, data, hdr->ih_size);
-
-    if (loadaddr)
-        *loadaddr = hdr->ih_load;
-
-    ret = hdr->ih_size;
-
-out:
-    if (data)
-        qemu_free(data);
-    close(fd);
-    return ret;
-}
diff --git a/sysemu.h b/sysemu.h
index 644a97d..8bf90ee 100644
--- a/sysemu.h
+++ b/sysemu.h
@@ -237,24 +237,6 @@ extern CharDriverState *virtcon_hds[MAX_VIRTIO_CONSOLES];
 
 #define TFR(expr) do { if ((expr) != -1) break; } while (errno == EINTR)
 
-#ifdef NEED_CPU_H
-/* loader.c */
-int get_image_size(const char *filename);
-int load_image(const char *filename, uint8_t *addr); /* deprecated */
-int load_image_targphys(const char *filename, target_phys_addr_t, int max_sz);
-int load_elf(const char *filename, int64_t address_offset,
-             uint64_t *pentry, uint64_t *lowaddr, uint64_t *highaddr);
-int load_aout(const char *filename, target_phys_addr_t addr, int max_sz);
-int load_uimage(const char *filename, target_ulong *ep, target_ulong *loadaddr,
-                int *is_linux);
-
-int fread_targphys(target_phys_addr_t dst_addr, size_t nbytes, FILE *f);
-int fread_targphys_ok(target_phys_addr_t dst_addr, size_t nbytes, FILE *f);
-int read_targphys(int fd, target_phys_addr_t dst_addr, size_t nbytes);
-void pstrcpy_targphys(target_phys_addr_t dest, int buf_size,
-                      const char *source);
-#endif
-
 #ifdef HAS_AUDIO
 struct soundhw {
     const char *name;




reply via email to

[Prev in Thread] Current Thread [Next in Thread]