Skip to content

Commit 394f0f7

Browse files
shamiali2008mstsirkin
authored andcommitted
fw_cfg: Migrate ACPI table mr sizes separately
Any sub-page size update to ACPI MRs will be lost during migration, as we use aligned size in ram_load_precopy() -> qemu_ram_resize() path. This will result in inconsistency in FWCfgEntry sizes between source and destination. In order to avoid this, save and restore them separately during migration. Up until now, this problem may not be that relevant for x86 as both ACPI table and Linker MRs gets padded and aligned. Also at present, qemu_ram_resize() doesn't invoke callback to update FWCfgEntry for unaligned size changes. But since we are going to fix the qemu_ram_resize() in the subsequent patch, the issue may become more serious especially for RSDP MR case. Moreover, the issue will soon become prominent in arm/virt as well where the MRs are not padded or aligned at all and eventually have acpi table changes as part of future additions like NVDIMM hot-add feature. Suggested-by: David Hildenbrand <[email protected]> Signed-off-by: Shameer Kolothum <[email protected]> Acked-by: David Hildenbrand <[email protected]> Message-Id: <[email protected]> Reviewed-by: Michael S. Tsirkin <[email protected]> Signed-off-by: Michael S. Tsirkin <[email protected]>
1 parent bac78f9 commit 394f0f7

File tree

3 files changed

+97
-1
lines changed

3 files changed

+97
-1
lines changed

hw/core/machine.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ GlobalProperty hw_compat_4_2[] = {
3939
{ "usb-redir", "suppress-remote-wake", "off" },
4040
{ "qxl", "revision", "4" },
4141
{ "qxl-vga", "revision", "4" },
42+
{ "fw_cfg", "acpi-mr-restore", "false" },
4243
};
4344
const size_t hw_compat_4_2_len = G_N_ELEMENTS(hw_compat_4_2);
4445

hw/nvram/fw_cfg.c

Lines changed: 90 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
#include "qemu/config-file.h"
4040
#include "qemu/cutils.h"
4141
#include "qapi/error.h"
42+
#include "hw/acpi/aml-build.h"
4243

4344
#define FW_CFG_FILE_SLOTS_DFLT 0x20
4445

@@ -610,6 +611,55 @@ bool fw_cfg_dma_enabled(void *opaque)
610611
return s->dma_enabled;
611612
}
612613

614+
static bool fw_cfg_acpi_mr_restore(void *opaque)
615+
{
616+
FWCfgState *s = opaque;
617+
bool mr_aligned;
618+
619+
mr_aligned = QEMU_IS_ALIGNED(s->table_mr_size, qemu_real_host_page_size) &&
620+
QEMU_IS_ALIGNED(s->linker_mr_size, qemu_real_host_page_size) &&
621+
QEMU_IS_ALIGNED(s->rsdp_mr_size, qemu_real_host_page_size);
622+
return s->acpi_mr_restore && !mr_aligned;
623+
}
624+
625+
static void fw_cfg_update_mr(FWCfgState *s, uint16_t key, size_t size)
626+
{
627+
MemoryRegion *mr;
628+
ram_addr_t offset;
629+
int arch = !!(key & FW_CFG_ARCH_LOCAL);
630+
void *ptr;
631+
632+
key &= FW_CFG_ENTRY_MASK;
633+
assert(key < fw_cfg_max_entry(s));
634+
635+
ptr = s->entries[arch][key].data;
636+
mr = memory_region_from_host(ptr, &offset);
637+
638+
memory_region_ram_resize(mr, size, &error_abort);
639+
}
640+
641+
static int fw_cfg_acpi_mr_restore_post_load(void *opaque, int version_id)
642+
{
643+
FWCfgState *s = opaque;
644+
int i, index;
645+
646+
assert(s->files);
647+
648+
index = be32_to_cpu(s->files->count);
649+
650+
for (i = 0; i < index; i++) {
651+
if (!strcmp(s->files->f[i].name, ACPI_BUILD_TABLE_FILE)) {
652+
fw_cfg_update_mr(s, FW_CFG_FILE_FIRST + i, s->table_mr_size);
653+
} else if (!strcmp(s->files->f[i].name, ACPI_BUILD_LOADER_FILE)) {
654+
fw_cfg_update_mr(s, FW_CFG_FILE_FIRST + i, s->linker_mr_size);
655+
} else if (!strcmp(s->files->f[i].name, ACPI_BUILD_RSDP_FILE)) {
656+
fw_cfg_update_mr(s, FW_CFG_FILE_FIRST + i, s->rsdp_mr_size);
657+
}
658+
}
659+
660+
return 0;
661+
}
662+
613663
static const VMStateDescription vmstate_fw_cfg_dma = {
614664
.name = "fw_cfg/dma",
615665
.needed = fw_cfg_dma_enabled,
@@ -619,6 +669,20 @@ static const VMStateDescription vmstate_fw_cfg_dma = {
619669
},
620670
};
621671

672+
static const VMStateDescription vmstate_fw_cfg_acpi_mr = {
673+
.name = "fw_cfg/acpi_mr",
674+
.version_id = 1,
675+
.minimum_version_id = 1,
676+
.needed = fw_cfg_acpi_mr_restore,
677+
.post_load = fw_cfg_acpi_mr_restore_post_load,
678+
.fields = (VMStateField[]) {
679+
VMSTATE_UINT64(table_mr_size, FWCfgState),
680+
VMSTATE_UINT64(linker_mr_size, FWCfgState),
681+
VMSTATE_UINT64(rsdp_mr_size, FWCfgState),
682+
VMSTATE_END_OF_LIST()
683+
},
684+
};
685+
622686
static const VMStateDescription vmstate_fw_cfg = {
623687
.name = "fw_cfg",
624688
.version_id = 2,
@@ -631,6 +695,7 @@ static const VMStateDescription vmstate_fw_cfg = {
631695
},
632696
.subsections = (const VMStateDescription*[]) {
633697
&vmstate_fw_cfg_dma,
698+
&vmstate_fw_cfg_acpi_mr,
634699
NULL,
635700
}
636701
};
@@ -815,6 +880,23 @@ static struct {
815880
#define FW_CFG_ORDER_OVERRIDE_LAST 200
816881
};
817882

883+
/*
884+
* Any sub-page size update to these table MRs will be lost during migration,
885+
* as we use aligned size in ram_load_precopy() -> qemu_ram_resize() path.
886+
* In order to avoid the inconsistency in sizes save them seperately and
887+
* migrate over in vmstate post_load().
888+
*/
889+
static void fw_cfg_acpi_mr_save(FWCfgState *s, const char *filename, size_t len)
890+
{
891+
if (!strcmp(filename, ACPI_BUILD_TABLE_FILE)) {
892+
s->table_mr_size = len;
893+
} else if (!strcmp(filename, ACPI_BUILD_LOADER_FILE)) {
894+
s->linker_mr_size = len;
895+
} else if (!strcmp(filename, ACPI_BUILD_RSDP_FILE)) {
896+
s->rsdp_mr_size = len;
897+
}
898+
}
899+
818900
static int get_fw_cfg_order(FWCfgState *s, const char *name)
819901
{
820902
int i;
@@ -914,6 +996,7 @@ void fw_cfg_add_file_callback(FWCfgState *s, const char *filename,
914996
trace_fw_cfg_add_file(s, index, s->files->f[index].name, len);
915997

916998
s->files->count = cpu_to_be32(count+1);
999+
fw_cfg_acpi_mr_save(s, filename, len);
9171000
}
9181001

9191002
void fw_cfg_add_file(FWCfgState *s, const char *filename,
@@ -937,6 +1020,7 @@ void *fw_cfg_modify_file(FWCfgState *s, const char *filename,
9371020
ptr = fw_cfg_modify_bytes_read(s, FW_CFG_FILE_FIRST + i,
9381021
data, len);
9391022
s->files->f[i].size = cpu_to_be32(len);
1023+
fw_cfg_acpi_mr_save(s, filename, len);
9401024
return ptr;
9411025
}
9421026
}
@@ -973,7 +1057,10 @@ static void fw_cfg_machine_ready(struct Notifier *n, void *data)
9731057
qemu_register_reset(fw_cfg_machine_reset, s);
9741058
}
9751059

976-
1060+
static Property fw_cfg_properties[] = {
1061+
DEFINE_PROP_BOOL("acpi-mr-restore", FWCfgState, acpi_mr_restore, true),
1062+
DEFINE_PROP_END_OF_LIST(),
1063+
};
9771064

9781065
static void fw_cfg_common_realize(DeviceState *dev, Error **errp)
9791066
{
@@ -1097,6 +1184,8 @@ static void fw_cfg_class_init(ObjectClass *klass, void *data)
10971184

10981185
dc->reset = fw_cfg_reset;
10991186
dc->vmsd = &vmstate_fw_cfg;
1187+
1188+
device_class_set_props(dc, fw_cfg_properties);
11001189
}
11011190

11021191
static const TypeInfo fw_cfg_info = {

include/hw/nvram/fw_cfg.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,12 @@ struct FWCfgState {
5353
dma_addr_t dma_addr;
5454
AddressSpace *dma_as;
5555
MemoryRegion dma_iomem;
56+
57+
/* restore during migration */
58+
bool acpi_mr_restore;
59+
uint64_t table_mr_size;
60+
uint64_t linker_mr_size;
61+
uint64_t rsdp_mr_size;
5662
};
5763

5864
struct FWCfgIoState {

0 commit comments

Comments
 (0)