summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--hw/core/loader.c30
-rw-r--r--hw/s390x/ipl.c4
-rw-r--r--include/hw/elf_ops.h19
-rw-r--r--include/hw/loader.h6
4 files changed, 46 insertions, 13 deletions
diff --git a/hw/core/loader.c b/hw/core/loader.c
index e1c3f3a860..b323c0c7b8 100644
--- a/hw/core/loader.c
+++ b/hw/core/loader.c
@@ -284,12 +284,30 @@ static void *load_at(int fd, int offset, int size)
 #define SZ		64
 #include "hw/elf_ops.h"
 
+const char *load_elf_strerror(int error)
+{
+    switch (error) {
+    case 0:
+        return "No error";
+    case ELF_LOAD_FAILED:
+        return "Failed to load ELF";
+    case ELF_LOAD_NOT_ELF:
+        return "The image is not ELF";
+    case ELF_LOAD_WRONG_ARCH:
+        return "The image is from incompatible architecture";
+    case ELF_LOAD_WRONG_ENDIAN:
+        return "The image has incorrect endianness";
+    default:
+        return "Unknown error";
+    }
+}
+
 /* return < 0 if error, otherwise the number of bytes loaded in memory */
 int load_elf(const char *filename, uint64_t (*translate_fn)(void *, uint64_t),
              void *translate_opaque, 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;
+    int fd, data_order, target_data_order, must_swab, ret = ELF_LOAD_FAILED;
     uint8_t e_ident[EI_NIDENT];
 
     fd = open(filename, O_RDONLY | O_BINARY);
@@ -302,8 +320,10 @@ int load_elf(const char *filename, uint64_t (*translate_fn)(void *, uint64_t),
     if (e_ident[0] != ELFMAG0 ||
         e_ident[1] != ELFMAG1 ||
         e_ident[2] != ELFMAG2 ||
-        e_ident[3] != ELFMAG3)
+        e_ident[3] != ELFMAG3) {
+        ret = ELF_LOAD_NOT_ELF;
         goto fail;
+    }
 #ifdef HOST_WORDS_BIGENDIAN
     data_order = ELFDATA2MSB;
 #else
@@ -317,6 +337,7 @@ int load_elf(const char *filename, uint64_t (*translate_fn)(void *, uint64_t),
     }
 
     if (target_data_order != e_ident[EI_DATA]) {
+        ret = ELF_LOAD_WRONG_ENDIAN;
         goto fail;
     }
 
@@ -329,12 +350,9 @@ int load_elf(const char *filename, uint64_t (*translate_fn)(void *, uint64_t),
                          pentry, lowaddr, highaddr, elf_machine, clear_lsb);
     }
 
-    close(fd);
-    return ret;
-
  fail:
     close(fd);
-    return -1;
+    return ret;
 }
 
 static void bswap_uboot_header(uboot_image_header_t *hdr)
diff --git a/hw/s390x/ipl.c b/hw/s390x/ipl.c
index 04fb1a8e05..32d38a08f6 100644
--- a/hw/s390x/ipl.c
+++ b/hw/s390x/ipl.c
@@ -98,10 +98,10 @@ static int s390_ipl_init(SysBusDevice *dev)
         uint64_t pentry = KERN_IMAGE_START;
         kernel_size = load_elf(ipl->kernel, NULL, NULL, &pentry, NULL,
                                NULL, 1, ELF_MACHINE, 0);
-        if (kernel_size == -1) {
+        if (kernel_size < 0) {
             kernel_size = load_image_targphys(ipl->kernel, 0, ram_size);
         }
-        if (kernel_size == -1) {
+        if (kernel_size < 0) {
             fprintf(stderr, "could not load kernel '%s'\n", ipl->kernel);
             return -1;
         }
diff --git a/include/hw/elf_ops.h b/include/hw/elf_ops.h
index acc701e3a4..c6b5129bab 100644
--- a/include/hw/elf_ops.h
+++ b/include/hw/elf_ops.h
@@ -201,6 +201,7 @@ static int glue(load_elf, SZ)(const char *name, int fd,
     uint64_t addr, low = (uint64_t)-1, high = 0;
     uint8_t *data = NULL;
     char label[128];
+    int ret = ELF_LOAD_FAILED;
 
     if (read(fd, &ehdr, sizeof(ehdr)) != sizeof(ehdr))
         goto fail;
@@ -211,22 +212,30 @@ static int glue(load_elf, SZ)(const char *name, int fd,
     switch (elf_machine) {
         case EM_PPC64:
             if (EM_PPC64 != ehdr.e_machine)
-                if (EM_PPC != ehdr.e_machine)
+                if (EM_PPC != ehdr.e_machine) {
+                    ret = ELF_LOAD_WRONG_ARCH;
                     goto fail;
+                }
             break;
         case EM_X86_64:
             if (EM_X86_64 != ehdr.e_machine)
-                if (EM_386 != ehdr.e_machine)
+                if (EM_386 != ehdr.e_machine) {
+                    ret = ELF_LOAD_WRONG_ARCH;
                     goto fail;
+                }
             break;
         case EM_MICROBLAZE:
             if (EM_MICROBLAZE != ehdr.e_machine)
-                if (EM_MICROBLAZE_OLD != ehdr.e_machine)
+                if (EM_MICROBLAZE_OLD != ehdr.e_machine) {
+                    ret = ELF_LOAD_WRONG_ARCH;
                     goto fail;
+                }
             break;
         default:
-            if (elf_machine != ehdr.e_machine)
+            if (elf_machine != ehdr.e_machine) {
+                ret = ELF_LOAD_WRONG_ARCH;
                 goto fail;
+            }
     }
 
     if (pentry)
@@ -305,5 +314,5 @@ static int glue(load_elf, SZ)(const char *name, int fd,
  fail:
     g_free(data);
     g_free(phdr);
-    return -1;
+    return ret;
 }
diff --git a/include/hw/loader.h b/include/hw/loader.h
index 91b01224a3..aaf08c377e 100644
--- a/include/hw/loader.h
+++ b/include/hw/loader.h
@@ -15,6 +15,12 @@ int get_image_size(const char *filename);
 int load_image(const char *filename, uint8_t *addr); /* deprecated */
 int load_image_targphys(const char *filename, hwaddr,
                         uint64_t max_sz);
+
+#define ELF_LOAD_FAILED       -1
+#define ELF_LOAD_NOT_ELF      -2
+#define ELF_LOAD_WRONG_ARCH   -3
+#define ELF_LOAD_WRONG_ENDIAN -4
+const char *load_elf_strerror(int error);
 int load_elf(const char *filename, uint64_t (*translate_fn)(void *, uint64_t),
              void *translate_opaque, uint64_t *pentry, uint64_t *lowaddr,
              uint64_t *highaddr, int big_endian, int elf_machine,