📄 pass-through.c
字号:
/* map only valid guest address */ if (e_phys != -1) { /* Create new mapping */ 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_ADD_MAPPING); if ( ret != 0 ) { PT_LOG("Error: create new mapping failed!\n"); } ret = remove_msix_mapping(assigned_device, i); if ( ret != 0 ) PT_LOG("Error: remove MSI-X mmio mapping failed!\n"); }}/* Being called each time a pio region has been updated */void pt_ioport_map(PCIDevice *d, int i, uint32_t e_phys, uint32_t e_size, int type){ struct pt_dev *assigned_device = (struct pt_dev *)d; uint32_t old_ebase = assigned_device->bases[i].e_physbase; int first_map = ( assigned_device->bases[i].e_size == 0 ); int ret = 0; assigned_device->bases[i].e_physbase = e_phys; assigned_device->bases[i].e_size= e_size; PT_LOG("e_phys=%04x pio_base=%04x len=%d index=%d first_map=%d\n", (uint16_t)e_phys, (uint16_t)assigned_device->bases[i].access.pio_base, (uint16_t)e_size, i, first_map); if ( e_size == 0 ) return; if ( !first_map && old_ebase != -1 ) { /* Remove old mapping */ ret = xc_domain_ioport_mapping(xc_handle, domid, old_ebase, assigned_device->bases[i].access.pio_base, e_size, DPCI_REMOVE_MAPPING); if ( ret != 0 ) { PT_LOG("Error: remove old mapping failed!\n"); return; } } /* map only valid guest address (include 0) */ if (e_phys != -1) { /* Create new mapping */ ret = xc_domain_ioport_mapping(xc_handle, domid, e_phys, assigned_device->bases[i].access.pio_base, e_size, DPCI_ADD_MAPPING); if ( ret != 0 ) { PT_LOG("Error: create new mapping failed!\n"); } }}/* find emulate register group entry */struct pt_reg_grp_tbl* pt_find_reg_grp( struct pt_dev *ptdev, uint32_t address){ struct pt_reg_grp_tbl* reg_grp_entry = NULL; /* find register group entry */ for (reg_grp_entry = ptdev->reg_grp_tbl_head.lh_first; reg_grp_entry; reg_grp_entry = reg_grp_entry->entries.le_next) { /* check address */ if ((reg_grp_entry->base_offset <= address) && ((reg_grp_entry->base_offset + reg_grp_entry->size) > address)) goto out; } /* group entry not found */ reg_grp_entry = NULL;out: return reg_grp_entry;}/* find emulate register entry */struct pt_reg_tbl* pt_find_reg( struct pt_reg_grp_tbl* reg_grp, uint32_t address){ struct pt_reg_tbl* reg_entry = NULL; struct pt_reg_info_tbl* reg = NULL; uint32_t real_offset = 0; /* find register entry */ for (reg_entry = reg_grp->reg_tbl_head.lh_first; reg_entry; reg_entry = reg_entry->entries.le_next) { reg = reg_entry->reg; real_offset = (reg_grp->base_offset + reg->offset); /* check address */ if ((real_offset <= address) && ((real_offset + reg->size) > address)) goto out; } /* register entry not found */ reg_entry = NULL;out: return reg_entry;}/* get BAR index */static int pt_bar_offset_to_index(uint32_t offset){ int index = 0; /* check Exp ROM BAR */ if (offset == PCI_ROM_ADDRESS) { index = PCI_ROM_SLOT; goto out; } /* calculate BAR index */ index = ((offset - PCI_BASE_ADDRESS_0) >> 2); if (index >= PCI_NUM_REGIONS) index = -1;out: return index;}static void pt_pci_write_config(PCIDevice *d, uint32_t address, uint32_t val, int len){ struct pt_dev *assigned_device = (struct pt_dev *)d; struct pci_dev *pci_dev = assigned_device->pci_dev; struct pt_reg_grp_tbl *reg_grp_entry = NULL; struct pt_reg_grp_info_tbl *reg_grp = NULL; struct pt_reg_tbl *reg_entry = NULL; struct pt_reg_info_tbl *reg = NULL; uint32_t find_addr = address; uint32_t real_offset = 0; uint32_t valid_mask = 0xFFFFFFFF; uint32_t read_val = 0; uint8_t *ptr_val = NULL; int emul_len = 0; int index = 0; int ret = 0;#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 /* check offset range */ if (address >= 0xFF) { PT_LOG("Failed to write register with offset exceeding FFh. " "[%02x:%02x.%x][Offset:%02xh][Length:%d]\n", pci_bus_num(d->bus), ((d->devfn >> 3) & 0x1F), (d->devfn & 0x7), address, len); goto exit; } /* check write size */ if ((len != 1) && (len != 2) && (len != 4)) { PT_LOG("Failed to write register with invalid access length. " "[%02x:%02x.%x][Offset:%02xh][Length:%d]\n", pci_bus_num(d->bus), ((d->devfn >> 3) & 0x1F), (d->devfn & 0x7), address, len); goto exit; } /* check offset alignment */ if (address & (len-1)) { PT_LOG("Failed to write register with invalid access size alignment. " "[%02x:%02x.%x][Offset:%02xh][Length:%d]\n", pci_bus_num(d->bus), ((d->devfn >> 3) & 0x1F), (d->devfn & 0x7), address, len); goto exit; } /* check unused BAR register */ index = pt_bar_offset_to_index(address); if ((index >= 0) && (val > 0 && val < PT_BAR_ALLF) && (assigned_device->bases[index].bar_flag == PT_BAR_FLAG_UNUSED)) { PT_LOG("Guest attempt to set address to unused Base Address Register. " "[%02x:%02x.%x][Offset:%02xh][Length:%d]\n", pci_bus_num(d->bus), ((d->devfn >> 3) & 0x1F), (d->devfn & 0x7), address, len); } /* find register group entry */ reg_grp_entry = pt_find_reg_grp(assigned_device, address); if (reg_grp_entry) { reg_grp = reg_grp_entry->reg_grp; /* check 0 Hardwired register group */ if (reg_grp->grp_type == GRP_TYPE_HARDWIRED) { /* ignore silently */ PT_LOG("Access to 0 Hardwired register. " "[%02x:%02x.%x][Offset:%02xh][Length:%d]\n", pci_bus_num(d->bus), ((d->devfn >> 3) & 0x1F), (d->devfn & 0x7), address, len); goto exit; } } /* read I/O device register value */ switch (len) { case 1: read_val = pci_read_byte(pci_dev, address); break; case 2: read_val = pci_read_word(pci_dev, address); break; case 4: read_val = pci_read_long(pci_dev, address); break; } /* check libpci result */ valid_mask = (0xFFFFFFFF >> ((4 - len) << 3)); if ((read_val & valid_mask) == valid_mask) { PT_LOG("Warning: Return ALL F from libpci read. " "[%02x:%02x.%x][Offset:%02xh][Length:%d]\n", pci_bus_num(d->bus), ((d->devfn >> 3) & 0x1F), (d->devfn & 0x7), address, len); } /* pass directly to libpci for passthrough type register group */ if (reg_grp_entry == NULL) goto out; /* adjust the read and write value to appropriate CFC-CFF window */ read_val <<= ((address & 3) << 3); val <<= ((address & 3) << 3); emul_len = len; /* loop Guest request size */ 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 write to byte register */ if (reg->u.b.write) ret = reg->u.b.write(assigned_device, reg_entry, (uint8_t *)ptr_val, (uint8_t)(read_val >> ((real_offset & 3) << 3)), (uint8_t)valid_mask); break; case 2: /* emulate write to word register */ if (reg->u.w.write) ret = reg->u.w.write(assigned_device, reg_entry, (uint16_t *)ptr_val, (uint16_t)(read_val >> ((real_offset & 3) << 3)), (uint16_t)valid_mask); break; case 4: /* emulate write to double word register */ if (reg->u.dw.write) ret = reg->u.dw.write(assigned_device, reg_entry, (uint32_t *)ptr_val, (uint32_t)(read_val >> ((real_offset & 3) << 3)), (uint32_t)valid_mask); break; } /* write emulation error */ if (ret < 0) { /* exit I/O emulator */ PT_LOG("Internal error: Invalid write 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 passing them to libpci */ val >>= ((address & 3) << 3);out: switch (len){ case 1: pci_write_byte(pci_dev, address, val); break; case 2: pci_write_word(pci_dev, address, val); break; case 4: pci_write_long(pci_dev, address, val); break; }exit: return;}static uint32_t pt_pci_read_config(PCIDevice *d, uint32_t address, int len){ struct pt_dev *assigned_device = (struct pt_dev *)d; struct pci_dev *pci_dev = assigned_device->pci_dev; uint32_t val = 0xFFFFFFFF; struct pt_reg_grp_tbl *reg_grp_entry = NULL; struct pt_reg_grp_info_tbl *reg_grp = NULL; struct pt_reg_tbl *reg_entry = NULL; struct pt_reg_info_tbl *reg = NULL; uint32_t find_addr = address; uint32_t real_offset = 0; uint32_t valid_mask = 0xFFFFFFFF; uint8_t *ptr_val = NULL; int emul_len = 0; int ret = 0; /* check offset range */ if (address >= 0xFF) { PT_LOG("Failed to read register with offset exceeding FFh. " "[%02x:%02x.%x][Offset:%02xh][Length:%d]\n", pci_bus_num(d->bus), ((d->devfn >> 3) & 0x1F), (d->devfn & 0x7), address, len); goto exit; } /* check read size */ if ((len != 1) && (len != 2) && (len != 4)) { PT_LOG("Failed to read register with invalid access length. " "[%02x:%02x.%x][Offset:%02xh][Length:%d]\n", pci_bus_num(d->bus), ((d->devfn >> 3) & 0x1F), (d->devfn & 0x7), address, len); goto exit; } /* check offset alignment */ if (address & (len-1)) { PT_LOG("Failed to read register with invalid access size alignment. " "[%02x:%02x.%x][Offset:%02xh][Length:%d]\n", pci_bus_num(d->bus), ((d->devfn >> 3) & 0x1F), (d->devfn & 0x7), address, len); goto exit; } /* find register group entry */ reg_grp_entry = pt_find_reg_grp(assigned_device, address); if (reg_grp_entry) { reg_grp = reg_grp_entry->reg_grp; /* check 0 Hardwired register group */ if (reg_grp->grp_type == GRP_TYPE_HARDWIRED) { /* no need to emulate, just return 0 */ val = 0; goto exit; } } /* read I/O device register value */ switch (len) { case 1: val = pci_read_byte(pci_dev, address); break; case 2: val = pci_read_word(pci_dev, address); break; case 4: val = pci_read_long(pci_dev, address); break; } /* check libpci result */ valid_mask = (0xFFFFFFFF >> ((4 - len) << 3)); if ((val & valid_mask) == valid_mask) { PT_LOG("Warning: Return ALL F from libpci read. " "[%02x:%02x.%x][Offset:%02xh][Length:%d]\n", pci_bus_num(d->bus), ((d->devfn >> 3) & 0x1F), (d->devfn & 0x7), address, len); } /* just return the I/O device register value for * passthrough type register group */ if (reg_grp_entry == NULL) goto exit; /* adjust the read value to appropriate CFC-CFF window */ val <<= ((address & 3) << 3); emul_len = len; /* loop Guest request size */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -