diff --git a/misc/config_tools/board_inspector/acpiparser/rdt.py b/misc/config_tools/board_inspector/acpiparser/rdt.py index bf2048a96..f72f59848 100644 --- a/misc/config_tools/board_inspector/acpiparser/rdt.py +++ b/misc/config_tools/board_inspector/acpiparser/rdt.py @@ -611,6 +611,9 @@ def rdt_factory(field_list): for f in self._fields_: yield getattr(self, f[0]) + def __getitem__(self, index): + return getattr(self, self._fields_[index][0]) + class ResourceData(cdata.Struct): _pack_ = 1 _fields_ = [ diff --git a/misc/config_tools/board_inspector/extractors/50-acpi.py b/misc/config_tools/board_inspector/extractors/50-acpi.py index 541f8563b..7a917ca5c 100644 --- a/misc/config_tools/board_inspector/extractors/50-acpi.py +++ b/misc/config_tools/board_inspector/extractors/50-acpi.py @@ -5,8 +5,10 @@ import logging import lxml.etree +from collections import defaultdict -from acpiparser import parse_dsdt +from acpiparser import parse_dsdt, parse_resource_data, parse_pci_routing +import acpiparser.aml.context as context from acpiparser.aml.interpreter import ConcreteInterpreter from acpiparser.aml.exception import UndefinedSymbol, FutureWork from acpiparser.rdt import * @@ -68,19 +70,20 @@ def get_device_element(devices_node, namepath, hid): element.set("id", hid) return element -def parse_irq(item, elem): - add_child(elem, "resource", type="irq", int=hex(item._INT)) +def parse_irq(idx, item, elem): + irqs = ", ".join(map(str, item.irqs)) + add_child(elem, "resource", id=f"res{idx}", type="irq", int=irqs) -def parse_io_port(item, elem): - add_child(elem, "resource", type="io_port", min=hex(item._MIN), max=hex(item._MAX), len=hex(item._LEN)) +def parse_io_port(idx, item, elem): + add_child(elem, "resource", id=f"res{idx}", type="io_port", min=hex(item._MIN), max=hex(item._MAX), len=hex(item._LEN)) -def parse_fixed_io_port(item, elem): - add_child(elem, "resource", type="io_port", min=hex(item._BAS), max=hex(item._BAS + item._LEN - 1), len=hex(item._LEN)) +def parse_fixed_io_port(idx, item, elem): + add_child(elem, "resource", id=f"res{idx}", type="io_port", min=hex(item._BAS), max=hex(item._BAS + item._LEN - 1), len=hex(item._LEN)) -def parse_fixed_memory_range(item, elem): - add_child(elem, "resource", type="memory", min=hex(item._BAS), max=hex(item._BAS + item._LEN - 1), len=hex(item._LEN)) +def parse_fixed_memory_range(idx, item, elem): + add_child(elem, "resource", id=f"res{idx}", type="memory", min=hex(item._BAS), max=hex(item._BAS + item._LEN - 1), len=hex(item._LEN)) -def parse_address_space_resource(item, elem): +def parse_address_space_resource(idx, item, elem): if item._TYP == 0: typ = "memory" elif item._TYP == 1: @@ -89,17 +92,17 @@ def parse_address_space_resource(item, elem): typ = "bus_number" else: typ = "custom" - add_child(elem, "resource", type=typ, min=hex(item._MIN), max=hex(item._MAX), len=hex(item._LEN)) + add_child(elem, "resource", id=f"res{idx}", type=typ, min=hex(item._MIN), max=hex(item._MAX), len=hex(item._LEN)) -def parse_extended_irq(item, elem): - for irq in item._INT: - add_child(elem, "resource", type="irq", int=hex(irq)) +def parse_extended_irq(idx, item, elem): + irqs = ", ".join(map(str, item._INT)) + add_child(elem, "resource", id=f"res{idx}", type="irq", int=irqs) resource_parsers = { (0, SMALL_RESOURCE_ITEM_IRQ_FORMAT): parse_irq, (0, SMALL_RESOURCE_ITEM_IO_PORT): parse_io_port, (0, SMALL_RESOURCE_ITEM_FIXED_LOCATION_IO_PORT): parse_fixed_io_port, - (0, SMALL_RESOURCE_ITEM_END_TAG): (lambda x,y: None), + (0, SMALL_RESOURCE_ITEM_END_TAG): (lambda x,y,z: None), (1, LARGE_RESOURCE_ITEM_32BIT_FIXED_MEMORY_RANGE): parse_fixed_memory_range, (1, LARGE_RESOURCE_ITEM_ADDRESS_SPACE_RESOURCE): parse_address_space_resource, (1, LARGE_RESOURCE_ITEM_WORD_ADDRESS_SPACE): parse_address_space_resource, @@ -173,16 +176,41 @@ def fetch_device_info(devices_node, interpreter, namepath): data = interpreter.interpret_method_call(f"{namepath}._CRS").get() rdt = parse_resource_data(data) - for item in rdt.items: + for idx, item in enumerate(rdt.items): p = (item.type, item.name) if p in resource_parsers.keys(): - resource_parsers[p](item, element) + resource_parsers[p](idx, item, element) else: - add_child(element, "resource", type=item.__class__.__name__) + add_child(element, "resource", type=item.__class__.__name__, id=f"res{idx}") # PCI interrupt routing if interpreter.context.has_symbol(f"{namepath}._PRT"): - interpreter.interpret_method_call(f"{namepath}._PRT") + pkg = interpreter.interpret_method_call(f"{namepath}._PRT") + prt = parse_pci_routing(pkg) + prt_info = defaultdict(lambda: {}) + for mapping in prt: + if isinstance(mapping.source, int): + assert mapping.source == 0, "A _PRT mapping package should not contain a byte of non-zero as source" + prt_info[mapping.address][mapping.pin] = mapping.source_index + elif isinstance(mapping.source, context.DeviceDecl): + prt_info[mapping.address][mapping.pin] = (mapping.source.name, mapping.source_index) + else: + logging.warning(f"The _PRT of {namepath} has a mapping with invalid source {mapping.source}") + + pin_routing_element = add_child(element, "interrupt_pin_routing") + for address, pins in prt_info.items(): + mapping_element = add_child(pin_routing_element, "routing", address=hex(address)) + pin_names = { + 0: "INTA#", + 1: "INTB#", + 2: "INTC#", + 3: "INTD#", + } + for pin, info in pins.items(): + if isinstance(info, int): + add_child(mapping_element, "mapping", pin=pin_names[pin], source=str(info)) + else: + add_child(mapping_element, "mapping", pin=pin_names[pin], source=info[0], index=str(info[1])) except FutureWork: pass @@ -198,6 +226,14 @@ def extract(board_etree): return interpreter = ConcreteInterpreter(namespace) + + # With IOAPIC, Linux kernel will choose APIC mode as the IRQ model. Evalaute the \_PIC method (if exists) to inform the ACPI + # namespace of this. + try: + interpreter.interpret_method_call("\\_PIC", 1) + except: + logging.info(f"\\_PIC is not evaluated.") + for device in sorted(namespace.devices, key=lambda x:x.name): try: fetch_device_info(devices_node, interpreter, device.name) diff --git a/misc/config_tools/board_inspector/extractors/60-pci.py b/misc/config_tools/board_inspector/extractors/60-pci.py index 61c48434f..523446fbf 100644 --- a/misc/config_tools/board_inspector/extractors/60-pci.py +++ b/misc/config_tools/board_inspector/extractors/60-pci.py @@ -15,6 +15,13 @@ from extractors.helpers import add_child, get_node PCI_ROOT_PATH = "/sys/devices/pci0000:00" bdf_regex = re.compile(r"^([0-9a-f]{4}):([0-9a-f]{2}):([0-9a-f]{2}).([0-7]{1})$") +interrupt_pin_names = { + 1: "INTA#", + 2: "INTB#", + 3: "INTC#", + 4: "INTD#", +} + def collect_hostbridge_resources(bus_node): with open("/proc/iomem", "r") as f: for line in f.readlines(): @@ -114,6 +121,17 @@ def parse_device(bus_node, device_path): if cap.name in cap_parsers: cap_parsers[cap.name](cap_node, cap) + # Interrupt pin + pin = cfg.header.interrupt_pin + if pin > 0 and pin <= 4: + pin_name = interrupt_pin_names[pin] + res_node = add_child(device_node, "resource", type="interrupt_pin", pin=pin_name) + + prt_address = hex(int(device_node.get("address"), 16) | 0xffff) + mapping = device_node.xpath(f"../interrupt_pin_routing/routing[@address='{prt_address}']/mapping[@pin='{pin_name}']") + if len(mapping) > 0: + res_node.set("source", mapping[0].get("source")) + # Secondary bus if cfg.header.header_type == 1: # According to section 3.2.5.6, PCI to PCI Bridge Architecture Specification, the I/O Limit register contains a @@ -134,6 +152,14 @@ def parse_device(bus_node, device_path): min=hex(memory_base), max=hex(memory_end), len=hex(memory_end - memory_base + 1)) secondary_bus_node = add_child(device_node, "bus", type="pci", address=hex(cfg.header.secondary_bus_number)) + + # If a PCI routing table is provided for the root port / switch, move the routing table down to the bus node, in + # order to align the relative position of devices and routing tables. + prt = device_node.find("interrupt_pin_routing") + if prt is not None: + device_node.remove(prt) + secondary_bus_node.append(prt) + return secondary_bus_node return device_node diff --git a/misc/config_tools/board_inspector/extractors/90-sorting.py b/misc/config_tools/board_inspector/extractors/90-sorting.py index 29d6539ff..9a8b448ce 100644 --- a/misc/config_tools/board_inspector/extractors/90-sorting.py +++ b/misc/config_tools/board_inspector/extractors/90-sorting.py @@ -11,7 +11,7 @@ def getkey(child): if typ in ["memory", "io_port"]: return int(node.get("min"), base=16) elif typ == "irq": - return int(node.get("int"), base=16) + return int(node.get("int").split(", ")[0]) else: return 0 @@ -22,7 +22,9 @@ def getkey(child): else: return 0xFFFFFFFF - tags = ["vendor", "identifier", "subsystem_vendor", "subsystem_identifier", "class", "acpi_object", "status", "resource", "capability", "bus", "device"] + tags = ["vendor", "identifier", "subsystem_vendor", "subsystem_identifier", "class", + "acpi_object", "status", + "resource", "capability", "interrupt_pin_routing", "bus", "device"] if child.tag == "resource": return (tags.index(child.tag), child.get("type"), resource_subkey(child)) diff --git a/misc/config_tools/static_allocators/gpa.py b/misc/config_tools/static_allocators/gpa.py index 18223cbc6..276809ffc 100644 --- a/misc/config_tools/static_allocators/gpa.py +++ b/misc/config_tools/static_allocators/gpa.py @@ -204,7 +204,7 @@ def get_devs_mem_passthrough(board_etree, scenario_etree): def get_pci_hole_native(board_etree): resources = board_etree.xpath(f"//bus[@type = 'pci']/device[@address]/resource[@type = 'memory' and @len != '0x0']") - resources_hostbridge = board_etree.xpath("//bus[@address = '0x0']/resource[@type = 'memory' and @len != '0x0' and not(@id) and not(@width)]") + resources_hostbridge = board_etree.xpath("//bus[@address = '0x0']/resource[@type = 'memory' and @len != '0x0' and not(starts-with(@id, 'bar')) and not(@width)]") low_mem = set() high_mem = set() for resource_hostbridge in resources_hostbridge: