All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH] Reorganize option rom (+linux kernel) loading.
@ 2009-09-30 15:43 Gerd Hoffmann
       [not found] ` <m34oqkmf0n.fsf@neno.mitica>
  2009-09-30 19:51 ` [Qemu-devel] " Blue Swirl
  0 siblings, 2 replies; 11+ messages in thread
From: Gerd Hoffmann @ 2009-09-30 15:43 UTC (permalink / raw)
  To: qemu-devel; +Cc: Gerd Hoffmann

This patch adds infrastructure to maintain memory regions which must be
restored on reset.  That includes roms (vga bios and option roms on pc),
but is also used when loading linux kernels directly.  Features:

  - loading files is supported.
  - passing blobs is supported.
  - target address range is supported (for optionrom area).
  - fixed target memory address is supported (linux kernel).

The final memory layout is created once all memory regions are
registered.  The option roms get addresses assigned and the
registered regions are checked against overlaps.  Finally all data
is copyed to the guest memory.

Advantages:

  (1) Filling memory on initial boot and on reset takes the same
      code path, making reset more robust.
  (2) The need to keep track of the option rom load address is gone.
  (3) Due to (2) option roms can be loaded outside pc_init().  This
      allows to move the pxe rom loading into the nic drivers for
      example.

Additional bonus:  There is a 'info roms' monitor command now.

The patch also switches over pc.c and removes the
option_rom_setup_reset() and load_option_rom() functions.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 hw/elf_ops.h |    6 +-
 hw/loader.c  |  166 +++++++++++++++++++++++++++++++++++-
 hw/loader.h  |   24 +++++
 hw/pc.c      |  269 ++++++++++++++++++----------------------------------------
 monitor.c    |    3 +
 vl.c         |    3 +
 6 files changed, 282 insertions(+), 189 deletions(-)

diff --git a/hw/elf_ops.h b/hw/elf_ops.h
index 8376465..6093dea 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 5d83a66..e363320 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"
@@ -343,10 +344,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);
     }
 
@@ -544,3 +545,164 @@ 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;
+
+    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(const char *type, 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 (-1 == fd) {
+        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("file", 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("blob", rom);
+    return 0;
+}
+
+static void rom_reset(void *unused)
+{
+    Rom *rom;
+
+    QTAILQ_FOREACH(rom, &roms, next) {
+        cpu_physical_memory_write_rom(rom->addr, rom->data, rom->romsize);
+    }
+}
+
+int rom_load_all(void)
+{
+    target_phys_addr_t addr = 0;
+    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;
+    }
+    qemu_register_reset(rom_reset, NULL);
+    rom_reset(NULL);
+    return 0;
+}
+
+void do_info_roms(Monitor *mon)
+{
+    Rom *rom;
+
+    QTAILQ_FOREACH(rom, &roms, next) {
+        cpu_physical_memory_write_rom(rom->addr, rom->data, rom->romsize);
+        monitor_printf(mon, "addr=" TARGET_FMT_plx
+                       " size=0x%06zx name=\"%s\"\n",
+                       rom->addr, rom->romsize, rom->name);
+    }
+}
diff --git a/hw/loader.h b/hw/loader.h
index 3632008..8efeac0 100644
--- a/hw/loader.h
+++ b/hw/loader.h
@@ -18,4 +18,28 @@ 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);
+
+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 bc2875e..3e3e78e 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'\n",
-		    initrd_filename);
-	    exit(1);
-	}
-
-	initrd_size = get_file_size(fi);
+	initrd_size = get_image_size(initrd_filename);
 	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'\n",
-		    initrd_filename);
-	    exit(1);
-	}
-	fclose(fi);
+        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 };
@@ -1058,35 +998,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;
@@ -1124,7 +1035,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;
@@ -1223,25 +1134,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),
@@ -1250,14 +1153,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++) {
@@ -1271,8 +1171,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 167041e..c9e86ef 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"
@@ -1884,6 +1885,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 7bfd415..57609eb 100644
--- a/vl.c
+++ b/vl.c
@@ -140,6 +140,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"
@@ -5875,6 +5876,8 @@ int main(int argc, char **argv, char **envp)
         exit(1);
     }
 
+    rom_load_all();
+
     if (loadvm) {
         if (load_vmstate(cur_mon, loadvm) < 0) {
             autostart = 0;
-- 
1.6.2.5

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [Qemu-devel] Re: [PATCH] Reorganize option rom (+linux kernel) loading.
       [not found] ` <m34oqkmf0n.fsf@neno.mitica>
@ 2009-09-30 19:07   ` Gerd Hoffmann
  0 siblings, 0 replies; 11+ messages in thread
From: Gerd Hoffmann @ 2009-09-30 19:07 UTC (permalink / raw)
  To: Juan Quintela; +Cc: qemu-devel

On 09/30/09 21:03, Juan Quintela wrote:
> Gerd Hoffmann<kraxel@redhat.com>  wrote:
>
>> +
>> +static void rom_insert(const char *type, Rom *rom)
>
> You are not using the type parameter,

Indeed.  There was a debug message which used the type parameter.  Guess 
it can be zapped now.

> I guess that a field inside struct
> Rom could make sense.

I don't think so.  What for?

cheers,
   Gerd

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [Qemu-devel] [PATCH] Reorganize option rom (+linux kernel) loading.
  2009-09-30 15:43 [Qemu-devel] [PATCH] Reorganize option rom (+linux kernel) loading Gerd Hoffmann
       [not found] ` <m34oqkmf0n.fsf@neno.mitica>
@ 2009-09-30 19:51 ` Blue Swirl
  2009-10-01  9:11   ` Gerd Hoffmann
  1 sibling, 1 reply; 11+ messages in thread
From: Blue Swirl @ 2009-09-30 19:51 UTC (permalink / raw)
  To: Gerd Hoffmann; +Cc: qemu-devel

On Wed, Sep 30, 2009 at 6:43 PM, Gerd Hoffmann <kraxel@redhat.com> wrote:
> This patch adds infrastructure to maintain memory regions which must be
> restored on reset.  That includes roms (vga bios and option roms on pc),
> but is also used when loading linux kernels directly.  Features:
>
>  - loading files is supported.
>  - passing blobs is supported.
>  - target address range is supported (for optionrom area).
>  - fixed target memory address is supported (linux kernel).
>
> The final memory layout is created once all memory regions are
> registered.  The option roms get addresses assigned and the
> registered regions are checked against overlaps.  Finally all data
> is copyed to the guest memory.
>
> Advantages:
>
>  (1) Filling memory on initial boot and on reset takes the same
>      code path, making reset more robust.
>  (2) The need to keep track of the option rom load address is gone.
>  (3) Due to (2) option roms can be loaded outside pc_init().  This
>      allows to move the pxe rom loading into the nic drivers for
>      example.
>
> Additional bonus:  There is a 'info roms' monitor command now.
>
> The patch also switches over pc.c and removes the
> option_rom_setup_reset() and load_option_rom() functions.

Nice idea. The implementation seems to be buggy, I only ever see one
rom and for example sparc-test crashes when issuing 'info roms'.

Perhaps 'info roms' could also check whether the rom has been changed?
On most platforms roms are really read only memories.

> +    fd = open(rom->path, O_RDONLY);
> +    if (-1 == fd) {

Not again!

> +    rom->align    = align;
> +    rom->min      = min;
> +    rom->max      = max;
> +    rom->romsize  = lseek(fd, 0, SEEK_END);
> +    rom->data     = qemu_mallocz(rom->romsize);

There are plenty of extra spaces.

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [Qemu-devel] [PATCH] Reorganize option rom (+linux kernel) loading.
  2009-09-30 19:51 ` [Qemu-devel] " Blue Swirl
@ 2009-10-01  9:11   ` Gerd Hoffmann
  2009-10-01 16:25     ` Blue Swirl
  0 siblings, 1 reply; 11+ messages in thread
From: Gerd Hoffmann @ 2009-10-01  9:11 UTC (permalink / raw)
  To: Blue Swirl; +Cc: qemu-devel

   Hi,

> Nice idea. The implementation seems to be buggy, I only ever see one
> rom

On !pc platforms only elf roms will show up.

> and for example sparc-test crashes when issuing 'info roms'.

Huh?  Works for me.  Details please.  sparc is one of the archs I've 
actually tested:

(qemu) info roms
addr=0000000070000000 size=0x0e4000 name="phdr #0: 
/home/kraxel/projects/qemu/pc-bios/openbios-sparc32"

ppc has two entries from the two elf phdr sections:

(qemu) info roms
addr=00000000fff00000 size=0x052c88 name="phdr #0: 
/home/kraxel/projects/qemu/pc-bios/openbios-ppc"
addr=00000000fffffffc size=0x000004 name="phdr #1: 
/home/kraxel/projects/qemu/pc-bios/openbios-ppc"

pc has multiple entries when loading option roms (for network booting), 
looks like this then:

(qemu) info roms
addr=00000000000c0000 size=0x008c00 name="vgabios-cirrus.bin"
addr=00000000000c9000 size=0x008000 name="pxe-e1000.bin"

Booting linux kernels (pc too) directly will produce even more entries:

(qemu) info roms
addr=0000000000010000 size=0x003800 name="linux-setup"
addr=0000000000020000 size=0x000001 name="linux-cmdline"
addr=00000000000c0000 size=0x008c00 name="vgabios-cirrus.bin"
addr=00000000000c9000 size=0x000200 name="linux-bootsect"
addr=0000000000100000 size=0x342910 
name="/boot/vmlinuz-2.6.30.5-43.fc11.x86_64"

> Perhaps 'info roms' could also check whether the rom has been changed?

Point being?

> On most platforms roms are really read only memories.

Yep, I've noticed on a quick glimpse.  So in that case writing roms on 
reset isn't very useful because the guest shouldn't be able to modify 
them in the first place.  It doesn't harm though, except that we keep a 
copy of the roms around for no reason.  Maybe make restore-on-reset opt-in?

>> +    fd = open(rom->path, O_RDONLY);
>> +    if (-1 == fd) {
>
> Not again!

Oops.  Fixed.

>> +    rom->align    = align;
>> +    rom->min      = min;
>> +    rom->max      = max;
>> +    rom->romsize  = lseek(fd, 0, SEEK_END);
>> +    rom->data     = qemu_mallocz(rom->romsize);
>
> There are plenty of extra spaces.

The vertical alignment makes the code more readable IMHO.

cheers,
   Gerd

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [Qemu-devel] [PATCH] Reorganize option rom (+linux kernel) loading.
  2009-10-01  9:11   ` Gerd Hoffmann
@ 2009-10-01 16:25     ` Blue Swirl
  2009-10-02 11:40       ` Gerd Hoffmann
  0 siblings, 1 reply; 11+ messages in thread
From: Blue Swirl @ 2009-10-01 16:25 UTC (permalink / raw)
  To: Gerd Hoffmann; +Cc: qemu-devel

On Thu, Oct 1, 2009 at 12:11 PM, Gerd Hoffmann <kraxel@redhat.com> wrote:
>  Hi,
>
>> Nice idea. The implementation seems to be buggy, I only ever see one
>> rom
>
> On !pc platforms only elf roms will show up.
>
>> and for example sparc-test crashes when issuing 'info roms'.
>
> Huh?  Works for me.  Details please.  sparc is one of the archs I've
> actually tested:

OK, V2 seems to work, except that the command line is not passed:
NET: Registered protocol family 1
NET: Registered protocol family 17
Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(1,0)
 <0>Press L1-A to return to the boot prom

>> Perhaps 'info roms' could also check whether the rom has been changed?
>
> Point being?

Could be useful information. Maybe not.

>> On most platforms roms are really read only memories.
>
> Yep, I've noticed on a quick glimpse.  So in that case writing roms on reset
> isn't very useful because the guest shouldn't be able to modify them in the
> first place.  It doesn't harm though, except that we keep a copy of the roms
> around for no reason.  Maybe make restore-on-reset opt-in?

Or make writability opt-in feature?

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [Qemu-devel] [PATCH] Reorganize option rom (+linux kernel) loading.
  2009-10-01 16:25     ` Blue Swirl
@ 2009-10-02 11:40       ` Gerd Hoffmann
  2009-10-02 15:19         ` Gerd Hoffmann
  2009-10-02 17:56         ` Blue Swirl
  0 siblings, 2 replies; 11+ messages in thread
From: Gerd Hoffmann @ 2009-10-02 11:40 UTC (permalink / raw)
  To: Blue Swirl; +Cc: qemu-devel

> OK, V2 seems to work, except that the command line is not passed:
> NET: Registered protocol family 1
> NET: Registered protocol family 17
> Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(1,0)
>   <0>Press L1-A to return to the boot prom

So you are booting sparc via -kernel I guess?

>> around for no reason.  Maybe make restore-on-reset opt-in?
>
> Or make writability opt-in feature?

v2 does it automagically by checking the memory type.
'info roms' got a new mem=[ram|rom] entry.

cheers,
   Gerd

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [Qemu-devel] [PATCH] Reorganize option rom (+linux kernel) loading.
  2009-10-02 11:40       ` Gerd Hoffmann
@ 2009-10-02 15:19         ` Gerd Hoffmann
  2009-10-02 17:58           ` Blue Swirl
  2009-10-02 17:56         ` Blue Swirl
  1 sibling, 1 reply; 11+ messages in thread
From: Gerd Hoffmann @ 2009-10-02 15:19 UTC (permalink / raw)
  To: Blue Swirl; +Cc: qemu-devel

On 10/02/09 13:40, Gerd Hoffmann wrote:
>> OK, V2 seems to work, except that the command line is not passed:
>> NET: Registered protocol family 1
>> NET: Registered protocol family 17
>> Kernel panic - not syncing: VFS: Unable to mount root fs on
>> unknown-block(1,0)
>> <0>Press L1-A to return to the boot prom
>
> So you are booting sparc via -kernel I guess?

One more question: Fails it on first boot or only after reset?
In case it fails after reset only: Does that work without the patch?

thanks,
   Gerd

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [Qemu-devel] [PATCH] Reorganize option rom (+linux kernel) loading.
  2009-10-02 11:40       ` Gerd Hoffmann
  2009-10-02 15:19         ` Gerd Hoffmann
@ 2009-10-02 17:56         ` Blue Swirl
  1 sibling, 0 replies; 11+ messages in thread
From: Blue Swirl @ 2009-10-02 17:56 UTC (permalink / raw)
  To: Gerd Hoffmann; +Cc: qemu-devel

On Fri, Oct 2, 2009 at 2:40 PM, Gerd Hoffmann <kraxel@redhat.com> wrote:
>> OK, V2 seems to work, except that the command line is not passed:
>> NET: Registered protocol family 1
>> NET: Registered protocol family 17
>> Kernel panic - not syncing: VFS: Unable to mount root fs on
>> unknown-block(1,0)
>>  <0>Press L1-A to return to the boot prom
>
> So you are booting sparc via -kernel I guess?

Yes, the sparc-test setup from QEMU download page.

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [Qemu-devel] [PATCH] Reorganize option rom (+linux kernel) loading.
  2009-10-02 15:19         ` Gerd Hoffmann
@ 2009-10-02 17:58           ` Blue Swirl
  2009-10-06 21:18             ` Gerd Hoffmann
  0 siblings, 1 reply; 11+ messages in thread
From: Blue Swirl @ 2009-10-02 17:58 UTC (permalink / raw)
  To: Gerd Hoffmann; +Cc: qemu-devel

On Fri, Oct 2, 2009 at 6:19 PM, Gerd Hoffmann <kraxel@redhat.com> wrote:
> On 10/02/09 13:40, Gerd Hoffmann wrote:
>>>
>>> OK, V2 seems to work, except that the command line is not passed:
>>> NET: Registered protocol family 1
>>> NET: Registered protocol family 17
>>> Kernel panic - not syncing: VFS: Unable to mount root fs on
>>> unknown-block(1,0)
>>> <0>Press L1-A to return to the boot prom
>>
>> So you are booting sparc via -kernel I guess?
>
> One more question: Fails it on first boot or only after reset?
> In case it fails after reset only: Does that work without the patch?

First boot, identical result after reset. Without patch:

NET: Registered protocol family 1
NET: Registered protocol family 17
RAMDISK: ext2 filesystem found at block 0
RAMDISK: Loading 4096KiB [1 disk] into ram disk... done.
VFS: Mounted root (ext2 filesystem) readonly.
Freeing unused kernel memory: 156k freed
sh: can't access tty; job control turned off
#

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [Qemu-devel] [PATCH] Reorganize option rom (+linux kernel) loading.
  2009-10-02 17:58           ` Blue Swirl
@ 2009-10-06 21:18             ` Gerd Hoffmann
  0 siblings, 0 replies; 11+ messages in thread
From: Gerd Hoffmann @ 2009-10-06 21:18 UTC (permalink / raw)
  To: Blue Swirl; +Cc: qemu-devel

[-- Attachment #1: Type: text/plain, Size: 1158 bytes --]

On 10/02/09 19:58, Blue Swirl wrote:
> On Fri, Oct 2, 2009 at 6:19 PM, Gerd Hoffmann<kraxel@redhat.com>  wrote:
>> On 10/02/09 13:40, Gerd Hoffmann wrote:
>>>>
>>>> OK, V2 seems to work, except that the command line is not passed:
>>>> NET: Registered protocol family 1
>>>> NET: Registered protocol family 17
>>>> Kernel panic - not syncing: VFS: Unable to mount root fs on
>>>> unknown-block(1,0)
>>>> <0>Press L1-A to return to the boot prom
>>>
>>> So you are booting sparc via -kernel I guess?
>>
>> One more question: Fails it on first boot or only after reset?
>> In case it fails after reset only: Does that work without the patch?
>
> First boot, identical result after reset. Without patch:
>
> NET: Registered protocol family 1
> NET: Registered protocol family 17
> RAMDISK: ext2 filesystem found at block 0
> RAMDISK: Loading 4096KiB [1 disk] into ram disk... done.
> VFS: Mounted root (ext2 filesystem) readonly.
> Freeing unused kernel memory: 156k freed
> sh: can't access tty; job control turned off
> #

Incremental fix attached.

Booting works now.
system_reset in monitor works fine too.

Will respin the patch tomorrow.

cheers,
   Gerd

[-- Attachment #2: 0001-fix-sparc.patch --]
[-- Type: text/plain, Size: 11910 bytes --]

From 73928f9846fc8493d56f5a42c25b68707f6679e7 Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Tue, 6 Oct 2009 23:09:50 +0200
Subject: [PATCH] fix sparc.

---
 hw/axis_dev88.c               |    2 +-
 hw/etraxfs.c                  |    2 +-
 hw/loader.c                   |   38 ++++++++++++++++++++++++++++++++------
 hw/loader.h                   |    4 +++-
 hw/mips_malta.c               |    2 +-
 hw/mips_r4k.c                 |    2 +-
 hw/pc.c                       |    2 +-
 hw/petalogix_s3adsp1800_mmu.c |    2 +-
 hw/ppc.c                      |    2 +-
 hw/ppc_newworld.c             |    2 +-
 hw/ppc_oldworld.c             |    2 +-
 hw/r2d.c                      |    2 +-
 hw/sun4m.c                    |   14 ++++++++------
 hw/sun4u.c                    |    2 +-
 14 files changed, 54 insertions(+), 24 deletions(-)

diff --git a/hw/axis_dev88.c b/hw/axis_dev88.c
index 81a41c9..2a79d33 100644
--- a/hw/axis_dev88.c
+++ b/hw/axis_dev88.c
@@ -365,7 +365,7 @@ void axisdev88_init (ram_addr_t ram_size,
             /* Let the kernel know we are modifying the cmdline.  */
             env->regs[10] = 0x87109563;
             env->regs[11] = 0x40000000;
-            pstrcpy_targphys(env->regs[11], 256, kernel_cmdline);
+            pstrcpy_targphys("cmdline", env->regs[11], 256, kernel_cmdline);
         }
     }
     env->pc = bootstrap_pc;
diff --git a/hw/etraxfs.c b/hw/etraxfs.c
index 4f451c5..9304b15 100644
--- a/hw/etraxfs.c
+++ b/hw/etraxfs.c
@@ -157,7 +157,7 @@ void bareetraxfs_init (ram_addr_t ram_size,
             /* Let the kernel know we are modifying the cmdline.  */
             env->regs[10] = 0x87109563;
             env->regs[11] = 0x40000000;
-            pstrcpy_targphys(env->regs[11], 256, kernel_cmdline);
+            pstrcpy_targphys("cmdline", env->regs[11], 256, kernel_cmdline);
         }
     }
     env->pc = bootstrap_pc;
diff --git a/hw/loader.c b/hw/loader.c
index c436ec6..40112b9 100644
--- a/hw/loader.c
+++ b/hw/loader.c
@@ -108,20 +108,20 @@ int load_image_targphys(const char *filename,
     return size;
 }
 
-void pstrcpy_targphys(target_phys_addr_t dest, int buf_size,
+void pstrcpy_targphys(const char *name, target_phys_addr_t dest, int buf_size,
                       const char *source)
 {
-    static const uint8_t nul_byte = 0;
     const char *nulp;
+    char *ptr;
 
     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);
+        rom_add_blob_fixed(name, source, (nulp - source) + 1, dest);
     } else {
-	cpu_physical_memory_write_rom(dest, (uint8_t *)source, buf_size - 1);
-	cpu_physical_memory_write_rom(dest, &nul_byte, 1);
+        rom_add_blob_fixed(name, source, buf_size, dest);
+        ptr = rom_ptr(dest + buf_size - 1);
+        *ptr = 0;
     }
 }
 
@@ -672,6 +672,32 @@ int rom_load_all(void)
     return 0;
 }
 
+static Rom *find_rom(target_phys_addr_t addr)
+{
+    Rom *rom;
+
+    QTAILQ_FOREACH(rom, &roms, next) {
+        if (rom->max)
+            continue;
+        if (rom->min > addr)
+            continue;
+        if (rom->min + rom->romsize < addr)
+            continue;
+        return rom;
+    }
+    return NULL;
+}
+
+void *rom_ptr(target_phys_addr_t addr)
+{
+    Rom *rom;
+
+    rom = find_rom(addr);
+    if (!rom || !rom->data)
+        return NULL;
+    return rom->data + (addr - rom->min);
+}
+
 void do_info_roms(Monitor *mon)
 {
     Rom *rom;
diff --git a/hw/loader.h b/hw/loader.h
index 031e6ad..945c662 100644
--- a/hw/loader.h
+++ b/hw/loader.h
@@ -15,7 +15,8 @@ int load_uimage(const char *filename, target_phys_addr_t *ep,
 
 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,
+void pstrcpy_targphys(const char *name,
+                      target_phys_addr_t dest, int buf_size,
                       const char *source);
 
 int rom_add_file(const char *file,
@@ -23,6 +24,7 @@ int rom_add_file(const char *file,
 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 *rom_ptr(target_phys_addr_t addr);
 void do_info_roms(Monitor *mon);
 
 #define rom_add_file_fixed(_f, _a)              \
diff --git a/hw/mips_malta.c b/hw/mips_malta.c
index d0266d5..6b224e5 100644
--- a/hw/mips_malta.c
+++ b/hw/mips_malta.c
@@ -679,7 +679,7 @@ static void prom_set(int index, const char *string, ...)
     va_start(ap, string);
     vsnprintf(buf, ENVP_ENTRY_SIZE, string, ap);
     va_end(ap);
-    pstrcpy_targphys(table_addr + VIRT_TO_PHYS_ADDEND, ENVP_ENTRY_SIZE, buf);
+    pstrcpy_targphys("prom", table_addr + VIRT_TO_PHYS_ADDEND, ENVP_ENTRY_SIZE, buf);
 }
 
 /* Kernel */
diff --git a/hw/mips_r4k.c b/hw/mips_r4k.c
index d7b301a..d525c63 100644
--- a/hw/mips_r4k.c
+++ b/hw/mips_r4k.c
@@ -130,7 +130,7 @@ static void load_kernel (CPUState *env)
     } else {
         ret = 0;
     }
-    pstrcpy_targphys((16 << 20) - 256 + ret, 256,
+    pstrcpy_targphys("cmdline", (16 << 20) - 256 + ret, 256,
                      loaderparams.kernel_cmdline);
 
     stl_phys((16 << 20) - 260, 0x12345678);
diff --git a/hw/pc.c b/hw/pc.c
index b72a1a9..d7ab47d 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -865,7 +865,7 @@ static void load_linux(void *fw_cfg,
     	initrd_max = max_ram_size-ACPI_DATA_SIZE-1;
 
     /* kernel command line */
-    rom_add_blob_fixed("linux-cmdline", kernel_cmdline,
+    rom_add_blob_fixed("cmdline", kernel_cmdline,
                        strlen(kernel_cmdline)+1, cmdline_addr);
 
     if (protocol >= 0x202) {
diff --git a/hw/petalogix_s3adsp1800_mmu.c b/hw/petalogix_s3adsp1800_mmu.c
index f343dbf..93ce87f 100644
--- a/hw/petalogix_s3adsp1800_mmu.c
+++ b/hw/petalogix_s3adsp1800_mmu.c
@@ -176,7 +176,7 @@ petalogix_s3adsp1800_init(ram_addr_t ram_size,
 
         env->regs[5] = ddr_base + kernel_size;
         if (kernel_cmdline && (kcmdline_len = strlen(kernel_cmdline))) {
-            pstrcpy_targphys(env->regs[5], 256, kernel_cmdline);
+            pstrcpy_targphys("cmdline", env->regs[5], 256, kernel_cmdline);
         }
         env->regs[6] = 0;
         /* Provide a device-tree.  */
diff --git a/hw/ppc.c b/hw/ppc.c
index 09ee2e4..2502e21 100644
--- a/hw/ppc.c
+++ b/hw/ppc.c
@@ -1256,7 +1256,7 @@ int PPC_NVRAM_set_params (nvram_t *nvram, uint16_t NVRAM_size,
     NVRAM_set_lword(nvram,  0x3C, kernel_size);
     if (cmdline) {
         /* XXX: put the cmdline in NVRAM too ? */
-        pstrcpy_targphys(CMDLINE_ADDR, RAM_size - CMDLINE_ADDR, cmdline);
+        pstrcpy_targphys("cmdline", CMDLINE_ADDR, RAM_size - CMDLINE_ADDR, cmdline);
         NVRAM_set_lword(nvram,  0x40, CMDLINE_ADDR);
         NVRAM_set_lword(nvram,  0x44, strlen(cmdline));
     } else {
diff --git a/hw/ppc_newworld.c b/hw/ppc_newworld.c
index d1a82bf..d9f45b5 100644
--- a/hw/ppc_newworld.c
+++ b/hw/ppc_newworld.c
@@ -364,7 +364,7 @@ static void ppc_core99_init (ram_addr_t ram_size,
     fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_SIZE, kernel_size);
     if (kernel_cmdline) {
         fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_CMDLINE, CMDLINE_ADDR);
-        pstrcpy_targphys(CMDLINE_ADDR, TARGET_PAGE_SIZE, kernel_cmdline);
+        pstrcpy_targphys("cmdline", CMDLINE_ADDR, TARGET_PAGE_SIZE, kernel_cmdline);
     } else {
         fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_CMDLINE, 0);
     }
diff --git a/hw/ppc_oldworld.c b/hw/ppc_oldworld.c
index 79f17e8..3f23713 100644
--- a/hw/ppc_oldworld.c
+++ b/hw/ppc_oldworld.c
@@ -384,7 +384,7 @@ static void ppc_heathrow_init (ram_addr_t ram_size,
     fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_SIZE, kernel_size);
     if (kernel_cmdline) {
         fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_CMDLINE, CMDLINE_ADDR);
-        pstrcpy_targphys(CMDLINE_ADDR, TARGET_PAGE_SIZE, kernel_cmdline);
+        pstrcpy_targphys("cmdline", CMDLINE_ADDR, TARGET_PAGE_SIZE, kernel_cmdline);
     } else {
         fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_CMDLINE, 0);
     }
diff --git a/hw/r2d.c b/hw/r2d.c
index f8a5968..c074a6e 100644
--- a/hw/r2d.c
+++ b/hw/r2d.c
@@ -250,7 +250,7 @@ static void r2d_init(ram_addr_t ram_size,
 				   SDRAM_BASE + LINUX_LOAD_OFFSET,
 				   SDRAM_SIZE - LINUX_LOAD_OFFSET);
           env->pc = (SDRAM_BASE + LINUX_LOAD_OFFSET) | 0xa0000000;
-          pstrcpy_targphys(SDRAM_BASE + 0x10100, 256, kernel_cmdline);
+          pstrcpy_targphys("cmdline", SDRAM_BASE + 0x10100, 256, kernel_cmdline);
       } else {
           kernel_size = load_image_targphys(kernel_filename, SDRAM_BASE, SDRAM_SIZE);
           env->pc = SDRAM_BASE | 0xa0000000; /* Start from P2 area */
diff --git a/hw/sun4m.c b/hw/sun4m.c
index 01c7cb4..144bec1 100644
--- a/hw/sun4m.c
+++ b/hw/sun4m.c
@@ -299,6 +299,7 @@ static unsigned long sun4m_load_kernel(const char *kernel_filename,
     int linux_boot;
     unsigned int i;
     long initrd_size, kernel_size;
+    uint8_t *ptr;
 
     linux_boot = (kernel_filename != NULL);
 
@@ -341,9 +342,10 @@ static unsigned long sun4m_load_kernel(const char *kernel_filename,
         }
         if (initrd_size > 0) {
             for (i = 0; i < 64 * TARGET_PAGE_SIZE; i += TARGET_PAGE_SIZE) {
-                if (ldl_phys(KERNEL_LOAD_ADDR + i) == 0x48647253) { // HdrS
-                    stl_phys(KERNEL_LOAD_ADDR + i + 16, INITRD_LOAD_ADDR);
-                    stl_phys(KERNEL_LOAD_ADDR + i + 20, initrd_size);
+                ptr = rom_ptr(KERNEL_LOAD_ADDR + i);
+                if (ldl_p(ptr) == 0x48647253) { // HdrS
+                    stl_p(ptr + 16, INITRD_LOAD_ADDR);
+                    stl_p(ptr + 20, initrd_size);
                     break;
                 }
             }
@@ -875,7 +877,7 @@ static void sun4m_hw_init(const struct sun4m_hwdef *hwdef, ram_addr_t RAM_size,
     fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_SIZE, kernel_size);
     if (kernel_cmdline) {
         fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_CMDLINE, CMDLINE_ADDR);
-        pstrcpy_targphys(CMDLINE_ADDR, TARGET_PAGE_SIZE, kernel_cmdline);
+        pstrcpy_targphys("cmdline", CMDLINE_ADDR, TARGET_PAGE_SIZE, kernel_cmdline);
     } else {
         fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_CMDLINE, 0);
     }
@@ -1457,7 +1459,7 @@ static void sun4d_hw_init(const struct sun4d_hwdef *hwdef, ram_addr_t RAM_size,
     fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_SIZE, kernel_size);
     if (kernel_cmdline) {
         fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_CMDLINE, CMDLINE_ADDR);
-        pstrcpy_targphys(CMDLINE_ADDR, TARGET_PAGE_SIZE, kernel_cmdline);
+        pstrcpy_targphys("cmdline", CMDLINE_ADDR, TARGET_PAGE_SIZE, kernel_cmdline);
     } else {
         fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_CMDLINE, 0);
     }
@@ -1645,7 +1647,7 @@ static void sun4c_hw_init(const struct sun4c_hwdef *hwdef, ram_addr_t RAM_size,
     fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_SIZE, kernel_size);
     if (kernel_cmdline) {
         fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_CMDLINE, CMDLINE_ADDR);
-        pstrcpy_targphys(CMDLINE_ADDR, TARGET_PAGE_SIZE, kernel_cmdline);
+        pstrcpy_targphys("cmdline", CMDLINE_ADDR, TARGET_PAGE_SIZE, kernel_cmdline);
     } else {
         fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_CMDLINE, 0);
     }
diff --git a/hw/sun4u.c b/hw/sun4u.c
index 58d708a..30f5138 100644
--- a/hw/sun4u.c
+++ b/hw/sun4u.c
@@ -651,7 +651,7 @@ static void sun4uv_init(ram_addr_t RAM_size,
     fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_SIZE, kernel_size);
     if (kernel_cmdline) {
         fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_CMDLINE, CMDLINE_ADDR);
-        pstrcpy_targphys(CMDLINE_ADDR, TARGET_PAGE_SIZE, kernel_cmdline);
+        pstrcpy_targphys("cmdline", CMDLINE_ADDR, TARGET_PAGE_SIZE, kernel_cmdline);
     } else {
         fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_CMDLINE, 0);
     }
-- 
1.6.2.5


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [Qemu-devel] [PATCH] Reorganize option rom (+linux kernel) loading.
@ 2009-10-01 14:42 Gerd Hoffmann
  0 siblings, 0 replies; 11+ messages in thread
From: Gerd Hoffmann @ 2009-10-01 14:42 UTC (permalink / raw)
  To: qemu-devel; +Cc: Gerd Hoffmann

This patch adds infrastructure to maintain memory regions which must be
restored on reset.  That includes roms (vga bios and option roms on pc),
but is also used when loading linux kernels directly.  Features:

  - loading files is supported.
  - passing blobs is supported.
  - target address range is supported (for optionrom area).
  - fixed target memory address is supported (linux kernel).

New in v2:
  - writes to ROM are done only at initial boot.
  - also handle aout and uimage loaders.
  - drop unused fread_targphys() function.

The final memory layout is created once all memory regions are
registered.  The option roms get addresses assigned and the
registered regions are checked against overlaps.  Finally all data
is copyed to the guest memory.

Advantages:

  (1) Filling memory on initial boot and on reset takes the same
      code path, making reset more robust.
  (2) The need to keep track of the option rom load address is gone.
  (3) Due to (2) option roms can be loaded outside pc_init().  This
      allows to move the pxe rom loading into the nic drivers for
      example.

Additional bonus:  There is a 'info roms' monitor command now.

The patch also switches over pc.c and removes the
option_rom_setup_reset() and load_option_rom() functions.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 hw/elf_ops.h |    6 +-
 hw/loader.c  |  254 ++++++++++++++++++++++++++++++++++++++++++------------
 hw/loader.h  |   29 ++++++-
 hw/pc.c      |  269 ++++++++++++++++++----------------------------------------
 monitor.c    |    3 +
 vl.c         |    3 +
 6 files changed, 317 insertions(+), 247 deletions(-)

diff --git a/hw/elf_ops.h b/hw/elf_ops.h
index 8376465..6093dea 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 5d83a66..c436ec6 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 3632008..031e6ad 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 bc2875e..3e3e78e 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'\n",
-		    initrd_filename);
-	    exit(1);
-	}
-
-	initrd_size = get_file_size(fi);
+	initrd_size = get_image_size(initrd_filename);
 	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'\n",
-		    initrd_filename);
-	    exit(1);
-	}
-	fclose(fi);
+        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 };
@@ -1058,35 +998,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;
@@ -1124,7 +1035,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;
@@ -1223,25 +1134,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),
@@ -1250,14 +1153,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++) {
@@ -1271,8 +1171,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 f105a2e..f79b833 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 7bfd415..57609eb 100644
--- a/vl.c
+++ b/vl.c
@@ -140,6 +140,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"
@@ -5875,6 +5876,8 @@ int main(int argc, char **argv, char **envp)
         exit(1);
     }
 
+    rom_load_all();
+
     if (loadvm) {
         if (load_vmstate(cur_mon, loadvm) < 0) {
             autostart = 0;
-- 
1.6.2.5

^ permalink raw reply related	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2009-10-06 21:18 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-09-30 15:43 [Qemu-devel] [PATCH] Reorganize option rom (+linux kernel) loading Gerd Hoffmann
     [not found] ` <m34oqkmf0n.fsf@neno.mitica>
2009-09-30 19:07   ` [Qemu-devel] " Gerd Hoffmann
2009-09-30 19:51 ` [Qemu-devel] " Blue Swirl
2009-10-01  9:11   ` Gerd Hoffmann
2009-10-01 16:25     ` Blue Swirl
2009-10-02 11:40       ` Gerd Hoffmann
2009-10-02 15:19         ` Gerd Hoffmann
2009-10-02 17:58           ` Blue Swirl
2009-10-06 21:18             ` Gerd Hoffmann
2009-10-02 17:56         ` Blue Swirl
2009-10-01 14:42 Gerd Hoffmann

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.