diff --git a/hw/elf_ops.h b/hw/elf_ops.h index 8376465a10..6093deaa73 100644 --- a/hw/elf_ops.h +++ b/hw/elf_ops.h @@ -179,7 +179,7 @@ static int glue(load_symbols, SZ)(struct elfhdr *ehdr, int fd, int must_swab, return -1; } -static int glue(load_elf, SZ)(int fd, int64_t address_offset, +static int glue(load_elf, SZ)(const char *name, int fd, int64_t address_offset, int must_swab, uint64_t *pentry, uint64_t *lowaddr, uint64_t *highaddr, int elf_machine, int clear_lsb) @@ -190,6 +190,7 @@ static int glue(load_elf, SZ)(int fd, int64_t address_offset, elf_word mem_size; uint64_t addr, low = (uint64_t)-1, high = 0; uint8_t *data = NULL; + char label[128]; if (read(fd, &ehdr, sizeof(ehdr)) != sizeof(ehdr)) goto fail; @@ -249,7 +250,8 @@ static int glue(load_elf, SZ)(int fd, int64_t address_offset, linked at the wrong physical address. */ addr = ph->p_paddr + address_offset; - cpu_physical_memory_write_rom(addr, data, mem_size); + snprintf(label, sizeof(label), "phdr #%d: %s", i, name); + rom_add_blob_fixed(label, data, mem_size, addr); total_size += mem_size; if (addr < low) diff --git a/hw/loader.c b/hw/loader.c index 5d83a66041..c436ec6a33 100644 --- a/hw/loader.c +++ b/hw/loader.c @@ -44,6 +44,7 @@ #include "hw.h" #include "disas.h" +#include "monitor.h" #include "sysemu.h" #include "uboot_image.h" #include "loader.h" @@ -80,66 +81,31 @@ int load_image(const char *filename, uint8_t *addr) 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) +int read_targphys(const char *name, + 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; + uint8_t *buf; + size_t 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; + buf = qemu_malloc(nbytes); + did = read(fd, buf, nbytes); + if (did > 0) + rom_add_blob_fixed("read", buf, did, dst_addr); + qemu_free(buf); + return did; } /* 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; + int size; - 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; + size = get_image_size(filename); + if (size > 0) + rom_add_file_fixed(filename, addr); + return size; } void pstrcpy_targphys(target_phys_addr_t dest, int buf_size, @@ -231,7 +197,7 @@ int load_aout(const char *filename, target_phys_addr_t addr, int max_sz, 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); + size = read_targphys(filename, fd, addr, e.a_text + e.a_data); if (size < 0) goto fail; break; @@ -239,10 +205,10 @@ int load_aout(const char *filename, target_phys_addr_t addr, int max_sz, 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); + size = read_targphys(filename, fd, addr, e.a_text); if (size < 0) goto fail; - ret = read_targphys(fd, addr + N_DATADDR(e, target_page_size), + ret = read_targphys(filename, fd, addr + N_DATADDR(e, target_page_size), e.a_data); if (ret < 0) goto fail; @@ -343,10 +309,10 @@ int load_elf(const char *filename, int64_t address_offset, lseek(fd, 0, SEEK_SET); if (e_ident[EI_CLASS] == ELFCLASS64) { - ret = load_elf64(fd, address_offset, must_swab, pentry, + ret = load_elf64(filename, fd, address_offset, must_swab, pentry, lowaddr, highaddr, elf_machine, clear_lsb); } else { - ret = load_elf32(fd, address_offset, must_swab, pentry, + ret = load_elf32(filename, fd, address_offset, must_swab, pentry, lowaddr, highaddr, elf_machine, clear_lsb); } @@ -531,7 +497,7 @@ int load_uimage(const char *filename, target_phys_addr_t *ep, hdr->ih_size = bytes; } - cpu_physical_memory_write_rom(hdr->ih_load, data, hdr->ih_size); + rom_add_blob_fixed(filename, data, hdr->ih_size, hdr->ih_load); if (loadaddr) *loadaddr = hdr->ih_load; @@ -544,3 +510,177 @@ out: close(fd); return ret; } + +/* + * Functions for reboot-persistent memory regions. + * - used for vga bios and option roms. + * - also linux kernel (-kernel / -initrd). + */ + +typedef struct Rom Rom; + +struct Rom { + char *name; + char *path; + size_t romsize; + uint8_t *data; + int align; + int isrom; + + target_phys_addr_t min; + target_phys_addr_t max; + target_phys_addr_t addr; + QTAILQ_ENTRY(Rom) next; +}; + +static QTAILQ_HEAD(, Rom) roms = QTAILQ_HEAD_INITIALIZER(roms); + +static void rom_insert(Rom *rom) +{ + Rom *item; + + /* list is ordered by load address */ + QTAILQ_FOREACH(item, &roms, next) { + if (rom->min >= item->min) + continue; + QTAILQ_INSERT_BEFORE(item, rom, next); + return; + } + QTAILQ_INSERT_TAIL(&roms, rom, next); +} + +int rom_add_file(const char *file, + target_phys_addr_t min, target_phys_addr_t max, int align) +{ + Rom *rom; + int rc, fd = -1; + + rom = qemu_mallocz(sizeof(*rom)); + rom->name = qemu_strdup(file); + rom->path = qemu_find_file(QEMU_FILE_TYPE_BIOS, rom->name); + if (rom->path == NULL) { + fprintf(stderr, "Could not find option rom '%s'\n", rom->name); + goto err; + } + + fd = open(rom->path, O_RDONLY); + if (fd == -1) { + fprintf(stderr, "Could not open option rom '%s': %s\n", + rom->path, strerror(errno)); + goto err; + } + + rom->align = align; + rom->min = min; + rom->max = max; + rom->romsize = lseek(fd, 0, SEEK_END); + rom->data = qemu_mallocz(rom->romsize); + lseek(fd, 0, SEEK_SET); + rc = read(fd, rom->data, rom->romsize); + if (rc != rom->romsize) { + fprintf(stderr, "rom: file %-20s: read error: rc=%d (expected %zd)\n", + rom->name, rc, rom->romsize); + goto err; + } + close(fd); + rom_insert(rom); + return 0; + +err: + if (fd != -1) + close(fd); + qemu_free(rom->data); + qemu_free(rom->path); + qemu_free(rom->name); + qemu_free(rom); + return -1; +} + +int rom_add_blob(const char *name, const void *blob, size_t len, + target_phys_addr_t min, target_phys_addr_t max, int align) +{ + Rom *rom; + + rom = qemu_mallocz(sizeof(*rom)); + rom->name = qemu_strdup(name); + rom->align = align; + rom->min = min; + rom->max = max; + rom->romsize = len; + rom->data = qemu_mallocz(rom->romsize); + memcpy(rom->data, blob, len); + rom_insert(rom); + return 0; +} + +static void rom_reset(void *unused) +{ + Rom *rom; + + QTAILQ_FOREACH(rom, &roms, next) { + if (rom->data == NULL) + continue; + cpu_physical_memory_write_rom(rom->addr, rom->data, rom->romsize); + if (rom->isrom) { + /* rom needs to be written only once */ + qemu_free(rom->data); + rom->data = NULL; + } + } +} + +int rom_load_all(void) +{ + target_phys_addr_t addr = 0; + int memtype; + Rom *rom; + + QTAILQ_FOREACH(rom, &roms, next) { + if (addr < rom->min) + addr = rom->min; + if (rom->max) { + /* load address range */ + if (rom->align) { + addr += (rom->align-1); + addr &= ~(rom->align-1); + } + if (addr + rom->romsize > rom->max) { + fprintf(stderr, "rom: out of memory (rom %s, " + "addr 0x" TARGET_FMT_plx + ", size 0x%zx, max 0x" TARGET_FMT_plx ")\n", + rom->name, addr, rom->romsize, rom->max); + return -1; + } + } else { + /* fixed address requested */ + if (addr != rom->min) { + fprintf(stderr, "rom: requested regions overlap " + "(rom %s. free=0x" TARGET_FMT_plx + ", addr=0x" TARGET_FMT_plx ")\n", + rom->name, addr, rom->min); + return -1; + } + } + rom->addr = addr; + addr += rom->romsize; + memtype = cpu_get_physical_page_desc(rom->addr) & (3 << IO_MEM_SHIFT); + if (memtype == IO_MEM_ROM) + rom->isrom = 1; + } + qemu_register_reset(rom_reset, NULL); + rom_reset(NULL); + return 0; +} + +void do_info_roms(Monitor *mon) +{ + Rom *rom; + + QTAILQ_FOREACH(rom, &roms, next) { + monitor_printf(mon, "addr=" TARGET_FMT_plx + " size=0x%06zx mem=%s name=\"%s\" \n", + rom->addr, rom->romsize, + rom->isrom ? "rom" : "ram", + rom->name); + } +} diff --git a/hw/loader.h b/hw/loader.h index 3632008928..031e6adabb 100644 --- a/hw/loader.h +++ b/hw/loader.h @@ -13,9 +13,32 @@ int load_aout(const char *filename, target_phys_addr_t addr, int max_sz, 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); +int read_targphys(const char *name, + 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); + +int rom_add_file(const char *file, + target_phys_addr_t min, target_phys_addr_t max, int align); +int rom_add_blob(const char *name, const void *blob, size_t len, + target_phys_addr_t min, target_phys_addr_t max, int align); +int rom_load_all(void); +void do_info_roms(Monitor *mon); + +#define rom_add_file_fixed(_f, _a) \ + rom_add_file(_f, _a, 0, 0) +#define rom_add_blob_fixed(_f, _b, _l, _a) \ + rom_add_blob(_f, _b, _l, _a, 0, 0) + +#define PC_ROM_MIN_VGA 0xc0000 +#define PC_ROM_MIN_OPTION 0xc8000 +#define PC_ROM_MAX 0xe0000 +#define PC_ROM_ALIGN 0x800 +#define PC_ROM_SIZE (PC_ROM_MAX - PC_ROM_MIN_VGA) + +#define rom_add_vga(_f) \ + rom_add_file(_f, PC_ROM_MIN_VGA, PC_ROM_MAX, PC_ROM_ALIGN) +#define rom_add_option(_f) \ + rom_add_file(_f, PC_ROM_MIN_OPTION, PC_ROM_MAX, PC_ROM_ALIGN) + #endif diff --git a/hw/pc.c b/hw/pc.c index 06826297e9..2ca15a373b 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -66,30 +66,6 @@ static RTCState *rtc_state; static PITState *pit; static PCII440FXState *i440fx_state; -typedef struct rom_reset_data { - uint8_t *data; - target_phys_addr_t addr; - unsigned size; -} RomResetData; - -static void option_rom_reset(void *_rrd) -{ - RomResetData *rrd = _rrd; - - cpu_physical_memory_write_rom(rrd->addr, rrd->data, rrd->size); -} - -static void option_rom_setup_reset(target_phys_addr_t addr, unsigned size) -{ - RomResetData *rrd = qemu_malloc(sizeof *rrd); - - rrd->data = qemu_malloc(size); - cpu_physical_memory_read(addr, rrd->data, size); - rrd->addr = addr; - rrd->size = size; - qemu_register_reset(option_rom_reset, rrd); -} - typedef struct isa_irq_state { qemu_irq *i8259; qemu_irq *ioapic; @@ -515,8 +491,7 @@ static void *bochs_bios_init(void) /* Generate an initial boot sector which sets state and jump to a specified vector */ -static void generate_bootsect(target_phys_addr_t option_rom, - uint32_t gpr[8], uint16_t segs[6], uint16_t ip) +static void generate_bootsect(uint32_t gpr[8], uint16_t segs[6], uint16_t ip) { uint8_t rom[512], *p, *reloc; uint8_t sum; @@ -589,8 +564,8 @@ static void generate_bootsect(target_phys_addr_t option_rom, sum += rom[i]; rom[sizeof(rom) - 1] = -sum; - cpu_physical_memory_write_rom(option_rom, rom, sizeof(rom)); - option_rom_setup_reset(option_rom, sizeof (rom)); + rom_add_blob("linux-bootsect", rom, sizeof(rom), + PC_ROM_MIN_OPTION, PC_ROM_MAX, PC_ROM_ALIGN); } static long get_file_size(FILE *f) @@ -620,15 +595,16 @@ static int load_multiboot(void *fw_cfg, const char *kernel_cmdline, uint8_t *header) { - int i, t, is_multiboot = 0; + int i, is_multiboot = 0; uint32_t flags = 0; uint32_t mh_entry_addr; uint32_t mh_load_addr; uint32_t mb_kernel_size; uint32_t mmap_addr = MULTIBOOT_STRUCT_ADDR; uint32_t mb_bootinfo = MULTIBOOT_STRUCT_ADDR + 0x500; - uint32_t mb_cmdline = mb_bootinfo + 0x200; uint32_t mb_mod_end; + uint8_t bootinfo[0x500]; + uint32_t cmdline = 0x200; /* Ok, let's see if it is a multiboot image. The header is 12x32bit long, so the latest entry may be 8192 - 48. */ @@ -651,6 +627,7 @@ static int load_multiboot(void *fw_cfg, #ifdef DEBUG_MULTIBOOT fprintf(stderr, "qemu: I believe we found a multiboot image!\n"); #endif + memset(bootinfo, 0, sizeof(bootinfo)); if (flags & 0x00000004) { /* MULTIBOOT_HEADER_HAS_VBE */ fprintf(stderr, "qemu: multiboot knows VBE. we don't.\n"); @@ -681,6 +658,7 @@ static int load_multiboot(void *fw_cfg, uint32_t mh_bss_end_addr = ldl_p(header+i+24); #endif uint32_t mb_kernel_text_offset = i - (mh_header_addr - mh_load_addr); + uint8_t *kernel; mh_entry_addr = ldl_p(header+i+28); mb_kernel_size = get_file_size(f) - mb_kernel_text_offset; @@ -696,20 +674,16 @@ static int load_multiboot(void *fw_cfg, fprintf(stderr, "multiboot: mh_load_addr = %#x\n", mh_load_addr); fprintf(stderr, "multiboot: mh_load_end_addr = %#x\n", mh_load_end_addr); fprintf(stderr, "multiboot: mh_bss_end_addr = %#x\n", mh_bss_end_addr); -#endif - - fseek(f, mb_kernel_text_offset, SEEK_SET); - -#ifdef DEBUG_MULTIBOOT fprintf(stderr, "qemu: loading multiboot kernel (%#x bytes) at %#x\n", mb_kernel_size, mh_load_addr); #endif - if (!fread_targphys_ok(mh_load_addr, mb_kernel_size, f)) { - fprintf(stderr, "qemu: read error on multiboot kernel '%s' (%#x)\n", - kernel_filename, mb_kernel_size); - exit(1); - } + kernel = qemu_malloc(mb_kernel_size); + fseek(f, mb_kernel_text_offset, SEEK_SET); + fread(kernel, 1, mb_kernel_size, f); + rom_add_blob_fixed(kernel_filename, kernel, mb_kernel_size, + mh_load_addr); + qemu_free(kernel); fclose(f); } @@ -717,10 +691,10 @@ static int load_multiboot(void *fw_cfg, mb_mod_end = mh_load_addr + mb_kernel_size; /* load modules */ - stl_phys(mb_bootinfo + 20, 0x0); /* mods_count */ + stl_p(bootinfo + 20, 0x0); /* mods_count */ if (initrd_filename) { - uint32_t mb_mod_info = mb_bootinfo + 0x100; - uint32_t mb_mod_cmdline = mb_bootinfo + 0x300; + uint32_t mb_mod_info = 0x100; + uint32_t mb_mod_cmdline = 0x300; uint32_t mb_mod_start = mh_load_addr; uint32_t mb_mod_length = mb_kernel_size; char *next_initrd; @@ -733,72 +707,63 @@ static int load_multiboot(void *fw_cfg, *next_initrd = '\0'; /* if a space comes after the module filename, treat everything after that as parameters */ - cpu_physical_memory_write(mb_mod_cmdline, (uint8_t*)initrd_filename, - strlen(initrd_filename) + 1); - stl_phys(mb_mod_info + 8, mb_mod_cmdline); /* string */ + pstrcpy((char*)bootinfo + mb_mod_cmdline, + sizeof(bootinfo) - mb_mod_cmdline, + initrd_filename); + stl_p(bootinfo + mb_mod_info + 8, mb_mod_cmdline); /* string */ mb_mod_cmdline += strlen(initrd_filename) + 1; + if (mb_mod_cmdline > sizeof(bootinfo)) + mb_mod_cmdline = sizeof(bootinfo); if ((next_space = strchr(initrd_filename, ' '))) *next_space = '\0'; #ifdef DEBUG_MULTIBOOT printf("multiboot loading module: %s\n", initrd_filename); #endif - f = fopen(initrd_filename, "rb"); - if (f) { - mb_mod_start = (mb_mod_start + mb_mod_length + (TARGET_PAGE_SIZE - 1)) - & (TARGET_PAGE_MASK); - mb_mod_length = get_file_size(f); - mb_mod_end = mb_mod_start + mb_mod_length; - - if (!fread_targphys_ok(mb_mod_start, mb_mod_length, f)) { - fprintf(stderr, "qemu: read error on multiboot module '%s' (%#x)\n", - initrd_filename, mb_mod_length); - exit(1); - } - - mb_mod_count++; - stl_phys(mb_mod_info + 0, mb_mod_start); - stl_phys(mb_mod_info + 4, mb_mod_start + mb_mod_length); -#ifdef DEBUG_MULTIBOOT - printf("mod_start: %#x\nmod_end: %#x\n", mb_mod_start, - mb_mod_start + mb_mod_length); -#endif - stl_phys(mb_mod_info + 12, 0x0); /* reserved */ + mb_mod_start = (mb_mod_start + mb_mod_length + (TARGET_PAGE_SIZE - 1)) + & (TARGET_PAGE_MASK); + mb_mod_length = get_image_size(initrd_filename); + if (mb_mod_length < 0) { + fprintf(stderr, "failed to get %s image size\n", initrd_filename); + exit(1); } + mb_mod_end = mb_mod_start + mb_mod_length; + rom_add_file_fixed(initrd_filename, mb_mod_start); + + mb_mod_count++; + stl_p(bootinfo + mb_mod_info + 0, mb_mod_start); + stl_p(bootinfo + mb_mod_info + 4, mb_mod_start + mb_mod_length); + stl_p(bootinfo + mb_mod_info + 12, 0x0); /* reserved */ +#ifdef DEBUG_MULTIBOOT + printf("mod_start: %#x\nmod_end: %#x\n", mb_mod_start, + mb_mod_start + mb_mod_length); +#endif initrd_filename = next_initrd+1; mb_mod_info += 16; } while (next_initrd); - stl_phys(mb_bootinfo + 20, mb_mod_count); /* mods_count */ - stl_phys(mb_bootinfo + 24, mb_bootinfo + 0x100); /* mods_addr */ + stl_p(bootinfo + 20, mb_mod_count); /* mods_count */ + stl_p(bootinfo + 24, mb_bootinfo + 0x100); /* mods_addr */ } - /* Make sure we're getting kernel + modules back after reset */ - option_rom_setup_reset(mh_load_addr, mb_mod_end - mh_load_addr); - /* Commandline support */ - stl_phys(mb_bootinfo + 16, mb_cmdline); - t = strlen(kernel_filename); - cpu_physical_memory_write(mb_cmdline, (uint8_t*)kernel_filename, t); - mb_cmdline += t; - stb_phys(mb_cmdline++, ' '); - t = strlen(kernel_cmdline) + 1; - cpu_physical_memory_write(mb_cmdline, (uint8_t*)kernel_cmdline, t); + stl_p(bootinfo + 16, mb_bootinfo + cmdline); + snprintf((char*)bootinfo + cmdline, 0x100, "%s %s", + kernel_filename, kernel_cmdline); /* the kernel is where we want it to be now */ - #define MULTIBOOT_FLAGS_MEMORY (1 << 0) #define MULTIBOOT_FLAGS_BOOT_DEVICE (1 << 1) #define MULTIBOOT_FLAGS_CMDLINE (1 << 2) #define MULTIBOOT_FLAGS_MODULES (1 << 3) #define MULTIBOOT_FLAGS_MMAP (1 << 6) - stl_phys(mb_bootinfo, MULTIBOOT_FLAGS_MEMORY - | MULTIBOOT_FLAGS_BOOT_DEVICE - | MULTIBOOT_FLAGS_CMDLINE - | MULTIBOOT_FLAGS_MODULES - | MULTIBOOT_FLAGS_MMAP); - stl_phys(mb_bootinfo + 4, 640); /* mem_lower */ - stl_phys(mb_bootinfo + 8, ram_size / 1024); /* mem_upper */ - stl_phys(mb_bootinfo + 12, 0x8001ffff); /* XXX: use the -boot switch? */ - stl_phys(mb_bootinfo + 48, mmap_addr); /* mmap_addr */ + stl_p(bootinfo, MULTIBOOT_FLAGS_MEMORY + | MULTIBOOT_FLAGS_BOOT_DEVICE + | MULTIBOOT_FLAGS_CMDLINE + | MULTIBOOT_FLAGS_MODULES + | MULTIBOOT_FLAGS_MMAP); + stl_p(bootinfo + 4, 640); /* mem_lower */ + stl_p(bootinfo + 8, ram_size / 1024); /* mem_upper */ + stl_p(bootinfo + 12, 0x8001ffff); /* XXX: use the -boot switch? */ + stl_p(bootinfo + 48, mmap_addr); /* mmap_addr */ #ifdef DEBUG_MULTIBOOT fprintf(stderr, "multiboot: mh_entry_addr = %#x\n", mh_entry_addr); @@ -809,8 +774,8 @@ static int load_multiboot(void *fw_cfg, fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_ADDR, mb_bootinfo); fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_SIZE, mmap_addr); - /* Make sure we're getting the config space back after reset */ - option_rom_setup_reset(mb_bootinfo, 0x500); + rom_add_blob_fixed("multiboot-info", bootinfo, sizeof(bootinfo), + mb_bootinfo); option_rom[nb_option_roms] = "multiboot.bin"; nb_option_roms++; @@ -819,11 +784,10 @@ static int load_multiboot(void *fw_cfg, } static void load_linux(void *fw_cfg, - target_phys_addr_t option_rom, const char *kernel_filename, const char *initrd_filename, const char *kernel_cmdline, - target_phys_addr_t max_ram_size) + target_phys_addr_t max_ram_size) { uint16_t protocol; uint32_t gpr[8]; @@ -831,9 +795,9 @@ static void load_linux(void *fw_cfg, uint16_t real_seg; int setup_size, kernel_size, initrd_size = 0, cmdline_size; uint32_t initrd_max; - uint8_t header[8192]; + uint8_t header[8192], *setup, *kernel; target_phys_addr_t real_addr, prot_addr, cmdline_addr, initrd_addr = 0; - FILE *f, *fi; + FILE *f; char *vmode; /* Align to 16 bytes as a paranoia measure */ @@ -901,7 +865,8 @@ static void load_linux(void *fw_cfg, initrd_max = max_ram_size-ACPI_DATA_SIZE-1; /* kernel command line */ - pstrcpy_targphys(cmdline_addr, 4096, kernel_cmdline); + rom_add_blob_fixed("linux-cmdline", kernel_cmdline, + strlen(kernel_cmdline)+1, cmdline_addr); if (protocol >= 0x202) { stl_p(header+0x228, cmdline_addr); @@ -948,53 +913,34 @@ static void load_linux(void *fw_cfg, exit(1); } - fi = fopen(initrd_filename, "rb"); - if (!fi) { - fprintf(stderr, "qemu: could not load initial ram disk '%s': %s\n", - initrd_filename, strerror(errno)); - exit(1); - } - - initrd_size = get_file_size(fi); - initrd_addr = (initrd_max-initrd_size) & ~4095; - - if (!fread_targphys_ok(initrd_addr, initrd_size, fi)) { - fprintf(stderr, "qemu: read error on initial ram disk '%s': %s\n", - initrd_filename, strerror(errno)); - exit(1); - } - fclose(fi); + initrd_size = get_image_size(initrd_filename); + initrd_addr = (initrd_max-initrd_size) & ~4095; + rom_add_file_fixed(initrd_filename, initrd_addr); stl_p(header+0x218, initrd_addr); stl_p(header+0x21c, initrd_size); } - /* store the finalized header and load the rest of the kernel */ - cpu_physical_memory_write(real_addr, header, ARRAY_SIZE(header)); - + /* load kernel and setup */ setup_size = header[0x1f1]; if (setup_size == 0) setup_size = 4; - setup_size = (setup_size+1)*512; - /* Size of protected-mode code */ - kernel_size -= (setup_size > ARRAY_SIZE(header)) ? setup_size : ARRAY_SIZE(header); + kernel_size -= setup_size; - /* In case we have read too much already, copy that over */ - if (setup_size < ARRAY_SIZE(header)) { - cpu_physical_memory_write(prot_addr, header + setup_size, ARRAY_SIZE(header) - setup_size); - prot_addr += (ARRAY_SIZE(header) - setup_size); - setup_size = ARRAY_SIZE(header); - } - - if (!fread_targphys_ok(real_addr + ARRAY_SIZE(header), - setup_size - ARRAY_SIZE(header), f) || - !fread_targphys_ok(prot_addr, kernel_size, f)) { - fprintf(stderr, "qemu: read error on kernel '%s'\n", - kernel_filename); - exit(1); - } + setup = qemu_malloc(setup_size); + kernel = qemu_malloc(kernel_size); + fseek(f, 0, SEEK_SET); + fread(setup, 1, setup_size, f); + fread(kernel, 1, kernel_size, f); fclose(f); + memcpy(setup, header, MIN(sizeof(header), setup_size)); + rom_add_blob_fixed("linux-setup", setup, + setup_size, real_addr); + rom_add_blob_fixed(kernel_filename, kernel, + kernel_size, prot_addr); + qemu_free(setup); + qemu_free(kernel); /* generate bootsector to set up the initial register state */ real_seg = real_addr >> 4; @@ -1003,13 +949,7 @@ static void load_linux(void *fw_cfg, memset(gpr, 0, sizeof gpr); gpr[4] = cmdline_addr-real_addr-16; /* SP (-16 is paranoia) */ - option_rom_setup_reset(real_addr, setup_size); - option_rom_setup_reset(prot_addr, kernel_size); - option_rom_setup_reset(cmdline_addr, cmdline_size); - if (initrd_filename) - option_rom_setup_reset(initrd_addr, initrd_size); - - generate_bootsect(option_rom, gpr, seg, 0); + generate_bootsect(gpr, seg, 0); } static const int ide_iobase[2] = { 0x1f0, 0x170 }; @@ -1055,35 +995,6 @@ static void pc_init_ne2k_isa(NICInfo *nd) nb_ne2k++; } -static int load_option_rom(const char *oprom, target_phys_addr_t start, - target_phys_addr_t end) -{ - int size; - char *filename; - - filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, oprom); - if (filename) { - size = get_image_size(filename); - if (size > 0 && start + size > end) { - fprintf(stderr, "Not enough space to load option rom '%s'\n", - oprom); - exit(1); - } - size = load_image_targphys(filename, start, end - start); - qemu_free(filename); - } else { - size = -1; - } - if (size < 0) { - fprintf(stderr, "Could not load option rom '%s'\n", oprom); - exit(1); - } - /* Round up optiom rom size to the next 2k boundary */ - size = (size + 2047) & ~2047; - option_rom_setup_reset(start, size); - return size; -} - int cpu_is_bsp(CPUState *env) { return env->cpuid_apic_id == 0; @@ -1121,7 +1032,7 @@ static void pc_init1(ram_addr_t ram_size, int ret, linux_boot, i; ram_addr_t ram_addr, bios_offset, option_rom_offset; ram_addr_t below_4g_mem_size, above_4g_mem_size = 0; - int bios_size, isa_bios_size, oprom_area_size; + int bios_size, isa_bios_size; PCIBus *pci_bus; ISADevice *isa_dev; int piix3_devfn = -1; @@ -1219,25 +1130,17 @@ static void pc_init1(ram_addr_t ram_size, - option_rom_offset = qemu_ram_alloc(0x20000); - oprom_area_size = 0; - cpu_register_physical_memory(0xc0000, 0x20000, option_rom_offset); + option_rom_offset = qemu_ram_alloc(PC_ROM_SIZE); + cpu_register_physical_memory(PC_ROM_MIN_VGA, PC_ROM_SIZE, option_rom_offset); if (using_vga) { - const char *vgabios_filename; /* VGA BIOS load */ if (cirrus_vga_enabled) { - vgabios_filename = VGABIOS_CIRRUS_FILENAME; + rom_add_vga(VGABIOS_CIRRUS_FILENAME); } else { - vgabios_filename = VGABIOS_FILENAME; + rom_add_vga(VGABIOS_FILENAME); } - oprom_area_size = load_option_rom(vgabios_filename, 0xc0000, 0xe0000); } - /* Although video roms can grow larger than 0x8000, the area between - * 0xc0000 - 0xc8000 is reserved for them. It means we won't be looking - * for any other kind of option rom inside this area */ - if (oprom_area_size < 0x8000) - oprom_area_size = 0x8000; /* map all the bios at the top of memory */ cpu_register_physical_memory((uint32_t)(-bios_size), @@ -1246,14 +1149,11 @@ static void pc_init1(ram_addr_t ram_size, fw_cfg = bochs_bios_init(); if (linux_boot) { - load_linux(fw_cfg, 0xc0000 + oprom_area_size, - kernel_filename, initrd_filename, kernel_cmdline, below_4g_mem_size); - oprom_area_size += 2048; + load_linux(fw_cfg, kernel_filename, initrd_filename, kernel_cmdline, below_4g_mem_size); } for (i = 0; i < nb_option_roms; i++) { - oprom_area_size += load_option_rom(option_rom[i], 0xc0000 + oprom_area_size, - 0xe0000); + rom_add_option(option_rom[i]); } for (i = 0; i < nb_nics; i++) { @@ -1267,8 +1167,7 @@ static void pc_init1(ram_addr_t ram_size, model = "e1000"; snprintf(nic_oprom, sizeof(nic_oprom), "pxe-%s.bin", model); - oprom_area_size += load_option_rom(nic_oprom, 0xc0000 + oprom_area_size, - 0xe0000); + rom_add_option(nic_oprom); } cpu_irq = qemu_allocate_irqs(pic_irq_request, NULL, 1); diff --git a/monitor.c b/monitor.c index f105a2ec1b..f79b83355a 100644 --- a/monitor.c +++ b/monitor.c @@ -29,6 +29,7 @@ #include "hw/pc.h" #include "hw/pci.h" #include "hw/watchdog.h" +#include "hw/loader.h" #include "gdbstub.h" #include "net.h" #include "qemu-char.h" @@ -1887,6 +1888,8 @@ static const mon_cmd_t info_cmds[] = { "", "show device tree" }, { "qdm", "", do_info_qdm, "", "show qdev device model list" }, + { "roms", "", do_info_roms, + "", "show roms" }, { NULL, NULL, }, }; diff --git a/vl.c b/vl.c index be0776fd0b..6d79912172 100644 --- a/vl.c +++ b/vl.c @@ -143,6 +143,7 @@ int main(int argc, char **argv) #include "hw/smbios.h" #include "hw/xen.h" #include "hw/qdev.h" +#include "hw/loader.h" #include "bt-host.h" #include "net.h" #include "monitor.h" @@ -5955,6 +5956,8 @@ int main(int argc, char **argv, char **envp) qdev_machine_creation_done(); + rom_load_all(); + if (loadvm) { if (load_vmstate(cur_mon, loadvm) < 0) { autostart = 0;