📄 pci.py
字号:
else: self.dev_type = DEV_TYPE_PCIe_BRIDGE else: if pos != 0: self.dev_type = DEV_TYPE_PCIe_ENDPOINT else: self.dev_type = DEV_TYPE_PCI # Force 0000:00:00.0 to be DEV_TYPE_PCIe_BRIDGE if self.name == '0000:00:00.0': self.dev_type = DEV_TYPE_PCIe_BRIDGE if (self.dev_type == DEV_TYPE_PCI_BRIDGE) or \ (self.dev_type == DEV_TYPE_PCIe_BRIDGE): return # Try to findthe PCIe FLR capability if self.dev_type == DEV_TYPE_PCIe_ENDPOINT: dev_cap = self.pci_conf_read32(pos + PCI_EXP_DEVCAP) if dev_cap & PCI_EXP_DEVCAP_FLR: self.pcie_flr = True elif self.dev_type == DEV_TYPE_PCI: # Try to find the "PCI Advanced Capabilities" pos = self.find_cap_offset(PCI_CAP_ID_AF) if pos != 0: af_cap = self.pci_conf_read8(pos + PCI_AF_CAPs) if (af_cap & PCI_AF_CAPs_TP_FLR) == PCI_AF_CAPs_TP_FLR: self.pci_af_flr = True bar_addr = PCI_BAR_0 while bar_addr <= PCI_BAR_5: bar = self.pci_conf_read32(bar_addr) if (bar & PCI_BAR_SPACE) == PCI_BAR_MEM: bar = bar & PCI_BAR_MEM_MASK bar = bar & ~PAGE_MASK if bar != 0: self.has_non_page_aligned_bar = True break bar_addr = bar_addr + 4 def devs_check_driver(self, devs): if len(devs) == 0: return for pci_dev in devs: (dom, b, d, f) = parse_pci_name(pci_dev) dev = PciDevice(dom, b, d, f) if dev.driver == 'pciback': continue err_msg = 'pci: %s must be co-assigned to the same guest with %s' + \ ', but it is not owned by pciback.' raise PciDeviceAssignmentError(err_msg % (pci_dev, self.name)) def do_FLR(self): """ Perform FLR (Functional Level Reset) for the device. """ if self.dev_type == DEV_TYPE_PCIe_ENDPOINT: # If PCIe device supports FLR, we use it. if self.pcie_flr: (pci_list, cfg_list) = save_pci_conf_space([self.name]) pos = self.find_cap_offset(PCI_CAP_ID_EXP) self.pci_conf_write32(pos + PCI_EXP_DEVCTL, PCI_EXP_DEVCTL_FLR) # We must sleep at least 100ms for the completion of FLR time.sleep(0.200) restore_pci_conf_space((pci_list, cfg_list)) else: if self.bus == 0: self.do_Dstate_transition() else: funcs = self.find_all_the_multi_functions() self.devs_check_driver(funcs) parent = '%04x:%02x:%02x.%01x' % self.find_parent() # Do Secondary Bus Reset. self.do_secondary_bus_reset(parent, funcs) # PCI devices else: # For PCI device on host bus, we test "PCI Advanced Capabilities". if self.bus == 0 and self.pci_af_flr: (pci_list, cfg_list) = save_pci_conf_space([self.name]) # We use Advanced Capability to do FLR. pos = self.find_cap_offset(PCI_CAP_ID_AF) self.pci_conf_write8(pos + PCI_AF_CTL, PCI_AF_CTL_FLR) time.sleep(0.200) restore_pci_conf_space((pci_list, cfg_list)) else: if self.bus == 0: self.do_Dstate_transition() else: devs = self.find_coassigned_devices(False) # Remove the element 0 which is a bridge target_bus = devs[0] del devs[0] self.devs_check_driver(devs) # Do Secondary Bus Reset. self.do_secondary_bus_reset(target_bus, devs) def find_capability(self, type): sysfs_mnt = find_sysfs_mnt() if sysfs_mnt == None: return False path = sysfs_mnt+SYSFS_PCI_DEVS_PATH+'/'+ \ self.name+SYSFS_PCI_DEV_CONFIG_PATH try: conf_file = open(path, 'rb') conf_file.seek(PCI_HEADER_TYPE) header_type = ord(conf_file.read(1)) & PCI_HEADER_TYPE_MASK if header_type == PCI_HEADER_TYPE_CARDBUS: return conf_file.seek(PCI_STATUS_OFFSET) status = ord(conf_file.read(1)) if status&PCI_STATUS_CAP_MASK: conf_file.seek(PCI_CAP_OFFSET) capa_pointer = ord(conf_file.read(1)) capa_count = 0 while capa_pointer: if capa_pointer < 0x40: raise PciDeviceParseError( ('Broken capability chain: %s' % self.name)) capa_count += 1 if capa_count > 96: raise PciDeviceParseError( ('Looped capability chain: %s' % self.name)) conf_file.seek(capa_pointer) capa_id = ord(conf_file.read(1)) capa_pointer = ord(conf_file.read(1)) if capa_id == type: # get the type message_cont_lo = ord(conf_file.read(1)) message_cont_hi = ord(conf_file.read(1)) self.msix=1 self.msix_entries = (message_cont_lo + \ (message_cont_hi << 8)) \ & MSIX_SIZE_MASK t_off=conf_file.read(4) p_off=conf_file.read(4) self.table_offset=ord(t_off[0]) | (ord(t_off[1])<<8) | \ (ord(t_off[2])<<16)| \ (ord(t_off[3])<<24) self.pba_offset=ord(p_off[0]) | (ord(p_off[1]) << 8)| \ (ord(p_off[2])<<16) | \ (ord(p_off[3])<<24) self.table_index = self.table_offset & MSIX_BIR_MASK self.table_offset = self.table_offset & ~MSIX_BIR_MASK self.pba_index = self.pba_offset & MSIX_BIR_MASK self.pba_offset = self.pba_offset & ~MSIX_BIR_MASK break except IOError, (errno, strerr): raise PciDeviceParseError(('Failed to locate sysfs mount: %s: %s (%d)' % (PROC_PCI_PATH, strerr, errno))) def remove_msix_iomem(self, index, start, size): if (index == self.table_index): table_start = start+self.table_offset table_end = table_start + self.msix_entries * 16 table_start = table_start & PAGE_MASK table_end = (table_end + PAGE_SIZE) & PAGE_MASK self.msix_iomem.append((table_start, table_end-table_start)) if (index==self.pba_index): pba_start = start + self.pba_offset pba_end = pba_start + self.msix_entries/8 pba_start = pba_start & PAGE_MASK pba_end = (pba_end + PAGE_SIZE) & PAGE_MASK self.msix_iomem.append((pba_start, pba_end-pba_start)) def get_info_from_sysfs(self): self.find_capability(0x11) sysfs_mnt = find_sysfs_mnt() if sysfs_mnt == None: return False path = sysfs_mnt+SYSFS_PCI_DEVS_PATH+'/'+ \ self.name+SYSFS_PCI_DEV_RESOURCE_PATH try: resource_file = open(path,'r') for i in range(PROC_PCI_NUM_RESOURCES): line = resource_file.readline() sline = line.split() if len(sline)<3: continue start = int(sline[0],16) end = int(sline[1],16) flags = int(sline[2],16) size = end-start+1 if start!=0: if flags&PCI_BAR_IO: self.ioports.append( (start,size) ) else: self.iomem.append( (start,size) ) if (self.msix): self.remove_msix_iomem(i, start, size) except IOError, (errno, strerr): raise PciDeviceParseError(('Failed to open & read %s: %s (%d)' % (path, strerr, errno))) path = sysfs_mnt+SYSFS_PCI_DEVS_PATH+'/'+ \ self.name+SYSFS_PCI_DEV_IRQ_PATH try: self.irq = int(open(path,'r').readline()) except IOError, (errno, strerr): raise PciDeviceParseError(('Failed to open & read %s: %s (%d)' % (path, strerr, errno))) path = sysfs_mnt+SYSFS_PCI_DEVS_PATH+'/'+ \ self.name+SYSFS_PCI_DEV_DRIVER_DIR_PATH try: self.driver = os.path.basename(os.readlink(path)) except OSError, (errno, strerr): self.driver = "" path = sysfs_mnt+SYSFS_PCI_DEVS_PATH+'/'+ \ self.name+SYSFS_PCI_DEV_VENDOR_PATH try: self.vendor = int(open(path,'r').readline(), 16) except IOError, (errno, strerr): raise PciDeviceParseError(('Failed to open & read %s: %s (%d)' % (path, strerr, errno))) path = sysfs_mnt+SYSFS_PCI_DEVS_PATH+'/'+ \ self.name+SYSFS_PCI_DEV_DEVICE_PATH try: self.device = int(open(path,'r').readline(), 16) except IOError, (errno, strerr): raise PciDeviceParseError(('Failed to open & read %s: %s (%d)' % (path, strerr, errno))) path = sysfs_mnt+SYSFS_PCI_DEVS_PATH+'/'+ \ self.name+SYSFS_PCI_DEV_SUBVENDOR_PATH try: self.subvendor = int(open(path,'r').readline(), 16) except IOError, (errno, strerr): raise PciDeviceParseError(('Failed to open & read %s: %s (%d)' % (path, strerr, errno))) path = sysfs_mnt+SYSFS_PCI_DEVS_PATH+'/'+ \ self.name+SYSFS_PCI_DEV_SUBDEVICE_PATH try: self.subdevice = int(open(path,'r').readline(), 16) except IOError, (errno, strerr): raise PciDeviceParseError(('Failed to open & read %s: %s (%d)' % (path, strerr, errno))) path = sysfs_mnt+SYSFS_PCI_DEVS_PATH+'/'+ \ self.name+SYSFS_PCI_DEV_CLASS_PATH try: self.classcode = int(open(path,'r').readline(), 16) except IOError, (errno, strerr): raise PciDeviceParseError(('Failed to open & read %s: %s (%d)' % (path, strerr, errno))) return True def get_info_from_lspci(self): """ Get information such as vendor name, device name, class name, etc. Since we cannot obtain these data from sysfs, use 'lspci' command. """ global lspci_info if lspci_info is None: create_lspci_info() try: device_info = lspci_info[self.name] self.revision = int(device_info['Rev'], 16) self.vendorname = device_info['Vendor'] self.devicename = device_info['Device'] self.classname = device_info['Class'] self.subvendorname = device_info['SVendor'] self.subdevicename = device_info['SDevice'] except KeyError: pass return True def __str__(self): str = "PCI Device %s\n" % (self.name) for (start,size) in self.ioports: str = str + "IO Port 0x%02x [size=%d]\n"%(start,size) for (start,size) in self.iomem: str = str + "IO Mem 0x%02x [size=%d]\n"%(start,size) str = str + "IRQ %d\n"%(self.irq) str = str + "Vendor ID 0x%04x\n"%(self.vendor) str = str + "Device ID 0x%04x\n"%(self.device) str = str + "Sybsystem Vendor ID 0x%04x\n"%(self.subvendor) str = str + "Subsystem Device ID 0x%04x"%(self.subdevice) return strdef main(): if len(sys.argv)<5: print "Usage: %s <domain> <bus> <slot> <func>\n" % sys.argv[0] sys.exit(2) dev = PciDevice(int(sys.argv[1],16), int(sys.argv[2],16), int(sys.argv[3],16), int(sys.argv[4],16)) print str(dev)if __name__=='__main__': main()
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -