diff options
Diffstat (limited to 'qemu/hw/core/loader.c')
-rw-r--r-- | qemu/hw/core/loader.c | 131 |
1 files changed, 116 insertions, 15 deletions
diff --git a/qemu/hw/core/loader.c b/qemu/hw/core/loader.c index 216eeeb91..c0499571c 100644 --- a/qemu/hw/core/loader.c +++ b/qemu/hw/core/loader.c @@ -42,6 +42,8 @@ * with this program; if not, see <http://www.gnu.org/licenses/>. */ +#include "qemu/osdep.h" +#include "qapi/error.h" #include "hw/hw.h" #include "disas/disas.h" #include "monitor/monitor.h" @@ -51,12 +53,11 @@ #include "hw/nvram/fw_cfg.h" #include "exec/memory.h" #include "exec/address-spaces.h" +#include "hw/boards.h" +#include "qemu/cutils.h" #include <zlib.h> -bool option_rom_has_mr = false; -bool rom_file_has_mr = true; - static int roms_loaded; /* return the size or -1 if error */ @@ -148,6 +149,28 @@ int load_image_targphys(const char *filename, return size; } +int load_image_mr(const char *filename, MemoryRegion *mr) +{ + int size; + + if (!memory_access_is_direct(mr, false)) { + /* Can only load an image into RAM or ROM */ + return -1; + } + + size = get_image_size(filename); + + if (size > memory_region_size(mr)) { + return -1; + } + if (size > 0) { + if (rom_add_file_mr(filename, mr, -1) < 0) { + return -1; + } + } + return size; +} + void pstrcpy_targphys(const char *name, hwaddr dest, int buf_size, const char *source) { @@ -333,10 +356,66 @@ const char *load_elf_strerror(int error) } } +void load_elf_hdr(const char *filename, void *hdr, bool *is64, Error **errp) +{ + int fd; + uint8_t e_ident_local[EI_NIDENT]; + uint8_t *e_ident; + size_t hdr_size, off; + bool is64l; + + if (!hdr) { + hdr = e_ident_local; + } + e_ident = hdr; + + fd = open(filename, O_RDONLY | O_BINARY); + if (fd < 0) { + error_setg_errno(errp, errno, "Failed to open file: %s", filename); + return; + } + if (read(fd, hdr, EI_NIDENT) != EI_NIDENT) { + error_setg_errno(errp, errno, "Failed to read file: %s", filename); + goto fail; + } + if (e_ident[0] != ELFMAG0 || + e_ident[1] != ELFMAG1 || + e_ident[2] != ELFMAG2 || + e_ident[3] != ELFMAG3) { + error_setg(errp, "Bad ELF magic"); + goto fail; + } + + is64l = e_ident[EI_CLASS] == ELFCLASS64; + hdr_size = is64l ? sizeof(Elf64_Ehdr) : sizeof(Elf32_Ehdr); + if (is64) { + *is64 = is64l; + } + + off = EI_NIDENT; + while (hdr != e_ident_local && off < hdr_size) { + size_t br = read(fd, hdr + off, hdr_size - off); + switch (br) { + case 0: + error_setg(errp, "File too short: %s", filename); + goto fail; + case -1: + error_setg_errno(errp, errno, "Failed to read file: %s", + filename); + goto fail; + } + off += br; + } + +fail: + close(fd); +} + /* return < 0 if error, otherwise the number of bytes loaded in memory */ int load_elf(const char *filename, uint64_t (*translate_fn)(void *, uint64_t), void *translate_opaque, uint64_t *pentry, uint64_t *lowaddr, - uint64_t *highaddr, int big_endian, int elf_machine, int clear_lsb) + uint64_t *highaddr, int big_endian, int elf_machine, + int clear_lsb, int data_swab) { int fd, data_order, target_data_order, must_swab, ret = ELF_LOAD_FAILED; uint8_t e_ident[EI_NIDENT]; @@ -375,10 +454,12 @@ int load_elf(const char *filename, uint64_t (*translate_fn)(void *, uint64_t), lseek(fd, 0, SEEK_SET); if (e_ident[EI_CLASS] == ELFCLASS64) { ret = load_elf64(filename, fd, translate_fn, translate_opaque, must_swab, - pentry, lowaddr, highaddr, elf_machine, clear_lsb); + pentry, lowaddr, highaddr, elf_machine, clear_lsb, + data_swab); } else { ret = load_elf32(filename, fd, translate_fn, translate_opaque, must_swab, - pentry, lowaddr, highaddr, elf_machine, clear_lsb); + pentry, lowaddr, highaddr, elf_machine, clear_lsb, + data_swab); } fail: @@ -594,8 +675,7 @@ static int load_uboot_image(const char *filename, hwaddr *ep, hwaddr *loadaddr, ret = hdr->ih_size; out: - if (data) - g_free(data); + g_free(data); close(fd); return ret; } @@ -741,7 +821,7 @@ static void *rom_set_mr(Rom *rom, Object *owner, const char *name) memory_region_init_resizeable_ram(rom->mr, owner, name, rom->datasize, rom->romsize, fw_cfg_resized, - &error_abort); + &error_fatal); memory_region_set_readonly(rom->mr, true); vmstate_register_ram_global(rom->mr); @@ -753,8 +833,9 @@ static void *rom_set_mr(Rom *rom, Object *owner, const char *name) int rom_add_file(const char *file, const char *fw_dir, hwaddr addr, int32_t bootindex, - bool option_rom) + bool option_rom, MemoryRegion *mr) { + MachineClass *mc = MACHINE_GET_CLASS(qdev_get_machine()); Rom *rom; int rc, fd = -1; char devpath[100]; @@ -811,7 +892,7 @@ int rom_add_file(const char *file, const char *fw_dir, basename); snprintf(devpath, sizeof(devpath), "/rom@%s", fw_file_name); - if ((!option_rom || option_rom_has_mr) && rom_file_has_mr) { + if ((!option_rom || mc->option_rom_has_mr) && mc->rom_file_has_mr) { data = rom_set_mr(rom, OBJECT(fw_cfg), devpath); } else { data = rom->data; @@ -819,7 +900,12 @@ int rom_add_file(const char *file, const char *fw_dir, fw_cfg_add_file(fw_cfg, fw_file_name, data, rom->romsize); } else { - snprintf(devpath, sizeof(devpath), "/rom@" TARGET_FMT_plx, addr); + if (mr) { + rom->mr = mr; + snprintf(devpath, sizeof(devpath), "/rom@%s", file); + } else { + snprintf(devpath, sizeof(devpath), "/rom@" TARGET_FMT_plx, addr); + } } add_boot_device_path(bootindex, NULL, devpath); @@ -839,6 +925,7 @@ MemoryRegion *rom_add_blob(const char *name, const void *blob, size_t len, size_t max_len, hwaddr addr, const char *fw_file_name, FWCfgReadCallback fw_callback, void *callback_opaque) { + MachineClass *mc = MACHINE_GET_CLASS(qdev_get_machine()); Rom *rom; MemoryRegion *mr = NULL; @@ -856,7 +943,7 @@ MemoryRegion *rom_add_blob(const char *name, const void *blob, size_t len, snprintf(devpath, sizeof(devpath), "/rom@%s", fw_file_name); - if (rom_file_has_mr) { + if (mc->rom_file_has_mr) { data = rom_set_mr(rom, OBJECT(fw_cfg), devpath); mr = rom->mr; } else { @@ -892,12 +979,12 @@ int rom_add_elf_program(const char *name, void *data, size_t datasize, int rom_add_vga(const char *file) { - return rom_add_file(file, "vgaroms", 0, -1, true); + return rom_add_file(file, "vgaroms", 0, -1, true, NULL); } int rom_add_option(const char *file, int32_t bootindex) { - return rom_add_file(file, "genroms", 0, bootindex, true); + return rom_add_file(file, "genroms", 0, bootindex, true, NULL); } static void rom_reset(void *unused) @@ -966,6 +1053,20 @@ void rom_set_fw(FWCfgState *f) fw_cfg = f; } +void rom_set_order_override(int order) +{ + if (!fw_cfg) + return; + fw_cfg_set_order_override(fw_cfg, order); +} + +void rom_reset_order_override(void) +{ + if (!fw_cfg) + return; + fw_cfg_reset_order_override(fw_cfg); +} + static Rom *find_rom(hwaddr addr) { Rom *rom; |