summary refs log tree commit diff stats
path: root/hw/dma/sun4m_iommu.c
diff options
context:
space:
mode:
Diffstat (limited to 'hw/dma/sun4m_iommu.c')
-rw-r--r--hw/dma/sun4m_iommu.c101
1 files changed, 58 insertions, 43 deletions
diff --git a/hw/dma/sun4m_iommu.c b/hw/dma/sun4m_iommu.c
index 335ef63cbc..30a05e8823 100644
--- a/hw/dma/sun4m_iommu.c
+++ b/hw/dma/sun4m_iommu.c
@@ -36,7 +36,6 @@
  * http://mediacast.sun.com/users/Barton808/media/Sun4M_SystemArchitecture_edited2.pdf
  */
 
-#define IOMMU_NREGS         (4*4096/4)
 #define IOMMU_CTRL          (0x0000 >> 2)
 #define IOMMU_CTRL_IMPL     0xf0000000 /* Implementation */
 #define IOMMU_CTRL_VERS     0x0f000000 /* Version */
@@ -128,19 +127,6 @@
 #define IOMMU_PAGE_SIZE     (1 << IOMMU_PAGE_SHIFT)
 #define IOMMU_PAGE_MASK     ~(IOMMU_PAGE_SIZE - 1)
 
-#define TYPE_SUN4M_IOMMU "iommu"
-#define SUN4M_IOMMU(obj) OBJECT_CHECK(IOMMUState, (obj), TYPE_SUN4M_IOMMU)
-
-typedef struct IOMMUState {
-    SysBusDevice parent_obj;
-
-    MemoryRegion iomem;
-    uint32_t regs[IOMMU_NREGS];
-    hwaddr iostart;
-    qemu_irq irq;
-    uint32_t version;
-} IOMMUState;
-
 static uint64_t iommu_mem_read(void *opaque, hwaddr addr,
                                unsigned size)
 {
@@ -292,37 +278,47 @@ static void iommu_bad_addr(IOMMUState *s, hwaddr addr,
     qemu_irq_raise(s->irq);
 }
 
-void sparc_iommu_memory_rw(void *opaque, hwaddr addr,
-                           uint8_t *buf, int len, int is_write)
+/* Called from RCU critical section */
+static IOMMUTLBEntry sun4m_translate_iommu(IOMMUMemoryRegion *iommu,
+                                           hwaddr addr,
+                                           IOMMUAccessFlags flags)
 {
-    int l;
-    uint32_t flags;
-    hwaddr page, phys_addr;
-
-    while (len > 0) {
-        page = addr & IOMMU_PAGE_MASK;
-        l = (page + IOMMU_PAGE_SIZE) - addr;
-        if (l > len)
-            l = len;
-        flags = iommu_page_get_flags(opaque, page);
-        if (!(flags & IOPTE_VALID)) {
-            iommu_bad_addr(opaque, page, is_write);
-            return;
-        }
-        phys_addr = iommu_translate_pa(addr, flags);
-        if (is_write) {
-            if (!(flags & IOPTE_WRITE)) {
-                iommu_bad_addr(opaque, page, is_write);
-                return;
-            }
-            cpu_physical_memory_write(phys_addr, buf, l);
-        } else {
-            cpu_physical_memory_read(phys_addr, buf, l);
-        }
-        len -= l;
-        buf += l;
-        addr += l;
+    IOMMUState *is = container_of(iommu, IOMMUState, iommu);
+    hwaddr page, pa;
+    int is_write = (flags & IOMMU_WO) ? 1 : 0;
+    uint32_t pte;
+    IOMMUTLBEntry ret = {
+        .target_as = &address_space_memory,
+        .iova = 0,
+        .translated_addr = 0,
+        .addr_mask = ~(hwaddr)0,
+        .perm = IOMMU_NONE,
+    };
+
+    page = addr & IOMMU_PAGE_MASK;
+    pte = iommu_page_get_flags(is, page);
+    if (!(pte & IOPTE_VALID)) {
+        iommu_bad_addr(is, page, is_write);
+        return ret;
     }
+
+    pa = iommu_translate_pa(addr, pte);
+    if (is_write && !(pte & IOPTE_WRITE)) {
+        iommu_bad_addr(is, page, is_write);
+        return ret;
+    }
+
+    if (pte & IOPTE_WRITE) {
+        ret.perm = IOMMU_RW;
+    } else {
+        ret.perm = IOMMU_RO;
+    }
+
+    ret.iova = page;
+    ret.translated_addr = pa;
+    ret.addr_mask = ~IOMMU_PAGE_MASK;
+
+    return ret;
 }
 
 static const VMStateDescription vmstate_iommu = {
@@ -354,6 +350,11 @@ static void iommu_init(Object *obj)
     IOMMUState *s = SUN4M_IOMMU(obj);
     SysBusDevice *dev = SYS_BUS_DEVICE(obj);
 
+    memory_region_init_iommu(&s->iommu, sizeof(s->iommu),
+                             TYPE_SUN4M_IOMMU_MEMORY_REGION, OBJECT(dev),
+                             "iommu-sun4m", UINT64_MAX);
+    address_space_init(&s->iommu_as, MEMORY_REGION(&s->iommu), "iommu-as");
+
     sysbus_init_irq(dev, &s->irq);
 
     memory_region_init_io(&s->iomem, obj, &iommu_mem_ops, s, "iommu",
@@ -383,9 +384,23 @@ static const TypeInfo iommu_info = {
     .class_init    = iommu_class_init,
 };
 
+static void sun4m_iommu_memory_region_class_init(ObjectClass *klass, void *data)
+{
+    IOMMUMemoryRegionClass *imrc = IOMMU_MEMORY_REGION_CLASS(klass);
+
+    imrc->translate = sun4m_translate_iommu;
+}
+
+static const TypeInfo sun4m_iommu_memory_region_info = {
+    .parent = TYPE_IOMMU_MEMORY_REGION,
+    .name = TYPE_SUN4M_IOMMU_MEMORY_REGION,
+    .class_init = sun4m_iommu_memory_region_class_init,
+};
+
 static void iommu_register_types(void)
 {
     type_register_static(&iommu_info);
+    type_register_static(&sun4m_iommu_memory_region_info);
 }
 
 type_init(iommu_register_types)