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

📄 pass-through.c

📁 xen虚拟机源代码安装包
💻 C
📖 第 1 页 / 共 5 页
字号:
    while (0 < emul_len)    {        /* find register entry to be emulated */        reg_entry = pt_find_reg(reg_grp_entry, find_addr);        if (reg_entry)        {            reg = reg_entry->reg;            real_offset = (reg_grp_entry->base_offset + reg->offset);            valid_mask = (0xFFFFFFFF >> ((4 - emul_len) << 3));            valid_mask <<= ((find_addr - real_offset) << 3);            ptr_val = ((uint8_t *)&val + (real_offset & 3));            /* do emulation depend on register size */            switch (reg->size) {            case 1:                /* emulate read to byte register */                if (reg->u.b.read)                    ret = reg->u.b.read(assigned_device, reg_entry,                                        (uint8_t *)ptr_val,                                         (uint8_t)valid_mask);                break;            case 2:                /* emulate read to word register */                if (reg->u.w.read)                    ret = reg->u.w.read(assigned_device, reg_entry,                                        (uint16_t *)ptr_val,                                         (uint16_t)valid_mask);                break;            case 4:                /* emulate read to double word register */                if (reg->u.dw.read)                    ret = reg->u.dw.read(assigned_device, reg_entry,                                        (uint32_t *)ptr_val,                                         (uint32_t)valid_mask);                break;            }            /* read emulation error */            if (ret < 0)            {                /* exit I/O emulator */                PT_LOG("Internal error: Invalid read emulation "                    "return value[%d]. I/O emulator exit.\n", ret);                exit(1);            }            /* calculate next address to find */            emul_len -= reg->size;            if (emul_len > 0)                find_addr = real_offset + reg->size;        }        else        {            /* nothing to do with passthrough type register,              * continue to find next byte              */            emul_len--;            find_addr++;        }    }        /* need to shift back before returning them to pci bus emulator */    val >>= ((address & 3) << 3);exit:#ifdef PT_DEBUG_PCI_CONFIG_ACCESS    PT_LOG("[%02x:%02x.%x]: address=%04x val=0x%08x len=%d\n",       pci_bus_num(d->bus), (d->devfn >> 3) & 0x1F, (d->devfn & 0x7),       address, val, len);#endif    return val;}static int pt_register_regions(struct pt_dev *assigned_device){    int i = 0;    uint32_t bar_data = 0;    struct pci_dev *pci_dev = assigned_device->pci_dev;    PCIDevice *d = &assigned_device->dev;    /* Register PIO/MMIO BARs */    for ( i = 0; i < PCI_BAR_ENTRIES; i++ )    {        if ( pci_dev->base_addr[i] )        {            assigned_device->bases[i].e_physbase = pci_dev->base_addr[i];            assigned_device->bases[i].access.u = pci_dev->base_addr[i];            /* Register current region */            bar_data = *((uint32_t*)(d->config + PCI_BASE_ADDRESS_0) + i);            if ( bar_data & PCI_ADDRESS_SPACE_IO )                pci_register_io_region((PCIDevice *)assigned_device, i,                    (uint32_t)pci_dev->size[i], PCI_ADDRESS_SPACE_IO,                    pt_ioport_map);            else if ( bar_data & PCI_ADDRESS_SPACE_MEM_PREFETCH )                pci_register_io_region((PCIDevice *)assigned_device, i,                    (uint32_t)pci_dev->size[i], PCI_ADDRESS_SPACE_MEM_PREFETCH,                    pt_iomem_map);            else                pci_register_io_region((PCIDevice *)assigned_device, i,                     (uint32_t)pci_dev->size[i], PCI_ADDRESS_SPACE_MEM,                    pt_iomem_map);            PT_LOG("IO region registered (size=0x%08x base_addr=0x%08x)\n",                (uint32_t)(pci_dev->size[i]),                (uint32_t)(pci_dev->base_addr[i]));        }    }    /* Register expansion ROM address */    if ( pci_dev->rom_base_addr && pci_dev->rom_size )    {        assigned_device->bases[PCI_ROM_SLOT].e_physbase =            pci_dev->rom_base_addr;        assigned_device->bases[PCI_ROM_SLOT].access.maddr =            pci_dev->rom_base_addr;        pci_register_io_region((PCIDevice *)assigned_device, PCI_ROM_SLOT,            pci_dev->rom_size, PCI_ADDRESS_SPACE_MEM_PREFETCH,            pt_iomem_map);        PT_LOG("Expansion ROM registered (size=0x%08x base_addr=0x%08x)\n",            (uint32_t)(pci_dev->rom_size), (uint32_t)(pci_dev->rom_base_addr));    }    return 0;}static void pt_unregister_regions(struct pt_dev *assigned_device){    int i, type, ret;    uint32_t e_size;    PCIDevice *d = (PCIDevice*)assigned_device;    for ( i = 0; i < PCI_NUM_REGIONS; i++ )    {        e_size = assigned_device->bases[i].e_size;        if ( (e_size == 0) || (assigned_device->bases[i].e_physbase == -1) )            continue;        type = d->io_regions[i].type;        if ( type == PCI_ADDRESS_SPACE_MEM ||             type == PCI_ADDRESS_SPACE_MEM_PREFETCH )        {            ret = xc_domain_memory_mapping(xc_handle, domid,                    assigned_device->bases[i].e_physbase >> XC_PAGE_SHIFT,                    assigned_device->bases[i].access.maddr >> XC_PAGE_SHIFT,                    (e_size+XC_PAGE_SIZE-1) >> XC_PAGE_SHIFT,                    DPCI_REMOVE_MAPPING);            if ( ret != 0 )            {                PT_LOG("Error: remove old mem mapping failed!\n");                continue;            }        }        else if ( type == PCI_ADDRESS_SPACE_IO )        {            ret = xc_domain_ioport_mapping(xc_handle, domid,                        assigned_device->bases[i].e_physbase,                        assigned_device->bases[i].access.pio_base,                        e_size,                        DPCI_REMOVE_MAPPING);            if ( ret != 0 )            {                PT_LOG("Error: remove old io mapping failed!\n");                continue;            }        }            }}uint8_t find_cap_offset(struct pci_dev *pci_dev, uint8_t cap){    int id;    int max_cap = 48;    int pos = PCI_CAPABILITY_LIST;    int status;    status = pci_read_byte(pci_dev, PCI_STATUS);    if ( (status & PCI_STATUS_CAP_LIST) == 0 )        return 0;    while ( max_cap-- )    {        pos = pci_read_byte(pci_dev, pos);        if ( pos < 0x40 )            break;        pos &= ~3;        id = pci_read_byte(pci_dev, pos + PCI_CAP_LIST_ID);        if ( id == 0xff )            break;        if ( id == cap )            return pos;        pos += PCI_CAP_LIST_NEXT;    }    return 0;}/* parse BAR */static int pt_bar_reg_parse(        struct pt_dev *ptdev, struct pt_reg_info_tbl *reg){    PCIDevice *d = &ptdev->dev;    struct pt_region *region = NULL;    PCIIORegion *r;    uint32_t bar_64 = (reg->offset - 4);    int bar_flag = PT_BAR_FLAG_UNUSED;    int index = 0;    int i;    /* set again the BAR config because it has been overwritten     * by pci_register_io_region()     */    for (i=reg->offset; i<(reg->offset + 4); i++)        d->config[i] = pci_read_byte(ptdev->pci_dev, i);    /* check 64bit BAR */    index = pt_bar_offset_to_index(reg->offset);    if ((index > 0) && (index < PCI_ROM_SLOT) &&        ((d->config[bar_64] & (PCI_BASE_ADDRESS_SPACE |                               PCI_BASE_ADDRESS_MEM_TYPE_MASK)) ==         (PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64)))    {        region = &ptdev->bases[index-1];        if (region->bar_flag != PT_BAR_FLAG_UPPER)        {            bar_flag = PT_BAR_FLAG_UPPER;            goto out;        }    }    /* check unused BAR */    r = &d->io_regions[index];    if (!r->size)        goto out;    /* for ExpROM BAR */    if (index == PCI_ROM_SLOT)    {        bar_flag = PT_BAR_FLAG_MEM;        goto out;    }    /* check BAR I/O indicator */    if (d->config[reg->offset] & PCI_BASE_ADDRESS_SPACE_IO)        bar_flag = PT_BAR_FLAG_IO;    else        bar_flag = PT_BAR_FLAG_MEM;out:    return bar_flag;}/* mapping BAR */static void pt_bar_mapping(struct pt_dev *ptdev, int io_enable, int mem_enable){    PCIDevice *dev = (PCIDevice *)&ptdev->dev;    PCIIORegion *r;    struct pt_region *base = NULL;    uint32_t r_size = 0, r_addr = -1;    int ret = 0;    int i;    for (i=0; i<PCI_NUM_REGIONS; i++)    {        r = &dev->io_regions[i];        /* check valid region */        if (!r->size)            continue;        base = &ptdev->bases[i];        /* skip unused BAR or upper 64bit BAR */        if ((base->bar_flag == PT_BAR_FLAG_UNUSED) ||            (base->bar_flag == PT_BAR_FLAG_UPPER))               continue;        /* copy region address to temporary */        r_addr = r->addr;        /* need unmapping in case I/O Space or Memory Space disable */        if (((base->bar_flag == PT_BAR_FLAG_IO) && !io_enable ) ||            ((base->bar_flag == PT_BAR_FLAG_MEM) && !mem_enable ))            r_addr = -1;        /* prevent guest software mapping memory resource to 00000000h */        if ((base->bar_flag == PT_BAR_FLAG_MEM) && (r_addr == 0))            r_addr = -1;        /* align resource size (memory type only) */        r_size = r->size;        PT_GET_EMUL_SIZE(base->bar_flag, r_size);        /* check overlapped address */        ret = pt_chk_bar_overlap(dev->bus, dev->devfn, r_addr, r_size);        if (ret > 0)            PT_LOG("ptdev[%02x:%02x.%x][Region:%d][Address:%08xh][Size:%08xh] "                "is overlapped.\n", pci_bus_num(dev->bus),                 (dev->devfn >> 3) & 0x1F, (dev->devfn & 0x7),                i, r_addr, r_size);        /* check whether we need to update the mapping or not */        if (r_addr != ptdev->bases[i].e_physbase)        {            /* mapping BAR */            r->map_func((PCIDevice *)ptdev, i, r_addr,                          r_size, r->type);        }    }    return;}/* initialize emulate register */static int pt_config_reg_init(struct pt_dev *ptdev,        struct pt_reg_grp_tbl *reg_grp,        struct pt_reg_info_tbl *reg){    struct pt_reg_tbl *reg_entry;    uint32_t data = 0;    int err = 0;    /* allocate register entry */    reg_entry = qemu_mallocz(sizeof(struct pt_reg_tbl));    if (reg_entry == NULL)    {        PT_LOG("Failed to allocate memory.\n");        err = -1;        goto out;    }    /* initialize register entry */    reg_entry->reg = reg;    reg_entry->data = 0;    if (reg->init)    {        /* initialize emulate register */        data = reg->init(ptdev, reg_entry->reg,                        (reg_grp->base_offset + reg->offset));        if (data == PT_INVALID_REG)        {            /* free unused BAR register entry */            free(reg_entry);            goto out;        }        /* set register value */        reg_entry->data = data;    }    /* list add register entry */    LIST_INSERT_HEAD(&reg_grp->reg_tbl_head, reg_entry, entries);out:    return err;}/* initialize emulate register group */static int pt_config_init(struct pt_dev *ptdev){    struct pt_reg_grp_tbl *reg_grp_entry = NULL;    struct pt_reg_info_tbl *reg_tbl = NULL;    uint32_t reg_grp_offset = 0;    int i, j, err = 0;    /* initialize register group list */    LIST_INIT(&ptdev->reg_grp_tbl_head);    /* initialize register group */    for (i=0; pt_emu_reg_grp_tbl[i].grp_size != 0; i++)    {        if (pt_emu_reg_grp_tbl[i].grp_id != 0xFF)        {            reg_grp_offset = (uint32_t)find_cap_offset(ptdev->pci_dev,                                  pt_emu_reg_grp_tbl[i].grp_id);            if (!reg_grp_offset)                 continue;        }        /* allocate register group table */        reg_grp_entry = qemu_mallocz(sizeof(struct pt_reg_grp_tbl));        if (reg_grp_entry == NULL)        {            PT_LOG("Failed to allocate memory.\n");            err = -1;            goto out;        }        /* initialize register group entry */        LIST_INIT(&reg_grp_entry->reg_tbl_head);        /* need to declare here, to enable searching Cap Ptr reg          * (which is in the same reg group) when initializing Status reg          */        LIST_INSERT_HEAD(&ptdev->reg_grp_tbl_head, reg_grp_entry, entries);        reg_grp_entry->base_offset = reg_grp_offset;        reg_grp_entry->reg_grp =                 (struct pt_reg_grp_info_tbl*)&pt_emu_reg_grp_tbl[i];        if (pt_emu_reg_grp_tbl[i].size_init)        {            /* get register group size */            reg_grp_entry->size = pt_emu_reg_grp_tbl[i].size_init(ptdev,                                      reg_grp_entry->reg_grp,                                       reg_grp_offset);        }        if (pt_emu_reg_grp_tbl[i].grp_type == GRP_TYPE_EMU)        {            if (pt_emu_reg_grp_tbl[i].emu_reg_tbl)            {                reg_tbl = pt_emu_reg_grp_tbl[i].emu_reg_tbl;                /* initialize capability register */                for (j=0; reg_tbl->size != 0; j++, reg_tbl++)                {                    /* initialize capability register */                    err = pt_config_reg_init(ptdev, reg_grp_entry, reg_tbl);                    if (err < 0)                        goto out;                }            }

⌨️ 快捷键说明

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