mirror of
https://github.com/projectacrn/acrn-hypervisor.git
synced 2025-05-13 19:04:31 +00:00
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>
253 lines
7.7 KiB
Python
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)
|