📄 pass-through.c
字号:
} reg_grp_offset = 0; }out: return err;}/* delete all emulate register */static void pt_config_delete(struct pt_dev *ptdev){ struct pt_reg_grp_tbl *reg_grp_entry = NULL; struct pt_reg_tbl *reg_entry = NULL; /* free MSI/MSI-X info table */ if (ptdev->msix) pt_msix_delete(ptdev); if (ptdev->msi) free(ptdev->msi); /* free all register group entry */ while ((reg_grp_entry = ptdev->reg_grp_tbl_head.lh_first) != NULL) { /* free all register entry */ while ((reg_entry = reg_grp_entry->reg_tbl_head.lh_first) != NULL) { LIST_REMOVE(reg_entry, entries); qemu_free(reg_entry); } LIST_REMOVE(reg_grp_entry, entries); qemu_free(reg_grp_entry); }}/* initialize common register value */static uint32_t pt_common_reg_init(struct pt_dev *ptdev, struct pt_reg_info_tbl *reg, uint32_t real_offset){ return reg->init_val;}/* initialize Capabilities Pointer or Next Pointer register */static uint32_t pt_ptr_reg_init(struct pt_dev *ptdev, struct pt_reg_info_tbl *reg, uint32_t real_offset){ uint32_t reg_field = (uint32_t)ptdev->dev.config[real_offset]; int i; /* find capability offset */ while (reg_field) { for (i=0; pt_emu_reg_grp_tbl[i].grp_size != 0; i++) { /* check whether the next capability * should be exported to guest or not */ if (pt_emu_reg_grp_tbl[i].grp_id == ptdev->dev.config[reg_field]) { if (pt_emu_reg_grp_tbl[i].grp_type == GRP_TYPE_EMU) goto out; /* ignore the 0 hardwired capability, find next one */ break; } } /* next capability */ reg_field = (uint32_t)ptdev->dev.config[reg_field + 1]; }out: return reg_field;}/* initialize Status register */static uint32_t pt_status_reg_init(struct pt_dev *ptdev, struct pt_reg_info_tbl *reg, uint32_t real_offset){ struct pt_reg_grp_tbl *reg_grp_entry = NULL; struct pt_reg_tbl *reg_entry = NULL; int reg_field = 0; /* find Header register group */ reg_grp_entry = pt_find_reg_grp(ptdev, PCI_CAPABILITY_LIST); if (reg_grp_entry) { /* find Capabilities Pointer register */ reg_entry = pt_find_reg(reg_grp_entry, PCI_CAPABILITY_LIST); if (reg_entry) { /* check Capabilities Pointer register */ if (reg_entry->data) reg_field |= PCI_STATUS_CAP_LIST; else reg_field &= ~PCI_STATUS_CAP_LIST; } else { /* exit I/O emulator */ PT_LOG("Internal error: Couldn't find pt_reg_tbl for " "Capabilities Pointer register. I/O emulator exit.\n"); exit(1); } } else { /* exit I/O emulator */ PT_LOG("Internal error: Couldn't find pt_reg_grp_tbl for Header. " "I/O emulator exit.\n"); exit(1); } return reg_field;}/* initialize Interrupt Pin register */static uint32_t pt_irqpin_reg_init(struct pt_dev *ptdev, struct pt_reg_info_tbl *reg, uint32_t real_offset){ int reg_field = 0; /* set Interrupt Pin register to use INTA# if it has */ if (ptdev->dev.config[real_offset]) reg_field = 0x01; return reg_field;}/* initialize BAR */static uint32_t pt_bar_reg_init(struct pt_dev *ptdev, struct pt_reg_info_tbl *reg, uint32_t real_offset){ int reg_field = 0; int index; /* get BAR index */ index = pt_bar_offset_to_index(reg->offset); if (index < 0) { /* exit I/O emulator */ PT_LOG("Internal error: Invalid BAR index[%d]. " "I/O emulator exit.\n", index); exit(1); } /* set initial guest physical base address to -1 */ ptdev->bases[index].e_physbase = -1; /* set BAR flag */ ptdev->bases[index].bar_flag = pt_bar_reg_parse(ptdev, reg); if (ptdev->bases[index].bar_flag == PT_BAR_FLAG_UNUSED) reg_field = PT_INVALID_REG; return reg_field;}/* initialize Link Control 2 register */static uint32_t pt_linkctrl2_reg_init(struct pt_dev *ptdev, struct pt_reg_info_tbl *reg, uint32_t real_offset){ int reg_field = 0; /* set Supported Link Speed */ reg_field |= (0x0F & ptdev->dev.config[(real_offset - reg->offset) + PCI_EXP_LNKCAP]); return reg_field;}/* initialize Message Control register */static uint32_t pt_msgctrl_reg_init(struct pt_dev *ptdev, struct pt_reg_info_tbl *reg, uint32_t real_offset){ PCIDevice *d = (struct PCIDevice *)ptdev; struct pci_dev *pdev = ptdev->pci_dev; uint32_t reg_field = 0; /* use I/O device register's value as initial value */ reg_field |= *((uint16_t*)(d->config + real_offset)); if (reg_field & PCI_MSI_FLAGS_ENABLE) { PT_LOG("MSI enabled already, disable first\n"); pci_write_word(pdev, real_offset, reg_field & ~PCI_MSI_FLAGS_ENABLE); } ptdev->msi->flags |= (reg_field | MSI_FLAG_UNINIT); /* All register is 0 after reset, except first 4 byte */ reg_field &= reg->ro_mask; return reg_field;}/* initialize Message Address register */static uint32_t pt_msgaddr32_reg_init(struct pt_dev *ptdev, struct pt_reg_info_tbl *reg, uint32_t real_offset){ PCIDevice *d = (struct PCIDevice *)ptdev; uint32_t reg_field = 0; /* use I/O device register's value as initial value */ reg_field |= *((uint32_t*)(d->config + real_offset)); return reg_field;}/* initialize Message Upper Address register */static uint32_t pt_msgaddr64_reg_init(struct pt_dev *ptdev, struct pt_reg_info_tbl *reg, uint32_t real_offset){ PCIDevice *d = (struct PCIDevice *)ptdev; uint32_t reg_field = 0; /* no need to initialize in case of 32 bit type */ if (!(ptdev->msi->flags & PCI_MSI_FLAGS_64BIT)) return PT_INVALID_REG; /* use I/O device register's value as initial value */ reg_field |= *((uint32_t*)(d->config + real_offset)); return reg_field;}/* this function will be called twice (for 32 bit and 64 bit type) *//* initialize Message Data register */static uint32_t pt_msgdata_reg_init(struct pt_dev *ptdev, struct pt_reg_info_tbl *reg, uint32_t real_offset){ PCIDevice *d = (struct PCIDevice *)ptdev; uint32_t flags = ptdev->msi->flags; uint32_t offset = reg->offset; /* check the offset whether matches the type or not */ if (((offset == PCI_MSI_DATA_64) && (flags & PCI_MSI_FLAGS_64BIT)) || ((offset == PCI_MSI_DATA_32) && !(flags & PCI_MSI_FLAGS_64BIT))) return *((uint16_t*)(d->config + real_offset)); else return PT_INVALID_REG;}/* initialize Message Control register for MSI-X */static uint32_t pt_msixctrl_reg_init(struct pt_dev *ptdev, struct pt_reg_info_tbl *reg, uint32_t real_offset){ PCIDevice *d = (struct PCIDevice *)ptdev; struct pci_dev *pdev = ptdev->pci_dev; uint16_t reg_field = 0; /* use I/O device register's value as initial value */ reg_field |= *((uint16_t*)(d->config + real_offset)); if (reg_field & PCI_MSIX_ENABLE) { PT_LOG("MSIX enabled already, disable first\n"); pci_write_word(pdev, real_offset, reg_field & ~PCI_MSIX_ENABLE); reg_field &= ~(PCI_MSIX_ENABLE | PCI_MSIX_MASK); } return reg_field;}/* get register group size */static uint8_t pt_reg_grp_size_init(struct pt_dev *ptdev, struct pt_reg_grp_info_tbl *grp_reg, uint32_t base_offset){ return grp_reg->grp_size;}/* get MSI Capability Structure register group size */static uint8_t pt_msi_size_init(struct pt_dev *ptdev, struct pt_reg_grp_info_tbl *grp_reg, uint32_t base_offset){ PCIDevice *d = &ptdev->dev; uint16_t msg_ctrl = 0; uint8_t msi_size = 0xa; msg_ctrl = *((uint16_t*)(d->config + (base_offset + PCI_MSI_FLAGS))); /* check 64 bit address capable & Per-vector masking capable */ if (msg_ctrl & PCI_MSI_FLAGS_64BIT) msi_size += 4; if (msg_ctrl & PCI_MSI_FLAGS_MASK_BIT) msi_size += 10; ptdev->msi = malloc(sizeof(struct pt_msi_info)); if ( !ptdev->msi ) { /* exit I/O emulator */ PT_LOG("error allocation pt_msi_info. I/O emulator exit.\n"); exit(1); } memset(ptdev->msi, 0, sizeof(struct pt_msi_info)); return msi_size;}/* get MSI-X Capability Structure register group size */static uint8_t pt_msix_size_init(struct pt_dev *ptdev, struct pt_reg_grp_info_tbl *grp_reg, uint32_t base_offset){ int ret = 0; ret = pt_msix_init(ptdev, base_offset); if (ret == -1) { /* exit I/O emulator */ PT_LOG("Internal error: Invalid pt_msix_init return value[%d]. " "I/O emulator exit.\n", ret); exit(1); } return grp_reg->grp_size;}/* get Vendor Specific Capability Structure register group size */static uint8_t pt_vendor_size_init(struct pt_dev *ptdev, struct pt_reg_grp_info_tbl *grp_reg, uint32_t base_offset){ return ptdev->dev.config[base_offset + 0x02];}/* read byte size emulate register */static int pt_byte_reg_read(struct pt_dev *ptdev, struct pt_reg_tbl *cfg_entry, uint8_t *value, uint8_t valid_mask){ struct pt_reg_info_tbl *reg = cfg_entry->reg; uint8_t valid_emu_mask = 0; /* emulate byte register */ valid_emu_mask = reg->emu_mask & valid_mask; *value = ((*value & ~valid_emu_mask) | (cfg_entry->data & valid_emu_mask)); return 0;}/* read word size emulate register */static int pt_word_reg_read(struct pt_dev *ptdev, struct pt_reg_tbl *cfg_entry, uint16_t *value, uint16_t valid_mask){ struct pt_reg_info_tbl *reg = cfg_entry->reg; uint16_t valid_emu_mask = 0; /* emulate word register */ valid_emu_mask = reg->emu_mask & valid_mask; *value = ((*value & ~valid_emu_mask) | (cfg_entry->data & valid_emu_mask)); return 0;}/* read long size emulate register */static int pt_long_reg_read(struct pt_dev *ptdev, struct pt_reg_tbl *cfg_entry, uint32_t *value, uint32_t valid_mask){ struct pt_reg_info_tbl *reg = cfg_entry->reg; uint32_t valid_emu_mask = 0; /* emulate long register */ valid_emu_mask = reg->emu_mask & valid_mask; *value = ((*value & ~valid_emu_mask) | (cfg_entry->data & valid_emu_mask)); return 0;}/* read BAR */static int pt_bar_reg_read(struct pt_dev *ptdev, struct pt_reg_tbl *cfg_entry, uint32_t *value, uint32_t valid_mask){ struct pt_reg_info_tbl *reg = cfg_entry->reg; uint32_t valid_emu_mask = 0; uint32_t bar_emu_mask = 0; int index; /* get BAR index */ index = pt_bar_offset_to_index(reg->offset); if (index < 0) { /* exit I/O emulator */ PT_LOG("Internal error: Invalid BAR index[%d]. " "I/O emulator exit.\n", index); exit(1); } /* set emulate mask depend on BAR flag */ switch (ptdev->bases[index].bar_flag) { case PT_BAR_FLAG_MEM: bar_emu_mask = PT_BAR_MEM_EMU_MASK; break; case PT_BAR_FLAG_IO: bar_emu_mask = PT_BAR_IO_EMU_MASK; break; case PT_BAR_FLAG_UPPER: bar_emu_mask = PT_BAR_ALLF; break; default: break; } /* emulate BAR */ valid_emu_mask = bar_emu_mask & valid_mask; *value = ((*value & ~valid_emu_mask) | (cfg_entry->data & valid_emu_mask)); return 0;}/* write byte size emulate register */static int pt_byte_reg_write(struct pt_dev *ptdev, struct pt_reg_tbl *cfg_entry, uint8_t *value, uint8_t dev_value, uint8_t valid_mask){ struct pt_reg_info_tbl *reg = cfg_entry->reg; uint8_t writable_mask = 0; uint8_t throughable_mask = 0; /* modify emulate register */ writable_mask = reg->emu_mask & ~reg->ro_mask & valid_mask; cfg_entry->data = ((*val
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -