qemu-devel
[Top][All Lists]
Advanced

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

[Qemu-devel] [PATCH] Add MIPS ELF loader


From: Dirk Behme
Subject: [Qemu-devel] [PATCH] Add MIPS ELF loader
Date: Tue, 28 Mar 2006 08:57:15 +0200
User-agent: Mozilla Thunderbird 1.0.7 (X11/20050923)

Hi,

ELF loader feature for MIPS in patch

http://lists.gnu.org/archive/html/qemu-devel/2006-03/msg00033.html

was rejected because it breaks loading of raw kernel images:

http://lists.gnu.org/archive/html/qemu-devel/2006-03/msg00082.html

What about the patch in attachment? It first tries to load
image as an ELF file. If this fails it falls back to raw
image load. Additionally, it takes feature of patch above to
go on even if no BIOS is found.

Regards

Dirk

--- ./hw/mips_r4k.c_orig        2006-03-28 07:48:21.000000000 +0200
+++ ./hw/mips_r4k.c     2006-03-28 08:52:18.000000000 +0200
@@ -5,6 +5,30 @@
 #define KERNEL_LOAD_ADDR 0x80010000
 #define INITRD_LOAD_ADDR 0x80800000
 
+#include "disas.h"
+
+#define ELF_CLASS   ELFCLASS32
+#ifdef TARGET_WORDS_BIGENDIAN
+# define ELF_DATA    ELFDATA2MSB
+#else
+# define ELF_DATA    ELFDATA2LSB
+#endif
+#define ELF_ARCH    EM_MIPS
+
+#include "elf.h"
+
+#ifndef BSWAP_NEEDED
+#define bswap_ehdr32(e) do { } while (0)
+#define bswap_phdr32(e) do { } while (0)
+#define bswap_shdr32(e) do { } while (0)
+#define bswap_sym32(e) do { } while (0)
+#endif
+
+#define SZ             32
+#define elf_word        uint32_t
+#define bswapSZs       bswap32s
+#include "elf_ops.h"
+
 extern FILE *logfile;
 
 static PITState *pit;
@@ -101,6 +125,83 @@ void cpu_mips_clock_init (CPUState *env)
     cpu_mips_update_count(env, 1, 0);
 }
 
+static int load_mips_kernel_elf(const char *filename, elf_word *entry)
+{
+    struct elf32_hdr ehdr;
+    int retval, fd, i;
+    Elf32_Half machine;
+
+    fd = open(filename, O_RDONLY | O_BINARY);
+    if (fd < 0)
+       goto error;
+
+    retval = read(fd, &ehdr, sizeof(ehdr));
+    if (retval < 0)
+       goto error;
+
+    if (ehdr.e_ident[0] != 0x7f || ehdr.e_ident[1] != 'E'
+       || ehdr.e_ident[2] != 'L' || ehdr.e_ident[3] != 'F')
+       goto error;
+    machine = tswap16(ehdr.e_machine);
+    if (machine == EM_MIPS) {
+       struct elf32_phdr phdr;
+
+       bswap_ehdr32(&ehdr);
+
+       *entry = ehdr.e_entry;
+       retval = lseek(fd, ehdr.e_phoff, SEEK_SET);
+       if (retval < 0)
+           goto error;
+
+       for (i = 0; i < ehdr.e_phnum; i++) {
+           retval = read(fd, &phdr, sizeof(phdr));
+           if (retval < 0)
+               goto error;
+           bswap_phdr32(&phdr);
+           if (phdr.p_type == PT_LOAD) {
+               uint8_t *addr;
+               size_t sz = phdr.p_filesz;
+
+               if (phdr.p_vaddr < 0x80000000
+                   || phdr.p_memsz > 0x20000000
+                   || (phdr.p_vaddr < 0xa0000000 && (phdr.p_vaddr + 
+phdr.p_memsz) >= 0xa0000000)
+                   || (phdr.p_vaddr < 0xc0000000 && (phdr.p_vaddr + 
+phdr.p_memsz) >= 0xc0000000))
+                   goto error;
+               addr = (uint8_t *)(phys_ram_base + (phdr.p_vaddr & 0x1fffffff));
+               retval = lseek(fd, phdr.p_offset, SEEK_SET);
+               if (retval < 0)
+                   goto error;
+               while (sz) {
+                   retval = read(fd, addr, sz);
+                   switch (retval) {
+                   case -1:
+                       goto error;
+                   case 0: /* EOF */
+                       if (sz)
+                           goto error;
+                       break;
+                   default:
+                       if (sz < retval)
+                           goto error;
+                       sz -= retval;
+                       retval = 0;
+                       break;
+                   }
+               }
+           }
+       }
+       load_symbols32(&ehdr, fd);
+    }
+
+    close(fd);
+    return retval;
+error:
+    close(fd);
+    return -1;
+}
+
 static void io_writeb (void *opaque, target_phys_addr_t addr, uint32_t value)
 {
 #if 0
@@ -191,12 +292,12 @@ void mips_r4k_init (int ram_size, int vg
     char buf[1024];
     target_ulong kernel_base, kernel_size, initrd_base, initrd_size;
     unsigned long bios_offset;
+    elf_word entry = 0;
     int io_memory;
     int linux_boot;
     int ret;
     CPUState *env;
 
-    printf("%s: start\n", __func__);
     linux_boot = (kernel_filename != NULL);
 
     env = cpu_init();
@@ -204,47 +305,59 @@ void mips_r4k_init (int ram_size, int vg
 
     /* allocate RAM */
     cpu_register_physical_memory(0, ram_size, IO_MEM_RAM);
+
+    /* Try to load a BIOS image. If this fails, we continue regardless */
     bios_offset = ram_size + vga_ram_size;
     snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME);
-    printf("%s: load BIOS '%s' size %d\n", __func__, buf, BIOS_SIZE);
     ret = load_image(buf, phys_ram_base + bios_offset);
-    if (ret != BIOS_SIZE) {
-        fprintf(stderr, "qemu: could not load MIPS bios '%s'\n", buf);
-        exit(1);
+    if (ret == BIOS_SIZE) {
+       cpu_register_physical_memory((uint32_t)(0x1fc00000),
+                                    BIOS_SIZE, bios_offset | IO_MEM_ROM);
+       env->PC = 0xBFC00000;
+       printf("qemu: successfully loaded BIOS '%s' size %d\n", buf, BIOS_SIZE);
+       if (!kernel_filename)
+           return;
+    } else {
+       /* not fatal */
+        fprintf(stderr, "%s: Warning, could not load MIPS bios '%s', go on 
anyway\n",
+                __func__, buf);
     }
-    cpu_register_physical_memory((uint32_t)(0x1fc00000),
-                                 BIOS_SIZE, bios_offset | IO_MEM_ROM);
-#if 0
-    memcpy(phys_ram_base + 0x10000, phys_ram_base + bios_offset, BIOS_SIZE);
-    env->PC = 0x80010004;
-#else
-    env->PC = 0xBFC00004;
-#endif
     if (linux_boot) {
-        kernel_base = KERNEL_LOAD_ADDR;
-        /* now we can load the kernel */
-        kernel_size = load_image(kernel_filename,
-                                phys_ram_base + (kernel_base - 0x80000000));
-        if (kernel_size == (target_ulong) -1) {
-            fprintf(stderr, "qemu: could not load kernel '%s'\n", 
-                    kernel_filename);
-            exit(1);
-        }
+        /* load kernel. First try to load ELF file, if this fails
+           fall back to standard raw binary image */
+        if (!load_mips_kernel_elf(kernel_filename, &entry)) {
+            env->PC = entry;
+       } else {
+            /* ELF file load failed, seems to be a raw binary image */
+             kernel_base = KERNEL_LOAD_ADDR;
+            /* now we can load the kernel */
+            kernel_size = load_image(kernel_filename,
+                                     phys_ram_base + (kernel_base - 
0x80000000));
+            if (kernel_size == (target_ulong) -1) {
+                 fprintf(stderr, "%s: could not load kernel '%s'\n", 
+                          __func__, kernel_filename);
+                 exit(1);
+            }
+            env->PC = KERNEL_LOAD_ADDR;
+       }
+        printf("qemu: successfully loaded '%s' to start address 0x%08x\n", 
+               kernel_filename, env->PC);
+
         /* load initrd */
         if (initrd_filename) {
             initrd_base = INITRD_LOAD_ADDR;
             initrd_size = load_image(initrd_filename,
                                      phys_ram_base + initrd_base);
             if (initrd_size == (target_ulong) -1) {
-                fprintf(stderr, "qemu: could not load initial ram disk 
'%s'\n", 
-                        initrd_filename);
+                fprintf(stderr, "%s: could not load initial ram disk '%s'\n", 
+                        __func__, initrd_filename);
                 exit(1);
             }
         } else {
             initrd_base = 0;
             initrd_size = 0;
         }
-        env->PC = KERNEL_LOAD_ADDR;
+  
        /* Store command line.  */
         strcpy (phys_ram_base + (16 << 20) - 256, kernel_cmdline);
         /* FIXME: little endian support */


reply via email to

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