aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/exec/memory.h13
-rw-r--r--memory.c20
2 files changed, 33 insertions, 0 deletions
diff --git a/include/exec/memory.h b/include/exec/memory.h
index 5baaf48234..0f07159bb4 100644
--- a/include/exec/memory.h
+++ b/include/exec/memory.h
@@ -583,6 +583,19 @@ void memory_region_notify_iommu(MemoryRegion *mr,
void memory_region_register_iommu_notifier(MemoryRegion *mr, Notifier *n);
/**
+ * memory_region_iommu_replay: replay existing IOMMU translations to
+ * a notifier
+ *
+ * @mr: the memory region to observe
+ * @n: the notifier to which to replay iommu mappings
+ * @granularity: Minimum page granularity to replay notifications for
+ * @is_write: Whether to treat the replay as a translate "write"
+ * through the iommu
+ */
+void memory_region_iommu_replay(MemoryRegion *mr, Notifier *n,
+ hwaddr granularity, bool is_write);
+
+/**
* memory_region_unregister_iommu_notifier: unregister a notifier for
* changes to IOMMU translation entries.
*
diff --git a/memory.c b/memory.c
index ef87363067..1b03d2251c 100644
--- a/memory.c
+++ b/memory.c
@@ -1403,6 +1403,26 @@ void memory_region_register_iommu_notifier(MemoryRegion *mr, Notifier *n)
notifier_list_add(&mr->iommu_notify, n);
}
+void memory_region_iommu_replay(MemoryRegion *mr, Notifier *n,
+ hwaddr granularity, bool is_write)
+{
+ hwaddr addr;
+ IOMMUTLBEntry iotlb;
+
+ for (addr = 0; addr < memory_region_size(mr); addr += granularity) {
+ iotlb = mr->iommu_ops->translate(mr, addr, is_write);
+ if (iotlb.perm != IOMMU_NONE) {
+ n->notify(n, &iotlb);
+ }
+
+ /* if (2^64 - MR size) < granularity, it's possible to get an
+ * infinite loop here. This should catch such a wraparound */
+ if ((addr + granularity) < addr) {
+ break;
+ }
+ }
+}
+
void memory_region_unregister_iommu_notifier(Notifier *n)
{
notifier_remove(n);