[Top][All Lists]
[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 */
- [Qemu-devel] [PATCH] Add MIPS ELF loader,
Dirk Behme <=