All of lore.kernel.org
 help / color / mirror / Atom feed
From: Thiemo Seufer <ths@networkno.de>
To: qemu-devel@nongnu.org
Subject: Re: [Qemu-devel] [PATCH] Add MIPS ELF loader
Date: Tue, 28 Mar 2006 14:01:59 +0100	[thread overview]
Message-ID: <20060328130159.GA31939@networkno.de> (raw)
In-Reply-To: <4428DE4B.6040802@gmail.com>

On Tue, Mar 28, 2006 at 08:57:15AM +0200, Dirk Behme wrote:
> 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.

A slightly more polished version with less noisy messages is appended.
It also adjusts the ramdisk load address to physical addressing,
similiar to the binary kernel load.


Thiemo


Index: qemu-work/hw/mips_r4k.c
===================================================================
--- qemu-work.orig/hw/mips_r4k.c	2006-03-28 12:27:55.000000000 +0100
+++ qemu-work/hw/mips_r4k.c	2006-03-28 13:49:10.000000000 +0100
@@ -1,6 +1,8 @@
 #define KERNEL_LOAD_ADDR 0x80010000
 #define INITRD_LOAD_ADDR 0x80800000
 
+#define PHYSADDR(addr) ((addr) & 0x1fffffff)
+
 extern FILE *logfile;
 
 static PITState *pit;
@@ -101,6 +105,108 @@
     cpu_mips_update_count(env, 1, 0);
 }
 
+#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"
+
+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 + PHYSADDR(phdr.p_vaddr));
+		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
@@ -183,72 +319,70 @@
                     const char *initrd_filename)
 {
     char buf[1024];
-    target_ulong kernel_base, kernel_size, initrd_base, initrd_size;
+    elf_word entry = 0;
     unsigned long bios_offset;
     int io_memory;
-    int linux_boot;
     int ret;
     CPUState *env;
-
-    printf("%s: start\n", __func__);
-    linux_boot = (kernel_filename != NULL);
+    int i;
 
     env = cpu_init();
     register_savevm("cpu", 0, 3, cpu_save, cpu_load, env);
 
     /* allocate RAM */
     cpu_register_physical_memory(0, ram_size, IO_MEM_RAM);
+
+    /* Try to load a BIOS image. If this fails, we continue regardless,
+       but initialize the hardware ourselves. When a kernel gets
+       preloaded we also initialize the hardware, since the BIOS wasn't
+       run. */
     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;
+	if (!kernel_filename)
+	    return;
+    } else {
+	/* not fatal */
+        fprintf(stderr, "qemu: Warning, could not load MIPS bios '%s'\n",
+		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);
-        }
+
+    if (kernel_filename) {
+	if (!load_mips_kernel_elf(kernel_filename, &entry))
+	    env->PC = entry;
+	else {
+	    /* try to load as binary image */
+            if (load_image(kernel_filename,
+			   phys_ram_base + PHYSADDR(KERNEL_LOAD_ADDR))
+		== (target_ulong) -1) {
+		fprintf(stderr, "qemu: could not load kernel '%s'\n",
+			kernel_filename);
+                exit(1);
+            }
+	    env->PC = KERNEL_LOAD_ADDR;
+	}
+
         /* 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) {
+            if (load_image(initrd_filename,
+			   phys_ram_base + PHYSADDR(INITRD_LOAD_ADDR))
+		== (target_ulong) -1) {
                 fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", 
                         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 */
         *(int *)(phys_ram_base + (16 << 20) - 260) = tswap32 (0x12345678);
         *(int *)(phys_ram_base + (16 << 20) - 264) = tswap32 (ram_size);
-    } else {
-        kernel_base = 0;
-        kernel_size = 0;
-        initrd_base = 0;
-        initrd_size = 0;
     }
 
     /* Init internal devices */

  reply	other threads:[~2006-03-28 13:02 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2006-03-28  6:57 [Qemu-devel] [PATCH] Add MIPS ELF loader Dirk Behme
2006-03-28 13:01 ` Thiemo Seufer [this message]
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=20060328130159.GA31939@networkno.de \
    --to=ths@networkno.de \
    --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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.