Skip to content

Commit

Permalink
hw/virtio/virtio-iommu: Enforce power-of-two notify for both MAP and …
Browse files Browse the repository at this point in the history
…UNMAP

Currently we only enforce power-of-two mappings (required by the QEMU
notifier) for UNMAP requests. A MAP request not aligned on a
power-of-two may be successfully handled by VFIO, and then the
corresponding UNMAP notify will fail because it will attempt to split
that mapping. Ensure MAP and UNMAP notifications are consistent.

Fixes: dde3f08 ("virtio-iommu: Handle non power of 2 range invalidations")
Reported-by: Tina Zhang <tina.zhang@intel.com>
Signed-off-by: Jean-Philippe Brucker <jean-philippe@linaro.org>
Message-Id: <20220718135636.338264-1-jean-philippe@linaro.org>
Tested-by: Tina Zhang <tina.zhang@intel.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
  • Loading branch information
jpbrucker authored and mstsirkin committed Jul 26, 2022
1 parent b3e6982 commit 0522be9
Showing 1 changed file with 28 additions and 19 deletions.
47 changes: 28 additions & 19 deletions hw/virtio/virtio-iommu.c
Expand Up @@ -197,6 +197,32 @@ static gint interval_cmp(gconstpointer a, gconstpointer b, gpointer user_data)
}
}

static void virtio_iommu_notify_map_unmap(IOMMUMemoryRegion *mr,
IOMMUTLBEvent *event,
hwaddr virt_start, hwaddr virt_end)
{
uint64_t delta = virt_end - virt_start;

event->entry.iova = virt_start;
event->entry.addr_mask = delta;

if (delta == UINT64_MAX) {
memory_region_notify_iommu(mr, 0, *event);
}

while (virt_start != virt_end + 1) {
uint64_t mask = dma_aligned_pow2_mask(virt_start, virt_end, 64);

event->entry.addr_mask = mask;
event->entry.iova = virt_start;
memory_region_notify_iommu(mr, 0, *event);
virt_start += mask + 1;
if (event->entry.perm != IOMMU_NONE) {
event->entry.translated_addr += mask + 1;
}
}
}

static void virtio_iommu_notify_map(IOMMUMemoryRegion *mr, hwaddr virt_start,
hwaddr virt_end, hwaddr paddr,
uint32_t flags)
Expand All @@ -215,19 +241,16 @@ static void virtio_iommu_notify_map(IOMMUMemoryRegion *mr, hwaddr virt_start,

event.type = IOMMU_NOTIFIER_MAP;
event.entry.target_as = &address_space_memory;
event.entry.addr_mask = virt_end - virt_start;
event.entry.iova = virt_start;
event.entry.perm = perm;
event.entry.translated_addr = paddr;

memory_region_notify_iommu(mr, 0, event);
virtio_iommu_notify_map_unmap(mr, &event, virt_start, virt_end);
}

static void virtio_iommu_notify_unmap(IOMMUMemoryRegion *mr, hwaddr virt_start,
hwaddr virt_end)
{
IOMMUTLBEvent event;
uint64_t delta = virt_end - virt_start;

if (!(mr->iommu_notify_flags & IOMMU_NOTIFIER_UNMAP)) {
return;
Expand All @@ -239,22 +262,8 @@ static void virtio_iommu_notify_unmap(IOMMUMemoryRegion *mr, hwaddr virt_start,
event.entry.target_as = &address_space_memory;
event.entry.perm = IOMMU_NONE;
event.entry.translated_addr = 0;
event.entry.addr_mask = delta;
event.entry.iova = virt_start;

if (delta == UINT64_MAX) {
memory_region_notify_iommu(mr, 0, event);
}


while (virt_start != virt_end + 1) {
uint64_t mask = dma_aligned_pow2_mask(virt_start, virt_end, 64);

event.entry.addr_mask = mask;
event.entry.iova = virt_start;
memory_region_notify_iommu(mr, 0, event);
virt_start += mask + 1;
}
virtio_iommu_notify_map_unmap(mr, &event, virt_start, virt_end);
}

static gboolean virtio_iommu_notify_unmap_cb(gpointer key, gpointer value,
Expand Down

0 comments on commit 0522be9

Please sign in to comment.