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>
282 lines
8.5 KiB
Python
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)
|