diff options
author | Blue Swirl <blauwirbel@gmail.com> | 2009-09-20 14:58:02 +0000 |
---|---|---|
committer | Blue Swirl <blauwirbel@gmail.com> | 2009-09-20 14:58:02 +0000 |
commit | ca20cf32ab3d945155141ef737f5d08ebb373e1d (patch) | |
tree | 45515350fdf7b5322658095beec591565a78506d /hw | |
parent | a333cd7166d12397635e16dcade28da5ba8ec7b3 (diff) | |
download | qemu-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.c | 7 | ||||
-rw-r--r-- | hw/arm_boot.c | 14 | ||||
-rw-r--r-- | hw/armv7m.c | 12 | ||||
-rw-r--r-- | hw/axis_dev88.c | 4 | ||||
-rw-r--r-- | hw/dummy_m68k.c | 7 | ||||
-rw-r--r-- | hw/elf_ops.h | 274 | ||||
-rw-r--r-- | hw/etraxfs.c | 4 | ||||
-rw-r--r-- | hw/loader.c | 546 | ||||
-rw-r--r-- | hw/loader.h | 21 | ||||
-rw-r--r-- | hw/mcf5208.c | 7 | ||||
-rw-r--r-- | hw/mips_jazz.c | 1 | ||||
-rw-r--r-- | hw/mips_malta.c | 11 | ||||
-rw-r--r-- | hw/mips_mipssim.c | 11 | ||||
-rw-r--r-- | hw/mips_r4k.c | 10 | ||||
-rw-r--r-- | hw/nseries.c | 1 | ||||
-rw-r--r-- | hw/palm.c | 1 | ||||
-rw-r--r-- | hw/pc.c | 5 | ||||
-rw-r--r-- | hw/petalogix_s3adsp1800_mmu.c | 8 | ||||
-rw-r--r-- | hw/ppc.c | 1 | ||||
-rw-r--r-- | hw/ppc405_boards.c | 1 | ||||
-rw-r--r-- | hw/ppc440_bamboo.c | 8 | ||||
-rw-r--r-- | hw/ppc_newworld.c | 20 | ||||
-rw-r--r-- | hw/ppc_oldworld.c | 20 | ||||
-rw-r--r-- | hw/ppc_prep.c | 1 | ||||
-rw-r--r-- | hw/ppce500_mpc8544ds.c | 8 | ||||
-rw-r--r-- | hw/r2d.c | 1 | ||||
-rw-r--r-- | hw/shix.c | 1 | ||||
-rw-r--r-- | hw/smbios.c | 1 | ||||
-rw-r--r-- | hw/sun4m.c | 17 | ||||
-rw-r--r-- | hw/sun4u.c | 18 | ||||
-rw-r--r-- | hw/tc58128.c | 1 |
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 { @@ -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) { @@ -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); @@ -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; } @@ -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 @@ -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 |