diff options
Diffstat (limited to 'exec.c')
-rw-r--r-- | exec.c | 35 |
1 files changed, 33 insertions, 2 deletions
@@ -266,14 +266,45 @@ MemoryRegion *address_space_translate(AddressSpace *as, hwaddr addr, hwaddr *xlat, hwaddr *plen, bool is_write) { - return address_space_translate_internal(as, addr, xlat, plen, true)->mr; + IOMMUTLBEntry iotlb; + MemoryRegionSection *section; + MemoryRegion *mr; + hwaddr len = *plen; + + for (;;) { + section = address_space_translate_internal(as, addr, &addr, plen, true); + mr = section->mr; + + if (!mr->iommu_ops) { + break; + } + + iotlb = mr->iommu_ops->translate(mr, addr); + addr = ((iotlb.translated_addr & ~iotlb.addr_mask) + | (addr & iotlb.addr_mask)); + len = MIN(len, (addr | iotlb.addr_mask) - addr + 1); + if (!(iotlb.perm & (1 << is_write))) { + mr = &io_mem_unassigned; + break; + } + + as = iotlb.target_as; + } + + *plen = len; + *xlat = addr; + return mr; } MemoryRegionSection * address_space_translate_for_iotlb(AddressSpace *as, hwaddr addr, hwaddr *xlat, hwaddr *plen) { - return address_space_translate_internal(as, addr, xlat, plen, false); + MemoryRegionSection *section; + section = address_space_translate_internal(as, addr, xlat, plen, false); + + assert(!section->mr->iommu_ops); + return section; } #endif |