qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Dirk Behme <dirk.behme@googlemail.com>
To: qemu-devel@nongnu.org
Subject: [Qemu-devel] [PATCH] Add MIPS ELF loader
Date: Tue, 28 Mar 2006 08:57:15 +0200	[thread overview]
Message-ID: <4428DE4B.6040802@gmail.com> (raw)

[-- Attachment #1: Type: text/plain, Size: 466 bytes --]

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


[-- Attachment #2: mips_elf_load.txt --]
[-- Type: text/plain, Size: 7148 bytes --]

--- ./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	other threads:[~2006-03-28  6:57 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2006-03-28  6:57 Dirk Behme [this message]
2006-03-28 13:01 ` [Qemu-devel] [PATCH] Add MIPS ELF loader Thiemo Seufer
2006-03-30 13:40   ` Dirk Behme
2006-03-30 13:53     ` Thiemo Seufer
2006-03-30 14:29       ` Alexander Voropay
2006-03-30 17:34         ` Dirk Behme
     [not found]         ` <442C0F57.3010200@gmail.com>
2006-04-02 12:54           ` Alexander Voropay
2006-04-23 17:16 ` Fabrice Bellard
2006-04-25 23:57   ` Thiemo Seufer
     [not found] <154e01c66453$111e4f20$e90d11ac@spb.in.rosprint.ru>
2006-04-20 10:16 ` Marius Groeger
2006-04-20 10:28   ` Thiemo Seufer
2006-04-20 11:02     ` Alexander Voropay
2006-04-20 12:19       ` Alexander Voropay

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=4428DE4B.6040802@gmail.com \
    --to=dirk.behme@googlemail.com \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).