For cpr-exec mode, ramblock_is_ignored is always true, and the address of each migrated memory region must match the address of the statically initialized region on the target. However, for a PCI rom block, the region address is set when the guest writes to a BAR on the source, which does not occur on the target, causing a "Mismatched GPAs" error during cpr-exec migration.
To fix, unconditionally set the target's address to the source's address if the region does not have an address yet. Signed-off-by: Steve Sistare <[email protected]> --- include/exec/memory.h | 12 ++++++++++++ migration/ram.c | 17 ++++++++++------- softmmu/memory.c | 10 ++++++++-- 3 files changed, 30 insertions(+), 9 deletions(-) diff --git a/include/exec/memory.h b/include/exec/memory.h index 128bf3e..9b3bad5 100644 --- a/include/exec/memory.h +++ b/include/exec/memory.h @@ -738,6 +738,7 @@ struct MemoryRegion { bool flush_coalesced_mmio; uint8_t dirty_log_mask; bool is_iommu; + bool has_addr; RAMBlock *ram_block; Object *owner; @@ -2268,6 +2269,17 @@ void memory_region_set_enabled(MemoryRegion *mr, bool enabled); void memory_region_set_address(MemoryRegion *mr, hwaddr addr); /* + * memory_region_set_address_only: set the address of a region. + * + * Same as memory_region_set_address, but without causing transaction side + * effects. + * + * @mr: the region to be updated + * @addr: new address, relative to container region + */ +void memory_region_set_address_only(MemoryRegion *mr, hwaddr addr); + +/* * memory_region_set_size: dynamically update the size of a region. * * Dynamically updates the size of a region. diff --git a/migration/ram.c b/migration/ram.c index 4c868d2..6005c53 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -4314,13 +4314,16 @@ static int ram_load_precopy(QEMUFile *f) } if (migrate_ignore_shared()) { hwaddr addr = qemu_get_be64(f); - if (ramblock_is_ignored(block) && - block->mr->addr != addr) { - error_report("Mismatched GPAs for block %s " - "%" PRId64 "!= %" PRId64, - id, (uint64_t)addr, - (uint64_t)block->mr->addr); - ret = -EINVAL; + if (ramblock_is_ignored(block)) { + if (!block->mr->has_addr) { + memory_region_set_address_only(block->mr, addr); + } else if (block->mr->addr != addr) { + error_report("Mismatched GPAs for block %s " + "%" PRId64 "!= %" PRId64, + id, (uint64_t)addr, + (uint64_t)block->mr->addr); + ret = -EINVAL; + } } } ram_control_load_hook(f, RAM_CONTROL_BLOCK_REG, diff --git a/softmmu/memory.c b/softmmu/memory.c index 6aa3a2f..8825608 100644 --- a/softmmu/memory.c +++ b/softmmu/memory.c @@ -2552,7 +2552,7 @@ static void memory_region_add_subregion_common(MemoryRegion *mr, for (alias = subregion->alias; alias; alias = alias->alias) { alias->mapped_via_alias++; } - subregion->addr = offset; + memory_region_set_address_only(subregion, offset); memory_region_update_container_subregions(subregion); } @@ -2632,10 +2632,16 @@ static void memory_region_readd_subregion(MemoryRegion *mr) } } +void memory_region_set_address_only(MemoryRegion *mr, hwaddr addr) +{ + mr->addr = addr; + mr->has_addr = true; +} + void memory_region_set_address(MemoryRegion *mr, hwaddr addr) { if (addr != mr->addr) { - mr->addr = addr; + memory_region_set_address_only(mr, addr); memory_region_readd_subregion(mr); } } -- 1.8.3.1
