acrn-hypervisor/misc/config_tools/target/acpiparser/apic.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

282 lines
8.5 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
import acpiparser.unpack as unpack
from acpiparser._utils import TableHeader
class APICSubtable(cdata.Struct):
_pack_ = 1
_fields_ = [
('subtype', ctypes.c_uint8),
('length', ctypes.c_uint8),
]
class local_apic_flags_bits(cdata.Struct):
_pack_ = 1
_fields_ = [
('enabled', ctypes.c_uint32, 1),
]
class local_apic_flags(cdata.Union):
_pack_ = 1
_anonymous_ = ("bits",)
_fields_ = [
('data', ctypes.c_uint32),
('bits', local_apic_flags_bits),
]
class APICSubtableLocalApic(cdata.Struct):
_pack_ = 1
_fields_ = copy.copy(APICSubtable._fields_) + [
('proc_id', ctypes.c_uint8),
('apic_id', ctypes.c_uint8),
('flags', local_apic_flags),
]
class APICSubtableIOApic(cdata.Struct):
_pack_ = 1
_fields_ = copy.copy(APICSubtable._fields_) + [
('io_apic_id', ctypes.c_uint8),
('reserved', ctypes.c_uint8),
('io_apic_addr', ctypes.c_uint32),
('global_sys_int_base', ctypes.c_uint32),
]
mps_inti_polarity = {
0b00: 'Conforms to bus specifications',
0b01: 'Active high',
0b11: 'Active low',
}
mps_inti_trigger_mode = {
0b00: 'Conforms to bus specifications',
0b01: 'Edge-triggered',
0b11: 'Level-triggered',
}
class APICSubtable_int_flags_bits(cdata.Struct):
_pack_ = 1
_fields_ = [
('polarity', ctypes.c_uint16, 2),
('trigger_mode', ctypes.c_uint16, 2),
]
_formats = {
'polarity': unpack.format_table("{}", mps_inti_polarity),
'trigger_mode': unpack.format_table("{}", mps_inti_trigger_mode),
}
class APICSubtable_int_flags(cdata.Union):
_pack_ = 1
_anonymous_ = ("bits",)
_fields_ = [
('data', ctypes.c_uint16),
('bits', APICSubtable_int_flags_bits),
]
class APICSubtableNmiIntSrc(cdata.Struct):
_pack_ = 1
_fields_ = copy.copy(APICSubtable._fields_) + [
('flags', APICSubtable_int_flags),
('global_sys_interrupt', ctypes.c_uint32),
]
class APICSubtableLocalApicNmi(cdata.Struct):
_pack_ = 1
_fields_ = copy.copy(APICSubtable._fields_) + [
('proc_id', ctypes.c_uint8),
('flags', APICSubtable_int_flags),
('lint_num', ctypes.c_uint8),
]
class APICSubtableIntSrcOverride(cdata.Struct):
_pack_ = 1
_fields_ = copy.copy(APICSubtable._fields_) + [
('bus', ctypes.c_uint8),
('source', ctypes.c_uint8),
('global_sys_interrupt', ctypes.c_uint32),
('flags', APICSubtable_int_flags)
]
class APICSubtableLocalx2Apic(cdata.Struct):
_pack_ = 1
_fields_ = copy.copy(APICSubtable._fields_) + [
('reserved', ctypes.c_uint16),
('x2apicid', ctypes.c_uint32),
('flags', local_apic_flags),
('uid', ctypes.c_uint32),
]
class APICSubtableLocalx2ApicNmi(cdata.Struct):
_pack_ = 1
_fields_ = copy.copy(APICSubtable._fields_) + [
('flags', APICSubtable_int_flags),
('uid', ctypes.c_uint32),
('lint_num', ctypes.c_uint8),
('reserved', ctypes.c_uint8 * 3),
]
_performance_interrupt_mode = {
0: 'Level-triggered',
1: 'Edge-triggered',
}
class APICSubtableLocalGIC_flags_bits(cdata.Struct):
_pack_ = 1
_fields_ = [
('enabled', ctypes.c_uint32, 1),
('performance_interrupt_mode', ctypes.c_uint32, 1),
]
_formats = {
'performance_interrupt_mode': unpack.format_table("{}", mps_inti_polarity),
}
class APICSubtableLocalGIC_flags(cdata.Union):
_pack_ = 1
_anonymous_ = ("bits",)
_fields_ = [
('data', ctypes.c_uint32),
('bits', APICSubtableLocalGIC_flags_bits),
]
class APICSubtableLocalGIC(cdata.Struct):
_pack_ = 1
_fields_ = copy.copy(APICSubtable._fields_) + [
('reserved', ctypes.c_uint16),
('gic_id', ctypes.c_uint32),
('uid', ctypes.c_uint32),
('flags', APICSubtableLocalGIC_flags),
('parking_protocol_version', ctypes.c_uint32),
('performance_interrupt_gsiv', ctypes.c_uint32),
('parked_address', ctypes.c_uint64),
('physical_base_adddress', ctypes.c_uint64),
]
class APICSubtableLocalGICDistributor(cdata.Struct):
_pack_ = 1
_fields_ = copy.copy(APICSubtable._fields_) + [
('reserved1', ctypes.c_uint16),
('gic_id', ctypes.c_uint32),
('physical_base_adddress', ctypes.c_uint64),
('system_vector_base', ctypes.c_uint32),
('reserved2', ctypes.c_uint32),
]
def APICSubtableUnknown_factory(_len):
class APICSubtableUnknown(cdata.Struct):
_pack_ = 1
_fields_ = APICSubtable._fields_ + [
('data', ctypes.c_uint8 * _len),
]
return APICSubtableUnknown
MADT_TYPE_LOCAL_APIC = 0
MADT_TYPE_IO_APIC = 1
MADT_TYPE_INT_SRC_OVERRIDE = 2
MADT_TYPE_NMI_INT_SRC = 3
MADT_TYPE_LOCAL_APIC_NMI = 4
MADT_TYPE_LOCAL_X2APIC = 9
MADT_TYPE_LOCAL_X2APIC_NMI = 0xA
MADT_TYPE_LOCAL_GIC = 0xB
MADT_TYPE_LOCAL_GIC_DISTRIBUTOR = 0xC
class APIC_table_flags_bits(cdata.Struct):
_pack_ = 1
_fields_ = [
('pcat_compat', ctypes.c_uint32, 1),
]
class APIC_table_flags(cdata.Union):
_pack_ = 1
_anonymous_ = ("bits",)
_fields_ = [
('data', ctypes.c_uint32),
('bits', APIC_table_flags_bits),
]
def apic_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 APIC_v3(cdata.Struct):
_pack_ = 1
_fields_ = [
('header', TableHeader),
('local_apic_address', ctypes.c_uint32),
('flags', APIC_table_flags),
('interrupt_controller_structures', subtables),
]
@property
def procid_apicid(self):
procid_apicid_dict = {}
for subtable in self.interrupt_controller_structures:
# accumulate the dictionary
if subtable.subtype == MADT_TYPE_LOCAL_APIC:
if subtable.flags.bits.enabled == 1:
procid_apicid_dict[subtable.proc_id] = subtable.apic_id
return procid_apicid_dict
@property
def uid_x2apicid(self):
uid_x2apicid_dict = {}
for subtable in self.interrupt_controller_structures:
# accumulate the dictionary
if subtable.subtype == MADT_TYPE_LOCAL_X2APIC:
if subtable.flags.bits.enabled == 1:
uid_x2apicid_dict[subtable.uid] = subtable.x2apicid
return uid_x2apicid_dict
return APIC_v3
def apic_subtable_list(addr, length):
end = addr + length
field_list = list()
subtable_num = 0
while addr < end:
subtable_num += 1
subtable = APICSubtable.from_address(addr)
addr += subtable.length
if subtable.subtype == MADT_TYPE_LOCAL_APIC:
cls = APICSubtableLocalApic
elif subtable.subtype == MADT_TYPE_IO_APIC:
cls = APICSubtableIOApic
elif subtable.subtype == MADT_TYPE_INT_SRC_OVERRIDE:
cls = APICSubtableIntSrcOverride
elif subtable.subtype == MADT_TYPE_NMI_INT_SRC:
cls = APICSubtableNmiIntSrc
elif subtable.subtype == MADT_TYPE_LOCAL_APIC_NMI:
cls = APICSubtableLocalApicNmi
elif subtable.subtype == MADT_TYPE_LOCAL_X2APIC:
cls = APICSubtableLocalx2Apic
elif subtable.subtype == MADT_TYPE_LOCAL_X2APIC_NMI:
cls = APICSubtableLocalx2ApicNmi
elif subtable.subtype == MADT_TYPE_LOCAL_GIC:
cls = APICSubtableLocalGIC
elif subtable.subtype == MADT_TYPE_LOCAL_GIC_DISTRIBUTOR:
cls = APICSubtableLocalGICDistributor
else:
cls = APICSubtableUnknown_factory(subtable.length - ctypes.sizeof(APICSubtable))
field_list.append( ('subtable{}'.format(subtable_num), cls) )
return field_list
def APIC(val):
"""Create class based on decode of an APIC table from filename."""
preamble_length = ctypes.sizeof(apic_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)
subtable_list = apic_subtable_list(addr + preamble_length, hdr.length - preamble_length)
return apic_factory(subtable_list).from_buffer_copy(data)