# Copyright (C) 2021 Intel Corporation. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # import ctypes import copy import acpiparser.cdata as cdata from acpiparser._utils import TableHeader class DMARSubtable(cdata.Struct): _pack_ = 1 _fields_ = [ ('subtype', ctypes.c_uint16), ('length', ctypes.c_uint16), ] class DMARDeviceScopePath(cdata.Struct): _pack_ = 1 _fields_ = [ ('pci_device', ctypes.c_uint8), ('pci_function', ctypes.c_uint8), ] def DMARDeviceScope_factory(num_dev_scope_path): class DMARDeviceScope(cdata.Struct): _pack_ = 1 _fields_ = [ ('type', ctypes.c_uint8), ('length', ctypes.c_uint8), ('reserved', ctypes.c_uint16), ('enumeration_id', ctypes.c_uint8), ('start_bus_number', ctypes.c_uint8), ('paths', DMARDeviceScopePath * num_dev_scope_path), ] return DMARDeviceScope def dmar_device_scope_list(addr, length): end = addr + length field_list = list() subtable_num = 0 base_len_DMARDeviceScope = ctypes.sizeof(DMARDeviceScope_factory(0)) len_DMARDeviceScopePath = ctypes.sizeof(DMARDeviceScopePath) while addr < end: subtable_num += 1 subtable = DMARDeviceScope_factory(0).from_address(addr) num_dev_scope_path = (subtable.length - base_len_DMARDeviceScope) // len_DMARDeviceScopePath cls = DMARDeviceScope_factory(num_dev_scope_path) addr += subtable.length field_list.append( ('subtable{}'.format(subtable_num), cls) ) return field_list class drhd_flags_bits(cdata.Struct): _pack_ = 1 _fields_ = [ ('include_pci_all', ctypes.c_uint8, 1), ] class drhd_flags(cdata.Union): _pack_ = 1 _anonymous_ = ("bits",) _fields_ = [ ('data', ctypes.c_uint8), ('bits', drhd_flags_bits), ] def DMARSubtableDRHD_factory(field_list): class subtables(cdata.Struct): _pack_ = 1 _fields_ = field_list def __iter__(self): for f in self._fields_: yield getattr(self, f[0]) class DMARSubtableDRHD(cdata.Struct): _pack_ = 1 _fields_ = copy.copy(DMARSubtable._fields_) + [ ('flags', drhd_flags), ('reserved', ctypes.c_uint8), ('segment_number', ctypes.c_uint16), ('base_address', ctypes.c_uint64), ('device_scopes', subtables) ] return DMARSubtableDRHD def DMARSubtableRMRR_factory(field_list): class subtables(cdata.Struct): _pack_ = 1 _fields_ = field_list def __iter__(self): for f in self._fields_: yield getattr(self, f[0]) class DMARSubtableRMRR(cdata.Struct): _pack_ = 1 _fields_ = copy.copy(DMARSubtable._fields_) + [ ('reserved', ctypes.c_uint16), ('segment_number', ctypes.c_uint16), ('base_address', ctypes.c_uint64), ('limit_address', ctypes.c_uint64), ('device_scopes', subtables), ] return DMARSubtableRMRR class atsr_flags_bits(cdata.Struct): _pack_ = 1 _fields_ = [ ('all_ports', ctypes.c_uint8, 1), ] class atsr_flags(cdata.Union): _pack_ = 1 _anonymous_ = ("bits",) _fields_ = [ ('data', ctypes.c_uint8), ('bits', atsr_flags_bits), ] def DMARSubtableATSR_factory(field_list): class subtables(cdata.Struct): _pack_ = 1 _fields_ = field_list def __iter__(self): for f in self._fields_: yield getattr(self, f[0]) class DMARSubtableATSR(cdata.Struct): _pack = 1 _fields_ = copy.copy(DMARSubtable._fields_) + [ ('flags', atsr_flags), ('reserved', ctypes.c_uint8), ('segment_number', ctypes.c_uint16), ('device_scopes', subtables), ] return DMARSubtableATSR class DMARSubtableRHSA(cdata.Struct): _pack = 1 _fields_ = copy.copy(DMARSubtable._fields_) + [ ('reserved', ctypes.c_uint32), ('base_address', ctypes.c_uint64), ('proximity_domain', ctypes.c_uint32), ] def DMARSubTableANDD_factory(obj_name_len): class DMARSubTableANDD(cdata.Struct): _pack = 1 _fields_ = copy.copy(DMARSubtable._fields_) + [ ('reserved', ctypes.c_uint8 * 3), ('device_num', ctypes.c_uint8), ('object_name', ctypes.c_char * obj_name_len), ] return DMARSubTableANDD def DMARSubtableUnknown_factory(data_len): class DMARSubtableUnknown(cdata.Struct): _pack = 1 _fields_ = copy.copy(DMARSubtable._fields_) + [ ('data', ctypes.c_uint8 * data_len), ] return DMARSubtableUnknown ACPI_DMAR_TYPE_DRHD = 0 ACPI_DMAR_TYPE_RMRR = 1 ACPI_DMAR_TYPE_ATSR = 2 ACPI_DMAR_TYPE_RHSA = 3 ACPI_DMAR_TYPE_ANDD = 4 def dmar_subtable_list(addr, length): end = addr + length field_list = list() subtable_num = 0 base_len_DRHD = ctypes.sizeof(DMARSubtableDRHD_factory(list())) base_len_RMRR = ctypes.sizeof(DMARSubtableRMRR_factory(list())) base_len_ATSR = ctypes.sizeof(DMARSubtableATSR_factory(list())) base_len_ANDD = ctypes.sizeof(DMARSubTableANDD_factory(0)) while addr < end: subtable_num += 1 subtable = DMARSubtable.from_address(addr) if subtable.subtype == ACPI_DMAR_TYPE_DRHD: next_field_list = dmar_device_scope_list(addr + base_len_DRHD, subtable.length - base_len_DRHD) cls = DMARSubtableDRHD_factory(next_field_list) elif subtable.subtype == ACPI_DMAR_TYPE_RMRR: next_field_list = dmar_device_scope_list(addr + base_len_RMRR, subtable.length - base_len_RMRR) cls = DMARSubtableRMRR_factory(next_field_list) elif subtable.subtype == ACPI_DMAR_TYPE_ATSR: next_field_list = dmar_device_scope_list(addr + base_len_ATSR, subtable.length - base_len_ATSR) cls = DMARSubtableATSR_factory(next_field_list) elif subtable.subtype == ACPI_DMAR_TYPE_RHSA: cls = DMARSubtableRHSA elif subtable.subtype == ACPI_DMAR_TYPE_ANDD: cls = DMARSubTableANDD_factory(subtable.length - base_len_ANDD) else: cls = DMARSubtableUnknown_factory(subtable.length - ctypes.sizeof(DMARSubtable)) addr += subtable.length field_list.append( ('subtable{}'.format(subtable_num), cls) ) return field_list class dmar_flags_bits(cdata.Struct): _pack_ = 1 _fields_ = [ ('intr_remap', ctypes.c_uint8, 1), ('x2apic_opt_out', ctypes.c_uint8, 1), ] class dmar_flags(cdata.Union): _pack_ = 1 _anonymous_ = ("bits",) _fields_ = [ ('data', ctypes.c_uint8), ('bits', dmar_flags_bits), ] def dmar_factory(field_list): class subtables(cdata.Struct): _pack_ = 1 _fields_ = field_list def __iter__(self): for f in self._fields_: yield getattr(self, f[0]) class DMAR_v1(cdata.Struct): _pack = 1 _fields_ = [ ('header', TableHeader), ('host_addr_width', ctypes.c_uint8), ('flags', ctypes.c_uint8), ('reserved', ctypes.c_uint8 * 10), ('remapping_structures', subtables), ] return DMAR_v1 def DMAR(val): """Create class based on decode of an DMAR table from filename.""" base_length = ctypes.sizeof(dmar_factory(list())) data = open(val, mode='rb').read() buf = ctypes.create_string_buffer(data, len(data)) addr = ctypes.addressof(buf) hdr = TableHeader.from_address(addr) field_list = dmar_subtable_list(addr + base_length, hdr.length - base_length) return dmar_factory(field_list).from_buffer_copy(data)