📄 pass-through.c
字号:
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(®_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(®_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 + -