acrn-hypervisor/misc/config_tools/target/acpiparser/dmar.py
Junjie Mao ba02583f2d config_tools/acpiparser: port the ACPI module from BITS
This patch ports the ACPI parsing module from BITS (BIOS Implementation
Test Suite) in order to ease the access to ACPI tables during board XML
generation. This library allows accessing ACPI table fields as Python class
members, getting rid of hard coding or calculating offsets within tables.

Compared to the original library, this port makes the following changes.

 * Extract only the scripts and functions that contribute to ACPI parsing.
 * Separate the parser of each ACPI table into different files.
 * Read raw ACPI tables from Linux sysfs.
 * Adapt to Python 3.

Tracked-On: #5649
Signed-off-by: Junjie Mao <junjie.mao@intel.com>
2021-01-27 16:39:24 +08:00

253 lines
7.7 KiB
Python

# 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)