From 37baedf8e8a78cf799956447e40da79b967882bb Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Mon, 1 Jul 2024 10:48:53 +0200 Subject: [PATCH 1/9] virtio-iommu: Fix error handling in virtio_iommu_set_host_iova_ranges() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In case no IOMMUPciBus/IOMMUDevice are found we need to properly set the error handle and return. Fixes : Coverity CID 1549006 Signed-off-by: Eric Auger Fixes: cf2647a76e ("virtio-iommu: Compute host reserved regions") Reviewed-by: Cédric Le Goater Reviewed-by: Zhenzhong Duan Reviewed-by: Michael S. Tsirkin --- hw/virtio/virtio-iommu.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/hw/virtio/virtio-iommu.c b/hw/virtio/virtio-iommu.c index 7c54c6b5e2..8fe69ab094 100644 --- a/hw/virtio/virtio-iommu.c +++ b/hw/virtio/virtio-iommu.c @@ -563,10 +563,15 @@ static int virtio_iommu_set_host_iova_ranges(VirtIOIOMMU *s, PCIBus *bus, int ret = -EINVAL; if (!sbus) { - error_report("%s no sbus", __func__); + error_setg(errp, "%s: no IOMMUPciBus found!", __func__); + return ret; } sdev = sbus->pbdev[devfn]; + if (!sdev) { + error_setg(errp, "%s: no IOMMUDevice found!", __func__); + return ret; + } current_ranges = sdev->host_resv_ranges; From 3966bca539967a05b3256549eb00f9488c2790e6 Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Mon, 1 Jul 2024 10:48:54 +0200 Subject: [PATCH 2/9] vfio-container-base: Introduce vfio_container_get_iova_ranges() helper MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduce vfio_container_get_iova_ranges() to retrieve the usable IOVA regions of the base container and use it in the Host IOMMU device implementations of get_iova_ranges() callback. We also fix a UAF bug as the list was shallow copied while g_list_free_full() was used both on the single call site, in virtio_iommu_set_iommu_device() but also in vfio_container_instance_finalize(). Instead use g_list_copy_deep. Fixes: cf2647a76e ("virtio-iommu: Compute host reserved regions") Signed-off-by: Eric Auger Suggested-by: Cédric Le Goater Reviewed-by: Zhenzhong Duan Reviewed-by: Cédric Le Goater Reviewed-by: Michael S. Tsirkin --- hw/vfio/container-base.c | 15 +++++++++++++++ hw/vfio/container.c | 8 +------- hw/vfio/iommufd.c | 8 +------- include/hw/vfio/vfio-container-base.h | 2 ++ 4 files changed, 19 insertions(+), 14 deletions(-) diff --git a/hw/vfio/container-base.c b/hw/vfio/container-base.c index 50b1664f89..809b157674 100644 --- a/hw/vfio/container-base.c +++ b/hw/vfio/container-base.c @@ -83,6 +83,21 @@ int vfio_container_query_dirty_bitmap(const VFIOContainerBase *bcontainer, errp); } +static gpointer copy_iova_range(gconstpointer src, gpointer data) +{ + Range *source = (Range *)src; + Range *dest = g_new(Range, 1); + + range_set_bounds(dest, range_lob(source), range_upb(source)); + return dest; +} + +GList *vfio_container_get_iova_ranges(const VFIOContainerBase *bcontainer) +{ + assert(bcontainer); + return g_list_copy_deep(bcontainer->iova_ranges, copy_iova_range, NULL); +} + static void vfio_container_instance_finalize(Object *obj) { VFIOContainerBase *bcontainer = VFIO_IOMMU(obj); diff --git a/hw/vfio/container.c b/hw/vfio/container.c index 88ede913d6..0804c1b8de 100644 --- a/hw/vfio/container.c +++ b/hw/vfio/container.c @@ -1168,15 +1168,9 @@ static GList * hiod_legacy_vfio_get_iova_ranges(HostIOMMUDevice *hiod, Error **errp) { VFIODevice *vdev = hiod->agent; - GList *l = NULL; g_assert(vdev); - - if (vdev->bcontainer) { - l = g_list_copy(vdev->bcontainer->iova_ranges); - } - - return l; + return vfio_container_get_iova_ranges(vdev->bcontainer); } static void vfio_iommu_legacy_instance_init(Object *obj) diff --git a/hw/vfio/iommufd.c b/hw/vfio/iommufd.c index c2f158e603..890d8d6a38 100644 --- a/hw/vfio/iommufd.c +++ b/hw/vfio/iommufd.c @@ -647,15 +647,9 @@ static GList * hiod_iommufd_vfio_get_iova_ranges(HostIOMMUDevice *hiod, Error **errp) { VFIODevice *vdev = hiod->agent; - GList *l = NULL; g_assert(vdev); - - if (vdev->bcontainer) { - l = g_list_copy(vdev->bcontainer->iova_ranges); - } - - return l; + return vfio_container_get_iova_ranges(vdev->bcontainer); } static void hiod_iommufd_vfio_class_init(ObjectClass *oc, void *data) diff --git a/include/hw/vfio/vfio-container-base.h b/include/hw/vfio/vfio-container-base.h index 419e45ee7a..45d7c40fce 100644 --- a/include/hw/vfio/vfio-container-base.h +++ b/include/hw/vfio/vfio-container-base.h @@ -86,6 +86,8 @@ int vfio_container_set_dirty_page_tracking(VFIOContainerBase *bcontainer, int vfio_container_query_dirty_bitmap(const VFIOContainerBase *bcontainer, VFIOBitmap *vbmap, hwaddr iova, hwaddr size, Error **errp); +GList *vfio_container_get_iova_ranges(const VFIOContainerBase *bcontainer); + #define TYPE_VFIO_IOMMU "vfio-iommu" #define TYPE_VFIO_IOMMU_LEGACY TYPE_VFIO_IOMMU "-legacy" #define TYPE_VFIO_IOMMU_SPAPR TYPE_VFIO_IOMMU "-spapr" From d59ca1ca17480fc776aa02bf536ca3c87dc79323 Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Mon, 1 Jul 2024 10:48:55 +0200 Subject: [PATCH 3/9] HostIOMMUDevice : remove Error handle from get_iova_ranges callback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The error handle argument is not used anywhere. let's remove it. Signed-off-by: Eric Auger Reviewed-by: Cédric Le Goater Reviewed-by: Zhenzhong Duan Reviewed-by: Michael S. Tsirkin --- hw/vfio/container.c | 2 +- hw/vfio/iommufd.c | 2 +- hw/virtio/virtio-iommu.c | 2 +- include/sysemu/host_iommu_device.h | 3 +-- 4 files changed, 4 insertions(+), 5 deletions(-) diff --git a/hw/vfio/container.c b/hw/vfio/container.c index 0804c1b8de..ddd835996c 100644 --- a/hw/vfio/container.c +++ b/hw/vfio/container.c @@ -1165,7 +1165,7 @@ static int hiod_legacy_vfio_get_cap(HostIOMMUDevice *hiod, int cap, } static GList * -hiod_legacy_vfio_get_iova_ranges(HostIOMMUDevice *hiod, Error **errp) +hiod_legacy_vfio_get_iova_ranges(HostIOMMUDevice *hiod) { VFIODevice *vdev = hiod->agent; diff --git a/hw/vfio/iommufd.c b/hw/vfio/iommufd.c index 890d8d6a38..211e7223f1 100644 --- a/hw/vfio/iommufd.c +++ b/hw/vfio/iommufd.c @@ -644,7 +644,7 @@ static bool hiod_iommufd_vfio_realize(HostIOMMUDevice *hiod, void *opaque, } static GList * -hiod_iommufd_vfio_get_iova_ranges(HostIOMMUDevice *hiod, Error **errp) +hiod_iommufd_vfio_get_iova_ranges(HostIOMMUDevice *hiod) { VFIODevice *vdev = hiod->agent; diff --git a/hw/virtio/virtio-iommu.c b/hw/virtio/virtio-iommu.c index 8fe69ab094..f278417f2b 100644 --- a/hw/virtio/virtio-iommu.c +++ b/hw/virtio/virtio-iommu.c @@ -635,7 +635,7 @@ static bool virtio_iommu_set_iommu_device(PCIBus *bus, void *opaque, int devfn, if (hiodc->get_iova_ranges) { int ret; - host_iova_ranges = hiodc->get_iova_ranges(hiod, errp); + host_iova_ranges = hiodc->get_iova_ranges(hiod); if (!host_iova_ranges) { return true; /* some old kernels may not support that capability */ } diff --git a/include/sysemu/host_iommu_device.h b/include/sysemu/host_iommu_device.h index ee6c813c8b..05c7324a0d 100644 --- a/include/sysemu/host_iommu_device.h +++ b/include/sysemu/host_iommu_device.h @@ -87,9 +87,8 @@ struct HostIOMMUDeviceClass { * @hiod Host IOMMU device * * @hiod: handle to the host IOMMU device - * @errp: error handle */ - GList* (*get_iova_ranges)(HostIOMMUDevice *hiod, Error **errp); + GList* (*get_iova_ranges)(HostIOMMUDevice *hiod); }; /* From 8fe0ebe15d7775be72b1aaceb7405b68d3ec6368 Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Mon, 1 Jul 2024 10:48:56 +0200 Subject: [PATCH 4/9] HostIOMMUDevice: Introduce get_page_size_mask() callback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This callback will be used to retrieve the page size mask supported along a given Host IOMMU device. Signed-off-by: Eric Auger Reviewed-by: Zhenzhong Duan Reviewed-by: Cédric Le Goater Reviewed-by: Michael S. Tsirkin --- hw/vfio/container.c | 10 ++++++++++ hw/vfio/iommufd.c | 11 +++++++++++ include/hw/vfio/vfio-container-base.h | 7 +++++++ include/sysemu/host_iommu_device.h | 8 ++++++++ 4 files changed, 36 insertions(+) diff --git a/hw/vfio/container.c b/hw/vfio/container.c index ddd835996c..425db1a14c 100644 --- a/hw/vfio/container.c +++ b/hw/vfio/container.c @@ -1173,6 +1173,15 @@ hiod_legacy_vfio_get_iova_ranges(HostIOMMUDevice *hiod) return vfio_container_get_iova_ranges(vdev->bcontainer); } +static uint64_t +hiod_legacy_vfio_get_page_size_mask(HostIOMMUDevice *hiod) +{ + VFIODevice *vdev = hiod->agent; + + g_assert(vdev); + return vfio_container_get_page_size_mask(vdev->bcontainer); +} + static void vfio_iommu_legacy_instance_init(Object *obj) { VFIOContainer *container = VFIO_IOMMU_LEGACY(obj); @@ -1187,6 +1196,7 @@ static void hiod_legacy_vfio_class_init(ObjectClass *oc, void *data) hioc->realize = hiod_legacy_vfio_realize; hioc->get_cap = hiod_legacy_vfio_get_cap; hioc->get_iova_ranges = hiod_legacy_vfio_get_iova_ranges; + hioc->get_page_size_mask = hiod_legacy_vfio_get_page_size_mask; }; static const TypeInfo types[] = { diff --git a/hw/vfio/iommufd.c b/hw/vfio/iommufd.c index 211e7223f1..7b5f87a148 100644 --- a/hw/vfio/iommufd.c +++ b/hw/vfio/iommufd.c @@ -652,12 +652,23 @@ hiod_iommufd_vfio_get_iova_ranges(HostIOMMUDevice *hiod) return vfio_container_get_iova_ranges(vdev->bcontainer); } +static uint64_t +hiod_iommufd_vfio_get_page_size_mask(HostIOMMUDevice *hiod) +{ + VFIODevice *vdev = hiod->agent; + + g_assert(vdev); + return vfio_container_get_page_size_mask(vdev->bcontainer); +} + + static void hiod_iommufd_vfio_class_init(ObjectClass *oc, void *data) { HostIOMMUDeviceClass *hiodc = HOST_IOMMU_DEVICE_CLASS(oc); hiodc->realize = hiod_iommufd_vfio_realize; hiodc->get_iova_ranges = hiod_iommufd_vfio_get_iova_ranges; + hiodc->get_page_size_mask = hiod_iommufd_vfio_get_page_size_mask; }; static const TypeInfo types[] = { diff --git a/include/hw/vfio/vfio-container-base.h b/include/hw/vfio/vfio-container-base.h index 45d7c40fce..62a8b60d87 100644 --- a/include/hw/vfio/vfio-container-base.h +++ b/include/hw/vfio/vfio-container-base.h @@ -88,6 +88,13 @@ int vfio_container_query_dirty_bitmap(const VFIOContainerBase *bcontainer, GList *vfio_container_get_iova_ranges(const VFIOContainerBase *bcontainer); +static inline uint64_t +vfio_container_get_page_size_mask(const VFIOContainerBase *bcontainer) +{ + assert(bcontainer); + return bcontainer->pgsizes; +} + #define TYPE_VFIO_IOMMU "vfio-iommu" #define TYPE_VFIO_IOMMU_LEGACY TYPE_VFIO_IOMMU "-legacy" #define TYPE_VFIO_IOMMU_SPAPR TYPE_VFIO_IOMMU "-spapr" diff --git a/include/sysemu/host_iommu_device.h b/include/sysemu/host_iommu_device.h index 05c7324a0d..c1bf74ae2c 100644 --- a/include/sysemu/host_iommu_device.h +++ b/include/sysemu/host_iommu_device.h @@ -89,6 +89,14 @@ struct HostIOMMUDeviceClass { * @hiod: handle to the host IOMMU device */ GList* (*get_iova_ranges)(HostIOMMUDevice *hiod); + /** + * + * @get_page_size_mask: Return the page size mask supported along this + * @hiod Host IOMMU device + * + * @hiod: handle to the host IOMMU device + */ + uint64_t (*get_page_size_mask)(HostIOMMUDevice *hiod); }; /* From d7c8c95fbca2e07d11b98fb1b191d7194d084c7e Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Mon, 1 Jul 2024 10:48:57 +0200 Subject: [PATCH 5/9] virtio-iommu : Retrieve page size mask on virtio_iommu_set_iommu_device() Retrieve the Host IOMMU Device page size mask when this latter is set. This allows to get the information much sooner than when relying on IOMMU MR set_page_size_mask() call, whcih happens when the IOMMU MR gets enabled. We introduce check_page_size_mask() helper whose code is inherited from current virtio_iommu_set_page_size_mask() implementation. This callback will be removed in a subsequent patch. Signed-off-by: Eric Auger Reviewed-by: Zhenzhong Duan Reviewed-by: Michael S. Tsirkin --- hw/virtio/trace-events | 1 + hw/virtio/virtio-iommu.c | 57 ++++++++++++++++++++++++++++++++++++++-- 2 files changed, 56 insertions(+), 2 deletions(-) diff --git a/hw/virtio/trace-events b/hw/virtio/trace-events index 3cf84e04a7..599d855ff6 100644 --- a/hw/virtio/trace-events +++ b/hw/virtio/trace-events @@ -132,6 +132,7 @@ virtio_iommu_notify_map(const char *name, uint64_t virt_start, uint64_t virt_end virtio_iommu_notify_unmap(const char *name, uint64_t virt_start, uint64_t virt_end) "mr=%s virt_start=0x%"PRIx64" virt_end=0x%"PRIx64 virtio_iommu_remap(const char *name, uint64_t virt_start, uint64_t virt_end, uint64_t phys_start) "mr=%s virt_start=0x%"PRIx64" virt_end=0x%"PRIx64" phys_start=0x%"PRIx64 virtio_iommu_set_page_size_mask(const char *name, uint64_t old, uint64_t new) "mr=%s old_mask=0x%"PRIx64" new_mask=0x%"PRIx64 +virtio_iommu_update_page_size_mask(const char *name, uint64_t old, uint64_t new) "host iommu device=%s old_mask=0x%"PRIx64" new_mask=0x%"PRIx64 virtio_iommu_notify_flag_add(const char *name) "add notifier to mr %s" virtio_iommu_notify_flag_del(const char *name) "del notifier from mr %s" virtio_iommu_switch_address_space(uint8_t bus, uint8_t slot, uint8_t fn, bool on) "Device %02x:%02x.%x switching address space (iommu enabled=%d)" diff --git a/hw/virtio/virtio-iommu.c b/hw/virtio/virtio-iommu.c index f278417f2b..d6654985bd 100644 --- a/hw/virtio/virtio-iommu.c +++ b/hw/virtio/virtio-iommu.c @@ -618,9 +618,39 @@ out: return ret; } +static bool check_page_size_mask(VirtIOIOMMU *viommu, uint64_t new_mask, + Error **errp) +{ + uint64_t cur_mask = viommu->config.page_size_mask; + + if ((cur_mask & new_mask) == 0) { + error_setg(errp, "virtio-iommu reports a page size mask 0x%"PRIx64 + " incompatible with currently supported mask 0x%"PRIx64, + new_mask, cur_mask); + return false; + } + /* + * Once the granule is frozen we can't change the mask anymore. If by + * chance the hotplugged device supports the same granule, we can still + * accept it. + */ + if (viommu->granule_frozen) { + int cur_granule = ctz64(cur_mask); + + if (!(BIT_ULL(cur_granule) & new_mask)) { + error_setg(errp, + "virtio-iommu does not support frozen granule 0x%llx", + BIT_ULL(cur_granule)); + return false; + } + } + return true; +} + static bool virtio_iommu_set_iommu_device(PCIBus *bus, void *opaque, int devfn, HostIOMMUDevice *hiod, Error **errp) { + ERRP_GUARD(); VirtIOIOMMU *viommu = opaque; HostIOMMUDeviceClass *hiodc = HOST_IOMMU_DEVICE_GET_CLASS(hiod); struct hiod_key *new_key; @@ -643,8 +673,28 @@ static bool virtio_iommu_set_iommu_device(PCIBus *bus, void *opaque, int devfn, hiod->aliased_devfn, host_iova_ranges, errp); if (ret) { - g_list_free_full(host_iova_ranges, g_free); - return false; + goto error; + } + } + if (hiodc->get_page_size_mask) { + uint64_t new_mask = hiodc->get_page_size_mask(hiod); + + if (check_page_size_mask(viommu, new_mask, errp)) { + /* + * The default mask depends on the "granule" property. For example, + * with 4k granule, it is -(4 * KiB). When an assigned device has + * page size restrictions due to the hardware IOMMU configuration, + * apply this restriction to the mask. + */ + trace_virtio_iommu_update_page_size_mask(hiod->name, + viommu->config.page_size_mask, + new_mask); + if (!viommu->granule_frozen) { + viommu->config.page_size_mask &= new_mask; + } + } else { + error_prepend(errp, "%s: ", hiod->name); + goto error; } } @@ -657,6 +707,9 @@ static bool virtio_iommu_set_iommu_device(PCIBus *bus, void *opaque, int devfn, g_list_free_full(host_iova_ranges, g_free); return true; +error: + g_list_free_full(host_iova_ranges, g_free); + return false; } static void From 2457343d05a168963b52ab6d5c2932dd29b93f46 Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Mon, 1 Jul 2024 10:48:58 +0200 Subject: [PATCH 6/9] memory: remove IOMMU MR iommu_set_page_size_mask() callback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Everything is now in place to use the Host IOMMU Device callbacks to retrieve the page size mask usable with a given assigned device. This new method brings the advantage to pass the info much earlier to the virtual IOMMU and before the IOMMU MR gets enabled. So let's remove the call to memory_region_iommu_set_page_size_mask in vfio common.c and remove the single implementation of the IOMMU MR callback in the virtio-iommu.c Signed-off-by: Eric Auger Reviewed-by: Cédric Le Goater Reviewed-by: Zhenzhong Duan Reviewed-by: Michael S. Tsirkin --- hw/vfio/common.c | 8 ------- hw/virtio/trace-events | 1 - hw/virtio/virtio-iommu.c | 45 ---------------------------------------- include/exec/memory.h | 38 --------------------------------- system/memory.c | 13 ------------ 5 files changed, 105 deletions(-) diff --git a/hw/vfio/common.c b/hw/vfio/common.c index 7cdb969fd3..6d15b36e0b 100644 --- a/hw/vfio/common.c +++ b/hw/vfio/common.c @@ -622,14 +622,6 @@ static void vfio_listener_region_add(MemoryListener *listener, int128_get64(llend), iommu_idx); - ret = memory_region_iommu_set_page_size_mask(giommu->iommu_mr, - bcontainer->pgsizes, - &err); - if (ret) { - g_free(giommu); - goto fail; - } - ret = memory_region_register_iommu_notifier(section->mr, &giommu->n, &err); if (ret) { diff --git a/hw/virtio/trace-events b/hw/virtio/trace-events index 599d855ff6..b7c04f0856 100644 --- a/hw/virtio/trace-events +++ b/hw/virtio/trace-events @@ -131,7 +131,6 @@ virtio_iommu_fill_resv_property(uint32_t devid, uint8_t subtype, uint64_t start, virtio_iommu_notify_map(const char *name, uint64_t virt_start, uint64_t virt_end, uint64_t phys_start, uint32_t flags) "mr=%s virt_start=0x%"PRIx64" virt_end=0x%"PRIx64" phys_start=0x%"PRIx64" flags=%d" virtio_iommu_notify_unmap(const char *name, uint64_t virt_start, uint64_t virt_end) "mr=%s virt_start=0x%"PRIx64" virt_end=0x%"PRIx64 virtio_iommu_remap(const char *name, uint64_t virt_start, uint64_t virt_end, uint64_t phys_start) "mr=%s virt_start=0x%"PRIx64" virt_end=0x%"PRIx64" phys_start=0x%"PRIx64 -virtio_iommu_set_page_size_mask(const char *name, uint64_t old, uint64_t new) "mr=%s old_mask=0x%"PRIx64" new_mask=0x%"PRIx64 virtio_iommu_update_page_size_mask(const char *name, uint64_t old, uint64_t new) "host iommu device=%s old_mask=0x%"PRIx64" new_mask=0x%"PRIx64 virtio_iommu_notify_flag_add(const char *name) "add notifier to mr %s" virtio_iommu_notify_flag_del(const char *name) "del notifier from mr %s" diff --git a/hw/virtio/virtio-iommu.c b/hw/virtio/virtio-iommu.c index d6654985bd..76f34ea6b3 100644 --- a/hw/virtio/virtio-iommu.c +++ b/hw/virtio/virtio-iommu.c @@ -1408,50 +1408,6 @@ static int virtio_iommu_notify_flag_changed(IOMMUMemoryRegion *iommu_mr, return 0; } -/* - * The default mask depends on the "granule" property. For example, with - * 4k granule, it is -(4 * KiB). When an assigned device has page size - * restrictions due to the hardware IOMMU configuration, apply this restriction - * to the mask. - */ -static int virtio_iommu_set_page_size_mask(IOMMUMemoryRegion *mr, - uint64_t new_mask, - Error **errp) -{ - IOMMUDevice *sdev = container_of(mr, IOMMUDevice, iommu_mr); - VirtIOIOMMU *s = sdev->viommu; - uint64_t cur_mask = s->config.page_size_mask; - - trace_virtio_iommu_set_page_size_mask(mr->parent_obj.name, cur_mask, - new_mask); - - if ((cur_mask & new_mask) == 0) { - error_setg(errp, "virtio-iommu %s reports a page size mask 0x%"PRIx64 - " incompatible with currently supported mask 0x%"PRIx64, - mr->parent_obj.name, new_mask, cur_mask); - return -1; - } - - /* - * Once the granule is frozen we can't change the mask anymore. If by - * chance the hotplugged device supports the same granule, we can still - * accept it. - */ - if (s->granule_frozen) { - int cur_granule = ctz64(cur_mask); - - if (!(BIT_ULL(cur_granule) & new_mask)) { - error_setg(errp, "virtio-iommu %s does not support frozen granule 0x%llx", - mr->parent_obj.name, BIT_ULL(cur_granule)); - return -1; - } - return 0; - } - - s->config.page_size_mask &= new_mask; - return 0; -} - static void virtio_iommu_system_reset(void *opaque) { VirtIOIOMMU *s = opaque; @@ -1776,7 +1732,6 @@ static void virtio_iommu_memory_region_class_init(ObjectClass *klass, imrc->translate = virtio_iommu_translate; imrc->replay = virtio_iommu_replay; imrc->notify_flag_changed = virtio_iommu_notify_flag_changed; - imrc->iommu_set_page_size_mask = virtio_iommu_set_page_size_mask; } static const TypeInfo virtio_iommu_info = { diff --git a/include/exec/memory.h b/include/exec/memory.h index c26ede33d2..02f7528ec0 100644 --- a/include/exec/memory.h +++ b/include/exec/memory.h @@ -504,32 +504,6 @@ struct IOMMUMemoryRegionClass { * @iommu: the IOMMUMemoryRegion */ int (*num_indexes)(IOMMUMemoryRegion *iommu); - - /** - * @iommu_set_page_size_mask: - * - * Restrict the page size mask that can be supported with a given IOMMU - * memory region. Used for example to propagate host physical IOMMU page - * size mask limitations to the virtual IOMMU. - * - * Optional method: if this method is not provided, then the default global - * page mask is used. - * - * @iommu: the IOMMUMemoryRegion - * - * @page_size_mask: a bitmask of supported page sizes. At least one bit, - * representing the smallest page size, must be set. Additional set bits - * represent supported block sizes. For example a host physical IOMMU that - * uses page tables with a page size of 4kB, and supports 2MB and 4GB - * blocks, will set mask 0x40201000. A granule of 4kB with indiscriminate - * block sizes is specified with mask 0xfffffffffffff000. - * - * Returns 0 on success, or a negative error. In case of failure, the error - * object must be created. - */ - int (*iommu_set_page_size_mask)(IOMMUMemoryRegion *iommu, - uint64_t page_size_mask, - Error **errp); }; typedef struct RamDiscardListener RamDiscardListener; @@ -1919,18 +1893,6 @@ int memory_region_iommu_attrs_to_index(IOMMUMemoryRegion *iommu_mr, */ int memory_region_iommu_num_indexes(IOMMUMemoryRegion *iommu_mr); -/** - * memory_region_iommu_set_page_size_mask: set the supported page - * sizes for a given IOMMU memory region - * - * @iommu_mr: IOMMU memory region - * @page_size_mask: supported page size mask - * @errp: pointer to Error*, to store an error if it happens. - */ -int memory_region_iommu_set_page_size_mask(IOMMUMemoryRegion *iommu_mr, - uint64_t page_size_mask, - Error **errp); - /** * memory_region_name: get a memory region's name * diff --git a/system/memory.c b/system/memory.c index 2d69521360..5e6eb459d5 100644 --- a/system/memory.c +++ b/system/memory.c @@ -1901,19 +1901,6 @@ static int memory_region_update_iommu_notify_flags(IOMMUMemoryRegion *iommu_mr, return ret; } -int memory_region_iommu_set_page_size_mask(IOMMUMemoryRegion *iommu_mr, - uint64_t page_size_mask, - Error **errp) -{ - IOMMUMemoryRegionClass *imrc = IOMMU_MEMORY_REGION_GET_CLASS(iommu_mr); - int ret = 0; - - if (imrc->iommu_set_page_size_mask) { - ret = imrc->iommu_set_page_size_mask(iommu_mr, page_size_mask, errp); - } - return ret; -} - int memory_region_register_iommu_notifier(MemoryRegion *mr, IOMMUNotifier *n, Error **errp) { From 956b30b9cf856470612e8d2c2c4985fb7e40a970 Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Mon, 1 Jul 2024 10:48:59 +0200 Subject: [PATCH 7/9] virtio-iommu: Revert transient enablement of IOMMU MR in bypass mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In 94df5b2180d6 ("virtio-iommu: Fix 64kB host page size VFIO device assignment"), in case of bypass mode, we transiently enabled the IOMMU MR to allow the set_page_size_mask() to be called and pass information about the page size mask constraint of cold plugged VFIO devices. Now we do not use the IOMMU MR callback anymore, we can just get rid of this hack. Signed-off-by: Eric Auger Reviewed-by: Cédric Le Goater Reviewed-by: Zhenzhong Duan Reviewed-by: Michael S. Tsirkin --- hw/virtio/virtio-iommu.c | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/hw/virtio/virtio-iommu.c b/hw/virtio/virtio-iommu.c index 76f34ea6b3..33ae61c4a6 100644 --- a/hw/virtio/virtio-iommu.c +++ b/hw/virtio/virtio-iommu.c @@ -1430,18 +1430,6 @@ static void virtio_iommu_freeze_granule(Notifier *notifier, void *data) VirtIOIOMMU *s = container_of(notifier, VirtIOIOMMU, machine_done); int granule; - if (likely(s->config.bypass)) { - /* - * Transient IOMMU MR enable to collect page_size_mask requirements - * through memory_region_iommu_set_page_size_mask() called by - * VFIO region_add() callback - */ - s->config.bypass = false; - virtio_iommu_switch_address_space_all(s); - /* restore default */ - s->config.bypass = true; - virtio_iommu_switch_address_space_all(s); - } s->granule_frozen = true; granule = ctz64(s->config.page_size_mask); trace_virtio_iommu_freeze_granule(BIT_ULL(granule)); From f15da599a1c5326e105425a74d2fb004a2a2649e Mon Sep 17 00:00:00 2001 From: Zhenzhong Duan Date: Mon, 1 Jul 2024 09:48:08 +0800 Subject: [PATCH 8/9] vfio/display: Fix potential memleak of edid info MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit EDID related device region info is leaked in vfio_display_edid_init() error path and VFIODisplay destroying path. Fixes: 08479114b0de ("vfio/display: add edid support.") Signed-off-by: Zhenzhong Duan Reviewed-by: Cédric Le Goater Reviewed-by: Marc-André Lureau --- hw/vfio/display.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/hw/vfio/display.c b/hw/vfio/display.c index 661e921616..9c57fd3888 100644 --- a/hw/vfio/display.c +++ b/hw/vfio/display.c @@ -171,7 +171,9 @@ static void vfio_display_edid_init(VFIOPCIDevice *vdev) err: trace_vfio_display_edid_write_error(); + g_free(dpy->edid_info); g_free(dpy->edid_regs); + dpy->edid_info = NULL; dpy->edid_regs = NULL; return; } @@ -182,6 +184,7 @@ static void vfio_display_edid_exit(VFIODisplay *dpy) return; } + g_free(dpy->edid_info); g_free(dpy->edid_regs); g_free(dpy->edid_blob); timer_free(dpy->edid_link_timer); From 83d90192026eaded6319a6d27466ad7d606a27e0 Mon Sep 17 00:00:00 2001 From: Zhenzhong Duan Date: Mon, 1 Jul 2024 09:48:09 +0800 Subject: [PATCH 9/9] vfio/display: Fix vfio_display_edid_init() error path MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit vfio_display_edid_init() can fail for many reasons and return silently. It would be good to report the error. Old mdev driver may not support vfio edid region and we allow to go through in this case. vfio_display_edid_update() isn't changed because it can be called at runtime when UI changes (i.e. window resize). Fixes: 08479114b0de ("vfio/display: add edid support.") Suggested-by: Cédric Le Goater Signed-off-by: Zhenzhong Duan Reviewed-by: Marc-André Lureau --- hw/vfio/display.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/hw/vfio/display.c b/hw/vfio/display.c index 9c57fd3888..ea87830fe0 100644 --- a/hw/vfio/display.c +++ b/hw/vfio/display.c @@ -124,7 +124,7 @@ static void vfio_display_edid_ui_info(void *opaque, uint32_t idx, } } -static void vfio_display_edid_init(VFIOPCIDevice *vdev) +static bool vfio_display_edid_init(VFIOPCIDevice *vdev, Error **errp) { VFIODisplay *dpy = vdev->dpy; int fd = vdev->vbasedev.fd; @@ -135,7 +135,8 @@ static void vfio_display_edid_init(VFIOPCIDevice *vdev) VFIO_REGION_SUBTYPE_GFX_EDID, &dpy->edid_info); if (ret) { - return; + /* Failed to get GFX edid info, allow to go through without edid. */ + return true; } trace_vfio_display_edid_available(); @@ -167,15 +168,16 @@ static void vfio_display_edid_init(VFIOPCIDevice *vdev) vfio_display_edid_link_up, vdev); vfio_display_edid_update(vdev, true, 0, 0); - return; + return true; err: + error_setg(errp, "vfio: failed to read GFX edid field"); trace_vfio_display_edid_write_error(); g_free(dpy->edid_info); g_free(dpy->edid_regs); dpy->edid_info = NULL; dpy->edid_regs = NULL; - return; + return false; } static void vfio_display_edid_exit(VFIODisplay *dpy) @@ -368,8 +370,7 @@ static bool vfio_display_dmabuf_init(VFIOPCIDevice *vdev, Error **errp) return false; } } - vfio_display_edid_init(vdev); - return true; + return vfio_display_edid_init(vdev, errp); } static void vfio_display_dmabuf_exit(VFIODisplay *dpy)