static MemoryRegionSection address_space_do_translate(AddressSpace *as,
                                                      hwaddr addr,
                                                      hwaddr *xlat,
                                                      hwaddr *plen,
                                                      bool is_write,
                                                      bool is_mmio)
{
    IOMMUTLBEntry iotlb;
    MemoryRegionSection *section;
    MemoryRegion *mr;

    for (;;) {
        AddressSpaceDispatch *d = atomic_rcu_read(&as->dispatch);
        section = address_space_translate_internal(d, addr, &addr, plen, is_mmio);
        mr = section->mr;

        if (!mr->iommu_ops) {
            break;
        }

        iotlb = mr->iommu_ops->translate(mr, addr, is_write ?
                                         IOMMU_WO : IOMMU_RO);
        addr = ((iotlb.translated_addr & ~iotlb.addr_mask)
                | (addr & iotlb.addr_mask));
        *plen = MIN(*plen, (addr | iotlb.addr_mask) - addr + 1);
        if (!(iotlb.perm & (1 << is_write))) {
            goto translate_fail;
        }

        as = iotlb.target_as;
    }

    *xlat = addr;

    return *section;

translate_fail:
    return (MemoryRegionSection) { .mr = &io_mem_unassigned };
}
Unknown