1# Copyright (C) 2021-2022 Intel Corporation. 2# 3# SPDX-License-Identifier: BSD-3-Clause 4# 5 6import ctypes 7import copy 8import inspectorlib.cdata as cdata 9 10class Common(cdata.Struct): 11 _pack_ = 1 12 _fields_ = [ 13 ('vendor_id', ctypes.c_uint16), 14 ('device_id', ctypes.c_uint16), 15 ('command', ctypes.c_uint16), 16 ('status', ctypes.c_uint16), 17 ('revision_id', ctypes.c_uint32, 8), 18 ('class_code', ctypes.c_uint32, 24), 19 ('cacheline_size', ctypes.c_uint8), 20 ('latency_timer', ctypes.c_uint8), 21 ('header_type', ctypes.c_uint8, 7), 22 ('multi_function', ctypes.c_uint8, 1), 23 ('bist', ctypes.c_uint8), 24 ] 25 26class MemoryBar32(cdata.Struct): 27 _pack_ = 1 28 _fields_ = [ 29 ('indicator', ctypes.c_uint8, 1), 30 ('type', ctypes.c_uint8, 2), 31 ('prefetchable', ctypes.c_uint8, 1), 32 ('base_z', ctypes.c_uint32, 28), 33 ] 34 35 resource_type = "memory" 36 37 @property 38 def base(self): 39 return self.base_z << 4 40 41class MemoryBar64(cdata.Struct): 42 _pack_ = 1 43 _fields_ = [ 44 ('indicator', ctypes.c_uint8, 1), 45 ('type', ctypes.c_uint8, 2), 46 ('prefetchable', ctypes.c_uint8, 1), 47 ('base_z', ctypes.c_uint64, 60), 48 ] 49 50 resource_type = "memory" 51 52 @property 53 def base(self): 54 return self.base_z << 4 55 56class IOBar(cdata.Struct): 57 _pack_ = 1 58 _fields_ = [ 59 ('indicator', ctypes.c_uint8, 1), 60 ('reserved', ctypes.c_uint8, 1), 61 ('base_z', ctypes.c_uint32, 30), 62 ] 63 64 resource_type = "io_port" 65 66 @property 67 def base(self): 68 return self.base_z << 2 69 70PCIE_BAR_SPACE_MASK = 0x1 71PCIE_BAR_MEMORY_SPACE = 0x0 72PCIE_BAR_IO_SPACE = 0x1 73 74PCIE_BAR_TYPE_MASK = 0x6 75PCIE_BAR_TYPE_32_BIT = 0x0 76PCIE_BAR_TYPE_64_BIT = 0x4 77 78def header_type_0_field_list(addr): 79 bar_list = list() 80 bar_addr = addr 81 bar_end = addr + 0x18 82 while bar_addr < bar_end: 83 bar = ctypes.c_uint32.from_address(bar_addr).value 84 idx = int((bar_addr - addr) / 4) 85 if (bar & PCIE_BAR_SPACE_MASK) == PCIE_BAR_MEMORY_SPACE: 86 if (bar & PCIE_BAR_TYPE_MASK) == PCIE_BAR_TYPE_64_BIT: 87 bar_list.append((f"bar{idx}", MemoryBar64)) 88 bar_addr += 0x8 89 else: 90 bar_list.append((f"bar{idx}", MemoryBar32)) 91 bar_addr += 0x4 92 else: 93 bar_list.append((f"bar{idx}", IOBar)) 94 bar_addr += 0x4 95 96 class Bars(cdata.Struct): 97 _pack_ = 1 98 _fields_ = bar_list 99 100 def __iter__(self): 101 for f in self._fields_: 102 yield getattr(self, f[0]) 103 104 return [ 105 ('bars', Bars), 106 ('cardbus_cis_pointer', ctypes.c_uint32), 107 ('subsystem_vendor_id', ctypes.c_uint16), 108 ('subsystem_device_id', ctypes.c_uint16), 109 ('expansion_rom_base_address', ctypes.c_uint32), 110 ('capability_pointer', ctypes.c_uint8), 111 ('reserved', ctypes.c_uint8 * 7), 112 ('interrupt_line', ctypes.c_uint8), 113 ('interrupt_pin', ctypes.c_uint8), 114 ('min_gnt', ctypes.c_uint8), 115 ('max_lat', ctypes.c_uint8), 116 ] 117 118def header_type_1_field_list(addr): 119 bar_list = list() 120 bar_addr = addr 121 bar_end = addr + 0x08 122 while bar_addr < bar_end: 123 bar = ctypes.c_uint32.from_address(addr).value 124 idx = int((bar_addr - addr) / 4) 125 if (bar & PCIE_BAR_SPACE_MASK) == PCIE_BAR_MEMORY_SPACE: 126 if (bar & PCIE_BAR_TYPE_MASK) == PCIE_BAR_TYPE_64_BIT: 127 bar_list.append((f"bar{idx}", MemoryBar64)) 128 bar_addr += 0x8 129 else: 130 bar_list.append((f"bar{idx}", MemoryBar32)) 131 bar_addr += 0x4 132 else: 133 bar_list.append((f"bar{idx}", IOBar)) 134 bar_addr += 0x4 135 136 class Bars(cdata.Struct): 137 _pack_ = 1 138 _fields_ = bar_list 139 140 def __iter__(self): 141 for f in self._fields_: 142 yield getattr(self, f[0]) 143 144 return [ 145 ('bars', Bars), 146 ('primary_bus_number', ctypes.c_uint8), 147 ('secondary_bus_number', ctypes.c_uint8), 148 ('subordinate_bus_number', ctypes.c_uint8), 149 ('secondary_latency_timer', ctypes.c_uint8), 150 ('io_base', ctypes.c_uint8), 151 ('io_limit', ctypes.c_uint8), 152 ('secondary_status', ctypes.c_uint16), 153 ('memory_base', ctypes.c_uint16), 154 ('memory_limit', ctypes.c_uint16), 155 ('prefetchable_memory_base', ctypes.c_uint16), 156 ('prefetchable_memory_limit', ctypes.c_uint16), 157 ('prefetchable_base_upper_32_bits', ctypes.c_uint32), 158 ('prefetchable_limit_upper_32_bits', ctypes.c_uint32), 159 ('io_base_upper_16_bits', ctypes.c_uint16), 160 ('io_limit_upper_16_bits', ctypes.c_uint16), 161 ('capability_pointer', ctypes.c_uint8), 162 ('reserved', ctypes.c_uint8 * 3), 163 ('expansion_rom_base_address', ctypes.c_uint32), 164 ('interrupt_line', ctypes.c_uint8), 165 ('interrupt_pin', ctypes.c_uint8), 166 ('bridge_control', ctypes.c_uint16), 167 ] 168 169def header_field_list(addr): 170 common_header = Common.from_address(addr) 171 if common_header.header_type == 0x00: 172 return header_type_0_field_list(addr + ctypes.sizeof(Common)) 173 elif common_header.header_type == 0x01: 174 return header_type_1_field_list(addr + ctypes.sizeof(Common)) 175 else: 176 return [('unparsed_data', ctypes.c_uint8 * 0x30)] 177 178def header_factory(field_list): 179 class Header(cdata.Struct): 180 _pack_ = 1 181 _fields_ = copy.copy(Common._fields_) + field_list 182 return Header 183 184def header(data): 185 """Create class based on decode of a PCI configuration space header from raw data.""" 186 buf = ctypes.create_string_buffer(data, len(data)) 187 addr = ctypes.addressof(buf) 188 field_list = header_field_list(addr) 189 return header_factory(field_list).from_buffer_copy(data) 190