qemu with hax to log dma reads & writes jcs.org/2018/11/12/vfio

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 <david@redhat.com>
Signed-off-by: Shameer Kolothum <shameerali.kolothum.thodi@huawei.com>
Acked-by: David Hildenbrand <david@redhat.com>
Message-Id: <20200403101827.30664-3-shameerali.kolothum.thodi@huawei.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>

authored by

Shameer Kolothum and committed by
Michael S. Tsirkin
394f0f72 bac78f9c

+97 -1
+1
hw/core/machine.c
··· 39 39 { "usb-redir", "suppress-remote-wake", "off" }, 40 40 { "qxl", "revision", "4" }, 41 41 { "qxl-vga", "revision", "4" }, 42 + { "fw_cfg", "acpi-mr-restore", "false" }, 42 43 }; 43 44 const size_t hw_compat_4_2_len = G_N_ELEMENTS(hw_compat_4_2); 44 45
+90 -1
hw/nvram/fw_cfg.c
··· 39 39 #include "qemu/config-file.h" 40 40 #include "qemu/cutils.h" 41 41 #include "qapi/error.h" 42 + #include "hw/acpi/aml-build.h" 42 43 43 44 #define FW_CFG_FILE_SLOTS_DFLT 0x20 44 45 ··· 610 611 return s->dma_enabled; 611 612 } 612 613 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 + 613 663 static const VMStateDescription vmstate_fw_cfg_dma = { 614 664 .name = "fw_cfg/dma", 615 665 .needed = fw_cfg_dma_enabled, ··· 619 669 }, 620 670 }; 621 671 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 + 622 686 static const VMStateDescription vmstate_fw_cfg = { 623 687 .name = "fw_cfg", 624 688 .version_id = 2, ··· 631 695 }, 632 696 .subsections = (const VMStateDescription*[]) { 633 697 &vmstate_fw_cfg_dma, 698 + &vmstate_fw_cfg_acpi_mr, 634 699 NULL, 635 700 } 636 701 }; ··· 815 880 #define FW_CFG_ORDER_OVERRIDE_LAST 200 816 881 }; 817 882 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 + 818 900 static int get_fw_cfg_order(FWCfgState *s, const char *name) 819 901 { 820 902 int i; ··· 914 996 trace_fw_cfg_add_file(s, index, s->files->f[index].name, len); 915 997 916 998 s->files->count = cpu_to_be32(count+1); 999 + fw_cfg_acpi_mr_save(s, filename, len); 917 1000 } 918 1001 919 1002 void fw_cfg_add_file(FWCfgState *s, const char *filename, ··· 937 1020 ptr = fw_cfg_modify_bytes_read(s, FW_CFG_FILE_FIRST + i, 938 1021 data, len); 939 1022 s->files->f[i].size = cpu_to_be32(len); 1023 + fw_cfg_acpi_mr_save(s, filename, len); 940 1024 return ptr; 941 1025 } 942 1026 } ··· 973 1057 qemu_register_reset(fw_cfg_machine_reset, s); 974 1058 } 975 1059 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 + }; 977 1064 978 1065 static void fw_cfg_common_realize(DeviceState *dev, Error **errp) 979 1066 { ··· 1097 1184 1098 1185 dc->reset = fw_cfg_reset; 1099 1186 dc->vmsd = &vmstate_fw_cfg; 1187 + 1188 + device_class_set_props(dc, fw_cfg_properties); 1100 1189 } 1101 1190 1102 1191 static const TypeInfo fw_cfg_info = {
+6
include/hw/nvram/fw_cfg.h
··· 53 53 dma_addr_t dma_addr; 54 54 AddressSpace *dma_as; 55 55 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; 56 62 }; 57 63 58 64 struct FWCfgIoState {