@@ -138,12 +138,84 @@ static void pc_system_flash_init(MemoryRegion *rom_memory,
pc_isa_bios_init(rom_memory, flash_mem, size);
}
+typedef struct SystemRomResizeState {
+ MemoryRegion *rom_memory;
+ MemoryRegion *isa_bios;
+} SystemRomResizeState;
+
+static void system_rom_memory_init(MemoryRegion *rom_memory,
+ int bios_size, bool resizable);
+
+static int system_rom_memory_resize(MemoryRegion *bios, uint64_t size,
+ void *opaque)
+{
+ SystemRomResizeState *resize_state = opaque;
+
+ memory_region_del_subregion(resize_state->rom_memory, bios);
+ memory_region_del_subregion(resize_state->rom_memory,
+ resize_state->isa_bios);
+ memory_region_destroy(resize_state->isa_bios);
+ memory_region_destroy(bios);
+ g_free(bios);
+ g_free(resize_state->isa_bios);
+
+ system_rom_memory_init(resize_state->rom_memory, size, false);
+
+ return 0;
+}
+
+static void system_rom_memory_resize_cleanup(void *opaque)
+{
+ SystemRomResizeState *resize_state = opaque;
+
+ g_free(resize_state);
+}
+
+static void system_rom_memory_init(MemoryRegion *rom_memory,
+ int bios_size, bool resizable)
+{
+ MemoryRegion *bios, *isa_bios;
+ int isa_bios_size;
+ SystemRomResizeState *resize_state;
+
+ bios = g_malloc(sizeof(*bios));
+ memory_region_init_ram(bios, "pc.bios", bios_size);
+ vmstate_register_ram_global(bios);
+ memory_region_set_readonly(bios, true);
+
+ /* map the last 128KB of the BIOS in ISA space */
+ isa_bios_size = bios_size;
+ if (isa_bios_size > (128 * 1024)) {
+ isa_bios_size = 128 * 1024;
+ }
+ isa_bios = g_malloc(sizeof(*isa_bios));
+ memory_region_init_alias(isa_bios, "isa-bios", bios,
+ bios_size - isa_bios_size, isa_bios_size);
+ memory_region_add_subregion_overlap(rom_memory,
+ 0x100000 - isa_bios_size,
+ isa_bios,
+ 1);
+ memory_region_set_readonly(isa_bios, true);
+
+ /* map all the bios at the top of memory */
+ memory_region_add_subregion(rom_memory,
+ (uint32_t)(-bios_size),
+ bios);
+
+ if (resizable) {
+ resize_state = g_malloc0(sizeof(SystemRomResizeState));
+ resize_state->rom_memory = rom_memory;
+ resize_state->isa_bios = isa_bios;
+ vmstate_register_ram_resizable(bios, system_rom_memory_resize,
+ system_rom_memory_resize_cleanup,
+ resize_state);
+ }
+}
+
static void old_pc_system_rom_init(MemoryRegion *rom_memory)
{
char *filename;
- MemoryRegion *bios, *isa_bios;
- int bios_size, isa_bios_size;
- int ret;
+ int ret, bios_size;
/* BIOS load */
if (bios_name == NULL) {
@@ -159,10 +231,9 @@ static void old_pc_system_rom_init(MemoryRegion *rom_memory)
(bios_size % 65536) != 0) {
goto bios_error;
}
- bios = g_malloc(sizeof(*bios));
- memory_region_init_ram(bios, "pc.bios", bios_size);
- vmstate_register_ram_global(bios);
- memory_region_set_readonly(bios, true);
+
+ system_rom_memory_init(rom_memory, bios_size, true);
+
ret = rom_add_file_fixed(bios_name, (uint32_t)(-bios_size), -1);
if (ret != 0) {
bios_error:
@@ -172,25 +243,6 @@ static void old_pc_system_rom_init(MemoryRegion *rom_memory)
if (filename) {
g_free(filename);
}
-
- /* map the last 128KB of the BIOS in ISA space */
- isa_bios_size = bios_size;
- if (isa_bios_size > (128 * 1024)) {
- isa_bios_size = 128 * 1024;
- }
- isa_bios = g_malloc(sizeof(*isa_bios));
- memory_region_init_alias(isa_bios, "isa-bios", bios,
- bios_size - isa_bios_size, isa_bios_size);
- memory_region_add_subregion_overlap(rom_memory,
- 0x100000 - isa_bios_size,
- isa_bios,
- 1);
- memory_region_set_readonly(isa_bios, true);
-
- /* map all the bios at the top of memory */
- memory_region_add_subregion(rom_memory,
- (uint32_t)(-bios_size),
- bios);
}
void pc_system_firmware_init(MemoryRegion *rom_memory)
SeaBIOS recently changed in tree from 128KB to 256KB. This causes migration from versions prior to 1.4 to fail due to the corresponding RAMBlock sizes not matching. Relaxing this check is insufficient since it results in a partially overwritten BIOS region that leads to a KVM exception on post-migration reboot. Instead, use a VMStateRAMResizeHandler to re-initialize the RAMBlock and relevant MemoryRegions in cases where the migrated ROM size is different than the current one. relevant 'info mtree' for 1.3: pci 0000000000000000-7ffffffffffffffe (prio 0, RW): pci 00000000000c0000-00000000000dffff (prio 1, RW): pc.rom 00000000000e0000-00000000000fffff (prio 1, R-): alias isa-bios \ @pc.bios 0000000000000000-000000000001ffff 00000000fffe0000-00000000ffffffff (prio 0, R-): pc.bios relevant 'info mtree' for 1.4 pre-migration: pci 0000000000000000-7ffffffffffffffe (prio 0, RW): pci 00000000000c0000-00000000000dffff (prio 1, RW): pc.rom 00000000000e0000-00000000000fffff (prio 1, R-): alias isa-bios \ @pc.bios 0000000000020000-000000000003ffff 00000000fffc0000-00000000ffffffff (prio 0, R-): pc.bios relevant 'info mtree' for 1.4 after the resize handler is called: pci 0000000000000000-7ffffffffffffffe (prio 0, RW): pci 00000000000c0000-00000000000dffff (prio 1, RW): pc.rom 00000000000e0000-00000000000fffff (prio 1, R-): alias isa-bios \ @pc.bios 0000000000000000-000000000001ffff 00000000fffe0000-00000000ffffffff (prio 0, R-): pc.bios Tested post-migration (from 1.3) functionality with qemu-jeos, Ubuntu 12.10, and Windows 7. Cc: qemu-stable@nongnu.org Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com> --- hw/pc_sysfw.c | 104 ++++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 78 insertions(+), 26 deletions(-)