@@ -53,6 +53,12 @@ struct FWCfgState {
dma_addr_t dma_addr;
AddressSpace *dma_as;
MemoryRegion dma_iomem;
+
+ /* restore during migration */
+ bool acpi_mr_restore;
+ uint64_t table_mr_size;
+ uint64_t linker_mr_size;
+ uint64_t rsdp_mr_size;
};
struct FWCfgIoState {
@@ -39,6 +39,7 @@ GlobalProperty hw_compat_4_2[] = {
{ "usb-redir", "suppress-remote-wake", "off" },
{ "qxl", "revision", "4" },
{ "qxl-vga", "revision", "4" },
+ { "fw_cfg", "acpi-mr-restore", "false" },
};
const size_t hw_compat_4_2_len = G_N_ELEMENTS(hw_compat_4_2);
@@ -39,6 +39,7 @@
#include "qemu/config-file.h"
#include "qemu/cutils.h"
#include "qapi/error.h"
+#include "hw/acpi/aml-build.h"
#define FW_CFG_FILE_SLOTS_DFLT 0x20
@@ -610,6 +611,55 @@ bool fw_cfg_dma_enabled(void *opaque)
return s->dma_enabled;
}
+static bool fw_cfg_acpi_mr_restore(void *opaque)
+{
+ FWCfgState *s = opaque;
+ bool mr_aligned;
+
+ mr_aligned = QEMU_IS_ALIGNED(s->table_mr_size, qemu_real_host_page_size) &&
+ QEMU_IS_ALIGNED(s->linker_mr_size, qemu_real_host_page_size) &&
+ QEMU_IS_ALIGNED(s->rsdp_mr_size, qemu_real_host_page_size);
+ return s->acpi_mr_restore && !mr_aligned;
+}
+
+static void fw_cfg_update_mr(FWCfgState *s, uint16_t key, size_t size)
+{
+ MemoryRegion *mr;
+ ram_addr_t offset;
+ int arch = !!(key & FW_CFG_ARCH_LOCAL);
+ void *ptr;
+
+ key &= FW_CFG_ENTRY_MASK;
+ assert(key < fw_cfg_max_entry(s));
+
+ ptr = s->entries[arch][key].data;
+ mr = memory_region_from_host(ptr, &offset);
+
+ memory_region_ram_resize(mr, size, &error_abort);
+}
+
+static int fw_cfg_acpi_mr_restore_post_load(void *opaque, int version_id)
+{
+ FWCfgState *s = opaque;
+ int i, index;
+
+ assert(s->files);
+
+ index = be32_to_cpu(s->files->count);
+
+ for (i = 0; i < index; i++) {
+ if (!strcmp(s->files->f[i].name, ACPI_BUILD_TABLE_FILE)) {
+ fw_cfg_update_mr(s, FW_CFG_FILE_FIRST + i, s->table_mr_size);
+ } else if (!strcmp(s->files->f[i].name, ACPI_BUILD_LOADER_FILE)) {
+ fw_cfg_update_mr(s, FW_CFG_FILE_FIRST + i, s->linker_mr_size);
+ } else if (!strcmp(s->files->f[i].name, ACPI_BUILD_RSDP_FILE)) {
+ fw_cfg_update_mr(s, FW_CFG_FILE_FIRST + i, s->rsdp_mr_size);
+ }
+ }
+
+ return 0;
+}
+
static const VMStateDescription vmstate_fw_cfg_dma = {
.name = "fw_cfg/dma",
.needed = fw_cfg_dma_enabled,
@@ -619,6 +669,20 @@ static const VMStateDescription vmstate_fw_cfg_dma = {
},
};
+static const VMStateDescription vmstate_fw_cfg_acpi_mr = {
+ .name = "fw_cfg/acpi_mr",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .needed = fw_cfg_acpi_mr_restore,
+ .post_load = fw_cfg_acpi_mr_restore_post_load,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT64(table_mr_size, FWCfgState),
+ VMSTATE_UINT64(linker_mr_size, FWCfgState),
+ VMSTATE_UINT64(rsdp_mr_size, FWCfgState),
+ VMSTATE_END_OF_LIST()
+ },
+};
+
static const VMStateDescription vmstate_fw_cfg = {
.name = "fw_cfg",
.version_id = 2,
@@ -631,6 +695,7 @@ static const VMStateDescription vmstate_fw_cfg = {
},
.subsections = (const VMStateDescription*[]) {
&vmstate_fw_cfg_dma,
+ &vmstate_fw_cfg_acpi_mr,
NULL,
}
};
@@ -815,6 +880,23 @@ static struct {
#define FW_CFG_ORDER_OVERRIDE_LAST 200
};
+/*
+ * Any sub-page size update to these table MRs will be lost during migration,
+ * as we use aligned size in ram_load_precopy() -> qemu_ram_resize() path.
+ * In order to avoid the inconsistency in sizes save them seperately and
+ * migrate over in vmstate post_load().
+ */
+static void fw_cfg_acpi_mr_save(FWCfgState *s, const char *filename, size_t len)
+{
+ if (!strcmp(filename, ACPI_BUILD_TABLE_FILE)) {
+ s->table_mr_size = len;
+ } else if (!strcmp(filename, ACPI_BUILD_LOADER_FILE)) {
+ s->linker_mr_size = len;
+ } else if (!strcmp(filename, ACPI_BUILD_RSDP_FILE)) {
+ s->rsdp_mr_size = len;
+ }
+}
+
static int get_fw_cfg_order(FWCfgState *s, const char *name)
{
int i;
@@ -914,6 +996,7 @@ void fw_cfg_add_file_callback(FWCfgState *s, const char *filename,
trace_fw_cfg_add_file(s, index, s->files->f[index].name, len);
s->files->count = cpu_to_be32(count+1);
+ fw_cfg_acpi_mr_save(s, filename, len);
}
void fw_cfg_add_file(FWCfgState *s, const char *filename,
@@ -937,6 +1020,7 @@ void *fw_cfg_modify_file(FWCfgState *s, const char *filename,
ptr = fw_cfg_modify_bytes_read(s, FW_CFG_FILE_FIRST + i,
data, len);
s->files->f[i].size = cpu_to_be32(len);
+ fw_cfg_acpi_mr_save(s, filename, len);
return ptr;
}
}
@@ -973,7 +1057,10 @@ static void fw_cfg_machine_ready(struct Notifier *n, void *data)
qemu_register_reset(fw_cfg_machine_reset, s);
}
-
+static Property fw_cfg_properties[] = {
+ DEFINE_PROP_BOOL("acpi-mr-restore", FWCfgState, acpi_mr_restore, true),
+ DEFINE_PROP_END_OF_LIST(),
+};
static void fw_cfg_common_realize(DeviceState *dev, Error **errp)
{
@@ -1097,6 +1184,8 @@ static void fw_cfg_class_init(ObjectClass *klass, void *data)
dc->reset = fw_cfg_reset;
dc->vmsd = &vmstate_fw_cfg;
+
+ device_class_set_props(dc, fw_cfg_properties);
}
static const TypeInfo fw_cfg_info = {