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