Пример #1
0
Файл: q35.c Проект: AlexHai/qemu
static AddressSpace *q35_host_dma_iommu(PCIBus *bus, void *opaque, int devfn)
{
    IntelIOMMUState *s = opaque;
    VTDAddressSpace **pvtd_as;
    int bus_num = pci_bus_num(bus);

    assert(0 <= bus_num && bus_num <= VTD_PCI_BUS_MAX);
    assert(0 <= devfn && devfn <= VTD_PCI_DEVFN_MAX);

    pvtd_as = s->address_spaces[bus_num];
    if (!pvtd_as) {
        /* No corresponding free() */
        pvtd_as = g_malloc0(sizeof(VTDAddressSpace *) * VTD_PCI_DEVFN_MAX);
        s->address_spaces[bus_num] = pvtd_as;
    }
    if (!pvtd_as[devfn]) {
        pvtd_as[devfn] = g_malloc0(sizeof(VTDAddressSpace));

        pvtd_as[devfn]->bus_num = (uint8_t)bus_num;
        pvtd_as[devfn]->devfn = (uint8_t)devfn;
        pvtd_as[devfn]->iommu_state = s;
        pvtd_as[devfn]->context_cache_entry.context_cache_gen = 0;
        memory_region_init_iommu(&pvtd_as[devfn]->iommu, OBJECT(s),
                                 &s->iommu_ops, "intel_iommu", UINT64_MAX);
        address_space_init(&pvtd_as[devfn]->as,
                           &pvtd_as[devfn]->iommu, "intel_iommu");
    }
    return &pvtd_as[devfn]->as;
}
Пример #2
0
/* Called from RCU critical section */
static IOMMUTLBEntry sun4m_translate_iommu(IOMMUMemoryRegion *iommu,
                                           hwaddr addr,
                                           IOMMUAccessFlags flags)
{
    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 = {
    .name ="iommu",
    .version_id = 2,
    .minimum_version_id = 2,
    .fields = (VMStateField[]) {
        VMSTATE_UINT32_ARRAY(regs, IOMMUState, IOMMU_NREGS),
        VMSTATE_UINT64(iostart, IOMMUState),
        VMSTATE_END_OF_LIST()
    }
};

static void iommu_reset(DeviceState *d)
{
    IOMMUState *s = SUN4M_IOMMU(d);

    memset(s->regs, 0, IOMMU_NREGS * 4);
    s->iostart = 0;
    s->regs[IOMMU_CTRL] = s->version;
    s->regs[IOMMU_ARBEN] = IOMMU_MID;
    s->regs[IOMMU_AFSR] = IOMMU_AFSR_RESV;
    s->regs[IOMMU_AER] = IOMMU_AER_EN_P0_ARB | IOMMU_AER_EN_P1_ARB;
    s->regs[IOMMU_MASK_ID] = IOMMU_TS_MASK;
}

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",
                          IOMMU_NREGS * sizeof(uint32_t));
    sysbus_init_mmio(dev, &s->iomem);
}