acrn-hypervisor/misc/config_tools/acpi_gen/asl_gen.py

504 lines
23 KiB
Python

# Copyright (C) 2019 Intel Corporation.
# SPDX-License-Identifier: BSD-3-Clause
"""the tool to generate ASL code of ACPI tables for Pre-launched VMs.
"""
import os, re, argparse, shutil
import xml.etree.ElementTree as ElementTree
from acpi_const import *
import board_cfg_lib
import collections
import lxml.etree
def calculate_checksum8():
'''
this function is implemented in iasl.
:return:
'''
pass
def gen_rsdp(dest_vm_acpi_path):
'''
generate rsdp.asl
:param dest_vm_acpi_path: the path to store generated ACPI asl code
:return:
'''
rsdp_asl = 'rsdp.asl'
p_xsdt_addr = r'XSDT Address : ([0-9a-fA-F]{16})'
with open(os.path.join(dest_vm_acpi_path, rsdp_asl), 'w') as dest:
lines = []
with open(os.path.join(TEMPLATE_ACPI_PATH, rsdp_asl), 'r') as src:
for line in src.readlines():
if re.search(p_xsdt_addr, line):
lines.append(re.sub(p_xsdt_addr, 'XSDT Address : {0:016X}'.format(ACPI_XSDT_ADDR), line))
else:
lines.append(line)
dest.writelines(lines)
def gen_xsdt(dest_vm_acpi_path, passthru_devices):
'''
generate xsdt.asl
:param dest_vm_acpi_path: the path to store generated ACPI asl code
:param passthru_devices: dict to store passthru device list
:return:
'''
xsdt_asl = 'xsdt.asl'
p_fadt_addr = r'ACPI Table Address 0 : ([0-9a-fA-F]{16})'
p_mcfg_addr = r'ACPI Table Address 1 : ([0-9a-fA-F]{16})'
p_madt_addr = r'ACPI Table Address 2 : ([0-9a-fA-F]{16})'
p_tpm2_addr = r'ACPI Table Address 3 : ([0-9a-fA-F]{16})'
p_rtct_addr = r'ACPI Table Address 4 : ([0-9a-fA-F]{16})'
with open(os.path.join(dest_vm_acpi_path, xsdt_asl), 'w') as dest:
lines = []
with open(os.path.join(TEMPLATE_ACPI_PATH, xsdt_asl), 'r') as src:
for line in src.readlines():
if re.search(p_fadt_addr, line):
lines.append(re.sub(p_fadt_addr, 'ACPI Table Address 0 : {0:016X}'.format(ACPI_FADT_ADDR), line))
elif re.search(p_mcfg_addr, line):
lines.append(re.sub(p_mcfg_addr, 'ACPI Table Address 1 : {0:016X}'.format(ACPI_MCFG_ADDR), line))
elif re.search(p_madt_addr, line):
lines.append(re.sub(p_madt_addr, 'ACPI Table Address 2 : {0:016X}'.format(ACPI_MADT_ADDR), line))
elif re.search(p_tpm2_addr, line):
if 'TPM2' in passthru_devices:
lines.append(re.sub(p_tpm2_addr, 'ACPI Table Address 3 : {0:016X}'.format(ACPI_TPM2_ADDR), line))
elif re.search(p_rtct_addr, line):
if 'PTCT' in passthru_devices or 'RTCT' in passthru_devices:
lines.append(re.sub(p_rtct_addr, 'ACPI Table Address 4 : {0:016X}'.format(ACPI_RTCT_ADDR), line))
else:
lines.append(line)
dest.writelines(lines)
def gen_fadt(dest_vm_acpi_path, board_root):
'''
generate facp.asl
:param dest_vm_acpi_path: the path to store generated ACPI asl code
:param board_root: the root element of board xml
:return:
'''
fadt_asl = 'facp.asl'
p_facs_addr = r'FACS Address : ([0-9a-fA-F]{8})'
p_dsdt_addr = r'DSDT Address : ([0-9a-fA-F]{8})$'
with open(os.path.join(dest_vm_acpi_path, fadt_asl), 'w') as dest:
lines = []
with open(os.path.join(TEMPLATE_ACPI_PATH, fadt_asl), 'r') as src:
for line in src.readlines():
if re.search(p_facs_addr, line):
lines.append(re.sub(p_facs_addr, 'FACS Address : {0:08X}'.format(ACPI_FACS_ADDR), line))
elif re.search(p_dsdt_addr, line):
lines.append(re.sub(p_dsdt_addr, 'DSDT Address : {0:08X}'.format(ACPI_DSDT_ADDR), line))
else:
lines.append(line)
dest.writelines(lines)
def gen_mcfg(dest_vm_acpi_path):
'''
generate mcfg.asl
:param dest_vm_acpi_path: the path to store generated ACPI asl code
:return:
'''
mcfg_asl = 'mcfg.asl'
p_base_addr = r'Base Address : ([0-9a-fA-F]{16})'
p_segment_group_num = r'Segment Group Number : (\d+)'
p_start_bus_num = r'Start Bus Number : (\d+)'
p_end_bus_num = r'End Bus Number : ([0-9a-fA-F]{2})'
with open(os.path.join(dest_vm_acpi_path, mcfg_asl), 'w') as dest:
lines = []
with open(os.path.join(TEMPLATE_ACPI_PATH, mcfg_asl), 'r') as src:
for line in src.readlines():
if re.search(p_base_addr, line):
lines.append(re.sub(p_base_addr, 'Base Address : {0:016X}'.format(VIRT_PCI_MMCFG_BASE), line))
elif re.search(p_segment_group_num, line):
lines.append(re.sub(p_segment_group_num, 'Segment Group Number : {0:04X}'.format(0), line))
elif re.search(p_start_bus_num, line):
lines.append(re.sub(p_start_bus_num, 'Start Bus Number : {0:02X}'.format(0), line))
elif re.search(p_end_bus_num, line):
lines.append(re.sub(p_end_bus_num, 'End Bus Number : {0:02X}'.format(0xff), line))
else:
lines.append(line)
dest.writelines(lines)
def gen_madt(dest_vm_acpi_path, max_cpu_num, apic_ids):
'''
generate apic.asl
:param dest_vm_acpi_path: the path to store generated ACPI asl code
:return:
'''
madt_asl = 'apic.asl'
lapic_index = 0
p_lapic_addr = r'Local Apic Address : ([0-9a-fA-F]{8})'
p_flags = r'\[0004\] Flags (decoded below) : (\d{8})' # dup flags
flags_index = 0
p_lapic_index = 0
p_lapic_type = r'Subtable Type : (\d+) \[Processor Local APIC\]'
p_lapic_len = r'\[0001\] Length : ([0-9a-fA-F]{2})' # dup len
p_lapic_len_index = 0
p_lapic_flags_index = 0
p_lapic_process_id = r'\[0001\] Processor ID : (\d+)' # dup processor
p_lapic_process_id_index = 0
p_lapic_id = r'Local Apic ID : ([0-9a-fA-F]{2})'
p_lapic_line_index = 0
lapic_lines = []
ioapic_index = 0
p_ioapic_type = r'Subtable Type : (\d+) \[I/O APIC\]'
p_ioapic_len_index = 0
p_ioapic_id = r'I/O Apic ID : (\d+)'
p_ioapic_addr = r'\[0004\] Address : ([0-9a-fA-F]{8})'
lapic_nmi_index = 0
p_lapic_nmi_type = r'Subtable Type : (\d+) \[Local APIC NMI\]'
p_lapic_nmi_len_index = 0
p_lapic_nmi_processor_id_index = 0
p_lapic_nmi_flags = r'\[0002\] Flags (decoded below) : ([0-9a-fA-F]{4})'
p_lapic_nmi_flags_index = 0
p_lapic_nmi_lint = r'Interrupt Input LINT : (\d+)'
with open(os.path.join(dest_vm_acpi_path, madt_asl), 'w') as dest:
lines = []
with open(os.path.join(TEMPLATE_ACPI_PATH, madt_asl), 'r') as src:
for line in src.readlines():
if re.search(p_lapic_addr, line):
lapic_index += 1
lines.append(re.sub(p_lapic_addr, 'Local Apic Address : {0:08X}'.format(0xFEE00000), line))
elif re.search(p_flags, line):
if lapic_index == 1 and flags_index == 0:
lines.append(
re.sub(p_flags, '[0004] Flags (decoded below) : {0:08X}'.format(0x1), line))
flags_index += 1
elif p_lapic_index == 1 and p_lapic_flags_index == 0:
lines.append(
re.sub(p_flags, '[0004] Flags (decoded below) : {0:08X}'.format(0x1),
line))
p_lapic_flags_index += 1
else:
lines.append(line)
elif re.search(p_lapic_type, line):
p_lapic_index += 1
if lapic_index == 1:
lines.append(re.sub(p_lapic_type, 'Subtable Type : {0:02X} [Processor Local APIC]'.format(
ACPI_MADT_TYPE_LOCAL_APIC), line))
else:
lines.append(line)
elif re.search(p_lapic_len, line):
if p_lapic_index == 1 and p_lapic_len_index == 0:
lines.append(
re.sub(p_lapic_len, '[0001] Length : {0:02X}'.format(0x8),
line))
p_lapic_len_index += 1
elif ioapic_index == 1 and p_ioapic_len_index == 0:
lines.append(
re.sub(p_lapic_len, '[0001] Length : {0:02X}'.format(0x0C),
line))
p_ioapic_len_index += 1
elif lapic_nmi_index == 1 and p_lapic_nmi_len_index == 0:
lines.append(
re.sub(p_lapic_len, '[0001] Length : {0:02X}'.format(0x06),
line))
p_lapic_nmi_len_index += 1
else:
lines.append(line)
elif re.search(p_lapic_process_id, line):
if p_lapic_index == 1 and p_lapic_process_id_index == 0:
lines.append(re.sub(p_lapic_process_id,
'[0001] Processor ID : {0:02X}'.format(0x0),
line))
p_lapic_process_id_index += 1
elif lapic_nmi_index == 1 and p_lapic_nmi_processor_id_index == 0:
lines.append(
re.sub(p_lapic_process_id,
'[0001] Processor ID : {0:02X}'.format(0xFF),
line))
p_lapic_nmi_processor_id_index += 1
else:
lines.append(line)
elif re.search(p_lapic_id, line):
lines.append(re.sub(p_lapic_id, 'Local Apic ID : {0:02X}'.format(apic_ids[0]), line))
elif re.search(p_ioapic_type, line):
ioapic_index += 1
lines.append(
re.sub(p_ioapic_type, 'Subtable Type : {0:02X} [I/O APIC]'.format(ACPI_MADT_TYPE_IOAPIC), line))
elif re.search(p_ioapic_id, line):
lines.append(re.sub(p_ioapic_id, 'I/O Apic ID : {0:02X}'.format(0x01), line))
elif re.search(p_ioapic_addr, line):
lines.append(re.sub(p_ioapic_addr,
'[0004] Address : {0:02X}'.format(VIOAPIC_BASE),
line))
elif re.search(p_lapic_nmi_type, line):
lapic_nmi_index += 1
if lapic_nmi_index == 1:
lines.append(re.sub(p_lapic_nmi_type, 'Subtable Type : {0:02X} [Local APIC NMI]'.format(
ACPI_MADT_TYPE_LOCAL_APIC_NMI), line))
else:
lines.append(line)
elif re.search(p_lapic_nmi_flags, line):
if lapic_nmi_index == 1 and p_lapic_nmi_flags_index == 0:
lines.append(
re.sub(p_lapic_nmi_flags, '[0002] Flags (decoded below) : {0:04X}'.format(0x5),
line))
p_lapic_nmi_flags_index += 1
else:
lines.append(line)
elif re.search(p_lapic_nmi_lint, line):
if lapic_nmi_index == 1:
lines.append(re.sub(p_lapic_nmi_lint, 'Interrupt Input LINT : {0:02X}'.format(0x1), line))
else:
lines.append(line)
else:
lines.append(line)
if p_lapic_index == 1 and p_lapic_line_index < 7:
lapic_lines.append(line)
p_lapic_line_index += 1
if p_lapic_index == 1 and p_lapic_line_index == 7:
p_lapic_line_index = 0
for process_id in range(1, max_cpu_num):
p_lapic_index = process_id + 1
lines.append('\n')
for lapic_line in lapic_lines:
if re.search(p_lapic_type, lapic_line):
lines.append(re.sub(p_lapic_type,
'Subtable Type : {0:02X} [Processor Local APIC]'.format(
ACPI_MADT_TYPE_LOCAL_APIC), lapic_line))
elif re.search(p_lapic_len, lapic_line):
lines.append(
re.sub(p_lapic_len,
'[0001] Length : {0:02X}'.format(0x8),
lapic_line))
elif re.search(p_flags, lapic_line):
lines.append(
re.sub(p_flags,
'[0004] Flags (decoded below) : {0:08X}'.format(0x1),
lapic_line))
elif re.search(p_lapic_process_id, lapic_line):
lines.append(re.sub(p_lapic_process_id,
'[0001] Processor ID : {0:02X}'.format(
process_id), lapic_line))
elif re.search(p_lapic_id, lapic_line):
lines.append(
re.sub(p_lapic_id, 'Local Apic ID : {0:02X}'.format(apic_ids[process_id]), lapic_line))
else:
lines.append(lapic_line)
dest.writelines(lines)
def gen_tpm2(dest_vm_acpi_path, passthru_devices):
'''
generate tpm2.asl
:param dest_vm_acpi_path: the path to store generated ACPI asl code
:param passthru_devices: dict to store passthru device list
:return:
'''
tpm2_asl = 'tpm2.asl'
p_control_addr = r'Control Address : ([0-9a-fA-F]{16})'
p_start_method = r'Start Method : (.*)'
if 'TPM2' not in passthru_devices:
if os.path.isfile(os.path.join(dest_vm_acpi_path, tpm2_asl)):
os.remove(os.path.join(dest_vm_acpi_path, tpm2_asl))
return
with open(os.path.join(dest_vm_acpi_path, tpm2_asl), 'w') as dest:
lines = []
with open(os.path.join(TEMPLATE_ACPI_PATH, tpm2_asl), 'r') as src:
for line in src.readlines():
if re.search(p_control_addr, line):
lines.append(re.sub(p_control_addr, 'Control Address : {0:016X}'.format(0xFED40040), line))
elif re.search(p_start_method, line):
lines.append(re.sub(p_start_method, 'Start Method : {0:02X}'.format(0x7), line))
else:
lines.append(line)
dest.writelines(lines)
def gen_dsdt(dest_vm_acpi_path, passthru_devices, board_info):
'''
generate dsdt.asl
:param dest_vm_acpi_path: the path to store generated ACPI asl code
:param passthru_devices:
:return:
'''
dsdt_asl = 'dsdt.asl'
p_dsdt_start = r'{'
(bdf_desc_map, bdf_vpid_map) = board_cfg_lib.get_pci_info(board_info)
with open(os.path.join(dest_vm_acpi_path, dsdt_asl), 'w') as dest:
lines = []
with open(os.path.join(TEMPLATE_ACPI_PATH, dsdt_asl), 'r') as src:
for line in src.readlines():
lines.append(line)
if line.startswith(p_dsdt_start):
for passthru_device in passthru_devices:
passthru_bdf = None
passthru_vpid = None
for bdf in bdf_desc_map.keys():
if bdf_desc_map[bdf].find(passthru_device) >= 0:
passthru_bdf = bdf
break
if passthru_bdf is not None and passthru_bdf in bdf_vpid_map.keys():
passthru_vpid = bdf_vpid_map[passthru_bdf]
if passthru_device in ['TPM2']:
tpm2_asl = os.path.join(TEMPLATE_ACPI_PATH, 'dsdt_tpm2.asl')
start = False
with open(tpm2_asl, 'r') as tpm2_src:
for tpm2_line in tpm2_src.readlines():
if tpm2_line.startswith('{'):
start = True
continue
if tpm2_line.startswith('}'):
start = False
continue
if start:
lines.append(tpm2_line)
elif passthru_vpid is not None and passthru_vpid == TSN_DEVICE_LIST[1]:
otn1_asl = os.path.join(TEMPLATE_ACPI_PATH, 'dsdt_tsn_otn1.asl')
start = False
with open(otn1_asl, 'r') as otn1_src:
for otn1_line in otn1_src.readlines():
if otn1_line.startswith('{'):
start = True
continue
if otn1_line.startswith('}'):
start = False
continue
if start:
lines.append(otn1_line)
else:
pass
dest.writelines(lines)
def main(args):
err_dic = {}
(err_dic, params) = common.get_param(args)
if err_dic:
return err_dic
board = params['--board']
scenario= params['--scenario']
out = params['--out']
board_etree = lxml.etree.parse(board)
board_root = ElementTree.parse(board).getroot()
scenario_root = ElementTree.parse(scenario).getroot()
board_type = board_root.attrib['board']
scenario_name = scenario_root.attrib['scenario']
pcpu_list = board_root.find('CPU_PROCESSOR_INFO').text.strip().split(',')
if isinstance(pcpu_list, list):
pcpu_list = [x.strip() for x in pcpu_list]
if out is None or out == '':
DEST_ACPI_PATH = os.path.join(VM_CONFIGS_PATH, 'scenarios', scenario_name)
else:
DEST_ACPI_PATH = os.path.join(common.SOURCE_ROOT_DIR, out, 'scenarios', scenario_name)
if os.path.isdir(DEST_ACPI_PATH):
for config in os.listdir(DEST_ACPI_PATH):
if config.startswith('ACPI_VM') and os.path.isdir(os.path.join(DEST_ACPI_PATH, config)):
shutil.rmtree(os.path.join(DEST_ACPI_PATH, config))
dict_passthru_devices = collections.OrderedDict()
dict_pcpu_list = collections.OrderedDict()
for vm in scenario_root.findall('vm'):
vm_id = vm.attrib['id']
vm_type_node = vm.find('vm_type')
if (vm_type_node is not None) and (vm_type_node.text in ['PRE_STD_VM', 'SAFETY_VM', 'PRE_RT_VM']):
dict_passthru_devices[vm_id] = []
for pci_dev_node in vm.findall('pci_devs/pci_dev'):
if pci_dev_node is not None and pci_dev_node.text is not None and pci_dev_node.text.strip():
dict_passthru_devices[vm_id].append(pci_dev_node.text)
mmio_dev_nodes = vm.find('mmio_resources')
if mmio_dev_nodes is not None:
for mmio_dev_node in list(mmio_dev_nodes):
if mmio_dev_node is not None and mmio_dev_node.text.strip() == 'y':
dict_passthru_devices[vm_id].append(mmio_dev_node.tag)
dict_pcpu_list[vm_id] = []
for pcpu_id in vm.findall('cpu_affinity/pcpu_id'):
if pcpu_id is not None and pcpu_id.text.strip() in pcpu_list:
dict_pcpu_list[vm_id].append(int(pcpu_id.text))
PASSTHROUGH_RTCT = False
PRELAUNCHED_RTVM_ID = None
try:
if scenario_root.find('hv/FEATURES/SSRAM/SSRAM_ENABLED').text.strip() == 'y':
PASSTHROUGH_RTCT = True
for vm in scenario_root.findall('vm'):
vm_id = vm.attrib['id']
vm_type_node = vm.find('vm_type')
if (vm_type_node is not None) and (vm_type_node.text in ['PRE_RT_VM']):
PRELAUNCHED_RTVM_ID = vm_id
break
except:
PASSTHROUGH_RTCT = False
kern_args = common.get_leaf_tag_map(scenario, "os_config", "bootargs")
kern_type = common.get_leaf_tag_map(scenario, "os_config", "kern_type")
for vm_id, passthru_devices in dict_passthru_devices.items():
if kern_args[int(vm_id)].find('reboot=acpi') == -1 and kern_type[int(vm_id)] in ['KERNEL_BZIMAGE']:
emsg = "you need to specify 'reboot=acpi' in scenario file's bootargs for VM{}".format(vm_id)
print(emsg)
err_dic['vm,bootargs'] = emsg
break
print('start to generate ACPI ASL code for VM{}'.format(vm_id))
dest_vm_acpi_path = os.path.join(DEST_ACPI_PATH, 'ACPI_VM'+vm_id)
if not os.path.isdir(dest_vm_acpi_path):
os.makedirs(dest_vm_acpi_path)
if PASSTHROUGH_RTCT is True and vm_id == PRELAUNCHED_RTVM_ID:
for f in RTCT:
if os.path.isfile(os.path.join(VM_CONFIGS_PATH, 'acpi_template', board_type, f)):
passthru_devices.append(f)
shutil.copy(os.path.join(VM_CONFIGS_PATH, 'acpi_template', board_type, f),
dest_vm_acpi_path)
break
gen_rsdp(dest_vm_acpi_path)
gen_xsdt(dest_vm_acpi_path, passthru_devices)
gen_fadt(dest_vm_acpi_path, board_root)
gen_mcfg(dest_vm_acpi_path)
if vm_id in dict_pcpu_list:
dict_pcpu_list[vm_id].sort()
apic_ids = []
for id in dict_pcpu_list[vm_id]:
apic_id = common.get_node(f"//processors/die/core/thread[cpu_id='{id}']/apic_id/text()", board_etree)
if apic_id is None:
emsg = 'some or all of the processors/die/core/thread/cpu_id tags are missing in board xml file for cpu {}, please run board_inspector.py to regenerate the board xml file!'.format(id)
print(emsg)
err_dic['board config: processors'] = emsg
return err_dic
else:
apic_ids.append(int(apic_id, 16))
gen_madt(dest_vm_acpi_path, len(dict_pcpu_list[vm_id]), apic_ids)
gen_tpm2(dest_vm_acpi_path, passthru_devices)
gen_dsdt(dest_vm_acpi_path, passthru_devices, board)
print('generate ASL code of ACPI tables for VM {} into {}'.format(vm_id, dest_vm_acpi_path))
else:
emsg = 'no cpu affinity config for VM {}'.format(vm_id)
print(emsg)
err_dic['vm,cpu_affinity,pcpu_id'] = emsg
return err_dic
if __name__ == '__main__':
main(sys.argv)