958e1b
From 9f136b4ed4ecd83a2de6ffa52775286b106bb5f5 Mon Sep 17 00:00:00 2001
240766
From: Laszlo Ersek <lersek@redhat.com>
240766
Date: Thu, 17 Apr 2014 11:13:59 +0200
240766
Subject: [PATCH 10/12] qemu_loadvm_state(): shadow SeaBIOS for VM incoming from RHEL-6 host
240766
240766
RH-Author: Laszlo Ersek <lersek@redhat.com>
240766
Message-id: <1397733239-8835-1-git-send-email-lersek@redhat.com>
240766
Patchwork-id: 58498
240766
O-Subject: [RHEL-7.0 0day qemu-kvm PATCH v2] qemu_loadvm_state(): shadow SeaBIOS for VM incoming from RHEL-6 host
958e1b
Bugzilla: 1027565
240766
RH-Acked-by: Dr. David Alan Gilbert (git) <dgilbert@redhat.com>
240766
RH-Acked-by: Marcel Apfelbaum <marcel.a@redhat.com>
240766
RH-Acked-by: Eduardo Habkost <ehabkost@redhat.com>
240766
240766
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1027565
240766
Brew:     https://brewweb.devel.redhat.com/taskinfo?taskID=7352678
240766
240766
RHEL-only patch.
240766
240766
SeaBIOS's shadowing logic has no effect on "pc.ram" (only on "pc.bios" and
240766
"pc.rom") when it runs on the RHEL-6 emulator. When such a guest is
240766
migrated to the RHEL-7 emulator, where the PAM registers actually work,
240766
these two UMBs under 1MB simply disappear from the guest's view, breaking
240766
reboot and S3 resume.
240766
240766
Tested extensively by QE.
240766
240766
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
240766
---
240766
240766
Notes:
240766
    Changes in v2:
240766
    - print message to stderr when we shadow the UMBs manually [Dave]
240766
    - also copy C and D segments from pc.rom to pc.ram
240766
    - move to qemu_loadvm_state() from ram_load() -- we must shadow only
240766
      when all RAMBlocks have been loaded [Dave]
240766
240766
 include/sysemu/sysemu.h |  1 +
240766
 hw/i386/pc_piix.c       |  1 +
240766
 savevm.c                | 66 +++++++++++++++++++++++++++++++++++++++++++++++++
240766
 3 files changed, 68 insertions(+)
240766
240766
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
240766
---
240766
 hw/i386/pc_piix.c       |    1 +
240766
 include/sysemu/sysemu.h |    1 +
240766
 savevm.c                |   66 +++++++++++++++++++++++++++++++++++++++++++++++
240766
 3 files changed, 68 insertions(+), 0 deletions(-)
240766
240766
diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c
240766
index 940816f..fea98b6 100644
240766
--- a/hw/i386/pc_piix.c
240766
+++ b/hw/i386/pc_piix.c
240766
@@ -954,6 +954,7 @@ static void pc_compat_rhel650(QEMUMachineInitArgs *args)
240766
     rom_file_has_mr = false; 
240766
     has_acpi_build = false;
240766
     gigabyte_align = false;
240766
+    shadow_bios_after_incoming = true;
240766
 }
240766
 
240766
 static void pc_init_rhel650(QEMUMachineInitArgs *args)
240766
diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h
240766
index 8dc0a4c..07181ac 100644
240766
--- a/include/sysemu/sysemu.h
240766
+++ b/include/sysemu/sysemu.h
240766
@@ -84,6 +84,7 @@ void qemu_savevm_state_complete(QEMUFile *f);
240766
 void qemu_savevm_state_cancel(void);
240766
 uint64_t qemu_savevm_state_pending(QEMUFile *f, uint64_t max_size);
240766
 int qemu_loadvm_state(QEMUFile *f);
240766
+extern bool shadow_bios_after_incoming;
240766
 
240766
 /* SLIRP */
240766
 void do_info_slirp(Monitor *mon);
240766
diff --git a/savevm.c b/savevm.c
240766
index 4d92a7b..6efbb75 100644
240766
--- a/savevm.c
240766
+++ b/savevm.c
240766
@@ -52,6 +52,8 @@
240766
 #define ARP_PTYPE_IP 0x0800
240766
 #define ARP_OP_REQUEST_REV 0x3
240766
 
240766
+bool shadow_bios_after_incoming;
240766
+
240766
 static int announce_self_create(uint8_t *buf,
240766
 				uint8_t *mac_addr)
240766
 {
240766
@@ -2195,6 +2197,63 @@ typedef struct LoadStateEntry {
240766
     int version_id;
240766
 } LoadStateEntry;
240766
 
240766
+static void shadow_bios(void)
240766
+{
240766
+    RAMBlock *block, *ram, *oprom, *bios;
240766
+    size_t one_meg, oprom_size, bios_size;
240766
+    uint8_t *cd_seg_host, *ef_seg_host;
240766
+
240766
+    ram = NULL;
240766
+    oprom = NULL;
240766
+    bios = NULL;
240766
+    QTAILQ_FOREACH(block, &ram_list.blocks, next) {
240766
+        if (strcmp("pc.ram", block->idstr) == 0) {
240766
+            assert(ram == NULL);
240766
+            ram = block;
240766
+        } else if (strcmp("pc.rom", block->idstr) == 0) {
240766
+            assert(oprom == NULL);
240766
+            oprom = block;
240766
+        } else if (strcmp("pc.bios", block->idstr) == 0) {
240766
+            assert(bios == NULL);
240766
+            bios = block;
240766
+        }
240766
+    }
240766
+    assert(ram != NULL);
240766
+    assert(oprom != NULL);
240766
+    assert(bios != NULL);
240766
+    assert(memory_region_is_ram(ram->mr));
240766
+    assert(memory_region_is_ram(oprom->mr));
240766
+    assert(memory_region_is_ram(bios->mr));
240766
+    assert(int128_eq(ram->mr->size, int128_make64(ram->length)));
240766
+    assert(int128_eq(oprom->mr->size, int128_make64(oprom->length)));
240766
+    assert(int128_eq(bios->mr->size, int128_make64(bios->length)));
240766
+
240766
+    one_meg = 1024 * 1024;
240766
+    oprom_size = 128 * 1024;
240766
+    bios_size = 128 * 1024;
240766
+    assert(ram->length >= one_meg);
240766
+    assert(oprom->length == oprom_size);
240766
+    assert(bios->length == bios_size);
240766
+
240766
+    ef_seg_host = memory_region_get_ram_ptr(ram->mr) + (one_meg - bios_size);
240766
+    cd_seg_host = ef_seg_host - oprom_size;
240766
+
240766
+    /* This is a crude hack, but we must distinguish a rhel6.x.0 machtype guest
240766
+     * coming in from a RHEL-6 emulator (where shadowing has had no effect on
240766
+     * "pc.ram") from a similar guest coming in from a RHEL-7 emulator (where
240766
+     * shadowing has worked). In the latter case we must not trample the live
240766
+     * SeaBIOS variables in "pc.ram".
240766
+     */
240766
+    if (buffer_is_zero(ef_seg_host, bios_size)) {
240766
+        fprintf(stderr, "copying E and F segments from pc.bios to pc.ram\n");
240766
+        memcpy(ef_seg_host, memory_region_get_ram_ptr(bios->mr), bios_size);
240766
+    }
240766
+    if (buffer_is_zero(cd_seg_host, oprom_size)) {
240766
+        fprintf(stderr, "copying C and D segments from pc.rom to pc.ram\n");
240766
+        memcpy(cd_seg_host, memory_region_get_ram_ptr(oprom->mr), oprom_size);
240766
+    }
240766
+}
240766
+
240766
 int qemu_loadvm_state(QEMUFile *f)
240766
 {
240766
     QLIST_HEAD(, LoadStateEntry) loadvm_handlers =
240766
@@ -2297,6 +2356,13 @@ int qemu_loadvm_state(QEMUFile *f)
240766
         }
240766
     }
240766
 
240766
+    /* Supplement SeaBIOS's shadowing now, because it was useless when the
240766
+     * incoming VM started on the RHEL-6 emulator.
240766
+     */
240766
+    if (shadow_bios_after_incoming) {
240766
+        shadow_bios();
240766
+    }
240766
+
240766
     cpu_synchronize_all_post_init();
240766
 
240766
     ret = 0;
240766
-- 
240766
1.7.1
240766