]>
Commit | Line | Data |
---|---|---|
39236c6e A |
1 | from xnu import * |
2 | ||
3 | ###################################### | |
4 | # Helper functions | |
5 | ###################################### | |
6 | def 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) | |
29 | def 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 | ||
42 | def 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 | ||
53 | def 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 | ||
64 | def 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 | ||
75 | def 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 | ||
100 | def 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 | ||
120 | def 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') | |
160 | def 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 | ||
185 | lldb_alias('pci_cfg_read8', 'pci_cfg_read 8') | |
186 | lldb_alias('pci_cfg_read16', 'pci_cfg_read 16') | |
187 | lldb_alias('pci_cfg_read32', 'pci_cfg_read 32') | |
188 | ||
189 | @lldb_command('pci_cfg_write') | |
190 | def 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 | ||
212 | lldb_alias('pci_cfg_write8', 'pci_cfg_write 8') | |
213 | lldb_alias('pci_cfg_write16', 'pci_cfg_write 16') | |
214 | lldb_alias('pci_cfg_write32', 'pci_cfg_write 32') | |
215 | ||
216 | @lldb_command('pci_cfg_dump') | |
217 | def 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') | |
234 | def 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') | |
252 | def 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) |