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: Wed, 26 Apr 2006 00:57:13 +0100	[thread overview]
Message-ID: <20060425235713.GA29550@networkno.de> (raw)
In-Reply-To: <444BB67B.3090301@bellard.org>

Fabrice Bellard wrote:
> I just added an ELF loader (inspirated from the SPARC one) which should 
> work for all architectures. It supports symbol loading and use the CPU 
> physical memory mappings to compute correct RAM addresses.

I extended it so that it provides the ELF entry point address, fixed
a memory leak for the failure case, put the large buffer read in a
read loop, and let the mips-4kc use it with fallback to raw binaries.

Also, the mips support handles a missing BIOS nor in a more graceful
way.

I was busier that I hoped the last days, collecting the MIPS specific
patches may take a few days longer.


Thiemo


Index: qemu-work/hw/mips_r4k.c
===================================================================
--- qemu-work.orig/hw/mips_r4k.c	2006-04-25 23:22:22.000000000 +0100
+++ qemu-work/hw/mips_r4k.c	2006-04-25 23:22:25.000000000 +0100
@@ -5,6 +5,8 @@
 #define KERNEL_LOAD_ADDR 0x80010000
 #define INITRD_LOAD_ADDR 0x80800000
 
+#define VIRT_TO_PHYS_ADDEND (-0x80000000LL)
+
 extern FILE *logfile;
 
 static PITState *pit;
@@ -101,6 +103,7 @@
     cpu_mips_update_count(env, 1, 0);
 }
 
+
 static void io_writeb (void *opaque, target_phys_addr_t addr, uint32_t value)
 {
 #if 0
@@ -189,72 +192,71 @@
                     const char *initrd_filename)
 {
     char buf[1024];
-    target_ulong kernel_base, kernel_size, initrd_base, initrd_size;
+    int64_t 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);
+    long kernel_size;
 
     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);
-        }
+
+    kernel_size = 0;
+    if (kernel_filename) {
+	kernel_size = load_elf(kernel_filename, VIRT_TO_PHYS_ADDEND, &entry);
+	if (kernel_size >= 0)
+	    env->PC = entry;
+	else {
+	    kernel_size = load_image(kernel_filename,
+                                     phys_ram_base + KERNEL_LOAD_ADDR + VIRT_TO_PHYS_ADDEND);
+            if (kernel_size < 0) {
+                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 + INITRD_LOAD_ADDR + VIRT_TO_PHYS_ADDEND)
+		== (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 */
Index: qemu-work/elf_ops.h
===================================================================
--- qemu-work.orig/elf_ops.h	2006-04-25 23:22:22.000000000 +0100
+++ qemu-work/elf_ops.h	2006-04-25 23:23:10.000000000 +0100
@@ -138,7 +138,8 @@
     return -1;
 }
 
-int glue(load_elf, SZ)(int fd, int64_t virt_to_phys_addend, int must_swab)
+int glue(load_elf, SZ)(int fd, int64_t virt_to_phys_addend,
+                       int must_swab, int64_t *entry)
 {
     struct elfhdr ehdr;
     struct elf_phdr *phdr = NULL, *ph;
@@ -152,6 +153,9 @@
         glue(bswap_ehdr, SZ)(&ehdr);
     }
 
+    if (entry)
+   	*entry = (int64_t)ehdr.e_entry;
+
     glue(load_symbols, SZ)(&ehdr, fd, must_swab);
 
     size = ehdr.e_phnum * sizeof(phdr[0]);
@@ -176,9 +180,29 @@
             /* XXX: avoid allocating */
             data = qemu_mallocz(mem_size);
             if (ph->p_filesz > 0) {
-                lseek(fd, ph->p_offset, SEEK_SET);
-                if (read(fd, data, ph->p_filesz) != ph->p_filesz)
-                    goto fail;
+                size_t sz = ph->p_filesz;
+                int retval;
+
+                retval = lseek(fd, ph->p_offset, SEEK_SET);
+		if (retval < 0)
+		    goto fail2;
+                while (sz) {
+		    retval = read(fd, data, sz);
+		    switch (retval) {
+		    case -1:
+                        goto fail2;
+		    case 0: /* EOF */
+			if (sz)
+			    goto fail;
+			break;
+		    default:
+			if (sz < retval)
+			    goto fail2;
+			sz -= retval;
+			retval = 0;
+			break;
+		    }
+		}
             }
             addr = ph->p_vaddr + virt_to_phys_addend;
 
@@ -190,6 +214,8 @@
         }
     }
     return total_size;
+ fail2:
+    qemu_free(data);
  fail:
     qemu_free(phdr);
     return -1;
Index: qemu-work/hw/sun4m.c
===================================================================
--- qemu-work.orig/hw/sun4m.c	2006-04-25 23:22:22.000000000 +0100
+++ qemu-work/hw/sun4m.c	2006-04-25 23:22:25.000000000 +0100
@@ -269,7 +269,7 @@
                                  prom_offset | IO_MEM_ROM);
 
     snprintf(buf, sizeof(buf), "%s/%s", bios_dir, PROM_FILENAMEE);
-    ret = load_elf(buf, 0);
+    ret = load_elf(buf, 0, NULL);
     if (ret < 0) {
 	snprintf(buf, sizeof(buf), "%s/%s", bios_dir, PROM_FILENAMEB);
 	ret = load_image(buf, phys_ram_base + prom_offset);
@@ -282,7 +282,7 @@
 
     kernel_size = 0;
     if (linux_boot) {
-        kernel_size = load_elf(kernel_filename, -0xf0000000);
+        kernel_size = load_elf(kernel_filename, -0xf0000000, NULL);
         if (kernel_size < 0)
 	    kernel_size = load_aout(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR);
 	if (kernel_size < 0)
Index: qemu-work/hw/sun4u.c
===================================================================
--- qemu-work.orig/hw/sun4u.c	2006-04-25 23:22:22.000000000 +0100
+++ qemu-work/hw/sun4u.c	2006-04-25 23:22:25.000000000 +0100
@@ -283,7 +283,7 @@
                                  prom_offset | IO_MEM_ROM);
 
     snprintf(buf, sizeof(buf), "%s/%s", bios_dir, PROM_FILENAMEE);
-    ret = load_elf(buf, 0);
+    ret = load_elf(buf, 0, NULL);
     if (ret < 0) {
 	snprintf(buf, sizeof(buf), "%s/%s", bios_dir, PROM_FILENAMEB);
 	ret = load_image(buf, phys_ram_base + prom_offset);
@@ -298,7 +298,7 @@
     initrd_size = 0;
     if (linux_boot) {
         /* XXX: put correct offset */
-        kernel_size = load_elf(kernel_filename, 0);
+        kernel_size = load_elf(kernel_filename, 0, NULL);
         if (kernel_size < 0)
 	    kernel_size = load_aout(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR);
 	if (kernel_size < 0)
Index: qemu-work/loader.c
===================================================================
--- qemu-work.orig/loader.c	2006-04-25 23:22:22.000000000 +0100
+++ qemu-work/loader.c	2006-04-25 23:22:25.000000000 +0100
@@ -194,7 +194,8 @@
 #include "elf_ops.h"
 
 /* return < 0 if error, otherwise the number of bytes loaded in memory */
-int load_elf(const char *filename, int64_t virt_to_phys_addend)
+int load_elf(const char *filename, int64_t virt_to_phys_addend,
+             int64_t *entry)
 {
     int fd, data_order, must_swab, ret;
     uint8_t e_ident[EI_NIDENT];
@@ -220,9 +221,9 @@
     
     lseek(fd, 0, SEEK_SET);
     if (e_ident[EI_CLASS] == ELFCLASS64) {
-        ret = load_elf64(fd, virt_to_phys_addend, must_swab);
+        ret = load_elf64(fd, virt_to_phys_addend, must_swab, entry);
     } else {
-        ret = load_elf32(fd, virt_to_phys_addend, must_swab);
+        ret = load_elf32(fd, virt_to_phys_addend, must_swab, entry);
     }
 
     close(fd);
Index: qemu-work/vl.h
===================================================================
--- qemu-work.orig/vl.h	2006-04-25 23:22:22.000000000 +0100
+++ qemu-work/vl.h	2006-04-25 23:22:25.000000000 +0100
@@ -872,7 +872,7 @@
 /* loader.c */
 int get_image_size(const char *filename);
 int load_image(const char *filename, uint8_t *addr);
-int load_elf(const char *filename, int64_t virt_to_phys_addend);
+int load_elf(const char *filename, int64_t virt_to_phys_addend, int64_t *entry);
 int load_aout(const char *filename, uint8_t *addr);
 
 /* slavio_timer.c */

  reply	other threads:[~2006-04-25 23:57 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
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 [this message]
     [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=20060425235713.GA29550@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.