📄 pci.py
字号:
#!/usr/bin/env python## PCI Device Information Class# - Helps obtain information about which I/O resources a PCI device needs## Author: Ryan Wilson <hap9@epoch.ncsc.mil>import sysimport os, os.pathimport resourceimport reimport typesimport structimport timePROC_MNT_PATH = '/proc/mounts'PROC_PCI_PATH = '/proc/bus/pci/devices'PROC_PCI_NUM_RESOURCES = 7SYSFS_PCI_DEVS_PATH = '/bus/pci/devices'SYSFS_PCI_DEV_RESOURCE_PATH = '/resource'SYSFS_PCI_DEV_CONFIG_PATH = '/config'SYSFS_PCI_DEV_IRQ_PATH = '/irq'SYSFS_PCI_DEV_DRIVER_DIR_PATH = '/driver'SYSFS_PCI_DEV_VENDOR_PATH = '/vendor'SYSFS_PCI_DEV_DEVICE_PATH = '/device'SYSFS_PCI_DEV_SUBVENDOR_PATH = '/subsystem_vendor'SYSFS_PCI_DEV_SUBDEVICE_PATH = '/subsystem_device'SYSFS_PCI_DEV_CLASS_PATH = '/class'SYSFS_PCIBACK_PATH = '/bus/pci/drivers/pciback/'LSPCI_CMD = 'lspci'PCI_DEV_REG_EXPRESS_STR = r"[0-9a-fA-F]{4}:[0-9a-fA-F]{2}:[0-9a-fA-F]{2}."+ \ r"[0-9a-fA-F]{1}"PCI_DEV_FORMAT_STR = '%04x:%02x:%02x.%01x'DEV_TYPE_PCIe_ENDPOINT = 0DEV_TYPE_PCIe_BRIDGE = 1DEV_TYPE_PCI_BRIDGE = 2DEV_TYPE_PCI = 3 PCI_STATUS = 0x6PCI_CLASS_DEVICE = 0x0aPCI_CLASS_BRIDGE_PCI = 0x0604PCI_HEADER_TYPE = 0x0ePCI_HEADER_TYPE_MASK = 0x7fPCI_HEADER_TYPE_NORMAL = 0PCI_HEADER_TYPE_BRIDGE = 1PCI_HEADER_TYPE_CARDBUS = 2PCI_CAPABILITY_LIST = 0x34PCI_CB_BRIDGE_CONTROL = 0x3ePCI_BRIDGE_CTL_BUS_RESET= 0x40PCI_CAP_ID_EXP = 0x10PCI_EXP_FLAGS = 0x2PCI_EXP_FLAGS_TYPE = 0x00f0PCI_EXP_TYPE_PCI_BRIDGE = 0x7PCI_EXP_DEVCAP = 0x4PCI_EXP_DEVCAP_FLR = (0x1 << 28)PCI_EXP_DEVCTL = 0x8PCI_EXP_DEVCTL_FLR = (0x1 << 15)PCI_CAP_ID_PM = 0x01PCI_PM_CTRL = 4PCI_PM_CTRL_NO_SOFT_RESET = 0x0004PCI_PM_CTRL_STATE_MASK = 0x0003PCI_D3hot = 3PCI_CAP_ID_AF = 0x13PCI_AF_CAPs = 0x3PCI_AF_CAPs_TP_FLR = 0x3PCI_AF_CTL = 0x4PCI_AF_CTL_FLR = 0x1PCI_BAR_0 = 0x10PCI_BAR_5 = 0x24PCI_BAR_SPACE = 0x01PCI_BAR_IO = 0x01PCI_BAR_IO_MASK = ~0x03PCI_BAR_MEM = 0x00PCI_BAR_MEM_MASK = ~0x0fPCI_STATUS_CAP_MASK = 0x10PCI_STATUS_OFFSET = 0x6PCI_CAP_OFFSET = 0x34MSIX_BIR_MASK = 0x7MSIX_SIZE_MASK = 0x7ff# Global variable to store information from lspcilspci_info = None# Global variable to store the sysfs mount pointsysfs_mnt_point = None#Calculate PAGE_SHIFT: number of bits to shift an address to get the page numberPAGE_SIZE = resource.getpagesize()PAGE_SHIFT = 0t = PAGE_SIZEwhile not (t&1): t>>=1 PAGE_SHIFT+=1PAGE_MASK=~(PAGE_SIZE - 1)# Definitions from Linux: include/linux/pci.hdef PCI_DEVFN(slot, func): return ((((slot) & 0x1f) << 3) | ((func) & 0x07))def parse_hex(val): try: if isinstance(val, types.StringTypes): return int(val, 16) else: return val except ValueError: return Nonedef parse_pci_name(pci_name_string): pci_match = re.match(r"((?P<domain>[0-9a-fA-F]{1,4})[:,])?" + \ r"(?P<bus>[0-9a-fA-F]{1,2})[:,]" + \ r"(?P<slot>[0-9a-fA-F]{1,2})[.,]" + \ r"(?P<func>[0-7])$", pci_name_string) if pci_match is None: raise PciDeviceParseError(('Failed to parse pci device name: %s' % pci_name_string)) pci_dev_info = pci_match.groupdict('0') domain = parse_hex(pci_dev_info['domain']) bus = parse_hex(pci_dev_info['bus']) slot = parse_hex(pci_dev_info['slot']) func = parse_hex(pci_dev_info['func']) return (domain, bus, slot, func) def find_sysfs_mnt(): global sysfs_mnt_point if not sysfs_mnt_point is None: return sysfs_mnt_point try: mounts_file = open(PROC_MNT_PATH,'r') for line in mounts_file: sline = line.split() if len(sline)<3: continue if sline[2]=='sysfs': sysfs_mnt_point= sline[1] return sysfs_mnt_point except IOError, (errno, strerr): raise PciDeviceParseError(('Failed to locate sysfs mount: %s: %s (%d)'% (PROC_PCI_PATH, strerr, errno))) return Nonedef get_all_pci_names(): sysfs_mnt = find_sysfs_mnt() pci_names = os.popen('ls ' + sysfs_mnt + SYSFS_PCI_DEVS_PATH).read().split() return pci_namesdef get_all_pci_devices(): pci_devs = [] for pci_name in get_all_pci_names(): pci_match = re.match(r"((?P<domain>[0-9a-fA-F]{1,4})[:,])?" + \ r"(?P<bus>[0-9a-fA-F]{1,2})[:,]" + \ r"(?P<slot>[0-9a-fA-F]{1,2})[.,]" + \ r"(?P<func>[0-7])$", pci_name) if pci_match is None: raise PciDeviceParseError(('Failed to parse pci device name: %s' % pci_name)) pci_dev_info = pci_match.groupdict('0') domain = parse_hex(pci_dev_info['domain']) bus = parse_hex(pci_dev_info['bus']) slot = parse_hex(pci_dev_info['slot']) func = parse_hex(pci_dev_info['func']) try: pci_dev = PciDevice(domain, bus, slot, func) except: continue pci_devs.append(pci_dev) return pci_devsdef create_lspci_info(): global lspci_info lspci_info = {} # Execute 'lspci' command and parse the result. # If the command does not exist, lspci_info will be kept blank ({}). for paragraph in os.popen(LSPCI_CMD + ' -vmm').read().split('\n\n'): device_name = None device_info = {} for line in paragraph.split('\n'): try: (opt, value) = line.split(':\t') if opt == 'Slot': device_name = PCI_DEV_FORMAT_STR % parse_pci_name(value) else: device_info[opt] = value except: pass if device_name is not None: lspci_info[device_name] = device_infodef save_pci_conf_space(devs_string): pci_list = [] cfg_list = [] sysfs_mnt = find_sysfs_mnt() for pci_str in devs_string: pci_path = sysfs_mnt + SYSFS_PCI_DEVS_PATH + '/' + pci_str + \ SYSFS_PCI_DEV_CONFIG_PATH fd = os.open(pci_path, os.O_RDONLY) configs = [] for i in range(0, 256, 4): configs = configs + [os.read(fd,4)] os.close(fd) pci_list = pci_list + [pci_path] cfg_list = cfg_list + [configs] return (pci_list, cfg_list)def restore_pci_conf_space(pci_cfg_list): pci_list = pci_cfg_list[0] cfg_list = pci_cfg_list[1] for i in range(0, len(pci_list)): pci_path = pci_list[i] configs = cfg_list[i] fd = os.open(pci_path, os.O_WRONLY) for dw in configs: os.write(fd, dw) os.close(fd) def find_all_devices_owned_by_pciback(): sysfs_mnt = find_sysfs_mnt() pciback_path = sysfs_mnt + SYSFS_PCIBACK_PATH pci_names = os.popen('ls ' + pciback_path).read() pci_list = re.findall(PCI_DEV_REG_EXPRESS_STR, pci_names) dev_list = [] for pci in pci_list: (dom, b, d, f) = parse_pci_name(pci) dev = PciDevice(dom, b, d, f) dev_list = dev_list + [dev] return dev_listdef transform_list(target, src): ''' src: its element is pci string (Format: xxxx:xx:xx:x). target: its element is pci string, or a list of pci string. If all the elements in src are in target, we remove them from target and add src into target; otherwise, we remove from target all the elements that also appear in src. ''' result = [] target_contains_src = True for e in src: if not e in target: target_contains_src = False break if target_contains_src: result = result + [src] for e in target: if not e in src: result = result + [e] return resultdef check_FLR_capability(dev_list): if len(dev_list) == 0: return [] pci_list = [] pci_dev_dict = {} for dev in dev_list: pci_list = pci_list + [dev.name] pci_dev_dict[dev.name] = dev while True: need_transform = False for pci in pci_list: if isinstance(pci, types.StringTypes): dev = pci_dev_dict[pci] if dev.bus == 0: continue if dev.dev_type == DEV_TYPE_PCIe_ENDPOINT and not dev.pcie_flr: coassigned_pci_list = dev.find_all_the_multi_functions() need_transform = True elif dev.dev_type == DEV_TYPE_PCI and not dev.pci_af_flr: coassigned_pci_list = dev.find_coassigned_devices(True) del coassigned_pci_list[0] need_transform = True if need_transform: pci_list = transform_list(pci_list, coassigned_pci_list) if not need_transform: break if len(pci_list) == 0: return [] for i in range(0, len(pci_list)): if isinstance(pci_list[i], types.StringTypes): pci_list[i] = [pci_list[i]] # Now every element in pci_list is a list of pci string. result = []
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -