xref: /xnu-10002.61.3/tools/lldbmacros/pci.py (revision 0f4c859e951fba394238ab619495c4e1d54d0f34)
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