acrn-config: generate a patch and apply to acrn-hypervisor

the script will parser the the board information which already generated on
target board, and apply to the acrn-hypervisor as a patch.

usage: board_cfg_gen.py --board <board_info_file>

sample:
	$ python3 board_cfg_gen.py --board ../target_board/board_info.xml

v1-v2:
1. allow to generate new board patch

v2-v3:
1. modify the description of generator tools
2. parser board_name.xml file
3. coding as PEP8 guildline

Tracked-On: #3480
Signed-off-by: Wei Liu <weix.w.liu@intel.com>
Reviewed-by: Shuang Zheng shuang.zheng@intel.com
Acked-by: Terry Zou <terry.zou@intel.com>
Acked-by: Victor Sun <victor.sun@intel.com>
This commit is contained in:
Wei Liu 2019-07-30 09:20:40 +08:00 committed by ACRN System Integration
parent 8adefe26ac
commit a03b134190
8 changed files with 684 additions and 0 deletions

8
misc/acrn-config/README Normal file
View File

@ -0,0 +1,8 @@
folder structure
Kconfig : Select working scenario and target board, configure ACRN hypervisor capabilities and features.
target : Get target board information under native Linux environment and generate board_info XML.
board_config : Parse board_info XML and scenario XML to generate board related configuration files under hypervisor/arch/x86/configs/$(BOARD)/ folder.
scenario_config : Parse board_info XML and scenario XML to generate scenario based VM configuration files under hypervisor/scenarios/$(SCENARIO)/ folder.
launch_config : Parse board_info XML, scenario XML and devicemodel param XML to generate launch script for post-launched vm under devicesmodel/samples/$(BOARD)/ folder.
library : The folder stores shared software modules or libs for acrn-config offline tool.

View File

@ -0,0 +1,5 @@
Please run board_cfg_gen.py to generate board related configuration patch, the patch would be applied on current acrn-hypervisor git tree automatically.
usage: python3 board_cfg_gen.py [h] --board <board_info_file>
positional arguments:
board_info_file : file name of the board info XML

View File

@ -0,0 +1,158 @@
# Copyright (C) 2019 Intel Corporation. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
import board_cfg_lib
PLATFORM_HEADER = r"""/* DO NOT MODIFY THIS FILE UNLESS YOU KNOW WHAT YOU ARE DOING!
*/
#ifndef PLATFORM_ACPI_INFO_H
#define PLATFORM_ACPI_INFO_H
"""
PLATFORM_END_HEADER = "\n#endif /* PLATFORM_ACPI_INFO_H */"
class OverridAccessSize():
"""The Pm access size which are needed to redefine"""
def __init__(self):
self.pm1a_cnt_ac_sz = True
self.pm1b_cnt_ac_sz = True
self.pm1b_evt_ac_sz = True
def style_check_1(self):
"""Style check if have public method"""
self.pm1a_cnt_ac_sz = True
def style_check_2(self):
"""Style check if have public method"""
self.pm1a_cnt_ac_sz = True
def multi_parser(line, s_line, pm_ac_sz, config):
"""Multi parser the line"""
addr = ['PM1A_EVT_ADDRESS', 'PM1B_EVT_ADDRESS', 'PM1A_CNT_ADDRESS', 'PM1B_CNT_ADDRESS']
space_id = ['PM1A_EVT_SPACE_ID', 'PM1B_EVT_SPACE_ID', 'PM1A_CNT_SPACE_ID', 'PM1B_CNT_SPACE_ID']
if line.split()[1] in space_id and line.split()[1] == s_line.split()[1]:
if line.split()[2] != s_line.split()[2]:
print("#undef {}".format(s_line.split()[1]), file=config)
print("{}".format(s_line.strip()), file=config)
return
if line.split()[1] in addr and line.split()[1] == s_line.split()[1]:
if int(line.split()[2].strip('UL'), 16) != \
int(s_line.split()[2].strip('UL'), 16) and \
int(s_line.split()[2].strip('UL'), 16) != 0:
print("#undef {}".format(s_line.split()[1]), file=config)
print("{}".format(s_line.strip()), file=config)
else:
if "PM1B_EVT" in line.split()[1]:
pm_ac_sz.pm1b_evt_ac_sz = False
if "PM1B_CNT" in line.split()[1]:
pm_ac_sz.pm1b_cnt_ac_sz = False
return
if line.split()[1] == s_line.split()[1]:
if "PM1B_EVT" in line.split()[1] and not pm_ac_sz.pm1b_evt_ac_sz:
return
if "PM1B_CNT" in line.split()[1] and not pm_ac_sz.pm1b_cnt_ac_sz:
return
if "PM1A_CNT" in line.split()[1] and not pm_ac_sz.pm1a_cnt_ac_sz:
return
if int(line.split()[2].strip('U'), 16) != int(s_line.split()[2].strip('U'), 16):
print("#undef {}".format(s_line.split()[1]), file=config)
print("{}".format(s_line.strip()), file=config)
def multi_info_parser(config, default_platform, msg_s, msg_e):
"""Parser multi information"""
write_direct = ['PM1A_EVT_ACCESS_SIZE', 'PM1A_EVT_ADDRESS', 'PM1A_CNT_ADDRESS']
pm_ac_sz = OverridAccessSize()
multi_lines = board_cfg_lib.get_info(board_cfg_lib.BOARD_INFO_FILE, msg_s, msg_e)
for s_line in multi_lines:
if s_line.split()[1] in write_direct:
if "PM1A_CNT" in s_line.split()[1] and int(s_line.split()[2].strip('UL'), 16) == 0:
pm_ac_sz.pm1a_cnt_ac_sz = False
print("{}".format(s_line.strip()), file=config)
continue
with open(default_platform, 'r') as default:
while True:
line = default.readline()
if not line:
break
if len(line.split()) < 2:
continue
multi_parser(line, s_line, pm_ac_sz, config)
def write_direct_info_parser(config, msg_s, msg_e):
"""Direct to write"""
vector_lines = board_cfg_lib.get_info(board_cfg_lib.BOARD_INFO_FILE, msg_s, msg_e)
for vector in vector_lines:
print("{}".format(vector.strip()), file=config)
print("", file=config)
def drhd_info_parser(config):
"""Parser DRHD information"""
prev_num = 0
drhd_lines = board_cfg_lib.get_info(
board_cfg_lib.BOARD_INFO_FILE, "<DRHD_INFO>", "</DRHD_INFO>")
# write DRHD
print("/* DRHD of DMAR */", file=config)
for drhd in drhd_lines:
cur_num = drhd.strip().split()[1][4:5]
if drhd.strip().split()[1] == "DRHD_COUNT":
print("", file=config)
print("{}".format(drhd.strip()), file=config)
continue
if cur_num != prev_num:
print("", file=config)
print("{}".format(drhd.strip()), file=config)
prev_num = cur_num
def platform_info_parser(config, default_platform):
"""Parser ACPI information"""
print("\n/* pm sstate data */", file=config)
multi_info_parser(config, default_platform, "<PM_INFO>", "</PM_INFO>")
multi_info_parser(config, default_platform, "<S3_INFO>", "</S3_INFO>")
multi_info_parser(config, default_platform, "<S5_INFO>", "</S5_INFO>")
print("", file=config)
write_direct_info_parser(config, "<WAKE_VECTOR_INFO>", "</WAKE_VECTOR_INFO>")
write_direct_info_parser(config, "<RESET_REGISTER_INFO>", "</RESET_REGISTER_INFO>")
drhd_info_parser(config)
def generate_file(config, default_platform):
"""write board_name_acpi_info.h"""
print("{}".format(board_cfg_lib.HEADER_LICENSE), file=config)
print("{}".format(PLATFORM_HEADER), file=config)
board_cfg_lib.handle_bios_info(config)
# parser for the platform info
platform_info_parser(config, default_platform)
print("{}".format(PLATFORM_END_HEADER), file=config)

View File

@ -0,0 +1,105 @@
# Copyright (C) 2019 Intel Corporation. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
import sys
import board_cfg_lib
def clos_info_parser():
"""Parser CLOS information"""
cache_support = False
clos_max = 0
cat_lines = board_cfg_lib.get_info(
board_cfg_lib.BOARD_INFO_FILE, "<CLOS_INFO>", "</CLOS_INFO>")
for line in cat_lines:
if line.split(':')[0] == "clos supported by cache":
cache_support = line.split(':')[1].strip()
elif line.split(':')[0] == "clos max":
clos_max = int(line.split(':')[1])
return (cache_support, clos_max)
def gen_cat(config):
"""Get CAT information"""
(cache_support, clos_max) = clos_info_parser()
print("\n#include <board.h>", file=config)
print("#include <acrn_common.h>", file=config)
if cache_support == "False" or clos_max == 0:
print("\nstruct platform_clos_info platform_clos_array[0];", file=config)
print("uint16_t platform_clos_num = 0;", file=config)
else:
print("\nstruct platform_clos_info platform_clos_array[{0}] = {{".format(
clos_max), file=config)
for i_cnt in range(clos_max):
print("\t{", file=config)
print("\t\t.clos_mask = {0},".format(hex(0xff)), file=config)
if cache_support == "L2":
print("\t\t.msr_index = MSR_IA32_{0}_MASK_{1},".format(
cache_support, i_cnt), file=config)
elif cache_support == "L3":
print("\t\t.msr_index = {0}U,".format(hex(0x00000C90+i_cnt)), file=config)
else:
board_cfg_lib.print_red("The input of board_info.txt was corrupted!")
sys.exit(1)
print("\t},", file=config)
print("};\n", file=config)
print("uint16_t platform_clos_num = ", file=config, end="")
print("(uint16_t)(sizeof(platform_clos_array)/sizeof(struct platform_clos_info));",
file=config)
print("", file=config)
def gen_px_cx(config):
"""Get Px/Cx and store them to board.c"""
cpu_brand_lines = board_cfg_lib.get_info(
board_cfg_lib.BOARD_INFO_FILE, "<CPU_BRAND>", "</CPU_BRAND>")
cx_lines = board_cfg_lib.get_info(board_cfg_lib.BOARD_INFO_FILE, "<CX_INFO>", "</CX_INFO>")
px_lines = board_cfg_lib.get_info(board_cfg_lib.BOARD_INFO_FILE, "<PX_INFO>", "</PX_INFO>")
cx_len = len(cx_lines)
px_len = len(px_lines)
#print("#ifdef CONFIG_CPU_POWER_STATES_SUPPORT", file=config)
print("static const struct cpu_cx_data board_cpu_cx[%s] = {"%str(cx_len), file=config)
for cx_l in cx_lines:
print("\t{0}".format(cx_l.strip()), file=config)
print("};\n", file=config)
print("static const struct cpu_px_data board_cpu_px[%s] = {"%str(px_len), file=config)
for px_l in px_lines:
print("\t{0}".format(px_l.strip()), file=config)
print("};\n", file=config)
for brand_line in cpu_brand_lines:
cpu_brand = brand_line
print("const struct cpu_state_table board_cpu_state_tbl = {", file=config)
print("\t{0},".format(cpu_brand.strip()), file=config)
print("\t{(uint8_t)ARRAY_SIZE(board_cpu_px), board_cpu_px,", file=config)
print("\t(uint8_t)ARRAY_SIZE(board_cpu_cx), board_cpu_cx}", file=config)
print("};", file=config)
#print("#endif", file=config)
def generate_file(config):
"""Start to generate board.c"""
print("{0}".format(board_cfg_lib.HEADER_LICENSE), file=config)
# insert bios info into board.c
board_cfg_lib.handle_bios_info(config)
# start to parser to get CAT info
gen_cat(config)
# start to parser PX/CX info
gen_px_cx(config)

View File

@ -0,0 +1,137 @@
# Copyright (C) 2019 Intel Corporation. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
import os
import sys
import shutil
import subprocess
import board_cfg_lib
import board_c
import pci_devices_h
import acpi_platform_h
ACRN_PATH = "../../../"
ACRN_CONFIG = ACRN_PATH + "hypervisor/arch/x86/configs/"
BOARD_NAMES = ['apl-mrb', 'apl-nuc', 'apl-up2', 'dnv-cb2', 'nuc6cayh',
'nuc7i7dnb', 'kbl-nuc-i7', 'icl-rvp']
ACRN_DEFAULT_PLATFORM = ACRN_PATH + "hypervisor/include/arch/x86/default_acpi_info.h"
GEN_FILE = ["vm_configurations.h", "vm_configurations.c", "pt_dev.c", "pci_devices.h",
"board.c", "_acpi_info.h"]
PY_CACHES = ["__pycache__", "board_config/__pycache__"]
BIN_LIST = ['git']
def prepare():
"""Prepare to check the environment"""
for excute in BIN_LIST:
res = subprocess.Popen("which {}".format(excute), shell=True, stdout=subprocess.PIPE,
stderr=subprocess.PIPE, close_fds=True)
line = res.stdout.readline().decode('ascii')
if not line:
board_cfg_lib.print_yel("'{}' not found, please install it!".format(excute))
sys.exit(1)
if excute == "git":
res = subprocess.Popen("git tag -l", shell=True, stdout=subprocess.PIPE,
stderr=subprocess.PIPE, close_fds=True)
line = res.stdout.readline().decode("ascii")
if "acrn" not in line:
board_cfg_lib.print_red("Run this tool in acrn-hypervisor mainline source code!")
sys.exit(1)
for py_cache in PY_CACHES:
if os.path.exists(py_cache):
shutil.rmtree(py_cache)
def gen_patch(srcs_list, board_name):
"""Generate patch and apply to local source code"""
changes = ' '.join(srcs_list)
git_add = "git add {}".format(changes)
subprocess.call(git_add, shell=True, stdout=subprocess.PIPE,
stderr=subprocess.PIPE, close_fds=True)
# commit this changes
git_commit = 'git commit -sm "acrn-config: config board patch for {}"'.format(board_name)
subprocess.call(git_commit, shell=True, stdout=subprocess.PIPE,
stderr=subprocess.PIPE, close_fds=True)
def main(board_info_file):
"""This is main function to start generate source code related with board"""
board = ''
config_srcs = []
config_dirs = []
# get board name
board = board_cfg_lib.get_board_name(board_info_file)
config_dirs.append(ACRN_CONFIG + board)
if board not in BOARD_NAMES:
for config_dir in config_dirs:
if not os.path.exists(config_dir):
os.makedirs(config_dir)
config_pci = config_dirs[0] + '/' + GEN_FILE[3]
config_board = config_dirs[0] + '/' + GEN_FILE[4]
config_platform = config_dirs[0] + '/' + board + GEN_FILE[5]
config_srcs.append(config_pci)
config_srcs.append(config_board)
config_srcs.append(config_platform)
# generate board.c
with open(config_board, 'w+') as config:
board_c.generate_file(config)
# generate pci_devices.h
with open(config_pci, 'w+') as config:
pci_devices_h.generate_file(config)
# generate acpi_platform.h
with open(config_platform, 'w+') as config:
acpi_platform_h.generate_file(config, ACRN_DEFAULT_PLATFORM)
# move changes to patch, and applay to the source code
gen_patch(config_srcs, board)
if board not in BOARD_NAMES:
print("Config patch for NEW board {} is committed successfully!".format(board))
else:
print("Config patch for {} is committed successfully!".format(board))
def usage():
"""This is usage for how to use this tool"""
print("usage= [h] --board <board_info_file>'")
print('board_info_file, : file name of the board info"')
sys.exit(1)
if __name__ == '__main__':
prepare()
ARGS = sys.argv[1:]
if ARGS[0] != '--board':
usage()
sys.exit(1)
BOARD_INFO_FILE = ARGS[1]
if not os.path.exists(BOARD_INFO_FILE):
board_cfg_lib.print_red("{} is not exist!".format(BOARD_INFO_FILE))
sys.exit(1)
# board_info.txt will be override
board_cfg_lib.BOARD_INFO_FILE = BOARD_INFO_FILE
main(BOARD_INFO_FILE)

View File

@ -0,0 +1,124 @@
# Copyright (C) 2019 Intel Corporation. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
import sys
HV_LICENSE_FILE = '../library/hypervisor_license'
BOARD_INFO_FILE = "board_info.txt"
BIOS_INFO = ['BIOS Information', 'Vendor:', 'Version:', 'Release Date:', 'BIOS Revision:']
BASE_BOARD = ['Base Board Information', 'Manufacturer:', 'Product Name:', 'Version:']
def open_license():
"""Get the license"""
with open(HV_LICENSE_FILE, 'r') as f_licence:
license_s = f_licence.read().strip()
return license_s
HEADER_LICENSE = open_license() + "\n"
#LOGICAL_PT_PROFILE = {}
#LOGICAL_PCI_DEV = {}
#LOGICAL_PCI_LINE = {}
def print_yel(msg, warn=False):
"""Print the message with color of yellow"""
if warn:
print("\033[1;33mWarning\033[0m:"+msg)
else:
print("\033[1;33m{0}\033[0m".format(msg))
def print_red(msg, err=False):
"""Print the message with color of red"""
if err:
print("\033[1;31mError\033[0m:"+msg)
else:
print("\033[1;31m{0}\033[0m".format(msg))
def get_board_name(board_info):
"""Get board name"""
with open(board_info, 'rt') as f_board:
line = f_board.readline()
if not "board=" in line:
print_red("acrn-config board info xml was corrupted!")
sys.exit(1)
board = line.split('"')[1].strip('"')
return board
def get_info(board_info, msg_s, msg_e):
"""Get information which specify by argument"""
info_start = False
info_end = False
info_lines = []
num = len(msg_s.split())
try:
with open(board_info, 'rt') as f_board:
while True:
line = f_board.readline()
if not line:
break
if " ".join(line.split()[0:num]) == msg_s:
info_start = True
info_end = False
continue
if " ".join(line.split()[0:num]) == msg_e:
info_start = False
info_end = True
continue
if info_start and not info_end:
info_lines.append(line)
continue
if not info_start and info_end:
return info_lines
except IOError as err:
print_red(str(err), err=True)
sys.exit(1)
def handle_bios_info(config):
"""Handle bios information"""
bios_lines = get_info(BOARD_INFO_FILE, "<BIOS_INFO>", "</BIOS_INFO>")
board_lines = get_info(BOARD_INFO_FILE, "<BASE_BOARD_INFO>", "</BASE_BOARD_INFO>")
print("/*", file=config)
if not bios_lines or not board_lines:
print(" * DMI info is not found", file=config)
else:
i_cnt = 0
bios_board = BIOS_INFO + BASE_BOARD
# remove the same value and keep origin sort
bios_board_info = list(set(bios_board))
bios_board_info.sort(key=bios_board.index)
bios_board_lines = bios_lines + board_lines
bios_info_len = len(bios_lines)
for line in bios_board_lines:
if i_cnt == bios_info_len:
print(" *", file=config)
i_cnt += 1
for mics_info in bios_board_info:
if mics_info == " ".join(line.split()[0:1]) or mics_info == \
" ".join(line.split()[0:2]) or mics_info == " ".join(line.split()[0:3]):
print(" * {0}".format(line.strip()), file=config)
print(" */", file=config)

View File

@ -0,0 +1,142 @@
# Copyright (C) 2019 Intel Corporation. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
import collections
import board_cfg_lib
PCI_HEADER = r"""
#ifndef PCI_DEVICES_H_
#define PCI_DEVICES_H_
"""
PCI_END_HEADER = r"""
#endif /* PCI_DEVICES_H_ */"""
def parser_pci():
"""Parser PCI lines"""
cur_bdf = 0
prev_bdf = 0
tmp_bar_dic = {}
pci_dev_dic = {}
pci_bar_dic = {}
bar_value = bar_num = '0'
pci_lines = board_cfg_lib.get_info(
board_cfg_lib.BOARD_INFO_FILE, "<PCI_DEVICE>", "</PCI_DEVICE>")
for line in pci_lines:
# get pci bar information into pci_bar_dic
if "Region" in line and "Memory at" in line:
bar_num = line.split()[1].strip(':')
bar_value = line.split()[4]
tmp_bar_dic[int(bar_num)] = hex(int(bar_value, 16))
else:
prev_bdf = cur_bdf
pci_bdf = line.split()[0]
pci_sub_name = " ".join(line.split(':')[1].split()[1:])
# remove '[*]' in pci subname
if '[' in pci_sub_name:
pci_sub_name = pci_sub_name.rsplit('[', 1)[0]
pci_dev_dic[pci_bdf] = pci_sub_name
cur_bdf = pci_bdf
#board_cfg_lib.LOGICAL_PCI_LINE[pci_bdf] = line
# skipt the first init value
if not prev_bdf:
prev_bdf = cur_bdf
if tmp_bar_dic and cur_bdf != prev_bdf:
pci_bar_dic[prev_bdf] = tmp_bar_dic
# clear the tmp_bar_dic before store the next dic
tmp_bar_dic = {}
# output all the pci device list to pci_device.h
sub_name_count = collections.Counter(pci_dev_dic.values())
# share the pci profile with pt_dev
#board_cfg_lib.LOGICAL_PT_PROFILE = sub_name_count
#board_cfg_lib.LOGICAL_PCI_DEV = pci_dev_dic
if tmp_bar_dic:
pci_bar_dic[cur_bdf] = tmp_bar_dic
return (pci_dev_dic, pci_bar_dic, sub_name_count)
def write_pbdf(i_cnt, bdf, subname, config):
"""Parser and generate pbdf"""
# if there is only one host bridge, then will discard the index of suffix
if i_cnt == 0 and subname.upper() == "HOST BRIDGE":
tmp_sub_name = "_".join(subname.split()).upper()
else:
tmp_sub_name = "_".join(subname.split()).upper() + "_" + str(i_cnt)
bus = int(bdf.split(':')[0], 16)
dev = int(bdf.split(':')[1].split('.')[0], 16)
fun = int(bdf.split('.')[1], 16)
print("#define %-32s" % tmp_sub_name, end="", file=config)
print(" .pbdf.bits = {{.b = 0x{:02X}U, .d = 0x{:02X}U, .f = 0x{:02X}U}}".format(
bus, dev, fun), end="", file=config)
def write_vbar(bdf, pci_bar_dic, config):
"""Parser and generate vbar"""
tail = 0
align = ' ' * 48
if bdf in pci_bar_dic.keys():
bar_list = list(pci_bar_dic[bdf].keys())
bar_len = len(bar_list)
bar_num = 0
for bar_i in bar_list:
if tail == 0:
print(", \\", file=config)
tail += 1
bar_num += 1
bar_val = pci_bar_dic[bdf][bar_i]
if bar_num == bar_len:
print("{}.vbar_base[{}] = {}UL".format(align, bar_i, bar_val), file=config)
else:
print("{}.vbar_base[{}] = {}UL, \\".format(
align, bar_i, bar_val), file=config)
# print("", file=config)
else:
print("", file=config)
def generate_file(config):
"""Get PCI device and generate pci_devices.h"""
# write the license into pci
print("{0}".format(board_cfg_lib.HEADER_LICENSE), file=config)
# add bios and base board info
board_cfg_lib.handle_bios_info(config)
# write the header into pci
print("{0}".format(PCI_HEADER), file=config)
(pci_dev_dic, pci_bar_dic, sub_name_count) = parser_pci()
compared_bdf = []
for cnt_sub_name in sub_name_count.keys():
i_cnt = 0
for bdf, subname in pci_dev_dic.items():
if cnt_sub_name == subname and bdf not in compared_bdf:
compared_bdf.append(bdf)
else:
continue
write_pbdf(i_cnt, bdf, subname, config)
write_vbar(bdf, pci_bar_dic, config)
i_cnt += 1
# write the end to the pci devices
print("{0}".format(PCI_END_HEADER), file=config)

View File

@ -0,0 +1,5 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/