summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--hw/elf_ops.h6
-rw-r--r--hw/loader.c254
-rw-r--r--hw/loader.h29
-rw-r--r--hw/pc.c271
-rw-r--r--monitor.c3
-rw-r--r--vl.c3
6 files changed, 318 insertions, 248 deletions
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;
-
- 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;
+ uint8_t *buf;
+ size_t did;
+
+ 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;
-
- f = fopen(filename, "rb");
- if (!f) return -1;
-
- got = fread_targphys(addr, max_sz, f);
- if (ferror(f)) { fclose(f); return -1; }
- fclose(f);
+ int size;
- 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_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_phys(mb_mod_info + 0, mb_mod_start);
- stl_phys(mb_mod_info + 4, mb_mod_start + mb_mod_length);
+ 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);
+ 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 */
- }
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);
-
- /* 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);
- }
+ kernel_size -= setup_size;
- 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;