Do you need to operate at physmem level? We have an API for PCI device for ATS and PRI (see pci_ats_request_translation and pci_pri_unregister_notifier)
On Tue, 2026-09-15 at 18:00 +0200, Ruslan Ruslichenko wrote: > From: Ruslan Ruslichenko > <[[email protected]](mailto:[email protected])> > > Add 'ats_do_translate' method to enable manual IOMMU address > translation. > > This allows the Remote Port subsystem to resolve guest virtual > addresses to physical addresses by querying the QEMU IOMMU > translation pipeline. This is required for the Remote Port > subsystem to support translation requests from external masters > in a co-simulation environment. > > Signed-off-by: Edgar E. Iglesias > <[[email protected]](mailto:[email protected])> > Signed-off-by: Takahiro Nakata > <[[email protected]](mailto:[email protected])> > Signed-off-by: Ruslan Ruslichenko > <[[email protected]](mailto:[email protected])> > --- > include/system/memory.h | 8 +++++++ > system/physmem.c | 53 +++++++++++++++++++++++++++++++++++++++++ > 2 files changed, 61 insertions(+) > > diff --git a/include/system/memory.h b/include/system/memory.h > index a7e03fc3e7..2032d3028d 100644 > --- a/include/system/memory.h > +++ b/include/system/memory.h > @@ -2583,6 +2583,14 @@ static inline MemoryRegion > *address_space_translate(AddressSpace *as, > addr, xlat, len, is_write, attrs); > } > > +MemoryRegion *ats_do_translate(AddressSpace *as, > + hwaddr addr, > + hwaddr *xlat, > + hwaddr *plen_out, > + AddressSpace **target_as, > + int *prot, > + MemTxAttrs attrs); > + > /* address_space_access_valid: check for validity of accessing an address > * space range > * > diff --git a/system/physmem.c b/system/physmem.c > index a4a6a4710c..1acda22ede 100644 > --- a/system/physmem.c > +++ b/system/physmem.c > @@ -525,6 +525,59 @@ static MemoryRegionSection > flatview_do_translate(FlatView *fv, > return *section; > } > > +/* This function is called from RCU critical section */ > +MemoryRegion *ats_do_translate(AddressSpace *as, > + hwaddr addr, > + hwaddr *xlat, > + hwaddr *plen_out, > + AddressSpace **target_as, > + int *prot, > + MemTxAttrs attrs) > +{ > + MemoryRegionSection *section; > + IOMMUMemoryRegion *iommu_mr; > + hwaddr plen = (hwaddr)(-1); > + FlatView *fv = address_space_to_flatview(as); > + IOMMUMemoryRegionClass *imrc; > + IOMMUTLBEntry iotlb; > + int iommu_idx = 0; > + > + if (!plen_out) { > + plen_out = &plen; > + } > + > + /* This can be MMIO, so setup MMIO bit. */ > + section = address_space_translate_internal( > + flatview_to_dispatch(fv), addr, xlat, > + plen_out, true); > + > + /* Illegal translation */ > + if (section->mr == &io_mem_unassigned) { > + return NULL; > + } > + > + iommu_mr = memory_region_get_iommu(section->mr); > + if (!iommu_mr) { > + return NULL; > + } > + > + imrc = memory_region_get_iommu_class_nocheck(iommu_mr); > + > + if (imrc->attrs_to_index) { > + iommu_idx = imrc->attrs_to_index(iommu_mr, attrs); > + } > + > + iotlb = imrc->translate(iommu_mr, addr, IOMMU_RO, iommu_idx); > + > + *xlat = ((iotlb.translated_addr & ~iotlb.addr_mask) > + | (addr & iotlb.addr_mask)); > + *plen_out = MIN(*plen_out, (addr | iotlb.addr_mask) - addr + 1); > + *prot = iotlb.perm; > + *target_as = iotlb.target_as; > + > + return section->mr; > +} > + > /* Called from RCU critical section */ > IOMMUTLBEntry address_space_get_iotlb_entry(AddressSpace *as, hwaddr addr, > bool is_write, MemTxAttrs attrs)
