When VHOST_USER_PROTOCOL_F_HOST_NOTIFIER feature negotiated and virtio_queue_set_host_notifier_mr success on system blk device's queue, the VM can't load MBR if the notify region's address above 4GB.
Assign the address of notify region in the modern bar above 4G, the vp_notify in SeaBIOS will use PCI Cfg Capability to write notify region. This will trap into QEMU and be handled by the host bridge when we don't enable mmconfig. QEMU will call virtio_write_config and since it writes to the BAR region through the PCI Cfg Capability, it will call virtio_address_space_write. virtio_queue_set_host_notifier_mr add host notifier subregion of notify region MR, QEMU need write the mmap address instead of eventfd notify the hardware accelerator at the vhost-user backend. So virtio_address_space_lookup in virtio_address_space_write need return a host-notifier subregion of notify MR instead of notify MR. Add lookup subregion of VirtIOPCIRegion MR instead of only lookup container MR. Fixes: a93c8d8 ("virtio-pci: Replace modern_as with direct access to modern_bar") Co-developed-by: Zuo Boqun <zuobo...@baidu.com> Signed-off-by: Gao Shiyuan <gaoshiy...@baidu.com> Signed-off-by: Zuo Boqun <zuobo...@baidu.com> --- hw/virtio/virtio-pci.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) --- v1 -> v2: * modify commit message * replace direct iteration over subregions with memory_region_find. diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index 9534730bba..5d2d27a6a3 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -610,19 +610,29 @@ static MemoryRegion *virtio_address_space_lookup(VirtIOPCIProxy *proxy, { int i; VirtIOPCIRegion *reg; + MemoryRegion *mr = NULL; + MemoryRegionSection mrs; for (i = 0; i < ARRAY_SIZE(proxy->regs); ++i) { reg = &proxy->regs[i]; if (*off >= reg->offset && *off + len <= reg->offset + reg->size) { - *off -= reg->offset; - return ®->mr; + mrs = memory_region_find(®->mr, *off - reg->offset, len); + if (!mrs.mr) { + error_report("Failed to find memory region for address" + "0x%" PRIx64 "", *off); + return NULL; + } + *off = mrs.offset_within_region; + memory_region_unref(mrs.mr); + return mrs.mr; } } return NULL; } + /* Below are generic functions to do memcpy from/to an address space, * without byteswaps, with input validation. * -- 2.39.3 (Apple Git-146)