utils.c

来自「xen 3.2.2 源码」· C语言 代码 · 共 347 行

C
347
字号
/* * Copyright (c) 2006, Intel Corporation. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., 59 Temple * Place - Suite 330, Boston, MA 02111-1307 USA. * * Copyright (C) Allen Kay <allen.m.kay@intel.com> */#include <xen/init.h>#include <xen/bitmap.h>#include <xen/irq.h>#include <xen/spinlock.h>#include <xen/sched.h>#include <xen/delay.h>#include <asm/iommu.h>#include <asm/hvm/vmx/intel-iommu.h>#include "dmar.h"#include "pci-direct.h"#include "pci_regs.h"#include "msi.h"#include <xen/mm.h>#include <xen/xmalloc.h>#include <xen/inttypes.h>#define INTEL   0x8086#define SEABURG 0x4000#define C_STEP  2int is_usb_device(struct pci_dev *pdev){    u8 bus = pdev->bus;    u8 dev = PCI_SLOT(pdev->devfn);    u8 func = PCI_FUNC(pdev->devfn);    u16 class = read_pci_config_16(bus, dev, func, PCI_CLASS_DEVICE);    return (class == 0xc03);}int vtd_hw_check(void){    u16 vendor, device;    u8 revision, stepping;    vendor   = read_pci_config_16(0, 0, 0, PCI_VENDOR_ID);    device   = read_pci_config_16(0, 0, 0, PCI_DEVICE_ID);    revision = read_pci_config_byte(0, 0, 0, PCI_REVISION_ID);    stepping = revision & 0xf;    if ( (vendor == INTEL) && (device == SEABURG) )    {        if ( stepping < C_STEP )        {            dprintk(XENLOG_WARNING VTDPREFIX,                    "*** VT-d disabled - pre C0-step Seaburg found\n");            dprintk(XENLOG_WARNING VTDPREFIX,                    "***  vendor = %x device = %x revision = %x\n",                    vendor, device, revision);            vtd_enabled = 0;            return -ENODEV;        }    }    return 0;}/* Disable vt-d protected memory registers. */void disable_pmr(struct iommu *iommu){    unsigned long start_time;    unsigned int val;    val = dmar_readl(iommu->reg, DMAR_PMEN_REG);    if ( !(val & DMA_PMEN_PRS) )        return;    dmar_writel(iommu->reg, DMAR_PMEN_REG, val & ~DMA_PMEN_EPM);    start_time = jiffies;    for ( ; ; )    {        val = dmar_readl(iommu->reg, DMAR_PMEN_REG);        if ( (val & DMA_PMEN_PRS) == 0 )            break;        if ( time_after(jiffies, start_time + DMAR_OPERATION_TIMEOUT) )            panic("Disable PMRs timeout\n");        cpu_relax();    }    dprintk(XENLOG_INFO VTDPREFIX,            "Disabled protected memory registers\n");}static u8 find_cap_offset(u8 bus, u8 dev, u8 func, u8 cap){    u8 id;    int max_cap = 48;    u8 pos = PCI_CAPABILITY_LIST;    u16 status;    status = read_pci_config_16(bus, dev, func, PCI_STATUS);    if ( (status & PCI_STATUS_CAP_LIST) == 0 )        return 0;    while ( max_cap-- )    {        pos = read_pci_config_byte(bus, dev, func, pos);        if ( pos < 0x40 )            break;        pos &= ~3;        id = read_pci_config_byte(bus, dev, func, pos + PCI_CAP_LIST_ID);        if ( id == 0xff )            break;        else if ( id == cap )            return pos;        pos += PCI_CAP_LIST_NEXT;    }    return 0;}#define PCI_D3hot   (3)#define PCI_CONFIG_DWORD_SIZE   (64)#define PCI_EXP_DEVCAP_FLR      (1 << 28)#define PCI_EXP_DEVCTL_FLR      (1 << 15)void pdev_flr(u8 bus, u8 devfn){    u8 pos;    u32 dev_cap, dev_status, pm_ctl;    int flr = 0;    u8 dev = PCI_SLOT(devfn);    u8 func = PCI_FUNC(devfn);    pos = find_cap_offset(bus, dev, func, PCI_CAP_ID_EXP);    if ( pos != 0 )    {        dev_cap = read_pci_config(bus, dev, func, pos + PCI_EXP_DEVCAP);        if ( dev_cap & PCI_EXP_DEVCAP_FLR )        {            write_pci_config(bus, dev, func,                             pos + PCI_EXP_DEVCTL, PCI_EXP_DEVCTL_FLR);            do {                dev_status = read_pci_config(bus, dev, func,                                             pos + PCI_EXP_DEVSTA);            } while ( dev_status & PCI_EXP_DEVSTA_TRPND );            flr = 1;        }    }    /* If this device doesn't support function level reset,     * program device from D0 t0 D3hot, and then return to D0     * to implement function level reset     */    if ( flr == 0 )    {        pos = find_cap_offset(bus, dev, func, PCI_CAP_ID_PM);        if ( pos != 0 )        {            int i;            u32 config[PCI_CONFIG_DWORD_SIZE];            for ( i = 0; i < PCI_CONFIG_DWORD_SIZE; i++ )                config[i] = read_pci_config(bus, dev, func, i*4);            /* Enter D3hot without soft reset */            pm_ctl = read_pci_config(bus, dev, func, pos + PCI_PM_CTRL);            pm_ctl |= PCI_PM_CTRL_NO_SOFT_RESET;            pm_ctl &= ~PCI_PM_CTRL_STATE_MASK;            pm_ctl |= PCI_D3hot;            write_pci_config(bus, dev, func, pos + PCI_PM_CTRL, pm_ctl);            mdelay(10);            /* From D3hot to D0 */            write_pci_config(bus, dev, func, pos + PCI_PM_CTRL, 0);            mdelay(10);            /* Write saved configurations to device */            for ( i = 0; i < PCI_CONFIG_DWORD_SIZE; i++ )                write_pci_config(bus, dev, func, i*4, config[i]);            flr = 1;        }    }}void print_iommu_regs(struct acpi_drhd_unit *drhd){    struct iommu *iommu = drhd->iommu;    printk("---- print_iommu_regs ----\n");    printk("print_iommu_regs: drhd->address = %lx\n", drhd->address);    printk("print_iommu_regs: DMAR_VER_REG = %x\n",           dmar_readl(iommu->reg,DMAR_VER_REG));    printk("print_iommu_regs: DMAR_CAP_REG = %"PRIx64"\n",           dmar_readq(iommu->reg,DMAR_CAP_REG));    printk("print_iommu_regs: n_fault_reg = %"PRIx64"\n",           cap_num_fault_regs(dmar_readq(iommu->reg, DMAR_CAP_REG)));    printk("print_iommu_regs: fault_recording_offset_l = %"PRIx64"\n",           cap_fault_reg_offset(dmar_readq(iommu->reg, DMAR_CAP_REG)));    printk("print_iommu_regs: fault_recording_offset_h = %"PRIx64"\n",           cap_fault_reg_offset(dmar_readq(iommu->reg, DMAR_CAP_REG)) + 8);    printk("print_iommu_regs: fault_recording_reg_l = %"PRIx64"\n",           dmar_readq(iommu->reg,               cap_fault_reg_offset(dmar_readq(iommu->reg, DMAR_CAP_REG))));    printk("print_iommu_regs: fault_recording_reg_h = %"PRIx64"\n",           dmar_readq(iommu->reg,               cap_fault_reg_offset(dmar_readq(iommu->reg, DMAR_CAP_REG)) + 8));    printk("print_iommu_regs: DMAR_ECAP_REG = %"PRIx64"\n",           dmar_readq(iommu->reg,DMAR_ECAP_REG));    printk("print_iommu_regs: DMAR_GCMD_REG = %x\n",           dmar_readl(iommu->reg,DMAR_GCMD_REG));    printk("print_iommu_regs: DMAR_GSTS_REG = %x\n",           dmar_readl(iommu->reg,DMAR_GSTS_REG));    printk("print_iommu_regs: DMAR_RTADDR_REG = %"PRIx64"\n",           dmar_readq(iommu->reg,DMAR_RTADDR_REG));    printk("print_iommu_regs: DMAR_CCMD_REG = %"PRIx64"\n",           dmar_readq(iommu->reg,DMAR_CCMD_REG));    printk("print_iommu_regs: DMAR_FSTS_REG = %x\n",           dmar_readl(iommu->reg,DMAR_FSTS_REG));    printk("print_iommu_regs: DMAR_FECTL_REG = %x\n",           dmar_readl(iommu->reg,DMAR_FECTL_REG));    printk("print_iommu_regs: DMAR_FEDATA_REG = %x\n",           dmar_readl(iommu->reg,DMAR_FEDATA_REG));    printk("print_iommu_regs: DMAR_FEADDR_REG = %x\n",           dmar_readl(iommu->reg,DMAR_FEADDR_REG));    printk("print_iommu_regs: DMAR_FEUADDR_REG = %x\n",           dmar_readl(iommu->reg,DMAR_FEUADDR_REG));}u32 get_level_index(unsigned long gmfn, int level){    while ( --level )        gmfn = gmfn >> LEVEL_STRIDE;    return gmfn & LEVEL_MASK;}void print_vtd_entries(struct domain *d, int bus, int devfn,                       unsigned long gmfn){    struct hvm_iommu *hd = domain_hvm_iommu(d);    struct acpi_drhd_unit *drhd;    struct iommu *iommu;    struct context_entry *ctxt_entry;    struct root_entry *root_entry;    struct dma_pte pte;    u64 *l;    u32 l_index;    u32 i = 0;    int level = agaw_to_level(hd->agaw);    printk("print_vtd_entries: domain_id = %x bdf = %x:%x:%x gmfn = %lx\n",           d->domain_id, bus, PCI_SLOT(devfn), PCI_FUNC(devfn), gmfn);    if ( hd->pgd == NULL )    {        printk("    hg->pgd == NULL\n");        return;    }    printk("    d->pgd = %p virt_to_maddr(hd->pgd) = %lx\n",           hd->pgd, virt_to_maddr(hd->pgd));    for_each_drhd_unit ( drhd )    {        printk("---- print_vtd_entries %d ----\n", i++);        iommu = drhd->iommu;        root_entry = iommu->root_entry;        if ( root_entry == NULL )        {            printk("    root_entry == NULL\n");            continue;        }        printk("    root_entry = %p\n", root_entry);        printk("    root_entry[%x] = %"PRIx64"\n", bus, root_entry[bus].val);        if ( !root_present(root_entry[bus]) )        {            printk("    root_entry[%x] not present\n", bus);            continue;        }        ctxt_entry =            maddr_to_virt((root_entry[bus].val >> PAGE_SHIFT) << PAGE_SHIFT);        if ( ctxt_entry == NULL )        {            printk("    ctxt_entry == NULL\n");            continue;        }        printk("    context = %p\n", ctxt_entry);        printk("    context[%x] = %"PRIx64" %"PRIx64"\n",               devfn, ctxt_entry[devfn].hi, ctxt_entry[devfn].lo);        if ( !context_present(ctxt_entry[devfn]) )        {            printk("    ctxt_entry[%x] not present\n", devfn);            continue;        }        if ( level != VTD_PAGE_TABLE_LEVEL_3 &&             level != VTD_PAGE_TABLE_LEVEL_4)        {            printk("Unsupported VTD page table level (%d)!\n", level);            continue;        }        l = maddr_to_virt(ctxt_entry[devfn].lo);        do        {            l = (u64*)(((unsigned long)l >> PAGE_SHIFT_4K) << PAGE_SHIFT_4K);            printk("    l%d = %p\n", level, l);            if ( l == NULL )            {                printk("    l%d == NULL\n", level);                break;            }            l_index = get_level_index(gmfn, level);            printk("    l%d_index = %x\n", level, l_index);            printk("    l%d[%x] = %"PRIx64"\n", level, l_index, l[l_index]);            pte.val = l[l_index];            if ( !dma_pte_present(pte) )            {                printk("    l%d[%x] not present\n", level, l_index);                break;            }            l = maddr_to_virt(l[l_index]);        } while ( --level );    }}

⌨️ 快捷键说明

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