Implement a better IOMMU access method. Index: qemu/hw/iommu.c =================================================================== --- qemu.orig/hw/iommu.c 2006-08-27 09:33:35.000000000 +0000 +++ qemu/hw/iommu.c 2006-08-27 09:33:45.000000000 +0000 @@ -186,21 +186,55 @@ iommu_mem_writew, }; -uint32_t iommu_translate_local(void *opaque, uint32_t addr) +static uint32_t iommu_page_get_flags(IOMMUState *s, uint32_t addr) { - IOMMUState *s = opaque; - uint32_t iopte, pa, tmppte; + uint32_t iopte; iopte = s->regs[1] << 4; addr &= ~s->iostart; iopte += (addr >> (PAGE_SHIFT - 2)) & ~3; - pa = ldl_phys(iopte); + return ldl_phys(iopte); +} + +static uint32_t iommu_translate(IOMMUState *s, uint32_t addr, uint32_t pa) +{ + uint32_t tmppte; + tmppte = pa; pa = ((pa & IOPTE_PAGE) << 4) + (addr & PAGE_MASK); - DPRINTF("xlate dva %x => pa %x (iopte[%x] = %x)\n", addr, pa, iopte, tmppte); + DPRINTF("xlate dva %x => pa %x (iopte = %x)\n", addr, pa, tmppte); return pa; } +void sparc_iommu_memory_rw_local(void *opaque, target_phys_addr_t addr, + uint8_t *buf, int len, int is_write) +{ + int l, flags; + target_ulong page, phys_addr; + void * p; + + while (len > 0) { + page = addr & TARGET_PAGE_MASK; + l = (page + TARGET_PAGE_SIZE) - addr; + if (l > len) + l = len; + flags = iommu_page_get_flags(opaque, page); + if (!(flags & IOPTE_VALID)) + return; + phys_addr = iommu_translate(opaque, addr, flags); + if (is_write) { + if (!(flags & IOPTE_WRITE)) + return; + cpu_physical_memory_write(phys_addr, buf, len); + } else { + cpu_physical_memory_read(phys_addr, buf, len); + } + len -= l; + buf += l; + addr += l; + } +} + static void iommu_save(QEMUFile *f, void *opaque) { IOMMUState *s = opaque; Index: qemu/hw/sun4m.c =================================================================== --- qemu.orig/hw/sun4m.c 2006-08-27 09:33:35.000000000 +0000 +++ qemu/hw/sun4m.c 2006-08-27 09:33:45.000000000 +0000 @@ -194,9 +194,16 @@ static void *iommu; -uint32_t iommu_translate(uint32_t addr) +void sparc_iommu_memory_read(target_phys_addr_t addr, + uint8_t *buf, int len) { - return iommu_translate_local(iommu, addr); + return sparc_iommu_memory_rw_local(iommu, addr, buf, len, 0); +} + +void sparc_iommu_memory_write(target_phys_addr_t addr, + uint8_t *buf, int len) +{ + return sparc_iommu_memory_rw_local(iommu, addr, buf, len, 1); } static void *slavio_misc; Index: qemu/vl.h =================================================================== --- qemu.orig/vl.h 2006-08-27 09:33:35.000000000 +0000 +++ qemu/vl.h 2006-08-27 09:33:45.000000000 +0000 @@ -1025,12 +1025,16 @@ /* sun4m.c */ extern QEMUMachine sun4m_machine; -uint32_t iommu_translate(uint32_t addr); void pic_set_irq_cpu(int irq, int level, unsigned int cpu); +void sparc_iommu_memory_read(target_phys_addr_t addr, + uint8_t *buf, int len); +void sparc_iommu_memory_write(target_phys_addr_t addr, + uint8_t *buf, int len); /* iommu.c */ void *iommu_init(uint32_t addr); -uint32_t iommu_translate_local(void *opaque, uint32_t addr); +void sparc_iommu_memory_rw_local(void *opaque, target_phys_addr_t addr, + uint8_t *buf, int len, int is_write); /* lance.c */ void lance_init(NICInfo *nd, int irq, uint32_t leaddr, uint32_t ledaddr);