⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 iommu.c

📁 xen虚拟机源代码安装包
💻 C
📖 第 1 页 / 共 4 页
字号:
    if ( pg_maddr == 0 )        return -ENOMEM;    page = (struct dma_pte *)map_vtd_domain_page(pg_maddr);    pte = page + (gfn & LEVEL_MASK);    pte_present = dma_pte_present(*pte);    dma_set_pte_addr(*pte, (paddr_t)mfn << PAGE_SHIFT_4K);    dma_set_pte_prot(*pte, DMA_PTE_READ | DMA_PTE_WRITE);    iommu_flush_cache_entry(pte);    unmap_vtd_domain_page(page);    for_each_drhd_unit ( drhd )    {        iommu = drhd->iommu;        if ( !test_bit(iommu->index, &hd->iommu_bitmap) )            continue;        if ( iommu_flush_iotlb_psi(iommu, domain_iommu_domid(d),                                   (paddr_t)gfn << PAGE_SHIFT_4K, 1,                                   !pte_present) )            iommu_flush_write_buffer(iommu);    }    return 0;}int intel_iommu_unmap_page(struct domain *d, unsigned long gfn){    struct acpi_drhd_unit *drhd;    struct iommu *iommu;    drhd = list_entry(acpi_drhd_units.next, typeof(*drhd), list);    iommu = drhd->iommu;#ifdef CONTEXT_PASSTHRU    /* do nothing if dom0 and iommu supports pass thru */    if ( ecap_pass_thru(iommu->ecap) && (d->domain_id == 0) )        return 0;#endif    dma_pte_clear_one(d, (paddr_t)gfn << PAGE_SHIFT_4K);    return 0;}int iommu_page_mapping(struct domain *domain, paddr_t iova,                       paddr_t hpa, size_t size, int prot){    struct hvm_iommu *hd = domain_hvm_iommu(domain);    struct acpi_drhd_unit *drhd;    struct iommu *iommu;    u64 start_pfn, end_pfn;    struct dma_pte *page = NULL, *pte = NULL;    int index;    u64 pg_maddr;    if ( (prot & (DMA_PTE_READ|DMA_PTE_WRITE)) == 0 )        return -EINVAL;    iova = (iova >> PAGE_SHIFT_4K) << PAGE_SHIFT_4K;    start_pfn = hpa >> PAGE_SHIFT_4K;    end_pfn = (PAGE_ALIGN_4K(hpa + size)) >> PAGE_SHIFT_4K;    index = 0;    while ( start_pfn < end_pfn )    {        pg_maddr = addr_to_dma_page_maddr(domain, iova + PAGE_SIZE_4K*index, 1);        if ( pg_maddr == 0 )            return -ENOMEM;        page = (struct dma_pte *)map_vtd_domain_page(pg_maddr);        pte = page + (start_pfn & LEVEL_MASK);        dma_set_pte_addr(*pte, (paddr_t)start_pfn << PAGE_SHIFT_4K);        dma_set_pte_prot(*pte, prot);        iommu_flush_cache_entry(pte);        unmap_vtd_domain_page(page);        start_pfn++;        index++;    }    if ( index > 0 )    {        for_each_drhd_unit ( drhd )        {            iommu = drhd->iommu;            if ( test_bit(iommu->index, &hd->iommu_bitmap) )                if ( iommu_flush_iotlb_psi(iommu, domain_iommu_domid(domain),                                           iova, index, 1))                    iommu_flush_write_buffer(iommu);        }    }    return 0;}int iommu_page_unmapping(struct domain *domain, paddr_t addr, size_t size){    dma_pte_clear_range(domain, addr, addr + size);    return 0;}static int iommu_prepare_rmrr_dev(struct domain *d,                                  struct acpi_rmrr_unit *rmrr,                                  u8 bus, u8 devfn){    u64 size;    int ret;    /* page table init */    size = rmrr->end_address - rmrr->base_address + 1;    ret = iommu_page_mapping(d, rmrr->base_address,                             rmrr->base_address, size,                             DMA_PTE_READ|DMA_PTE_WRITE);    if ( ret )        return ret;    if ( domain_context_mapped(bus, devfn) == 0 )        ret = domain_context_mapping(d, bus, devfn);    return ret;}static int intel_iommu_add_device(struct pci_dev *pdev){    struct acpi_rmrr_unit *rmrr;    u16 bdf;    int ret, i;    if ( !pdev->domain )        return -EINVAL;    ret = domain_context_mapping(pdev->domain, pdev->bus, pdev->devfn);    if ( ret )    {        gdprintk(XENLOG_ERR VTDPREFIX,                 "intel_iommu_add_device: context mapping failed\n");        return ret;    }    for_each_rmrr_device ( rmrr, bdf, i )    {        if ( PCI_BUS(bdf) == pdev->bus && PCI_DEVFN2(bdf) == pdev->devfn )        {            ret = iommu_prepare_rmrr_dev(pdev->domain, rmrr,                                         pdev->bus, pdev->devfn);            if ( ret )                gdprintk(XENLOG_ERR VTDPREFIX,                         "intel_iommu_add_device: RMRR mapping failed\n");            break;        }    }    return ret;}static int intel_iommu_remove_device(struct pci_dev *pdev){    struct acpi_rmrr_unit *rmrr;    u16 bdf;    int i;    if ( !pdev->domain )        return -EINVAL;    /* If the device belongs to dom0, and it has RMRR, don't remove it     * from dom0, because BIOS may use RMRR at booting time.     */    if ( pdev->domain->domain_id == 0 )    {        for_each_rmrr_device ( rmrr, bdf, i )        {            if ( PCI_BUS(bdf) == pdev->bus &&                 PCI_DEVFN2(bdf) == pdev->devfn )                return 0;        }    }    return domain_context_unmap(pdev->domain, pdev->bus, pdev->devfn);}static void setup_dom0_devices(struct domain *d){    struct hvm_iommu *hd;    struct pci_dev *pdev;    int bus, dev, func;    u32 l;    hd = domain_hvm_iommu(d);    write_lock(&pcidevs_lock);    for ( bus = 0; bus < 256; bus++ )    {        for ( dev = 0; dev < 32; dev++ )        {            for ( func = 0; func < 8; func++ )            {                l = pci_conf_read32(bus, dev, func, PCI_VENDOR_ID);                /* some broken boards return 0 or ~0 if a slot is empty: */                if ( (l == 0xffffffff) || (l == 0x00000000) ||                     (l == 0x0000ffff) || (l == 0xffff0000) )                    continue;                pdev = alloc_pdev(bus, PCI_DEVFN(dev, func));                pdev->domain = d;                list_add(&pdev->domain_list, &d->arch.pdev_list);                domain_context_mapping(d, pdev->bus, pdev->devfn);            }        }    }    write_unlock(&pcidevs_lock);}void clear_fault_bits(struct iommu *iommu){    u64 val;    val = dmar_readq(        iommu->reg,        cap_fault_reg_offset(dmar_readq(iommu->reg,DMAR_CAP_REG))+0x8);    dmar_writeq(        iommu->reg,        cap_fault_reg_offset(dmar_readq(iommu->reg,DMAR_CAP_REG))+8,        val);    dmar_writel(iommu->reg, DMAR_FSTS_REG, DMA_FSTS_FAULTS);}static int init_vtd_hw(void){    struct acpi_drhd_unit *drhd;    struct iommu *iommu;    struct iommu_flush *flush = NULL;    int vector;    int ret;    for_each_drhd_unit ( drhd )    {        iommu = drhd->iommu;        ret = iommu_set_root_entry(iommu);        if ( ret )        {            gdprintk(XENLOG_ERR VTDPREFIX, "IOMMU: set root entry failed\n");            return -EIO;        }        vector = iommu_set_interrupt(iommu);        dma_msi_data_init(iommu, vector);        dma_msi_addr_init(iommu, cpu_physical_id(first_cpu(cpu_online_map)));        iommu->vector = vector;        clear_fault_bits(iommu);        dmar_writel(iommu->reg, DMAR_FECTL_REG, 0);        /* initialize flush functions */        flush = iommu_get_flush(iommu);        flush->context = flush_context_reg;        flush->iotlb = flush_iotlb_reg;    }    for_each_drhd_unit ( drhd )    {        iommu = drhd->iommu;        if ( qinval_setup(iommu) != 0 )            dprintk(XENLOG_INFO VTDPREFIX,                    "Queued Invalidation hardware not found\n");    }    for_each_drhd_unit ( drhd )    {        iommu = drhd->iommu;        if ( intremap_setup(iommu) != 0 )            dprintk(XENLOG_INFO VTDPREFIX,                    "Interrupt Remapping hardware not found\n");    }    return 0;}static void setup_dom0_rmrr(struct domain *d){    struct acpi_rmrr_unit *rmrr;    u16 bdf;    int ret, i;    for_each_rmrr_device ( rmrr, bdf, i )    {        ret = iommu_prepare_rmrr_dev(d, rmrr, PCI_BUS(bdf), PCI_DEVFN2(bdf));        if ( ret )            gdprintk(XENLOG_ERR VTDPREFIX,                     "IOMMU: mapping reserved region failed\n");    }}int intel_vtd_setup(void){    struct acpi_drhd_unit *drhd;    struct iommu *iommu;    if ( !vtd_enabled )        return -ENODEV;    spin_lock_init(&domid_bitmap_lock);    clflush_size = get_clflush_size();    for_each_drhd_unit ( drhd )        if ( iommu_alloc(drhd) != 0 )            goto error;    /* Allocate IO page directory page for the domain. */    drhd = list_entry(acpi_drhd_units.next, typeof(*drhd), list);    iommu = drhd->iommu;    /* Allocate domain id bitmap, and set bit 0 as reserved */    domid_bitmap_size = cap_ndoms(iommu->cap);    domid_bitmap = xmalloc_array(unsigned long,                                 BITS_TO_LONGS(domid_bitmap_size));    if ( domid_bitmap == NULL )        goto error;    memset(domid_bitmap, 0, domid_bitmap_size / 8);    set_bit(0, domid_bitmap);    if ( init_vtd_hw() )        goto error;    register_keyhandler('V', dump_iommu_info, "dump iommu info");    return 0; error:    for_each_drhd_unit ( drhd )        iommu_free(drhd);    vtd_enabled = 0;    return -ENOMEM;}/* * If the device isn't owned by dom0, it means it already * has been assigned to other domain, or it's not exist. */int device_assigned(u8 bus, u8 devfn){    struct pci_dev *pdev;    if ( (pdev = pci_lock_domain_pdev(dom0, bus, devfn)) )    {        spin_unlock(&pdev->lock);        return 0;    }    return 1;}int intel_iommu_assign_device(struct domain *d, u8 bus, u8 devfn){    struct acpi_rmrr_unit *rmrr;    int ret = 0, i;    u16 bdf;    if ( list_empty(&acpi_drhd_units) )        return -ENODEV;    ret = reassign_device_ownership(dom0, d, bus, devfn);    if ( ret )        return ret;    /* Setup rmrr identity mapping */    for_each_rmrr_device( rmrr, bdf, i )    {        if ( PCI_BUS(bdf) == bus && PCI_DEVFN2(bdf) == devfn )        {            /* FIXME: Because USB RMRR conflicts with guest bios region,             * ignore USB RMRR temporarily.             */            if ( is_usb_device(bus, devfn) )                return 0;            ret = iommu_prepare_rmrr_dev(d, rmrr, bus, devfn);            if ( ret )                gdprintk(XENLOG_ERR VTDPREFIX,                         "IOMMU: mapping reserved region failed\n");            return ret;        }    }    return ret;}static int intel_iommu_group_id(u8 bus, u8 devfn){    u8 secbus;    if ( !bus2bridge[bus].map || find_pcie_endpoint(&bus, &devfn, &secbus) )        return PCI_BDF2(bus, devfn);    else        return -1;}u8 iommu_state[MAX_IOMMU_REGS * MAX_IOMMUS];int iommu_suspend(void){    struct acpi_drhd_unit *drhd;    struct iommu *iommu;    int i = 0;    iommu_flush_all();    for_each_drhd_unit ( drhd )    {        iommu = drhd->iommu;        iommu_state[DMAR_RTADDR_REG * i] =            (u64) dmar_readq(iommu->reg, DMAR_RTADDR_REG);        iommu_state[DMAR_FECTL_REG * i] =            (u32) dmar_readl(iommu->reg, DMAR_FECTL_REG);        iommu_state[DMAR_FEDATA_REG * i] =            (u32) dmar_readl(iommu->reg, DMAR_FEDATA_REG);        iommu_state[DMAR_FEADDR_REG * i] =            (u32) dmar_readl(iommu->reg, DMAR_FEADDR_REG);        iommu_state[DMAR_FEUADDR_REG * i] =            (u32) dmar_readl(iommu->reg, DMAR_FEUADDR_REG);        iommu_state[DMAR_PLMBASE_REG * i] =            (u32) dmar_readl(iommu->reg, DMAR_PLMBASE_REG);        iommu_state[DMAR_PLMLIMIT_REG * i] =            (u32) dmar_readl(iommu->reg, DMAR_PLMLIMIT_REG);        iommu_state[DMAR_PHMBASE_REG * i] =            (u64) dmar_readq(iommu->reg, DMAR_PHMBASE_REG);        iommu_state[DMAR_PHMLIMIT_REG * i] =            (u64) dmar_readq(iommu->reg, DMAR_PHMLIMIT_REG);        i++;    }    return 0;}int iommu_resume(void){    struct acpi_drhd_unit *drhd;    struct iommu *iommu;    int i = 0;    iommu_flush_all();    init_vtd_hw();    for_each_drhd_unit ( drhd )    {        iommu = drhd->iommu;        dmar_writeq( iommu->reg, DMAR_RTADDR_REG,                     (u64) iommu_state[DMAR_RTADDR_REG * i]);        dmar_writel(iommu->reg, DMAR_FECTL_REG,                    (u32) iommu_state[DMAR_FECTL_REG * i]);        dmar_writel(iommu->reg, DMAR_FEDATA_REG,                    (u32) iommu_state[DMAR_FEDATA_REG * i]);        dmar_writel(iommu->reg, DMAR_FEADDR_REG,                    (u32) iommu_state[DMAR_FEADDR_REG * i]);        dmar_writel(iommu->reg, DMAR_FEUADDR_REG,                    (u32) iommu_state[DMAR_FEUADDR_REG * i]);        dmar_writel(iommu->reg, DMAR_PLMBASE_REG,                    (u32) iommu_state[DMAR_PLMBASE_REG * i]);        dmar_writel(iommu->reg, DMAR_PLMLIMIT_REG,                    (u32) iommu_state[DMAR_PLMLIMIT_REG * i]);        dmar_writeq(iommu->reg, DMAR_PHMBASE_REG,                    (u64) iommu_state[DMAR_PHMBASE_REG * i]);        dmar_writeq(iommu->reg, DMAR_PHMLIMIT_REG,                    (u64) iommu_state[DMAR_PHMLIMIT_REG * i]);        if ( iommu_enable_translation(iommu) )            return -EIO;        i++;    }    return 0;}struct iommu_ops intel_iommu_ops = {    .init = intel_iommu_domain_init,    .add_device = intel_iommu_add_device,    .remove_device = intel_iommu_remove_device,    .assign_device  = intel_iommu_assign_device,    .teardown = iommu_domain_teardown,    .map_page = intel_iommu_map_page,    .unmap_page = intel_iommu_unmap_page,    .reassign_device = reassign_device_ownership,    .get_device_group_id = intel_iommu_group_id,    .update_ire_from_apic = io_apic_write_remap_rte,    .update_ire_from_msi = msi_msg_write_remap_rte,};/* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -