summaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
authorBlue Swirl <blauwirbel@gmail.com>2009-09-20 14:58:02 +0000
committerBlue Swirl <blauwirbel@gmail.com>2009-09-20 14:58:02 +0000
commitca20cf32ab3d945155141ef737f5d08ebb373e1d (patch)
tree45515350fdf7b5322658095beec591565a78506d /hw
parenta333cd7166d12397635e16dcade28da5ba8ec7b3 (diff)
downloadqemu-ca20cf32ab3d945155141ef737f5d08ebb373e1d.tar.gz
qemu-ca20cf32ab3d945155141ef737f5d08ebb373e1d.tar.bz2
qemu-ca20cf32ab3d945155141ef737f5d08ebb373e1d.zip
Compile loader only once
Callers must pass ELF machine, byte swapping and symbol LSB clearing information to ELF loader. A.out loader needs page size information, pass that too as a parameter. Extract prototypes to a separate file. Move loader.[ch] and elf_ops.h under hw. Adjust callers. Also use target_phys_addr_t instead of target_ulong for addresses: loader addresses aren't virtual. Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
Diffstat (limited to 'hw')
-rw-r--r--hw/an5206.c7
-rw-r--r--hw/arm_boot.c14
-rw-r--r--hw/armv7m.c12
-rw-r--r--hw/axis_dev88.c4
-rw-r--r--hw/dummy_m68k.c7
-rw-r--r--hw/elf_ops.h274
-rw-r--r--hw/etraxfs.c4
-rw-r--r--hw/loader.c546
-rw-r--r--hw/loader.h21
-rw-r--r--hw/mcf5208.c7
-rw-r--r--hw/mips_jazz.c1
-rw-r--r--hw/mips_malta.c11
-rw-r--r--hw/mips_mipssim.c11
-rw-r--r--hw/mips_r4k.c10
-rw-r--r--hw/nseries.c1
-rw-r--r--hw/palm.c1
-rw-r--r--hw/pc.c5
-rw-r--r--hw/petalogix_s3adsp1800_mmu.c8
-rw-r--r--hw/ppc.c1
-rw-r--r--hw/ppc405_boards.c1
-rw-r--r--hw/ppc440_bamboo.c8
-rw-r--r--hw/ppc_newworld.c20
-rw-r--r--hw/ppc_oldworld.c20
-rw-r--r--hw/ppc_prep.c1
-rw-r--r--hw/ppce500_mpc8544ds.c8
-rw-r--r--hw/r2d.c1
-rw-r--r--hw/shix.c1
-rw-r--r--hw/smbios.c1
-rw-r--r--hw/sun4m.c17
-rw-r--r--hw/sun4u.c18
-rw-r--r--hw/tc58128.c1
31 files changed, 1005 insertions, 37 deletions
diff --git a/hw/an5206.c b/hw/an5206.c
index d417d923b9..a4b83b0f44 100644
--- a/hw/an5206.c
+++ b/hw/an5206.c
@@ -11,6 +11,8 @@
#include "mcf.h"
#include "sysemu.h"
#include "boards.h"
+#include "loader.h"
+#include "elf.h"
#define KERNEL_LOAD_ADDR 0x10000
#define AN5206_MBAR_ADDR 0x10000000
@@ -35,7 +37,7 @@ static void an5206_init(ram_addr_t ram_size,
CPUState *env;
int kernel_size;
uint64_t elf_entry;
- target_ulong entry;
+ target_phys_addr_t entry;
if (!cpu_model)
cpu_model = "m5206";
@@ -66,7 +68,8 @@ static void an5206_init(ram_addr_t ram_size,
exit(1);
}
- kernel_size = load_elf(kernel_filename, 0, &elf_entry, NULL, NULL);
+ kernel_size = load_elf(kernel_filename, 0, &elf_entry, NULL, NULL,
+ 1, ELF_MACHINE, 0);
entry = elf_entry;
if (kernel_size < 0) {
kernel_size = load_uimage(kernel_filename, &entry, NULL, NULL);
diff --git a/hw/arm_boot.c b/hw/arm_boot.c
index 35f0130db1..a8a38c5a36 100644
--- a/hw/arm_boot.c
+++ b/hw/arm_boot.c
@@ -10,6 +10,8 @@
#include "hw.h"
#include "arm-misc.h"
#include "sysemu.h"
+#include "loader.h"
+#include "elf.h"
#define KERNEL_ARGS_ADDR 0x100
#define KERNEL_LOAD_ADDR 0x00010000
@@ -191,7 +193,8 @@ void arm_load_kernel(CPUState *env, struct arm_boot_info *info)
int n;
int is_linux = 0;
uint64_t elf_entry;
- target_ulong entry;
+ target_phys_addr_t entry;
+ int big_endian;
/* Load the kernel. */
if (!info->kernel_filename) {
@@ -206,8 +209,15 @@ void arm_load_kernel(CPUState *env, struct arm_boot_info *info)
qemu_register_reset(main_cpu_reset, env);
}
+#ifdef TARGET_WORDS_BIGENDIAN
+ big_endian = 1;
+#else
+ big_endian = 0;
+#endif
+
/* Assume that raw images are linux kernels, and ELF images are not. */
- kernel_size = load_elf(info->kernel_filename, 0, &elf_entry, NULL, NULL);
+ kernel_size = load_elf(info->kernel_filename, 0, &elf_entry, NULL, NULL,
+ big_endian, ELF_MACHINE, 1);
entry = elf_entry;
if (kernel_size < 0) {
kernel_size = load_uimage(info->kernel_filename, &entry, NULL,
diff --git a/hw/armv7m.c b/hw/armv7m.c
index 059a356e21..a96288d0dd 100644
--- a/hw/armv7m.c
+++ b/hw/armv7m.c
@@ -10,6 +10,8 @@
#include "sysbus.h"
#include "arm-misc.h"
#include "sysemu.h"
+#include "loader.h"
+#include "elf.h"
/* Bitbanded IO. Each word corresponds to a single bit. */
@@ -166,6 +168,7 @@ qemu_irq *armv7m_init(int flash_size, int sram_size,
uint64_t entry;
uint64_t lowaddr;
int i;
+ int big_endian;
flash_size *= 1024;
sram_size *= 1024;
@@ -206,7 +209,14 @@ qemu_irq *armv7m_init(int flash_size, int sram_size,
pic[i] = qdev_get_gpio_in(nvic, i);
}
- image_size = load_elf(kernel_filename, 0, &entry, &lowaddr, NULL);
+#ifdef TARGET_WORDS_BIGENDIAN
+ big_endian = 1;
+#else
+ big_endian = 0;
+#endif
+
+ image_size = load_elf(kernel_filename, 0, &entry, &lowaddr, NULL,
+ big_endian, ELF_MACHINE, 1);
if (image_size < 0) {
image_size = load_image_targphys(kernel_filename, 0, flash_size);
lowaddr = 0;
diff --git a/hw/axis_dev88.c b/hw/axis_dev88.c
index b5163b655f..81a41c9446 100644
--- a/hw/axis_dev88.c
+++ b/hw/axis_dev88.c
@@ -28,6 +28,8 @@
#include "boards.h"
#include "sysemu.h"
#include "etraxfs.h"
+#include "loader.h"
+#include "elf.h"
#define D(x)
#define DNAND(x)
@@ -344,7 +346,7 @@ void axisdev88_init (ram_addr_t ram_size,
/* Boots a kernel elf binary, os/linux-2.6/vmlinux from the axis
devboard SDK. */
kernel_size = load_elf(kernel_filename, -0x80000000LL,
- &entry, NULL, &high);
+ &entry, NULL, &high, 0, ELF_MACHINE, 0);
bootstrap_pc = entry;
if (kernel_size < 0) {
/* Takes a kimage from the axis devboard SDK. */
diff --git a/hw/dummy_m68k.c b/hw/dummy_m68k.c
index 5718ab64e1..ce45a597db 100644
--- a/hw/dummy_m68k.c
+++ b/hw/dummy_m68k.c
@@ -9,6 +9,8 @@
#include "hw.h"
#include "sysemu.h"
#include "boards.h"
+#include "loader.h"
+#include "elf.h"
#define KERNEL_LOAD_ADDR 0x10000
@@ -22,7 +24,7 @@ static void dummy_m68k_init(ram_addr_t ram_size,
CPUState *env;
int kernel_size;
uint64_t elf_entry;
- target_ulong entry;
+ target_phys_addr_t entry;
if (!cpu_model)
cpu_model = "cfv4e";
@@ -41,7 +43,8 @@ static void dummy_m68k_init(ram_addr_t ram_size,
/* Load kernel. */
if (kernel_filename) {
- kernel_size = load_elf(kernel_filename, 0, &elf_entry, NULL, NULL);
+ kernel_size = load_elf(kernel_filename, 0, &elf_entry, NULL, NULL,
+ 1, ELF_MACHINE, 0);
entry = elf_entry;
if (kernel_size < 0) {
kernel_size = load_uimage(kernel_filename, &entry, NULL, NULL);
diff --git a/hw/elf_ops.h b/hw/elf_ops.h
new file mode 100644
index 0000000000..8376465a10
--- /dev/null
+++ b/hw/elf_ops.h
@@ -0,0 +1,274 @@
+static void glue(bswap_ehdr, SZ)(struct elfhdr *ehdr)
+{
+ bswap16s(&ehdr->e_type); /* Object file type */
+ bswap16s(&ehdr->e_machine); /* Architecture */
+ bswap32s(&ehdr->e_version); /* Object file version */
+ bswapSZs(&ehdr->e_entry); /* Entry point virtual address */
+ bswapSZs(&ehdr->e_phoff); /* Program header table file offset */
+ bswapSZs(&ehdr->e_shoff); /* Section header table file offset */
+ bswap32s(&ehdr->e_flags); /* Processor-specific flags */
+ bswap16s(&ehdr->e_ehsize); /* ELF header size in bytes */
+ bswap16s(&ehdr->e_phentsize); /* Program header table entry size */
+ bswap16s(&ehdr->e_phnum); /* Program header table entry count */
+ bswap16s(&ehdr->e_shentsize); /* Section header table entry size */
+ bswap16s(&ehdr->e_shnum); /* Section header table entry count */
+ bswap16s(&ehdr->e_shstrndx); /* Section header string table index */
+}
+
+static void glue(bswap_phdr, SZ)(struct elf_phdr *phdr)
+{
+ bswap32s(&phdr->p_type); /* Segment type */
+ bswapSZs(&phdr->p_offset); /* Segment file offset */
+ bswapSZs(&phdr->p_vaddr); /* Segment virtual address */
+ bswapSZs(&phdr->p_paddr); /* Segment physical address */
+ bswapSZs(&phdr->p_filesz); /* Segment size in file */
+ bswapSZs(&phdr->p_memsz); /* Segment size in memory */
+ bswap32s(&phdr->p_flags); /* Segment flags */
+ bswapSZs(&phdr->p_align); /* Segment alignment */
+}
+
+static void glue(bswap_shdr, SZ)(struct elf_shdr *shdr)
+{
+ bswap32s(&shdr->sh_name);
+ bswap32s(&shdr->sh_type);
+ bswapSZs(&shdr->sh_flags);
+ bswapSZs(&shdr->sh_addr);
+ bswapSZs(&shdr->sh_offset);
+ bswapSZs(&shdr->sh_size);
+ bswap32s(&shdr->sh_link);
+ bswap32s(&shdr->sh_info);
+ bswapSZs(&shdr->sh_addralign);
+ bswapSZs(&shdr->sh_entsize);
+}
+
+static void glue(bswap_sym, SZ)(struct elf_sym *sym)
+{
+ bswap32s(&sym->st_name);
+ bswapSZs(&sym->st_value);
+ bswapSZs(&sym->st_size);
+ bswap16s(&sym->st_shndx);
+}
+
+static struct elf_shdr *glue(find_section, SZ)(struct elf_shdr *shdr_table,
+ int n, int type)
+{
+ int i;
+ for(i=0;i<n;i++) {
+ if (shdr_table[i].sh_type == type)
+ return shdr_table + i;
+ }
+ return NULL;
+}
+
+static int glue(symfind, SZ)(const void *s0, const void *s1)
+{
+ struct elf_sym *key = (struct elf_sym *)s0;
+ struct elf_sym *sym = (struct elf_sym *)s1;
+ int result = 0;
+ if (key->st_value < sym->st_value) {
+ result = -1;
+ } else if (key->st_value >= sym->st_value + sym->st_size) {
+ result = 1;
+ }
+ return result;
+}
+
+static const char *glue(lookup_symbol, SZ)(struct syminfo *s,
+ target_phys_addr_t orig_addr)
+{
+ struct elf_sym *syms = glue(s->disas_symtab.elf, SZ);
+ struct elf_sym key;
+ struct elf_sym *sym;
+
+ key.st_value = orig_addr;
+
+ sym = bsearch(&key, syms, s->disas_num_syms, sizeof(*syms), glue(symfind, SZ));
+ if (sym != NULL) {
+ return s->disas_strtab + sym->st_name;
+ }
+
+ return "";
+}
+
+static int glue(symcmp, SZ)(const void *s0, const void *s1)
+{
+ struct elf_sym *sym0 = (struct elf_sym *)s0;
+ struct elf_sym *sym1 = (struct elf_sym *)s1;
+ return (sym0->st_value < sym1->st_value)
+ ? -1
+ : ((sym0->st_value > sym1->st_value) ? 1 : 0);
+}
+
+static int glue(load_symbols, SZ)(struct elfhdr *ehdr, int fd, int must_swab,
+ int clear_lsb)
+{
+ struct elf_shdr *symtab, *strtab, *shdr_table = NULL;
+ struct elf_sym *syms = NULL;
+ struct syminfo *s;
+ int nsyms, i;
+ char *str = NULL;
+
+ shdr_table = load_at(fd, ehdr->e_shoff,
+ sizeof(struct elf_shdr) * ehdr->e_shnum);
+ if (!shdr_table)
+ return -1;
+
+ if (must_swab) {
+ for (i = 0; i < ehdr->e_shnum; i++) {
+ glue(bswap_shdr, SZ)(shdr_table + i);
+ }
+ }
+
+ symtab = glue(find_section, SZ)(shdr_table, ehdr->e_shnum, SHT_SYMTAB);
+ if (!symtab)
+ goto fail;
+ syms = load_at(fd, symtab->sh_offset, symtab->sh_size);
+ if (!syms)
+ goto fail;
+
+ nsyms = symtab->sh_size / sizeof(struct elf_sym);
+
+ i = 0;
+ while (i < nsyms) {
+ if (must_swab)
+ glue(bswap_sym, SZ)(&syms[i]);
+ /* We are only interested in function symbols.
+ Throw everything else away. */
+ if (syms[i].st_shndx == SHN_UNDEF ||
+ syms[i].st_shndx >= SHN_LORESERVE ||
+ ELF_ST_TYPE(syms[i].st_info) != STT_FUNC) {
+ nsyms--;
+ if (i < nsyms) {
+ syms[i] = syms[nsyms];
+ }
+ continue;
+ }
+ if (clear_lsb) {
+ /* The bottom address bit marks a Thumb or MIPS16 symbol. */
+ syms[i].st_value &= ~(glue(glue(Elf, SZ), _Addr))1;
+ }
+ i++;
+ }
+ syms = qemu_realloc(syms, nsyms * sizeof(*syms));
+
+ qsort(syms, nsyms, sizeof(*syms), glue(symcmp, SZ));
+
+ /* String table */
+ if (symtab->sh_link >= ehdr->e_shnum)
+ goto fail;
+ strtab = &shdr_table[symtab->sh_link];
+
+ str = load_at(fd, strtab->sh_offset, strtab->sh_size);
+ if (!str)
+ goto fail;
+
+ /* Commit */
+ s = qemu_mallocz(sizeof(*s));
+ s->lookup_symbol = glue(lookup_symbol, SZ);
+ glue(s->disas_symtab.elf, SZ) = syms;
+ s->disas_num_syms = nsyms;
+ s->disas_strtab = str;
+ s->next = syminfos;
+ syminfos = s;
+ qemu_free(shdr_table);
+ return 0;
+ fail:
+ qemu_free(syms);
+ qemu_free(str);
+ qemu_free(shdr_table);
+ return -1;
+}
+
+static int glue(load_elf, SZ)(int fd, int64_t address_offset,
+ int must_swab, uint64_t *pentry,
+ uint64_t *lowaddr, uint64_t *highaddr,
+ int elf_machine, int clear_lsb)
+{
+ struct elfhdr ehdr;
+ struct elf_phdr *phdr = NULL, *ph;
+ int size, i, total_size;
+ elf_word mem_size;
+ uint64_t addr, low = (uint64_t)-1, high = 0;
+ uint8_t *data = NULL;
+
+ if (read(fd, &ehdr, sizeof(ehdr)) != sizeof(ehdr))
+ goto fail;
+ if (must_swab) {
+ glue(bswap_ehdr, SZ)(&ehdr);
+ }
+
+ switch (elf_machine) {
+ case EM_PPC64:
+ if (EM_PPC64 != ehdr.e_machine)
+ if (EM_PPC != ehdr.e_machine)
+ goto fail;
+ break;
+ case EM_X86_64:
+ if (EM_X86_64 != ehdr.e_machine)
+ if (EM_386 != ehdr.e_machine)
+ goto fail;
+ break;
+ default:
+ if (elf_machine != ehdr.e_machine)
+ goto fail;
+ }
+
+ if (pentry)
+ *pentry = (uint64_t)(elf_sword)ehdr.e_entry;
+
+ glue(load_symbols, SZ)(&ehdr, fd, must_swab, clear_lsb);
+
+ size = ehdr.e_phnum * sizeof(phdr[0]);
+ lseek(fd, ehdr.e_phoff, SEEK_SET);
+ phdr = qemu_mallocz(size);
+ if (!phdr)
+ goto fail;
+ if (read(fd, phdr, size) != size)
+ goto fail;
+ if (must_swab) {
+ for(i = 0; i < ehdr.e_phnum; i++) {
+ ph = &phdr[i];
+ glue(bswap_phdr, SZ)(ph);
+ }
+ }
+
+ total_size = 0;
+ for(i = 0; i < ehdr.e_phnum; i++) {
+ ph = &phdr[i];
+ if (ph->p_type == PT_LOAD) {
+ mem_size = ph->p_memsz;
+ /* XXX: avoid allocating */
+ data = qemu_mallocz(mem_size);
+ if (ph->p_filesz > 0) {
+ if (lseek(fd, ph->p_offset, SEEK_SET) < 0)
+ goto fail;
+ if (read(fd, data, ph->p_filesz) != ph->p_filesz)
+ goto fail;
+ }
+ /* address_offset is hack for kernel images that are
+ linked at the wrong physical address. */
+ addr = ph->p_paddr + address_offset;
+
+ cpu_physical_memory_write_rom(addr, data, mem_size);
+
+ total_size += mem_size;
+ if (addr < low)
+ low = addr;
+ if ((addr + mem_size) > high)
+ high = addr + mem_size;
+
+ qemu_free(data);
+ data = NULL;
+ }
+ }
+ qemu_free(phdr);
+ if (lowaddr)
+ *lowaddr = (uint64_t)(elf_sword)low;
+ if (highaddr)
+ *highaddr = (uint64_t)(elf_sword)high;
+ return total_size;
+ fail:
+ qemu_free(data);
+ qemu_free(phdr);
+ return -1;
+}
diff --git a/hw/etraxfs.c b/hw/etraxfs.c
index ab6a3a302f..4f451c54c9 100644
--- a/hw/etraxfs.c
+++ b/hw/etraxfs.c
@@ -28,6 +28,8 @@
#include "net.h"
#include "flash.h"
#include "etraxfs.h"
+#include "loader.h"
+#include "elf.h"
#define FLASH_SIZE 0x2000000
#define INTMEM_SIZE (128 * 1024)
@@ -136,7 +138,7 @@ void bareetraxfs_init (ram_addr_t ram_size,
/* Boots a kernel elf binary, os/linux-2.6/vmlinux from the axis
devboard SDK. */
kernel_size = load_elf(kernel_filename, -0x80000000LL,
- &entry, NULL, &high);
+ &entry, NULL, &high, 0, ELF_MACHINE, 0);
bootstrap_pc = entry;
if (kernel_size < 0) {
/* Takes a kimage from the axis devboard SDK. */
diff --git a/hw/loader.c b/hw/loader.c
new file mode 100644
index 0000000000..5d83a66041
--- /dev/null
+++ b/hw/loader.c
@@ -0,0 +1,546 @@
+/*
+ * QEMU Executable loader
+ *
+ * Copyright (c) 2006 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * Gunzip functionality in this file is derived from u-boot:
+ *
+ * (C) Copyright 2008 Semihalf
+ *
+ * (C) Copyright 2000-2005
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "hw.h"
+#include "disas.h"
+#include "sysemu.h"
+#include "uboot_image.h"
+#include "loader.h"
+
+#include <zlib.h>
+
+/* return the size or -1 if error */
+int get_image_size(const char *filename)
+{
+ int fd, size;
+ fd = open(filename, O_RDONLY | O_BINARY);
+ if (fd < 0)
+ return -1;
+ size = lseek(fd, 0, SEEK_END);
+ close(fd);
+ return size;
+}
+
+/* return the size or -1 if error */
+/* deprecated, because caller does not specify buffer size! */
+int load_image(const char *filename, uint8_t *addr)
+{
+ int fd, size;
+ fd = open(filename, O_RDONLY | O_BINARY);
+ if (fd < 0)
+ return -1;
+ size = lseek(fd, 0, SEEK_END);
+ lseek(fd, 0, SEEK_SET);
+ if (read(fd, addr, size) != size) {
+ close(fd);
+ return -1;
+ }
+ close(fd);
+ return size;
+}
+
+/* return the amount read, just like fread. 0 may mean error or eof */
+int fread_targphys(target_phys_addr_t dst_addr, size_t nbytes, FILE *f)
+{
+ uint8_t buf[4096];
+ target_phys_addr_t dst_begin = dst_addr;
+ size_t want, did;
+
+ while (nbytes) {
+ want = nbytes > sizeof(buf) ? sizeof(buf) : nbytes;
+ did = fread(buf, 1, want, f);
+
+ cpu_physical_memory_write_rom(dst_addr, buf, did);
+ dst_addr += did;
+ nbytes -= did;
+ if (did != want)
+ break;
+ }
+ return dst_addr - dst_begin;
+}
+
+/* returns 0 on error, 1 if ok */
+int fread_targphys_ok(target_phys_addr_t dst_addr, size_t nbytes, FILE *f)
+{
+ return fread_targphys(dst_addr, nbytes, f) == nbytes;
+}
+
+/* read()-like version */
+int read_targphys(int fd, target_phys_addr_t dst_addr, size_t nbytes)
+{
+ uint8_t buf[4096];
+ target_phys_addr_t dst_begin = dst_addr;
+ size_t want, did;
+
+ while (nbytes) {
+ want = nbytes > sizeof(buf) ? sizeof(buf) : nbytes;
+ did = read(fd, buf, want);
+ if (did != want) break;
+
+ cpu_physical_memory_write_rom(dst_addr, buf, did);
+ dst_addr += did;
+ nbytes -= did;
+ }
+ return dst_addr - dst_begin;
+}
+
+/* return the size or -1 if error */
+int load_image_targphys(const char *filename,
+ target_phys_addr_t addr, int max_sz)
+{
+ FILE *f;
+ size_t got;
+
+ f = fopen(filename, "rb");
+ if (!f) return -1;
+
+ got = fread_targphys(addr, max_sz, f);
+ if (ferror(f)) { fclose(f); return -1; }
+ fclose(f);
+
+ return got;
+}
+
+void pstrcpy_targphys(target_phys_addr_t dest, int buf_size,
+ const char *source)
+{
+ static const uint8_t nul_byte = 0;
+ const char *nulp;
+
+ if (buf_size <= 0) return;
+ nulp = memchr(source, 0, buf_size);
+ if (nulp) {
+ cpu_physical_memory_write_rom(dest, (uint8_t *)source,
+ (nulp - source) + 1);
+ } else {
+ cpu_physical_memory_write_rom(dest, (uint8_t *)source, buf_size - 1);
+ cpu_physical_memory_write_rom(dest, &nul_byte, 1);
+ }
+}
+
+/* A.OUT loader */
+
+struct exec
+{
+ uint32_t a_info; /* Use macros N_MAGIC, etc for access */
+ uint32_t a_text; /* length of text, in bytes */
+ uint32_t a_data; /* length of data, in bytes */
+ uint32_t a_bss; /* length of uninitialized data area, in bytes */
+ uint32_t a_syms; /* length of symbol table data in file, in bytes */
+ uint32_t a_entry; /* start address */
+ uint32_t a_trsize; /* length of relocation info for text, in bytes */
+ uint32_t a_drsize; /* length of relocation info for data, in bytes */
+};
+
+static void bswap_ahdr(struct exec *e)
+{
+ bswap32s(&e->a_info);
+ bswap32s(&e->a_text);
+ bswap32s(&e->a_data);
+ bswap32s(&e->a_bss);
+ bswap32s(&e->a_syms);
+ bswap32s(&e->a_entry);
+ bswap32s(&e->a_trsize);
+ bswap32s(&e->a_drsize);
+}
+
+#define N_MAGIC(exec) ((exec).a_info & 0xffff)
+#define OMAGIC 0407
+#define NMAGIC 0410
+#define ZMAGIC 0413
+#define QMAGIC 0314
+#define _N_HDROFF(x) (1024 - sizeof (struct exec))
+#define N_TXTOFF(x) \
+ (N_MAGIC(x) == ZMAGIC ? _N_HDROFF((x)) + sizeof (struct exec) : \
+ (N_MAGIC(x) == QMAGIC ? 0 : sizeof (struct exec)))
+#define N_TXTADDR(x, target_page_size) (N_MAGIC(x) == QMAGIC ? target_page_size : 0)
+#define _N_SEGMENT_ROUND(x, target_page_size) (((x) + target_page_size - 1) & ~(target_page_size - 1))
+
+#define _N_TXTENDADDR(x, target_page_size) (N_TXTADDR(x, target_page_size)+(x).a_text)
+
+#define N_DATADDR(x, target_page_size) \
+ (N_MAGIC(x)==OMAGIC? (_N_TXTENDADDR(x, target_page_size)) \
+ : (_N_SEGMENT_ROUND (_N_TXTENDADDR(x, target_page_size), target_page_size)))
+
+
+int load_aout(const char *filename, target_phys_addr_t addr, int max_sz,
+ int bswap_needed, target_phys_addr_t target_page_size)
+{
+ int fd, size, ret;
+ struct exec e;
+ uint32_t magic;
+
+ fd = open(filename, O_RDONLY | O_BINARY);
+ if (fd < 0)
+ return -1;
+
+ size = read(fd, &e, sizeof(e));
+ if (size < 0)
+ goto fail;
+
+ if (bswap_needed) {
+ bswap_ahdr(&e);
+ }
+
+ magic = N_MAGIC(e);
+ switch (magic) {
+ case ZMAGIC:
+ case QMAGIC:
+ case OMAGIC:
+ if (e.a_text + e.a_data > max_sz)
+ goto fail;
+ lseek(fd, N_TXTOFF(e), SEEK_SET);
+ size = read_targphys(fd, addr, e.a_text + e.a_data);
+ if (size < 0)
+ goto fail;
+ break;
+ case NMAGIC:
+ if (N_DATADDR(e, target_page_size) + e.a_data > max_sz)
+ goto fail;
+ lseek(fd, N_TXTOFF(e), SEEK_SET);
+ size = read_targphys(fd, addr, e.a_text);
+ if (size < 0)
+ goto fail;
+ ret = read_targphys(fd, addr + N_DATADDR(e, target_page_size),
+ e.a_data);
+ if (ret < 0)
+ goto fail;
+ size += ret;
+ break;
+ default:
+ goto fail;
+ }
+ close(fd);
+ return size;
+ fail:
+ close(fd);
+ return -1;
+}
+
+/* ELF loader */
+
+static void *load_at(int fd, int offset, int size)
+{
+ void *ptr;
+ if (lseek(fd, offset, SEEK_SET) < 0)
+ return NULL;
+ ptr = qemu_malloc(size);
+ if (read(fd, ptr, size) != size) {
+ qemu_free(ptr);
+ return NULL;
+ }
+ return ptr;
+}
+
+#ifdef ELF_CLASS
+#undef ELF_CLASS
+#endif
+
+#define ELF_CLASS ELFCLASS32
+#include "elf.h"
+
+#define SZ 32
+#define elf_word uint32_t
+#define elf_sword int32_t
+#define bswapSZs bswap32s
+#include "elf_ops.h"
+
+#undef elfhdr
+#undef elf_phdr
+#undef elf_shdr
+#undef elf_sym
+#undef elf_note
+#undef elf_word
+#undef elf_sword
+#undef bswapSZs
+#undef SZ
+#define elfhdr elf64_hdr
+#define elf_phdr elf64_phdr
+#define elf_note elf64_note
+#define elf_shdr elf64_shdr
+#define elf_sym elf64_sym
+#define elf_word uint64_t
+#define elf_sword int64_t
+#define bswapSZs bswap64s
+#define SZ 64
+#include "elf_ops.h"
+
+/* return < 0 if error, otherwise the number of bytes loaded in memory */
+int load_elf(const char *filename, int64_t address_offset,
+ uint64_t *pentry, uint64_t *lowaddr, uint64_t *highaddr,
+ int big_endian, int elf_machine, int clear_lsb)
+{
+ int fd, data_order, target_data_order, must_swab, ret;
+ uint8_t e_ident[EI_NIDENT];
+
+ fd = open(filename, O_RDONLY | O_BINARY);
+ if (fd < 0) {
+ perror(filename);
+ return -1;
+ }
+ if (read(fd, e_ident, sizeof(e_ident)) != sizeof(e_ident))
+ goto fail;
+ if (e_ident[0] != ELFMAG0 ||
+ e_ident[1] != ELFMAG1 ||
+ e_ident[2] != ELFMAG2 ||
+ e_ident[3] != ELFMAG3)
+ goto fail;
+#ifdef HOST_WORDS_BIGENDIAN
+ data_order = ELFDATA2MSB;
+#else
+ data_order = ELFDATA2LSB;
+#endif
+ must_swab = data_order != e_ident[EI_DATA];
+ if (big_endian) {
+ target_data_order = ELFDATA2MSB;
+ } else {
+ target_data_order = ELFDATA2LSB;
+ }
+
+ if (target_data_order != e_ident[EI_DATA])
+ return -1;
+
+ lseek(fd, 0, SEEK_SET);
+ if (e_ident[EI_CLASS] == ELFCLASS64) {
+ ret = load_elf64(fd, address_offset, must_swab, pentry,
+ lowaddr, highaddr, elf_machine, clear_lsb);
+ } else {
+ ret = load_elf32(fd, address_offset, must_swab, pentry,
+ lowaddr, highaddr, elf_machine, clear_lsb);
+ }
+
+ close(fd);
+ return ret;
+
+ fail:
+ close(fd);
+ return -1;
+}
+
+static void bswap_uboot_header(uboot_image_header_t *hdr)
+{
+#ifndef HOST_WORDS_BIGENDIAN
+ bswap32s(&hdr->ih_magic);
+ bswap32s(&hdr->ih_hcrc);
+ bswap32s(&hdr->ih_time);
+ bswap32s(&hdr->ih_size);
+ bswap32s(&hdr->ih_load);
+ bswap32s(&hdr->ih_ep);
+ bswap32s(&hdr->ih_dcrc);
+#endif
+}
+
+
+#define ZALLOC_ALIGNMENT 16
+
+static void *zalloc(void *x, unsigned items, unsigned size)
+{
+ void *p;
+
+ size *= items;
+ size = (size + ZALLOC_ALIGNMENT - 1) & ~(ZALLOC_ALIGNMENT - 1);
+
+ p = qemu_malloc(size);
+
+ return (p);
+}
+
+static void zfree(void *x, void *addr)
+{
+ qemu_free(addr);
+}
+
+
+#define HEAD_CRC 2
+#define EXTRA_FIELD 4
+#define ORIG_NAME 8
+#define COMMENT 0x10
+#define RESERVED 0xe0
+
+#define DEFLATED 8
+
+/* This is the maximum in uboot, so if a uImage overflows this, it would
+ * overflow on real hardware too. */
+#define UBOOT_MAX_GUNZIP_BYTES 0x800000
+
+static ssize_t gunzip(void *dst, size_t dstlen, uint8_t *src,
+ size_t srclen)
+{
+ z_stream s;
+ ssize_t dstbytes;
+ int r, i, flags;
+
+ /* skip header */
+ i = 10;
+ flags = src[3];
+ if (src[2] != DEFLATED || (flags & RESERVED) != 0) {
+ puts ("Error: Bad gzipped data\n");
+ return -1;
+ }
+ if ((flags & EXTRA_FIELD) != 0)
+ i = 12 + src[10] + (src[11] << 8);
+ if ((flags & ORIG_NAME) != 0)
+ while (src[i++] != 0)
+ ;
+ if ((flags & COMMENT) != 0)
+ while (src[i++] != 0)
+ ;
+ if ((flags & HEAD_CRC) != 0)
+ i += 2;
+ if (i >= srclen) {
+ puts ("Error: gunzip out of data in header\n");
+ return -1;
+ }
+
+ s.zalloc = zalloc;
+ s.zfree = zfree;
+
+ r = inflateInit2(&s, -MAX_WBITS);
+ if (r != Z_OK) {
+ printf ("Error: inflateInit2() returned %d\n", r);
+ return (-1);
+ }
+ s.next_in = src + i;
+ s.avail_in = srclen - i;
+ s.next_out = dst;
+ s.avail_out = dstlen;
+ r = inflate(&s, Z_FINISH);
+ if (r != Z_OK && r != Z_STREAM_END) {
+ printf ("Error: inflate() returned %d\n", r);
+ return -1;
+ }
+ dstbytes = s.next_out - (unsigned char *) dst;
+ inflateEnd(&s);
+
+ return dstbytes;
+}
+
+/* Load a U-Boot image. */
+int load_uimage(const char *filename, target_phys_addr_t *ep,
+ target_phys_addr_t *loadaddr, int *is_linux)
+{
+ int fd;
+ int size;
+ uboot_image_header_t h;
+ uboot_image_header_t *hdr = &h;
+ uint8_t *data = NULL;
+ int ret = -1;
+
+ fd = open(filename, O_RDONLY | O_BINARY);
+ if (fd < 0)
+ return -1;
+
+ size = read(fd, hdr, sizeof(uboot_image_header_t));
+ if (size < 0)
+ goto out;
+
+ bswap_uboot_header(hdr);
+
+ if (hdr->ih_magic != IH_MAGIC)
+ goto out;
+
+ /* TODO: Implement other image types. */
+ if (hdr->ih_type != IH_TYPE_KERNEL) {
+ fprintf(stderr, "Can only load u-boot image type \"kernel\"\n");
+ goto out;
+ }
+
+ switch (hdr->ih_comp) {
+ case IH_COMP_NONE:
+ case IH_COMP_GZIP:
+ break;
+ default:
+ fprintf(stderr,
+ "Unable to load u-boot images with compression type %d\n",
+ hdr->ih_comp);
+ goto out;
+ }
+
+ /* TODO: Check CPU type. */
+ if (is_linux) {
+ if (hdr->ih_os == IH_OS_LINUX)
+ *is_linux = 1;
+ else
+ *is_linux = 0;
+ }
+
+ *ep = hdr->ih_ep;
+ data = qemu_malloc(hdr->ih_size);
+
+ if (read(fd, data, hdr->ih_size) != hdr->ih_size) {
+ fprintf(stderr, "Error reading file\n");
+ goto out;
+ }
+
+ if (hdr->ih_comp == IH_COMP_GZIP) {
+ uint8_t *compressed_data;
+ size_t max_bytes;
+ ssize_t bytes;
+
+ compressed_data = data;
+ max_bytes = UBOOT_MAX_GUNZIP_BYTES;
+ data = qemu_malloc(max_bytes);
+
+ bytes = gunzip(data, max_bytes, compressed_data, hdr->ih_size);
+ qemu_free(compressed_data);
+ if (bytes < 0) {
+ fprintf(stderr, "Unable to decompress gzipped image!\n");
+ goto out;
+ }
+ hdr->ih_size = bytes;
+ }
+
+ cpu_physical_memory_write_rom(hdr->ih_load, data, hdr->ih_size);
+
+ if (loadaddr)
+ *loadaddr = hdr->ih_load;
+
+ ret = hdr->ih_size;
+
+out:
+ if (data)
+ qemu_free(data);
+ close(fd);
+ return ret;
+}
diff --git a/hw/loader.h b/hw/loader.h
new file mode 100644
index 0000000000..3632008928
--- /dev/null
+++ b/hw/loader.h
@@ -0,0 +1,21 @@
+#ifndef LOADER_H
+#define LOADER_H
+
+/* loader.c */
+int get_image_size(const char *filename);
+int load_image(const char *filename, uint8_t *addr); /* deprecated */
+int load_image_targphys(const char *filename, target_phys_addr_t, int max_sz);
+int load_elf(const char *filename, int64_t address_offset,
+ uint64_t *pentry, uint64_t *lowaddr, uint64_t *highaddr,
+ int big_endian, int elf_machine, int clear_lsb);
+int load_aout(const char *filename, target_phys_addr_t addr, int max_sz,
+ int bswap_needed, target_phys_addr_t target_page_size);
+int load_uimage(const char *filename, target_phys_addr_t *ep,
+ target_phys_addr_t *loadaddr, int *is_linux);
+
+int fread_targphys(target_phys_addr_t dst_addr, size_t nbytes, FILE *f);
+int fread_targphys_ok(target_phys_addr_t dst_addr, size_t nbytes, FILE *f);
+int read_targphys(int fd, target_phys_addr_t dst_addr, size_t nbytes);
+void pstrcpy_targphys(target_phys_addr_t dest, int buf_size,
+ const char *source);
+#endif
diff --git a/hw/mcf5208.c b/hw/mcf5208.c
index 95a03fc0e6..5598611462 100644
--- a/hw/mcf5208.c
+++ b/hw/mcf5208.c
@@ -11,6 +11,8 @@
#include "sysemu.h"
#include "net.h"
#include "boards.h"
+#include "loader.h"
+#include "elf.h"
#define SYS_FREQ 66000000
@@ -201,7 +203,7 @@ static void mcf5208evb_init(ram_addr_t ram_size,
CPUState *env;
int kernel_size;
uint64_t elf_entry;
- target_ulong entry;
+ target_phys_addr_t entry;
qemu_irq *pic;
if (!cpu_model)
@@ -268,7 +270,8 @@ static void mcf5208evb_init(ram_addr_t ram_size,
exit(1);
}
- kernel_size = load_elf(kernel_filename, 0, &elf_entry, NULL, NULL);
+ kernel_size = load_elf(kernel_filename, 0, &elf_entry, NULL, NULL,
+ 1, ELF_MACHINE, 0);
entry = elf_entry;
if (kernel_size < 0) {
kernel_size = load_uimage(kernel_filename, &entry, NULL, NULL);
diff --git a/hw/mips_jazz.c b/hw/mips_jazz.c
index d62a584a9a..1a499fa397 100644
--- a/hw/mips_jazz.c
+++ b/hw/mips_jazz.c
@@ -33,6 +33,7 @@
#include "net.h"
#include "scsi.h"
#include "mips-bios.h"
+#include "loader.h"
enum jazz_model_e
{
diff --git a/hw/mips_malta.c b/hw/mips_malta.c
index 0a6eaa479a..4d72da8716 100644
--- a/hw/mips_malta.c
+++ b/hw/mips_malta.c
@@ -39,6 +39,8 @@
#include "qemu-log.h"
#include "mips-bios.h"
#include "ide.h"
+#include "loader.h"
+#include "elf.h"
//#define DEBUG_BOARD_INIT
@@ -687,10 +689,17 @@ static int64_t load_kernel (CPUState *env)
int index = 0;
long initrd_size;
ram_addr_t initrd_offset;
+ int big_endian;
+
+#ifdef TARGET_WORDS_BIGENDIAN
+ big_endian = 1;
+#else
+ big_endian = 0;
+#endif
if (load_elf(loaderparams.kernel_filename, VIRT_TO_PHYS_ADDEND,
(uint64_t *)&kernel_entry, (uint64_t *)&kernel_low,
- (uint64_t *)&kernel_high) < 0) {
+ (uint64_t *)&kernel_high, big_endian, ELF_MACHINE, 1) < 0) {
fprintf(stderr, "qemu: could not load kernel '%s'\n",
loaderparams.kernel_filename);
exit(1);
diff --git a/hw/mips_mipssim.c b/hw/mips_mipssim.c
index 6080dc825e..9aed40e1bd 100644
--- a/hw/mips_mipssim.c
+++ b/hw/mips_mipssim.c
@@ -32,6 +32,8 @@
#include "sysemu.h"
#include "boards.h"
#include "mips-bios.h"
+#include "loader.h"
+#include "elf.h"
#ifdef TARGET_MIPS64
#define PHYS_TO_VIRT(x) ((x) | ~0x7fffffffULL)
@@ -54,10 +56,17 @@ static void load_kernel (CPUState *env)
long kernel_size;
long initrd_size;
ram_addr_t initrd_offset;
+ int big_endian;
+
+#ifdef TARGET_WORDS_BIGENDIAN
+ big_endian = 1;
+#else
+ big_endian = 0;
+#endif
kernel_size = load_elf(loaderparams.kernel_filename, VIRT_TO_PHYS_ADDEND,
(uint64_t *)&entry, (uint64_t *)&kernel_low,
- (uint64_t *)&kernel_high);
+ (uint64_t *)&kernel_high, big_endian, ELF_MACHINE, 1);
if (kernel_size >= 0) {
if ((entry & ~0x7fffffffULL) == 0x80000000)
entry = (int32_t)entry;
diff --git a/hw/mips_r4k.c b/hw/mips_r4k.c
index fcc7fed5f1..b3abc61551 100644
--- a/hw/mips_r4k.c
+++ b/hw/mips_r4k.c
@@ -18,6 +18,8 @@
#include "qemu-log.h"
#include "mips-bios.h"
#include "ide.h"
+#include "loader.h"
+#include "elf.h"
#define PHYS_TO_VIRT(x) ((x) | ~(target_ulong)0x7fffffff)
@@ -77,10 +79,16 @@ static void load_kernel (CPUState *env)
long kernel_size, initrd_size;
ram_addr_t initrd_offset;
int ret;
+ int big_endian;
+#ifdef TARGET_WORDS_BIGENDIAN
+ big_endian = 1;
+#else
+ big_endian = 0;
+#endif
kernel_size = load_elf(loaderparams.kernel_filename, VIRT_TO_PHYS_ADDEND,
(uint64_t *)&entry, (uint64_t *)&kernel_low,
- (uint64_t *)&kernel_high);
+ (uint64_t *)&kernel_high, big_endian, ELF_MACHINE, 1);
if (kernel_size >= 0) {
if ((entry & ~0x7fffffffULL) == 0x80000000)
entry = (int32_t)entry;
diff --git a/hw/nseries.c b/hw/nseries.c
index e9b68a7f10..066a0f980f 100644
--- a/hw/nseries.c
+++ b/hw/nseries.c
@@ -30,6 +30,7 @@
#include "flash.h"
#include "hw.h"
#include "bt.h"
+#include "loader.h"
/* Nokia N8x0 support */
struct n800_s {
diff --git a/hw/palm.c b/hw/palm.c
index bba972276e..6d19167512 100644
--- a/hw/palm.c
+++ b/hw/palm.c
@@ -24,6 +24,7 @@
#include "boards.h"
#include "arm-misc.h"
#include "devices.h"
+#include "loader.h"
static uint32_t static_readb(void *opaque, target_phys_addr_t offset)
{
diff --git a/hw/pc.c b/hw/pc.c
index 58de372da6..bc2875e36d 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -37,6 +37,8 @@
#include "watchdog.h"
#include "smbios.h"
#include "ide.h"
+#include "loader.h"
+#include "elf.h"
/* output Bochs bios info messages */
//#define DEBUG_BIOS
@@ -657,7 +659,8 @@ static int load_multiboot(void *fw_cfg,
uint64_t elf_entry;
int kernel_size;
fclose(f);
- kernel_size = load_elf(kernel_filename, 0, &elf_entry, NULL, NULL);
+ kernel_size = load_elf(kernel_filename, 0, &elf_entry, NULL, NULL,
+ 0, ELF_MACHINE, 0);
if (kernel_size < 0) {
fprintf(stderr, "Error while loading elf kernel\n");
exit(1);
diff --git a/hw/petalogix_s3adsp1800_mmu.c b/hw/petalogix_s3adsp1800_mmu.c
index a04794d7f3..f343dbf7b8 100644
--- a/hw/petalogix_s3adsp1800_mmu.c
+++ b/hw/petalogix_s3adsp1800_mmu.c
@@ -32,6 +32,8 @@
#include "boards.h"
#include "device_tree.h"
#include "xilinx.h"
+#include "loader.h"
+#include "elf.h"
#define LMB_BRAM_SIZE (128 * 1024)
#define FLASH_SIZE (16 * 1024 * 1024)
@@ -155,11 +157,13 @@ petalogix_s3adsp1800_init(ram_addr_t ram_size,
/* Boots a kernel elf binary. */
kernel_size = load_elf(kernel_filename, 0,
- &entry, &low, &high);
+ &entry, &low, &high,
+ 1, ELF_MACHINE, 0);
base32 = entry;
if (base32 == 0xc0000000) {
kernel_size = load_elf(kernel_filename, -0x30000000LL,
- &entry, NULL, NULL);
+ &entry, NULL, NULL,
+ 1, ELF_MACHINE, 0);
}
/* Always boot into physical ram. */
bootstrap_pc = ddr_base + (entry & 0x0fffffff);
diff --git a/hw/ppc.c b/hw/ppc.c
index 2d66b9dc59..09ee2e46dd 100644
--- a/hw/ppc.c
+++ b/hw/ppc.c
@@ -27,6 +27,7 @@
#include "sysemu.h"
#include "nvram.h"
#include "qemu-log.h"
+#include "loader.h"
//#define PPC_DEBUG_IRQ
//#define PPC_DEBUG_TB
diff --git a/hw/ppc405_boards.c b/hw/ppc405_boards.c
index 0d7860edd6..9aa99c1781 100644
--- a/hw/ppc405_boards.c
+++ b/hw/ppc405_boards.c
@@ -30,6 +30,7 @@
#include "block.h"
#include "boards.h"
#include "qemu-log.h"
+#include "loader.h"
#define BIOS_FILENAME "ppc405_rom.bin"
#define BIOS_SIZE (2048 * 1024)
diff --git a/hw/ppc440_bamboo.c b/hw/ppc440_bamboo.c
index 3c59f33099..8a6b7ced92 100644
--- a/hw/ppc440_bamboo.c
+++ b/hw/ppc440_bamboo.c
@@ -22,6 +22,8 @@
#include "kvm.h"
#include "kvm_ppc.h"
#include "device_tree.h"
+#include "loader.h"
+#include "elf.h"
#define BINARY_DEVICE_TREE_FILE "bamboo.dtb"
@@ -93,8 +95,8 @@ static void bamboo_init(ram_addr_t ram_size,
CPUState *env;
uint64_t elf_entry;
uint64_t elf_lowaddr;
- target_ulong entry = 0;
- target_ulong loadaddr = 0;
+ target_phys_addr_t entry = 0;
+ target_phys_addr_t loadaddr = 0;
target_long kernel_size = 0;
target_ulong initrd_base = 0;
target_long initrd_size = 0;
@@ -126,7 +128,7 @@ static void bamboo_init(ram_addr_t ram_size,
kernel_size = load_uimage(kernel_filename, &entry, &loadaddr, NULL);
if (kernel_size < 0) {
kernel_size = load_elf(kernel_filename, 0, &elf_entry, &elf_lowaddr,
- NULL);
+ NULL, 1, ELF_MACHINE, 0);
entry = elf_entry;
loadaddr = elf_lowaddr;
}
diff --git a/hw/ppc_newworld.c b/hw/ppc_newworld.c
index 9a491eb7c6..6bd5234d8f 100644
--- a/hw/ppc_newworld.c
+++ b/hw/ppc_newworld.c
@@ -36,6 +36,8 @@
#include "escc.h"
#include "openpic.h"
#include "ide.h"
+#include "loader.h"
+#include "elf.h"
#define MAX_IDE_BUS 2
#define VGA_BIOS_SIZE 65536
@@ -145,7 +147,8 @@ static void ppc_core99_init (ram_addr_t ram_size,
/* Load OpenBIOS (ELF) */
if (filename) {
- bios_size = load_elf(filename, 0, NULL, NULL, NULL);
+ bios_size = load_elf(filename, 0, NULL, NULL, NULL, 1, ELF_MACHINE, 0);
+
qemu_free(filename);
} else {
bios_size = -1;
@@ -187,19 +190,28 @@ static void ppc_core99_init (ram_addr_t ram_size,
if (linux_boot) {
uint64_t lowaddr = 0;
+ int bswap_needed;
+
+#ifdef BSWAP_NEEDED
+ bswap_needed = 1;
+#else
+ bswap_needed = 0;
+#endif
kernel_base = KERNEL_LOAD_ADDR;
/* Now we can load the kernel. The first step tries to load the kernel
supposing PhysAddr = 0x00000000. If that was wrong the kernel is
loaded again, the new PhysAddr being computed from lowaddr. */
- kernel_size = load_elf(kernel_filename, kernel_base, NULL, &lowaddr, NULL);
+ kernel_size = load_elf(kernel_filename, kernel_base, NULL, &lowaddr, NULL,
+ 1, ELF_MACHINE, 0);
if (kernel_size > 0 && lowaddr != KERNEL_LOAD_ADDR) {
kernel_size = load_elf(kernel_filename, (2 * kernel_base) - lowaddr,
- NULL, NULL, NULL);
+ NULL, NULL, NULL, 1, ELF_MACHINE, 0);
}
if (kernel_size < 0)
kernel_size = load_aout(kernel_filename, kernel_base,
- ram_size - kernel_base);
+ ram_size - kernel_base, bswap_needed,
+ TARGET_PAGE_SIZE);
if (kernel_size < 0)
kernel_size = load_image_targphys(kernel_filename,
kernel_base,
diff --git a/hw/ppc_oldworld.c b/hw/ppc_oldworld.c
index 6933650711..bb8c969ca2 100644
--- a/hw/ppc_oldworld.c
+++ b/hw/ppc_oldworld.c
@@ -36,6 +36,8 @@
#include "fw_cfg.h"
#include "escc.h"
#include "ide.h"
+#include "loader.h"
+#include "elf.h"
#define MAX_IDE_BUS 2
#define VGA_BIOS_SIZE 65536
@@ -180,7 +182,8 @@ static void ppc_heathrow_init (ram_addr_t ram_size,
/* Load OpenBIOS (ELF) */
if (filename) {
- bios_size = load_elf(filename, 0, NULL, NULL, NULL);
+ bios_size = load_elf(filename, 0, NULL, NULL, NULL,
+ 1, ELF_MACHINE, 0);
qemu_free(filename);
} else {
bios_size = -1;
@@ -222,18 +225,27 @@ static void ppc_heathrow_init (ram_addr_t ram_size,
if (linux_boot) {
uint64_t lowaddr = 0;
+ int bswap_needed;
+
+#ifdef BSWAP_NEEDED
+ bswap_needed = 1;
+#else
+ bswap_needed = 0;
+#endif
kernel_base = KERNEL_LOAD_ADDR;
/* Now we can load the kernel. The first step tries to load the kernel
supposing PhysAddr = 0x00000000. If that was wrong the kernel is
loaded again, the new PhysAddr being computed from lowaddr. */
- kernel_size = load_elf(kernel_filename, kernel_base, NULL, &lowaddr, NULL);
+ kernel_size = load_elf(kernel_filename, kernel_base, NULL, &lowaddr, NULL,
+ 1, ELF_MACHINE, 0);
if (kernel_size > 0 && lowaddr != KERNEL_LOAD_ADDR) {
kernel_size = load_elf(kernel_filename, (2 * kernel_base) - lowaddr,
- NULL, NULL, NULL);
+ NULL, NULL, NULL, 1, ELF_MACHINE, 0);
}
if (kernel_size < 0)
kernel_size = load_aout(kernel_filename, kernel_base,
- ram_size - kernel_base);
+ ram_size - kernel_base, bswap_needed,
+ TARGET_PAGE_SIZE);
if (kernel_size < 0)
kernel_size = load_image_targphys(kernel_filename,
kernel_base,
diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c
index 5392072982..eb281f85f7 100644
--- a/hw/ppc_prep.c
+++ b/hw/ppc_prep.c
@@ -33,6 +33,7 @@
#include "boards.h"
#include "qemu-log.h"
#include "ide.h"
+#include "loader.h"
//#define HARD_DEBUG_PPC_IO
//#define DEBUG_PPC_IO
diff --git a/hw/ppce500_mpc8544ds.c b/hw/ppce500_mpc8544ds.c
index 51208215f1..504419458b 100644
--- a/hw/ppce500_mpc8544ds.c
+++ b/hw/ppce500_mpc8544ds.c
@@ -29,6 +29,8 @@
#include "device_tree.h"
#include "openpic.h"
#include "ppce500.h"
+#include "loader.h"
+#include "elf.h"
#define BINARY_DEVICE_TREE_FILE "mpc8544ds.dtb"
#define UIMAGE_LOAD_BASE 0
@@ -160,8 +162,8 @@ static void mpc8544ds_init(ram_addr_t ram_size,
CPUState *env;
uint64_t elf_entry;
uint64_t elf_lowaddr;
- target_ulong entry=0;
- target_ulong loadaddr=UIMAGE_LOAD_BASE;
+ target_phys_addr_t entry=0;
+ target_phys_addr_t loadaddr=UIMAGE_LOAD_BASE;
target_long kernel_size=0;
target_ulong dt_base=DTB_LOAD_BASE;
target_ulong initrd_base=INITRD_LOAD_BASE;
@@ -226,7 +228,7 @@ static void mpc8544ds_init(ram_addr_t ram_size,
kernel_size = load_uimage(kernel_filename, &entry, &loadaddr, NULL);
if (kernel_size < 0) {
kernel_size = load_elf(kernel_filename, 0, &elf_entry, &elf_lowaddr,
- NULL);
+ NULL, 1, ELF_MACHINE, 0);
entry = elf_entry;
loadaddr = elf_lowaddr;
}
diff --git a/hw/r2d.c b/hw/r2d.c
index ff514a482f..ea19ff623d 100644
--- a/hw/r2d.c
+++ b/hw/r2d.c
@@ -32,6 +32,7 @@
#include "net.h"
#include "sh7750_regs.h"
#include "ide.h"
+#include "loader.h"
#define SDRAM_BASE 0x0c000000 /* Physical location of SDRAM: Area 3 */
#define SDRAM_SIZE 0x04000000
diff --git a/hw/shix.c b/hw/shix.c
index 19b0155a49..638bf16e34 100644
--- a/hw/shix.c
+++ b/hw/shix.c
@@ -32,6 +32,7 @@
#include "sh.h"
#include "sysemu.h"
#include "boards.h"
+#include "loader.h"
#define BIOS_FILENAME "shix_bios.bin"
#define BIOS_ADDRESS 0xA0000000
diff --git a/hw/smbios.c b/hw/smbios.c
index e28beba2c8..a3ae1de824 100644
--- a/hw/smbios.c
+++ b/hw/smbios.c
@@ -13,6 +13,7 @@
#include "sysemu.h"
#include "smbios.h"
+#include "loader.h"
/*
* Structures shared with the BIOS
diff --git a/hw/sun4m.c b/hw/sun4m.c
index d97072393b..a869d15a81 100644
--- a/hw/sun4m.c
+++ b/hw/sun4m.c
@@ -37,6 +37,8 @@
#include "fw_cfg.h"
#include "escc.h"
#include "qdev-addr.h"
+#include "loader.h"
+#include "elf.h"
//#define DEBUG_IRQ
@@ -302,11 +304,19 @@ static unsigned long sun4m_load_kernel(const char *kernel_filename,
kernel_size = 0;
if (linux_boot) {
+ int bswap_needed;
+
+#ifdef BSWAP_NEEDED
+ bswap_needed = 1;
+#else
+ bswap_needed = 0;
+#endif
kernel_size = load_elf(kernel_filename, -0xf0000000ULL, NULL, NULL,
- NULL);
+ NULL, 1, ELF_MACHINE, 0);
if (kernel_size < 0)
kernel_size = load_aout(kernel_filename, KERNEL_LOAD_ADDR,
- RAM_size - KERNEL_LOAD_ADDR);
+ RAM_size - KERNEL_LOAD_ADDR, bswap_needed,
+ TARGET_PAGE_SIZE);
if (kernel_size < 0)
kernel_size = load_image_targphys(kernel_filename,
KERNEL_LOAD_ADDR,
@@ -608,7 +618,8 @@ static void prom_init(target_phys_addr_t addr, const char *bios_name)
}
filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
if (filename) {
- ret = load_elf(filename, addr - PROM_VADDR, NULL, NULL, NULL);
+ ret = load_elf(filename, addr - PROM_VADDR, NULL, NULL, NULL,
+ 1, ELF_MACHINE, 0);
if (ret < 0 || ret > PROM_SIZE_MAX) {
ret = load_image_targphys(filename, addr, PROM_SIZE_MAX);
}
diff --git a/hw/sun4u.c b/hw/sun4u.c
index 427ee764ce..2c97d9d702 100644
--- a/hw/sun4u.c
+++ b/hw/sun4u.c
@@ -34,6 +34,8 @@
#include "fw_cfg.h"
#include "sysbus.h"
#include "ide.h"
+#include "loader.h"
+#include "elf.h"
//#define DEBUG_IRQ
@@ -164,10 +166,19 @@ static unsigned long sun4u_load_kernel(const char *kernel_filename,
kernel_size = 0;
if (linux_boot) {
- kernel_size = load_elf(kernel_filename, 0, NULL, NULL, NULL);
+ int bswap_needed;
+
+#ifdef BSWAP_NEEDED
+ bswap_needed = 1;
+#else
+ bswap_needed = 0;
+#endif
+ kernel_size = load_elf(kernel_filename, 0, NULL, NULL, NULL,
+ 1, ELF_MACHINE, 0);
if (kernel_size < 0)
kernel_size = load_aout(kernel_filename, KERNEL_LOAD_ADDR,
- RAM_size - KERNEL_LOAD_ADDR);
+ RAM_size - KERNEL_LOAD_ADDR, bswap_needed,
+ TARGET_PAGE_SIZE);
if (kernel_size < 0)
kernel_size = load_image_targphys(kernel_filename,
KERNEL_LOAD_ADDR,
@@ -418,7 +429,8 @@ static void prom_init(target_phys_addr_t addr, const char *bios_name)
}
filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
if (filename) {
- ret = load_elf(filename, addr - PROM_VADDR, NULL, NULL, NULL);
+ ret = load_elf(filename, addr - PROM_VADDR, NULL, NULL, NULL,
+ 1, ELF_MACHINE, 0);
if (ret < 0 || ret > PROM_SIZE_MAX) {
ret = load_image_targphys(filename, addr, PROM_SIZE_MAX);
}
diff --git a/hw/tc58128.c b/hw/tc58128.c
index 21e808547e..264aa028da 100644
--- a/hw/tc58128.c
+++ b/hw/tc58128.c
@@ -1,6 +1,7 @@
#include "hw.h"
#include "sh.h"
#include "sysemu.h"
+#include "loader.h"
#define CE1 0x0100
#define CE2 0x0200