When a virtio-iommu is present, we currently require the guest to configure it before it can use DMA in any other PCI device. This prevents, for example, a bootloader that doesn't know how to drive virtio-iommu from loading an OS from storage.
Add the "boot-bypass" option, defaulting to true, to let DMA bypass the virtio-iommu during boot similarly to the other vIOMMUs. It makes the system vulnerable to malicious endpoints during boot, but that isn't much of a concern in virtual systems. Signed-off-by: Jean-Philippe Brucker <jean-phili...@linaro.org> --- include/hw/virtio/virtio-iommu.h | 1 + hw/virtio/virtio-iommu.c | 22 ++++++++++++++++++++-- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/include/hw/virtio/virtio-iommu.h b/include/hw/virtio/virtio-iommu.h index 49eb105cd84..ae57efab1f3 100644 --- a/include/hw/virtio/virtio-iommu.h +++ b/include/hw/virtio/virtio-iommu.h @@ -58,6 +58,7 @@ typedef struct VirtIOIOMMU { GTree *domains; QemuMutex mutex; GTree *endpoints; + bool boot_bypass; } VirtIOIOMMU; #endif diff --git a/hw/virtio/virtio-iommu.c b/hw/virtio/virtio-iommu.c index 5d56865e569..3b821fc005d 100644 --- a/hw/virtio/virtio-iommu.c +++ b/hw/virtio/virtio-iommu.c @@ -595,6 +595,24 @@ static void virtio_iommu_report_fault(VirtIOIOMMU *viommu, uint8_t reason, } +static bool virtio_iommu_bypass_is_allowed(VirtIOIOMMU *s) +{ + VirtIODevice *vdev = &s->parent_obj; + /* + * Allow bypass if: + * - boot_bypass is enabled and the BYPASS feature hasn't yet been + * acknowledged. + * - the BYPASS feature has been negotiated. + */ + if (s->boot_bypass && !(vdev->status & VIRTIO_CONFIG_S_FEATURES_OK)) { + return true; + } + if (virtio_vdev_has_feature(vdev, VIRTIO_IOMMU_F_BYPASS)) { + return true; + } + return false; +} + static IOMMUTLBEntry virtio_iommu_translate(IOMMUMemoryRegion *mr, hwaddr addr, IOMMUAccessFlags flag, int iommu_idx) @@ -621,8 +639,7 @@ static IOMMUTLBEntry virtio_iommu_translate(IOMMUMemoryRegion *mr, hwaddr addr, .perm = IOMMU_NONE, }; - bypass_allowed = virtio_vdev_has_feature(&s->parent_obj, - VIRTIO_IOMMU_F_BYPASS); + bypass_allowed = virtio_iommu_bypass_is_allowed(s); sid = virtio_iommu_get_bdf(sdev); @@ -947,6 +964,7 @@ static const VMStateDescription vmstate_virtio_iommu = { static Property virtio_iommu_properties[] = { DEFINE_PROP_LINK("primary-bus", VirtIOIOMMU, primary_bus, "PCI", PCIBus *), + DEFINE_PROP_BOOL("boot-bypass", VirtIOIOMMU, boot_bypass, true), DEFINE_PROP_END_OF_LIST(), }; -- 2.28.0