mirror of
https://github.com/darlinghq/darling-xnu.git
synced 2024-11-23 12:39:55 +00:00
266 lines
10 KiB
Python
Executable File
266 lines
10 KiB
Python
Executable File
from xnu import *
|
|
|
|
######################################
|
|
# Helper functions
|
|
######################################
|
|
def GetMemMappedPciCfgAddrFromRegistry():
|
|
""" Retrieve the base address of the memory mapped PCI config space. It is
|
|
found in registry entry AppleACPIPlatformExpert, property acpi-mmcfg-seg0.
|
|
Returns:
|
|
int base address of memory mapped PCI config space
|
|
"""
|
|
kgm_pci_cfg_base_default = 0xe0000000
|
|
acpi_pe_obj = FindRegistryObjectRecurse(kern.globals.gRegistryRoot,
|
|
"AppleACPIPlatformExpert")
|
|
if acpi_pe_obj is None:
|
|
print "Could not find AppleACPIPlatformExpert in registry, \
|
|
using default base address for memory mapped PCI config space"
|
|
return kgm_pci_cfg_base_default
|
|
entry = kern.GetValueFromAddress(int(acpi_pe_obj), 'IOService *')
|
|
acpi_mmcfg_seg_prop = LookupKeyInPropTable(entry.fPropertyTable, "acpi-mmcfg-seg0")
|
|
if acpi_mmcfg_seg_prop is None:
|
|
print "Could not find acpi-mmcfg-seg0 property, \
|
|
using default base address for memory mapped PCI config space"
|
|
return kgm_pci_cfg_base_default
|
|
else:
|
|
return int(GetNumber(acpi_mmcfg_seg_prop))
|
|
|
|
@static_var('kgm_pci_cfg_base', -1)
|
|
def GetMemMappedPciCfgAddrBase():
|
|
""" Returns the base address of the memory mapped PCI config space. The address
|
|
is retrieved once from the registry, and is remembered for all subsequent
|
|
calls to this function
|
|
Returns:
|
|
int base address of memory mapped PCI config space
|
|
"""
|
|
if GetMemMappedPciCfgAddrBase.kgm_pci_cfg_base == -1:
|
|
# Retrieve the base address from the registry if it hasn't been
|
|
# initialized yet
|
|
GetMemMappedPciCfgAddrBase.kgm_pci_cfg_base = GetMemMappedPciCfgAddrFromRegistry()
|
|
return GetMemMappedPciCfgAddrBase.kgm_pci_cfg_base
|
|
|
|
def MakeMemMappedPciCfgAddr(bus, dev, func, offs):
|
|
""" Construct the memory address for the PCI config register specified by the
|
|
bus, device, function, and offset
|
|
Params:
|
|
bus, dev, func, offs: int - bus, device, function, and offset that specifies
|
|
the PCI config space register
|
|
Returns:
|
|
int - the physical memory address that maps to the PCI config space register
|
|
"""
|
|
return GetMemMappedPciCfgAddrBase() | (bus << 20) | (dev << 15) | (func << 12) | offs
|
|
|
|
def DoPciCfgRead(bits, bus, dev, func, offs):
|
|
""" Helper function that performs PCI config space read
|
|
Params:
|
|
bits: int - bit width of access: 8, 16, or 32 bits
|
|
bus, dev, func, offs: int - PCI config bus, device, function and offset
|
|
Returns:
|
|
int - the value read from PCI config space
|
|
"""
|
|
phys_addr = MakeMemMappedPciCfgAddr(bus, dev, func, offs)
|
|
return ReadPhysInt(phys_addr, bits)
|
|
|
|
def DoPciCfgWrite(bits, bus, dev, func, offs, val):
|
|
""" Helper function that performs PCI config space write
|
|
Params:
|
|
bits: int - bit width of access: 8, 16, or 32 bits
|
|
bus, dev, func, offs: int - PCI config bus, device, function and offset
|
|
Returns:
|
|
boolean - True upon success, False otherwise
|
|
"""
|
|
phys_addr = MakeMemMappedPciCfgAddr(bus, dev, func, offs)
|
|
return WritePhysInt(phys_addr, val, bits)
|
|
|
|
def ShowPciCfgBytes(bus, dev, func, offset):
|
|
""" Prints 16 bytes of PCI config space starting at specified offset
|
|
Params:
|
|
bus, dev, func, offset: int - bus, dev, function, and offset of the
|
|
PCI config space register
|
|
"""
|
|
# Print mem-mapped address at beginning of each 16-byte line
|
|
phys_addr = MakeMemMappedPciCfgAddr(bus, dev, func, offset)
|
|
read_vals = [DoPciCfgRead(32, bus, dev, func, offset + byte)
|
|
for byte in range(0, 16, 4)]
|
|
# It would be nicer to have a shorter format that we could loop
|
|
# over, but each call to print results in a newline which
|
|
# would prevent us from printing all 16 bytes on one line.
|
|
bytes_fmt = "{:08x}:" + "{:02x} " * 16
|
|
print bytes_fmt.format(
|
|
phys_addr,
|
|
read_vals[0] & 0xff, (read_vals[0] >> 8) & 0xff,
|
|
(read_vals[0] >> 16) & 0xff, (read_vals[0] >> 24) & 0xff,
|
|
read_vals[1] & 0xff, (read_vals[1] >> 8) & 0xff,
|
|
(read_vals[1] >> 16) & 0xff, (read_vals[1] >> 24) & 0xff,
|
|
read_vals[2] & 0xff, (read_vals[2] >> 8) & 0xff,
|
|
(read_vals[2] >> 16) & 0xff, (read_vals[2] >> 24) & 0xff,
|
|
read_vals[3] & 0xff, (read_vals[3] >> 8) & 0xff,
|
|
(read_vals[3] >> 16) & 0xff, (read_vals[3] >> 24) & 0xff)
|
|
|
|
def DoPciCfgDump(bus, dev, func):
|
|
""" Dumps PCI config space of the PCI device specified by bus, dev, function
|
|
Params:
|
|
bus, dev, func: int - bus, dev, function of PCI config space to dump
|
|
"""
|
|
# Check for a valid PCI device
|
|
vendor_id = DoPciCfgRead(16, bus, dev, func, 0)
|
|
if (vendor_id == 0xbad10ad) or not (vendor_id > 0 and vendor_id < 0xffff):
|
|
return
|
|
# Show the standard PCI config space
|
|
print "address: 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F\n"
|
|
print "--------------------------------------------------------"
|
|
for offset in range(0, 256, 16):
|
|
ShowPciCfgBytes(bus, dev, func, offset)
|
|
# Check for PCIE extended capability config space
|
|
if DoPciCfgRead(8, bus, dev, func, 256) < 0xff:
|
|
print " \n"
|
|
for offset in range(256, 4096, 16):
|
|
ShowPciCfgBytes(bus, dev, func, offset)
|
|
|
|
def DoPciCfgScan(max_bus, dump):
|
|
""" Do a PCI config scan starting at bus 0 up to specified max bus
|
|
Params:
|
|
max_bus: int - maximum bus to scan
|
|
dump: bool - if True, dump the config space of each scanned device
|
|
if False, print basic information of each scanned device
|
|
"""
|
|
max_dev = 32
|
|
max_func = 8
|
|
bdfs = ({'bus':bus, 'dev':dev, 'func':func}
|
|
for bus in range(max_bus)
|
|
for dev in range(max_dev)
|
|
for func in range(max_func))
|
|
fmt_string = "{:03x}:" * 3 + " " + \
|
|
"{:02x}" * 2 + " " + \
|
|
"{:02x}" * 2 + " {:02x} | " + \
|
|
"{:02x}" * 3
|
|
for bdf in bdfs:
|
|
bus = bdf['bus']
|
|
dev = bdf['dev']
|
|
func = bdf['func']
|
|
vend_dev_id = DoPciCfgRead(32, bus, dev, func, 0)
|
|
if not (vend_dev_id > 0 and vend_dev_id < 0xffffffff):
|
|
continue
|
|
if dump == False:
|
|
class_rev_id = DoPciCfgRead(32, bus, dev, func, 8)
|
|
print fmt_string.format(
|
|
bus, dev, func,
|
|
(vend_dev_id >> 8) & 0xff, vend_dev_id & 0xff,
|
|
(vend_dev_id >> 24) & 0xff, (vend_dev_id >> 16) & 0xff,
|
|
class_rev_id & 0xff, (class_rev_id >> 24) & 0xff,
|
|
(class_rev_id >> 16) & 0xff, (class_rev_id >> 8) & 0xff)
|
|
else:
|
|
print "{:03x}:{:03x}:{:03x}".format(bus, dev, func)
|
|
DoPciCfgDump(bus, dev, func)
|
|
|
|
######################################
|
|
# LLDB commands
|
|
######################################
|
|
@lldb_command('pci_cfg_read')
|
|
def PciCfgRead(cmd_args=None):
|
|
""" Read PCI config space at the specified bus, device, function, and offset
|
|
Syntax: pci_cfg_read <bits> <bus> <device> <function> <offset>
|
|
bits: 8, 16, 32
|
|
"""
|
|
if cmd_args == None or len(cmd_args) < 5:
|
|
print PciCfgRead.__doc__
|
|
return
|
|
|
|
bits = ArgumentStringToInt(cmd_args[0])
|
|
bus = ArgumentStringToInt(cmd_args[1])
|
|
dev = ArgumentStringToInt(cmd_args[2])
|
|
func = ArgumentStringToInt(cmd_args[3])
|
|
offs = ArgumentStringToInt(cmd_args[4])
|
|
|
|
read_val = DoPciCfgRead(bits, bus, dev, func, offs)
|
|
if read_val == 0xbad10ad:
|
|
print "ERROR: Failed to read PCI config space"
|
|
return
|
|
|
|
format_for_bits = {8:"{:#04x}", 16:"{:#06x}", 32:"{:#010x}"}
|
|
phys_addr = MakeMemMappedPciCfgAddr(bus, dev, func, offs)
|
|
fmt_string = "{:08x}: " + format_for_bits[bits]
|
|
print fmt_string.format(phys_addr, read_val)
|
|
|
|
lldb_alias('pci_cfg_read8', 'pci_cfg_read 8')
|
|
lldb_alias('pci_cfg_read16', 'pci_cfg_read 16')
|
|
lldb_alias('pci_cfg_read32', 'pci_cfg_read 32')
|
|
|
|
@lldb_command('pci_cfg_write')
|
|
def PciCfgWrite(cmd_args=None):
|
|
""" Write PCI config space at the specified bus, device, function, and offset
|
|
Syntax: pci_cfg_write <bits> <bus> <device> <function> <offset> <write val>
|
|
bits: 8, 16, 32
|
|
|
|
Prints an error message if there was a problem
|
|
Prints nothing upon success.
|
|
"""
|
|
if cmd_args == None or len(cmd_args) < 6:
|
|
print PciCfgWrite.__doc__
|
|
return
|
|
|
|
bits = ArgumentStringToInt(cmd_args[0])
|
|
bus = ArgumentStringToInt(cmd_args[1])
|
|
dev = ArgumentStringToInt(cmd_args[2])
|
|
func = ArgumentStringToInt(cmd_args[3])
|
|
offs = ArgumentStringToInt(cmd_args[4])
|
|
write_val = ArgumentStringToInt(cmd_args[5])
|
|
|
|
if DoPciCfgWrite(bits, bus, dev, func, offs, write_val) == False:
|
|
print "ERROR: Failed to write PCI config space"
|
|
|
|
lldb_alias('pci_cfg_write8', 'pci_cfg_write 8')
|
|
lldb_alias('pci_cfg_write16', 'pci_cfg_write 16')
|
|
lldb_alias('pci_cfg_write32', 'pci_cfg_write 32')
|
|
|
|
@lldb_command('pci_cfg_dump')
|
|
def PciCfgDump(cmd_args=None):
|
|
""" Dump PCI config space for specified bus, device, and function
|
|
If an invalid/inaccessible PCI device is specified, nothing will
|
|
be printed out.
|
|
Syntax: pci_cfg_dump <bus> <dev> <fuction>
|
|
"""
|
|
if cmd_args == None or len(cmd_args) < 3:
|
|
print PciCfgDump.__doc__
|
|
return
|
|
|
|
bus = ArgumentStringToInt(cmd_args[0])
|
|
dev = ArgumentStringToInt(cmd_args[1])
|
|
func = ArgumentStringToInt(cmd_args[2])
|
|
|
|
DoPciCfgDump(bus, dev, func)
|
|
|
|
@lldb_command('pci_cfg_scan')
|
|
def PciCfgScan(cmd_args=None):
|
|
""" Scan for pci devices. The maximum bus number to be scanned defaults to 8,
|
|
but can be specified as an argument
|
|
Syntax: pci_cfg_scan [max bus number]
|
|
"""
|
|
if cmd_args == None or len(cmd_args) == 0:
|
|
max_bus = 8
|
|
elif len(cmd_args) == 1:
|
|
max_bus = ArgumentStringToInt(cmd_args[0])
|
|
else:
|
|
print PciCfgScan.__doc__
|
|
return
|
|
|
|
print "bus:dev:fcn: vendor device rev | class"
|
|
print "--------------------------------------"
|
|
DoPciCfgScan(max_bus, False)
|
|
|
|
@lldb_command('pci_cfg_dump_all')
|
|
def PciCfgDumpAll(cmd_args=None):
|
|
""" Dump config space for all scanned PCI devices. The maximum bus number to
|
|
be scanned defaults to 8, but can be specified as an argument
|
|
Syntax: pci_cfg_dump_all [max bus number]
|
|
"""
|
|
if cmd_args == None or len(cmd_args) == 0:
|
|
max_bus = 8
|
|
elif len(cmd_args) == 1:
|
|
max_bus = ArgumentStringToInt(cmd_args[0])
|
|
else:
|
|
print PciCfgDumpAll.__doc__
|
|
return
|
|
|
|
DoPciCfgScan(max_bus, True)
|