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)

Reply via email to