qemu-ppc
[Top][All Lists]
Advanced

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

[Qemu-ppc] [RFC PATCH v4 3/3] use elf_reset to reload elf image


From: Olivia Yin
Subject: [Qemu-ppc] [RFC PATCH v4 3/3] use elf_reset to reload elf image
Date: Wed, 14 Nov 2012 21:28:52 +0800

Signed-off-by: Olivia Yin <address@hidden>
---
 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





reply via email to

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