Files
acrn-hypervisor/misc/acrn-config/target/acpi.py
Wei Liu 28d1b909e6 acrn-config: generate a scenario patch and apply to acrn-hypervisor
1.the script will parse the the board information which already
generated, $(scenario).xml modified by user, generate scenario
vm configuration and apply to the acrn-hypervisor source code base.

2.parse cpu/memory/ttys/rootfs information from native os and store it to
the source code

3.implemnt scenario_config and it's usage

usage: scenario_cfg_gen.py --board <board_info_file> -scenario <scenario_info_file>
board_info_file :  file name of the board info
scenario_info_file :  file name of the scenario info

sample:
	$ python3 scenario_cfg_gen.py --board ../board-xmls/apl-mrb.xml
--scenario ../config-xmls/scenarios/sdc.xml

Also improvement board config generate usage:
sample:
	$ python3 board_cfg_gen.py --board ../board-xmls/apl-mrb.xml
--scenario ../config-xmls/scenarios/sdc.xml

V1-V2:
    1). parse board_setting.xml was removed as these configuration will be
stitch into scenario configuration
    2). parse console for different formats
    3). parse epc sections
    4). add logical partition rootfs
    5). support to parse clos, while webui set to None type
    6). support to parse bootargs, while webui set to nul
    7). convert '-' to '_' for pci sub class name while generating source file

Tracked-On: #3602
Signed-off-by: Wei Liu <weix.w.liu@intel.com>
Acked-by: Terry Zou <terry.zou@intel.com>
2019-09-16 09:34:37 +08:00

570 lines
22 KiB
Python

# Copyright (C) 2019 Intel Corporation. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
import os
import sys
import subprocess
from collections import defaultdict
import dmar
import parser_lib
SYS_PATH = ['/proc/cpuinfo', '/sys/firmware/acpi/tables/', '/sys/devices/system/cpu/']
ACPI_OP = {
'AML_ZERO_OP':0x00,
'AML_ONE_OP':0x01,
'AML_ALIAS_OP':0x06,
'AML_NAME_OP':0x08,
'AML_BYTE_OP':0x0a,
'AML_WORD_OP':0x0b,
'AML_DWORD_OP':0x0c,
'AML_PACKAGE_OP':0x12,
'AML_VARIABLE_PACKAGE_OP':0x13,
}
SPACE_ID = {
0:'SPACE_SYSTEM_MEMORY',
1:'SPACE_SYSTEM_IO',
2:'SPACE_PCI_CONFIG',
3:'SPACE_Embedded_Control',
4:'SPACE_SMBUS',
10:'SPACE_PLATFORM_COMM',
0x7F:'SPACE_FFixedHW',
}
FACP_OFF = {
'facs_addr':36,
'reset_addr':116,
'reset_value':128,
'pm1a_evt':148,
'pm1b_evt':160,
'pm1a_cnt':172,
'pm1b_cnt':184,
}
class SxPkg:
"""This is Sx state structure for power"""
def __init__(self):
# This is Sx state structure for power
self.val_pm1a = ''
self.val_pm1b = ''
self.reserved = ''
def style_check_1(self):
"""Style check if have public method"""
self.val_pm1a = ''
def style_check_2(self):
"""Style check if have public method"""
self.val_pm1a = ''
class GasType:
"""This is generic address structure for power"""
def __init__(self):
self.space_id_8b = 0
self.bit_width_8b = 0
self.bit_offset_8b = 0
self.access_size_8b = 0
self.address_64b = 0
def style_check_1(self):
"""Style check if have public method"""
self.space_id_8b = ''
def style_check_2(self):
"""Style check if have public method"""
self.space_id_8b = ''
class PxPkg:
"""This is Px state structure for power"""
def __init__(self):
self.core_freq = 0
self.power = 0
self.trans_latency = 0
self.bus_latency = 0
self.control = 0
self.status = 0
def style_check_1(self):
"""Style check if have public method"""
self.power = ''
def style_check_2(self):
"""Style check if have public method"""
self.power = ''
class ResetReg:
"""This is Reset Registers meta data"""
def __init__(self):
self.reset_reg_addr = 0
self.reset_reg_space_id = 0
self.reset_reg_val = 0
def style_check_1(self):
"""Style check if have public method"""
self.reset_reg_val = ''
def style_check_2(self):
"""Style check if have public method"""
self.reset_reg_val = ''
DWORD_LEN = 4
PACK_TYPE_LEN = 12
WAKE_VECTOR_OFFSET_32 = 12
WAKE_VECTOR_OFFSET_64 = 24
S3_PKG = SxPkg()
S5_PKG = SxPkg()
PackedGas = GasType
PackedCx = GasType
def store_cpu_info(sysnode, config):
"""This will get CPU information
:param sysnode: the path to get cpu information, like: /proc/cpuifo
:param config: file pointer that opened for writing board config information
"""
with open(sysnode, 'r') as f_node:
line = f_node.readline()
while line:
if len(line.split(':')) >= 2:
if line.split(':')[0].strip() == "model name":
model_name = line.split(':')[1].strip()
print('\t"{0}"'.format(model_name), file=config)
break
line = f_node.readline()
def write_reset_reg(rst_reg_addr, rst_reg_space_id, rst_reg_val, config):
"""Write reset register info
:param rst_reg_addr: reset register address
:param rst_reg_space_id: reset register space id
:param rst_reg_val: reset register value
:param config: file pointer that opened for writing board config information
"""
print("\t{0}".format("<RESET_REGISTER_INFO>"), file=config)
print("\t#define RESET_REGISTER_ADDRESS 0x{:0>2X}UL".format(
rst_reg_addr), file=config)
print("\t#define RESET_REGISTER_SPACE_ID {0}".format(
SPACE_ID[rst_reg_space_id]), file=config)
print("\t#define RESET_REGISTER_VALUE {0}U".format(
rst_reg_val), file=config)
print("\t{0}\n".format("</RESET_REGISTER_INFO>"), file=config)
def get_vector_reset(sysnode, config):
"""This will get reset register value
:param sysnode: the system node of Px power state, like:/sys/firmware/acpi/tables/FACP
:param config: file pointer that opened for writing board config information
"""
reset_reg = ResetReg()
for key, offset in FACP_OFF.items():
with open(sysnode, 'rb') as f_node:
f_node.seek(offset, 0)
if key == 'facs_addr':
packed_data = f_node.read(DWORD_LEN)
packed_data_32 = int.from_bytes(packed_data, 'little')+WAKE_VECTOR_OFFSET_32
packed_data_64 = int.from_bytes(packed_data, 'little')+WAKE_VECTOR_OFFSET_64
print("\t{0}".format("<WAKE_VECTOR_INFO>"), file=config)
print("\t#define WAKE_VECTOR_32 0x{:0>2X}UL".format(
packed_data_32), file=config)
print("\t#define WAKE_VECTOR_64 0x{:0>2X}UL".format(
packed_data_64), file=config)
print("\t{0}\n".format("</WAKE_VECTOR_INFO>"), file=config)
elif key == 'reset_addr':
packed_data = f_node.read(PACK_TYPE_LEN)
reset_reg.reset_reg_space_id = packed_data[0]
reset_reg.reset_reg_addr = int.from_bytes(packed_data[4:11], 'little')
elif key == 'reset_value':
packed_data = f_node.read(1)
reset_reg.reset_reg_val = hex(packed_data[0])
write_reset_reg(reset_reg.reset_reg_addr, reset_reg.reset_reg_space_id,
reset_reg.reset_reg_val, config)
def read_pm_sstate(sysnode, config):
"""This will read Px state of power
:param sysnode: the system node of Px power state, like:/sys/firmware/acpi/tables/FACP
:param config: file pointer that opened for writing board config information
"""
get_vector_reset(sysnode, config)
print("\t{0}".format("<PM_INFO>"), file=config)
for key, offset in FACP_OFF.items():
with open(sysnode, 'rb') as f_node:
f_node.seek(offset, 0)
packed_data = f_node.read(PACK_TYPE_LEN)
PackedGas.space_id_8b = packed_data[0]
PackedGas.bit_width_8b = packed_data[1]
PackedGas.bit_offset_8b = packed_data[2]
PackedGas.access_size_8b = packed_data[3]
PackedGas.address_64b = int.from_bytes(packed_data[4:11], 'little')
if key == 'pm1a_evt':
print("\t#define PM1A_EVT_SPACE_ID {0}".format(
SPACE_ID[PackedGas.space_id_8b]), file=config)
print("\t#define PM1A_EVT_BIT_WIDTH {0}U".format(
hex(PackedGas.bit_width_8b)), file=config)
print("\t#define PM1A_EVT_BIT_OFFSET {0}U".format(
hex(PackedGas.bit_offset_8b)), file=config)
print("\t#define PM1A_EVT_ADDRESS {0}UL".format(
hex(PackedGas.address_64b)), file=config)
print("\t#define PM1A_EVT_ACCESS_SIZE {0}U".format(
hex(PackedGas.access_size_8b)), file=config)
elif key == 'pm1a_cnt':
print("\t#define PM1A_CNT_SPACE_ID {0}".format(
SPACE_ID[PackedGas.space_id_8b]), file=config)
print("\t#define PM1A_CNT_BIT_WIDTH {0}U".format(
hex(PackedGas.bit_width_8b)), file=config)
print("\t#define PM1A_CNT_BIT_OFFSET {0}U".format(
hex(PackedGas.bit_offset_8b)), file=config)
print("\t#define PM1A_CNT_ADDRESS {0}UL".format(
hex(PackedGas.address_64b)), file=config)
print("\t#define PM1A_CNT_ACCESS_SIZE {0}U".format(
hex(PackedGas.access_size_8b)), file=config)
elif key == 'pm1b_evt':
print("\t#define PM1B_EVT_SPACE_ID {0}".format(
SPACE_ID[PackedGas.space_id_8b]), file=config)
print("\t#define PM1B_EVT_BIT_WIDTH {0}U".format(
hex(PackedGas.bit_width_8b)), file=config)
print("\t#define PM1B_EVT_BIT_OFFSET {0}U".format(
hex(PackedGas.bit_offset_8b)), file=config)
print("\t#define PM1B_EVT_ADDRESS {0}UL".format(
hex(PackedGas.address_64b)), file=config)
print("\t#define PM1B_EVT_ACCESS_SIZE {0}U".format(
hex(PackedGas.access_size_8b)), file=config)
elif key == 'pm1b_cnt':
print("\t#define PM1B_CNT_SPACE_ID {0}".format(
SPACE_ID[PackedGas.space_id_8b]), file=config)
print("\t#define PM1B_CNT_BIT_WIDTH {0}U".format(
hex(PackedGas.bit_width_8b)), file=config)
print("\t#define PM1B_CNT_BIT_OFFSET {0}U".format(
hex(PackedGas.bit_offset_8b)), file=config)
print("\t#define PM1B_CNT_ADDRESS {0}UL".format(
hex(PackedGas.address_64b)), file=config)
print("\t#define PM1B_CNT_ACCESS_SIZE {0}U".format(
hex(PackedGas.access_size_8b)), file=config)
print("\t{0}\n".format("</PM_INFO>"), file=config)
def if_sx_name(sx_name, f_node):
"""If sx name in this field
:param sx_name: Sx name in DSDT of apci table, like _s3_, _s5_
:param f_node: f_node: file pointer that opened for reading sx from
"""
need_break = need_continue = 0
name_buf = f_node.read(4)
if not name_buf:
need_break = True
return (need_break, need_continue)
try:
if name_buf.decode('ascii').find(sx_name) != -1:
pass
else:
need_continue = True
except ValueError:
need_continue = True
return (need_break, need_continue)
else:
pass
return (need_break, need_continue)
def read_sx_locate(sx_name, f_node):
"""Read the location of sx
:param sx_name: Sx name in DSDT of apci table, like _s3_, _s5_
:param f_node: file pointer that opened for sx reading from
"""
need_continue = need_break = pkg_len = 0
(need_break, need_continue) = if_sx_name(sx_name, f_node)
tmp_char = f_node.read(1)
if not tmp_char:
need_break = True
return (need_break, need_continue, pkg_len)
if hex(int.from_bytes(tmp_char, 'little')) != hex(ACPI_OP['AML_PACKAGE_OP']):
need_continue = True
return (need_break, need_continue, pkg_len)
pkg_len = f_node.read(1)
if not pkg_len:
need_break = True
return (need_break, need_continue, pkg_len)
if int.from_bytes(pkg_len, 'little') < 5 or int.from_bytes(pkg_len, 'little') > 28:
need_continue = True
return (need_break, need_continue, pkg_len)
return (need_break, need_continue, pkg_len)
def decode_sx_pkg(pkg_len, f_node):
"""Parse and decode the sx pkg
:param pkg_len: the length of sx package read from f_node
:param f_node: file pointer that opened for sx reading from
"""
pkg_val_pm1a = pkg_val_pm1b = pkg_val_resv = need_break = 0
pkg_buf = f_node.read(int.from_bytes(pkg_len, 'little'))
if hex(pkg_buf[1]) == ACPI_OP['AML_ZERO_OP'] or \
hex(pkg_buf[1]) == hex(ACPI_OP['AML_ONE_OP']):
pkg_val_pm1a = pkg_buf[1]
if hex(pkg_buf[2]) == hex(ACPI_OP['AML_ZERO_OP']) or \
hex(pkg_buf[2]) == hex(ACPI_OP['AML_ONE_OP']):
pkg_val_pm1b = pkg_buf[2]
pkg_val_resv = pkg_buf[3:5]
elif hex(pkg_buf[2]) == hex(ACPI_OP['AML_BYTE_OP']):
pkg_val_pm1b = pkg_buf[3]
pkg_val_resv = pkg_buf[4:6]
else:
need_break = True
return (pkg_val_pm1a, pkg_val_pm1b, pkg_val_resv, need_break)
elif hex(pkg_buf[1]) == hex(ACPI_OP['AML_BYTE_OP']):
pkg_val_pm1a = pkg_buf[2]
if hex(pkg_buf[3]) == hex(ACPI_OP['AML_ZERO_OP']) or \
hex(pkg_buf[3]) == hex(ACPI_OP['AML_ONE_OP']):
pkg_val_pm1b = pkg_buf[3]
pkg_val_resv = pkg_buf[4:6]
elif hex(pkg_buf[3]) == hex(ACPI_OP['AML_BYTE_OP']):
pkg_val_pm1b = pkg_buf[4]
pkg_val_resv = pkg_buf[5:7]
else:
need_break = True
return (pkg_val_pm1a, pkg_val_pm1b, pkg_val_resv, need_break)
else:
need_break = True
return (pkg_val_pm1a, pkg_val_pm1b, pkg_val_resv, need_break)
def read_pm_sdata(sysnode, sx_name, config):
"""This will read pm Sx state of power
:param sysnode: the system node of Sx power state, like:/sys/firmware/acpi/tables/DSDT
:param sx_name: Sx name in DSDT of apci table, like _s3_, _s5_
:param config: file pointer that opened for writing board config information
"""
with open(sysnode, 'rb') as f_node:
while True:
inc = f_node.read(1)
if inc:
if hex(int.from_bytes(inc, 'little')) != hex(ACPI_OP['AML_NAME_OP']):
continue
(need_break, need_continue, pkg_len) = read_sx_locate(sx_name, f_node)
if need_break:
break
if need_continue:
continue
# decode sx pkg
(pkg_val_pm1a, pkg_val_pm1b, pkg_val_resv, need_break) =\
decode_sx_pkg(pkg_len, f_node)
if need_break:
break
else:
break
if sx_name == '_S3_':
S3_PKG.val_pm1a = pkg_val_pm1a
S3_PKG.val_pm1b = pkg_val_pm1b
S3_PKG.reserved = pkg_val_resv
print("\t#define S3_PKG_VAL_PM1A {0}".format(
hex(S3_PKG.val_pm1a))+'U', file=config)
print("\t#define S3_PKG_VAL_PM1B {0}".format(
S3_PKG.val_pm1b)+'U', file=config)
print("\t#define S3_PKG_RESERVED {0}".format(
hex(int.from_bytes(S3_PKG.reserved, 'little')))+'U', file=config)
if sx_name == "_S5_":
S5_PKG.val_pm1a = pkg_val_pm1a
S5_PKG.val_pm1b = pkg_val_pm1b
S5_PKG.reserved = pkg_val_resv
print("\t#define S5_PKG_VAL_PM1A {0}".format(
hex(S5_PKG.val_pm1a))+'U', file=config)
print("\t#define S5_PKG_VAL_PM1B {0}".format(
S5_PKG.val_pm1b)+'U', file=config)
print("\t#define S5_PKG_RESERVED {0}".format(
hex(int.from_bytes(S5_PKG.reserved, 'little')))+'U', file=config)
def store_cx_data(sysnode1, sysnode2, config):
"""This will get Cx data of power and store it to PackedCx
:param sysnode1: the path of cx power state driver
:param sysnode2: the path of cpuidle
:param config: file pointer that opened for writing board config information
"""
i = 0
state_cpus = {}
with open(sysnode1, 'r') as acpi_idle:
idle_driver = acpi_idle.read(32)
if idle_driver.find("acpi_idle") == -1:
if idle_driver.find("intel_idle") == 0:
parser_lib.print_red("The tool need to run with acpi_idle driver, " +
"please add intel_idle.max_cstate=0 in kernel " +
"cmdline to fall back to acpi_idle driver", err=True)
else:
parser_lib.print_red("acpi_idle driver is not found.", err=True)
sys.exit(1)
files = os.listdir(sysnode2)
for d_path in files:
if os.path.isdir(sysnode2+d_path):
state_cpus[d_path] = sysnode2+d_path
state_cpus = sorted(state_cpus.keys())
del state_cpus[0]
cpu_state = ['desc', 'latency', 'power']
acpi_hw_type = ['HLT', 'MWAIT', 'IOPORT']
cx_state = defaultdict(dict)
c_cnt = 1
for state in state_cpus:
i += 1
for item in cpu_state:
cx_data_file = open(sysnode2+state+'/'+item, 'r')
cx_state[state][item] = cx_data_file.read().strip()
cx_state[state]['type'] = i
if cx_state[state][cpu_state[0]].find(acpi_hw_type[0]) != -1 or \
cx_state[state][cpu_state[0]].find(acpi_hw_type[1]) != -1:
PackedCx.space_id_8b = SPACE_ID[0x7F]
if cx_state[state][cpu_state[0]].find(acpi_hw_type[0]) != -1:
PackedCx.bit_width_8b = 0
PackedCx.bit_offset_8b = 0
PackedCx.access_size_8b = 0
PackedCx.address_64b = 0
else:
PackedCx.bit_width_8b = 1
PackedCx.bit_offset_8b = 2
PackedCx.access_size_8b = 1
PackedCx.address_64b = cx_state[state][cpu_state[0]].split()[3]
elif cx_state[state][cpu_state[0]].find(acpi_hw_type[2]) != -1:
PackedCx.space_id_8b = SPACE_ID[1]
PackedCx.bit_width_8b = 8
PackedCx.bit_offset_8b = 0
PackedCx.access_size_8b = 0
PackedCx.address_64b = cx_state[state][cpu_state[0]].split()[2]
print("\t{{{{{}, 0x{:0>2X}U, 0x{:0>2X}U, 0x{:0>2X}U, ".format(
PackedCx.space_id_8b, PackedCx.bit_width_8b, PackedCx.bit_offset_8b,
PackedCx.access_size_8b), file=config, end="")
print("0x{:0>2X}UL}}, 0x{:0>2X}U, 0x{:0>2X}U, 0x{:0>2X}U}},\t/* C{} */".format(
int(str(PackedCx.address_64b), 16),
cx_state[state]['type'], int(cx_state[state][cpu_state[1]]),
int(cx_state[state][cpu_state[2]]), c_cnt), file=config)
c_cnt += 1
def store_px_data(sysnode, config):
"""This will get Px data of power and store it to px data
:param sysnode: the path of system power state, such as: /sys/devices/system/cpu/
:param config: file pointer that opened for writing board config information
"""
px_tmp = PxPkg()
px_data = {}
with open(sysnode+'cpu0/cpufreq/scaling_driver', 'r') as f_node:
freq_driver = f_node.read()
if freq_driver.find("acpi-cpufreq") == -1:
if freq_driver.find("intel_pstate") == 0:
parser_lib.print_red("The tool need to run with acpi_cpufreq driver, " +
"please add intel_pstate=disable in kernel cmdline " +
"to fall back to acpi-cpufreq driver.", err=True)
else:
parser_lib.print_red("acpi-cpufreq driver is not found.", err=True)
sys.exit(1)
try:
with open(sysnode+'cpufreq/boost', 'r') as f_node:
boost = f_node.read()
except IOError:
boost = 0
parser_lib.print_yel("CPU turbo is not enabled!")
with open(sysnode + 'cpu0/cpufreq/scaling_available_frequencies', 'r') as f_node:
freqs = f_node.read()
with open(sysnode + 'cpu0/cpufreq/cpuinfo_transition_latency') as f_node:
latency = int(f_node.read().strip())
latency = latency//1000
i = 0
p_cnt = 0
for freq in freqs.split():
if boost != 0 and i == 0:
try:
subprocess.check_call('/usr/sbin/rdmsr 0x1ad', shell=True, stdout=subprocess.PIPE)
except subprocess.CalledProcessError:
parser_lib.print_red("MSR 0x1ad not support in this platform!", err=True)
sys.exit(1)
res = subprocess.Popen('/usr/sbin/rdmsr 0x1ad', shell=True,
stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True)
result = res.stdout.readline().strip()
#max_ratio_cpu = result[-2:]
ctl_state = int(result[-2:], 16) << 8
i += 1
else:
ctl_state = int(freq)//100000 << 8
px_tmp.core_freq = int(int(freq) / 1000)
px_tmp.power = 0
px_tmp.trans_latency = latency
px_tmp.bus_latency = latency
px_tmp.control = ctl_state
px_tmp.status = ctl_state
px_data[freq] = px_tmp
print("\t{{0x{:0>2X}UL, 0x{:0>2X}UL, 0x{:0>2X}UL, ".format(
px_data[freq].core_freq, px_data[freq].power,
px_data[freq].trans_latency), file=config, end="")
print("0x{:0>2X}UL, 0x{:0>6X}UL, 0x{:0>6X}UL}},\t/* P{} */".format(
px_data[freq].bus_latency, px_data[freq].control,
px_data[freq].status, p_cnt), file=config)
p_cnt += 1
def gen_acpi_info(config):
"""This will parser the sys node form SYS_PATH and generate ACPI info
:param config: file pointer that opened for writing board config information
"""
read_pm_sstate(SYS_PATH[1] + 'FACP', config)
print("{0}".format("\t<S3_INFO>"), file=config)
read_pm_sdata(SYS_PATH[1] + 'DSDT', '_S3_', config)
print("{0}".format("\t</S3_INFO>\n"), file=config)
print("{0}".format("\t<S5_INFO>"), file=config)
read_pm_sdata(SYS_PATH[1] + 'DSDT', '_S5_', config)
print("{0}".format("\t</S5_INFO>\n"), file=config)
print("{0}".format("\t<DRHD_INFO>"), file=config)
dmar.write_dmar_data(SYS_PATH[1] + 'DMAR', config)
print("{0}".format("\t</DRHD_INFO>\n"), file=config)
print("{0}".format("\t<CPU_BRAND>"), file=config)
store_cpu_info(SYS_PATH[0], config)
print("{0}".format("\t</CPU_BRAND>\n"), file=config)
print("{0}".format("\t<CX_INFO>"), file=config)
store_cx_data(SYS_PATH[2]+'cpuidle/current_driver', SYS_PATH[2]+'cpu0/cpuidle/', config)
print("{0}".format("\t</CX_INFO>\n"), file=config)
print("{0}".format("\t<PX_INFO>"), file=config)
store_px_data(SYS_PATH[2], config)
print("{0}".format("\t</PX_INFO>\n"), file=config)
def generate_info(board_file):
"""This will generate ACPI info from board file
:param board_file: this is the file which stores the hardware board information
"""
# Generate board info
with open(board_file, 'a+') as config:
gen_acpi_info(config)