From patchwork Mon Aug 26 16:43:08 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Michael S. Tsirkin" X-Patchwork-Id: 269932 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 37E4B2C0097 for ; Tue, 27 Aug 2013 02:42:03 +1000 (EST) Received: from localhost ([::1]:52224 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1VDzrd-0000Ra-EG for incoming@patchwork.ozlabs.org; Mon, 26 Aug 2013 12:42:01 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:54050) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1VDzqx-0000FE-4v for qemu-devel@nongnu.org; Mon, 26 Aug 2013 12:41:25 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1VDzqq-0003Gk-Vx for qemu-devel@nongnu.org; Mon, 26 Aug 2013 12:41:19 -0400 Received: from mx1.redhat.com ([209.132.183.28]:63672) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1VDzqq-0003GY-OB for qemu-devel@nongnu.org; Mon, 26 Aug 2013 12:41:12 -0400 Received: from int-mx01.intmail.prod.int.phx2.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id r7QGfBdi011235 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); Mon, 26 Aug 2013 12:41:11 -0400 Received: from redhat.com (vpn1-5-108.ams2.redhat.com [10.36.5.108]) by int-mx01.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with SMTP id r7QGf9QI008159; Mon, 26 Aug 2013 12:41:09 -0400 Date: Mon, 26 Aug 2013 19:43:08 +0300 From: "Michael S. Tsirkin" To: qemu-devel@nongnu.org Message-ID: <1377535318-30491-4-git-send-email-mst@redhat.com> References: <1377535318-30491-1-git-send-email-mst@redhat.com> MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: <1377535318-30491-1-git-send-email-mst@redhat.com> X-Mutt-Fcc: =sent X-Scanned-By: MIMEDefang 2.67 on 10.5.11.11 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 3.x X-Received-From: 209.132.183.28 Cc: Laszlo Ersek , Anthony Liguori Subject: [Qemu-devel] [PULL 03/14] loader: store FW CFG ROM files in RAM X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org ROM files that are put in FW CFG are copied to guest ram, by BIOS, but they are not backed by RAM so they don't get migrated. Each time we change two bytes in such a ROM this breaks cross-version migration: since we can migrate after BIOS has read the first byte but before it has read the second one, getting an inconsistent state. Future-proof this by creating, for each such ROM, an MR serving as the backing store. This MR is never mapped into guest memory, but it's registered as RAM so it's migrated with the guest. Naturally, this only helps for -M 1.7 and up, older machine types will still have the cross-version migration bug. Luckily the race window for the problem to trigger is very small, which is also likely why we didn't notice the cross-version migration bug in testing yet. Signed-off-by: Michael S. Tsirkin Reviewed-by: Laszlo Ersek --- hw/core/loader.c | 49 ++++++++++++++++++++++++++++++++++++++++++++++--- hw/i386/pc_piix.c | 2 ++ hw/i386/pc_q35.c | 2 ++ include/hw/loader.h | 1 + 4 files changed, 51 insertions(+), 3 deletions(-) diff --git a/hw/core/loader.c b/hw/core/loader.c index 6875b7e..7b3d3ee 100644 --- a/hw/core/loader.c +++ b/hw/core/loader.c @@ -54,6 +54,8 @@ #include +bool rom_file_in_ram = true; + static int roms_loaded; /* return the size or -1 if error */ @@ -576,6 +578,7 @@ struct Rom { size_t datasize; uint8_t *data; + MemoryRegion *mr; int isrom; char *fw_dir; char *fw_file; @@ -605,6 +608,21 @@ static void rom_insert(Rom *rom) QTAILQ_INSERT_TAIL(&roms, rom, next); } +static void *rom_set_mr(Rom *rom, Object *owner, const char *name) +{ + void *data; + + rom->mr = g_malloc(sizeof(*rom->mr)); + memory_region_init_ram(rom->mr, owner, name, rom->datasize); + memory_region_set_readonly(rom->mr, true); + vmstate_register_ram_global(rom->mr); + + data = memory_region_get_ram_ptr(rom->mr); + memcpy(data, rom->data, rom->datasize); + + return data; +} + int rom_add_file(const char *file, const char *fw_dir, hwaddr addr, int32_t bootindex) { @@ -646,6 +664,7 @@ int rom_add_file(const char *file, const char *fw_dir, if (rom->fw_file && fw_cfg) { const char *basename; char fw_file_name[56]; + void *data; basename = strrchr(rom->fw_file, '/'); if (basename) { @@ -655,8 +674,15 @@ int rom_add_file(const char *file, const char *fw_dir, } snprintf(fw_file_name, sizeof(fw_file_name), "%s/%s", rom->fw_dir, basename); - fw_cfg_add_file(fw_cfg, fw_file_name, rom->data, rom->romsize); snprintf(devpath, sizeof(devpath), "/rom@%s", fw_file_name); + + if (rom_file_in_ram) { + data = rom_set_mr(rom, OBJECT(fw_cfg), devpath); + } else { + data = rom->data; + } + + fw_cfg_add_file(fw_cfg, fw_file_name, data, rom->romsize); } else { snprintf(devpath, sizeof(devpath), "/rom@" TARGET_FMT_plx, addr); } @@ -731,7 +757,12 @@ static void rom_reset(void *unused) if (rom->data == NULL) { continue; } - cpu_physical_memory_write_rom(rom->addr, rom->data, rom->datasize); + if (rom->mr) { + void *host = memory_region_get_ram_ptr(rom->mr); + memcpy(host, rom->data, rom->datasize); + } else { + cpu_physical_memory_write_rom(rom->addr, rom->data, rom->datasize); + } if (rom->isrom) { /* rom needs to be written only once */ g_free(rom->data); @@ -781,6 +812,9 @@ static Rom *find_rom(hwaddr addr) if (rom->fw_file) { continue; } + if (rom->mr) { + continue; + } if (rom->addr > addr) { continue; } @@ -808,6 +842,9 @@ int rom_copy(uint8_t *dest, hwaddr addr, size_t size) if (rom->fw_file) { continue; } + if (rom->mr) { + continue; + } if (rom->addr + rom->romsize < addr) { continue; } @@ -866,7 +903,13 @@ void do_info_roms(Monitor *mon, const QDict *qdict) Rom *rom; QTAILQ_FOREACH(rom, &roms, next) { - if (!rom->fw_file) { + if (rom->mr) { + monitor_printf(mon, "%s" + " size=0x%06zx name=\"%s\"\n", + rom->mr->name, + rom->romsize, + rom->name); + } else if (!rom->fw_file) { monitor_printf(mon, "addr=" TARGET_FMT_plx " size=0x%06zx mem=%s name=\"%s\"\n", rom->addr, rom->romsize, diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index 46f1fd7..4591027 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -25,6 +25,7 @@ #include #include "hw/hw.h" +#include "hw/loader.h" #include "hw/i386/pc.h" #include "hw/i386/apic.h" #include "hw/pci/pci.h" @@ -252,6 +253,7 @@ static void pc_init_pci(QEMUMachineInitArgs *args) static void pc_init_pci_1_6(QEMUMachineInitArgs *args) { has_pci_info = false; + rom_file_in_ram = false; pc_init_pci(args); } diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c index ab0aa70..533a2d6 100644 --- a/hw/i386/pc_q35.c +++ b/hw/i386/pc_q35.c @@ -28,6 +28,7 @@ * THE SOFTWARE. */ #include "hw/hw.h" +#include "hw/loader.h" #include "sysemu/arch_init.h" #include "hw/i2c/smbus.h" #include "hw/boards.h" @@ -221,6 +222,7 @@ static void pc_q35_init(QEMUMachineInitArgs *args) static void pc_q35_init_1_6(QEMUMachineInitArgs *args) { has_pci_info = false; + rom_file_in_ram = false; pc_q35_init(args); } diff --git a/include/hw/loader.h b/include/hw/loader.h index eb9c9a3..6145736 100644 --- a/include/hw/loader.h +++ b/include/hw/loader.h @@ -36,6 +36,7 @@ void pstrcpy_targphys(const char *name, hwaddr dest, int buf_size, const char *source); +extern bool rom_file_in_ram; int rom_add_file(const char *file, const char *fw_dir, hwaddr addr, int32_t bootindex);