1from __future__ import absolute_import, print_function 2 3from builtins import range 4 5from xnu import * 6 7###################################### 8# Helper functions 9###################################### 10def GetMemMappedPciCfgAddrFromRegistry(): 11 """ Retrieve the base address of the memory mapped PCI config space. It is 12 found in registry entry AppleACPIPlatformExpert, property acpi-mmcfg-seg0. 13 Returns: 14 int base address of memory mapped PCI config space 15 """ 16 kgm_pci_cfg_base_default = 0xe0000000 17 acpi_pe_obj = FindRegistryObjectRecurse(kern.globals.gRegistryRoot, 18 "AppleACPIPlatformExpert") 19 if acpi_pe_obj is None: 20 print("Could not find AppleACPIPlatformExpert in registry, \ 21 using default base address for memory mapped PCI config space") 22 return kgm_pci_cfg_base_default 23 entry = kern.GetValueFromAddress(int(acpi_pe_obj), 'IOService *') 24 acpi_mmcfg_seg_prop = LookupKeyInPropTable(entry.fPropertyTable, "acpi-mmcfg-seg0") 25 if acpi_mmcfg_seg_prop is None: 26 print("Could not find acpi-mmcfg-seg0 property, \ 27 using default base address for memory mapped PCI config space") 28 return kgm_pci_cfg_base_default 29 else: 30 return int(GetNumber(acpi_mmcfg_seg_prop)) 31 32@static_var('kgm_pci_cfg_base', -1) 33def GetMemMappedPciCfgAddrBase(): 34 """ Returns the base address of the memory mapped PCI config space. The address 35 is retrieved once from the registry, and is remembered for all subsequent 36 calls to this function 37 Returns: 38 int base address of memory mapped PCI config space 39 """ 40 if GetMemMappedPciCfgAddrBase.kgm_pci_cfg_base == -1: 41 # Retrieve the base address from the registry if it hasn't been 42 # initialized yet 43 GetMemMappedPciCfgAddrBase.kgm_pci_cfg_base = GetMemMappedPciCfgAddrFromRegistry() 44 return GetMemMappedPciCfgAddrBase.kgm_pci_cfg_base 45 46def MakeMemMappedPciCfgAddr(bus, dev, func, offs): 47 """ Construct the memory address for the PCI config register specified by the 48 bus, device, function, and offset 49 Params: 50 bus, dev, func, offs: int - bus, device, function, and offset that specifies 51 the PCI config space register 52 Returns: 53 int - the physical memory address that maps to the PCI config space register 54 """ 55 return GetMemMappedPciCfgAddrBase() | (bus << 20) | (dev << 15) | (func << 12) | offs 56 57def DoPciCfgRead(bits, bus, dev, func, offs): 58 """ Helper function that performs PCI config space read 59 Params: 60 bits: int - bit width of access: 8, 16, or 32 bits 61 bus, dev, func, offs: int - PCI config bus, device, function and offset 62 Returns: 63 int - the value read from PCI config space 64 """ 65 phys_addr = MakeMemMappedPciCfgAddr(bus, dev, func, offs) 66 return ReadPhysInt(phys_addr, bits) 67 68def DoPciCfgWrite(bits, bus, dev, func, offs, val): 69 """ Helper function that performs PCI config space write 70 Params: 71 bits: int - bit width of access: 8, 16, or 32 bits 72 bus, dev, func, offs: int - PCI config bus, device, function and offset 73 Returns: 74 boolean - True upon success, False otherwise 75 """ 76 phys_addr = MakeMemMappedPciCfgAddr(bus, dev, func, offs) 77 return WritePhysInt(phys_addr, val, bits) 78 79def ShowPciCfgBytes(bus, dev, func, offset): 80 """ Prints 16 bytes of PCI config space starting at specified offset 81 Params: 82 bus, dev, func, offset: int - bus, dev, function, and offset of the 83 PCI config space register 84 """ 85 # Print mem-mapped address at beginning of each 16-byte line 86 phys_addr = MakeMemMappedPciCfgAddr(bus, dev, func, offset) 87 read_vals = [DoPciCfgRead(32, bus, dev, func, offset + byte) 88 for byte in range(0, 16, 4)] 89 # It would be nicer to have a shorter format that we could loop 90 # over, but each call to print results in a newline which 91 # would prevent us from printing all 16 bytes on one line. 92 bytes_fmt = "{:08x}:" + "{:02x} " * 16 93 print(bytes_fmt.format( 94 phys_addr, 95 read_vals[0] & 0xff, (read_vals[0] >> 8) & 0xff, 96 (read_vals[0] >> 16) & 0xff, (read_vals[0] >> 24) & 0xff, 97 read_vals[1] & 0xff, (read_vals[1] >> 8) & 0xff, 98 (read_vals[1] >> 16) & 0xff, (read_vals[1] >> 24) & 0xff, 99 read_vals[2] & 0xff, (read_vals[2] >> 8) & 0xff, 100 (read_vals[2] >> 16) & 0xff, (read_vals[2] >> 24) & 0xff, 101 read_vals[3] & 0xff, (read_vals[3] >> 8) & 0xff, 102 (read_vals[3] >> 16) & 0xff, (read_vals[3] >> 24) & 0xff)) 103 104def DoPciCfgDump(bus, dev, func): 105 """ Dumps PCI config space of the PCI device specified by bus, dev, function 106 Params: 107 bus, dev, func: int - bus, dev, function of PCI config space to dump 108 """ 109 # Check for a valid PCI device 110 vendor_id = DoPciCfgRead(16, bus, dev, func, 0) 111 if (vendor_id == 0xbad10ad) or not (vendor_id > 0 and vendor_id < 0xffff): 112 return 113 # Show the standard PCI config space 114 print("address: 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F\n") 115 print("--------------------------------------------------------") 116 for offset in range(0, 256, 16): 117 ShowPciCfgBytes(bus, dev, func, offset) 118 # Check for PCIE extended capability config space 119 if DoPciCfgRead(8, bus, dev, func, 256) < 0xff: 120 print(" \n") 121 for offset in range(256, 4096, 16): 122 ShowPciCfgBytes(bus, dev, func, offset) 123 124def DoPciCfgScan(max_bus, dump): 125 """ Do a PCI config scan starting at bus 0 up to specified max bus 126 Params: 127 max_bus: int - maximum bus to scan 128 dump: bool - if True, dump the config space of each scanned device 129 if False, print basic information of each scanned device 130 """ 131 max_dev = 32 132 max_func = 8 133 bdfs = ({'bus':bus, 'dev':dev, 'func':func} 134 for bus in range(max_bus) 135 for dev in range(max_dev) 136 for func in range(max_func)) 137 fmt_string = "{:03x}:" * 3 + " " + \ 138 "{:02x}" * 2 + " " + \ 139 "{:02x}" * 2 + " {:02x} | " + \ 140 "{:02x}" * 3 141 for bdf in bdfs: 142 bus = bdf['bus'] 143 dev = bdf['dev'] 144 func = bdf['func'] 145 vend_dev_id = DoPciCfgRead(32, bus, dev, func, 0) 146 if not (vend_dev_id > 0 and vend_dev_id < 0xffffffff): 147 continue 148 if not dump: 149 class_rev_id = DoPciCfgRead(32, bus, dev, func, 8) 150 print(fmt_string.format( 151 bus, dev, func, 152 (vend_dev_id >> 8) & 0xff, vend_dev_id & 0xff, 153 (vend_dev_id >> 24) & 0xff, (vend_dev_id >> 16) & 0xff, 154 class_rev_id & 0xff, (class_rev_id >> 24) & 0xff, 155 (class_rev_id >> 16) & 0xff, (class_rev_id >> 8) & 0xff)) 156 else: 157 print("{:03x}:{:03x}:{:03x}".format(bus, dev, func)) 158 DoPciCfgDump(bus, dev, func) 159 160###################################### 161# LLDB commands 162###################################### 163@lldb_command('pci_cfg_read') 164def PciCfgRead(cmd_args=None): 165 """ Read PCI config space at the specified bus, device, function, and offset 166 Syntax: pci_cfg_read <bits> <bus> <device> <function> <offset> 167 bits: 8, 16, 32 168 """ 169 if cmd_args is None or len(cmd_args) < 5: 170 print(PciCfgRead.__doc__) 171 return 172 173 bits = ArgumentStringToInt(cmd_args[0]) 174 bus = ArgumentStringToInt(cmd_args[1]) 175 dev = ArgumentStringToInt(cmd_args[2]) 176 func = ArgumentStringToInt(cmd_args[3]) 177 offs = ArgumentStringToInt(cmd_args[4]) 178 179 read_val = DoPciCfgRead(bits, bus, dev, func, offs) 180 if read_val == 0xbad10ad: 181 print("ERROR: Failed to read PCI config space") 182 return 183 184 format_for_bits = {8:"{:#04x}", 16:"{:#06x}", 32:"{:#010x}"} 185 phys_addr = MakeMemMappedPciCfgAddr(bus, dev, func, offs) 186 fmt_string = "{:08x}: " + format_for_bits[bits] 187 print(fmt_string.format(phys_addr, read_val)) 188 189lldb_alias('pci_cfg_read8', 'pci_cfg_read 8') 190lldb_alias('pci_cfg_read16', 'pci_cfg_read 16') 191lldb_alias('pci_cfg_read32', 'pci_cfg_read 32') 192 193@lldb_command('pci_cfg_write') 194def PciCfgWrite(cmd_args=None): 195 """ Write PCI config space at the specified bus, device, function, and offset 196 Syntax: pci_cfg_write <bits> <bus> <device> <function> <offset> <write val> 197 bits: 8, 16, 32 198 199 Prints an error message if there was a problem 200 Prints nothing upon success. 201 """ 202 if cmd_args is None or len(cmd_args) < 6: 203 print(PciCfgWrite.__doc__) 204 return 205 206 bits = ArgumentStringToInt(cmd_args[0]) 207 bus = ArgumentStringToInt(cmd_args[1]) 208 dev = ArgumentStringToInt(cmd_args[2]) 209 func = ArgumentStringToInt(cmd_args[3]) 210 offs = ArgumentStringToInt(cmd_args[4]) 211 write_val = ArgumentStringToInt(cmd_args[5]) 212 213 if not DoPciCfgWrite(bits, bus, dev, func, offs, write_val): 214 print("ERROR: Failed to write PCI config space") 215 216lldb_alias('pci_cfg_write8', 'pci_cfg_write 8') 217lldb_alias('pci_cfg_write16', 'pci_cfg_write 16') 218lldb_alias('pci_cfg_write32', 'pci_cfg_write 32') 219 220@lldb_command('pci_cfg_dump') 221def PciCfgDump(cmd_args=None): 222 """ Dump PCI config space for specified bus, device, and function 223 If an invalid/inaccessible PCI device is specified, nothing will 224 be printed out. 225 Syntax: pci_cfg_dump <bus> <dev> <fuction> 226 """ 227 if cmd_args is None or len(cmd_args) < 3: 228 print(PciCfgDump.__doc__) 229 return 230 231 bus = ArgumentStringToInt(cmd_args[0]) 232 dev = ArgumentStringToInt(cmd_args[1]) 233 func = ArgumentStringToInt(cmd_args[2]) 234 235 DoPciCfgDump(bus, dev, func) 236 237@lldb_command('pci_cfg_scan') 238def PciCfgScan(cmd_args=None): 239 """ Scan for pci devices. The maximum bus number to be scanned defaults to 8, 240 but can be specified as an argument 241 Syntax: pci_cfg_scan [max bus number] 242 """ 243 if cmd_args is None or len(cmd_args) == 0: 244 max_bus = 8 245 elif len(cmd_args) == 1: 246 max_bus = ArgumentStringToInt(cmd_args[0]) 247 else: 248 print(PciCfgScan.__doc__) 249 return 250 251 print("bus:dev:fcn: vendor device rev | class") 252 print("--------------------------------------") 253 DoPciCfgScan(max_bus, False) 254 255@lldb_command('pci_cfg_dump_all') 256def PciCfgDumpAll(cmd_args=None): 257 """ Dump config space for all scanned PCI devices. The maximum bus number to 258 be scanned defaults to 8, but can be specified as an argument 259 Syntax: pci_cfg_dump_all [max bus number] 260 """ 261 if cmd_args is None or len(cmd_args) == 0: 262 max_bus = 8 263 elif len(cmd_args) == 1: 264 max_bus = ArgumentStringToInt(cmd_args[0]) 265 else: 266 print(PciCfgDumpAll.__doc__) 267 return 268 269 DoPciCfgScan(max_bus, True) 270