acrn-config: generate board information on target board

These tools run on the target board and genearate board information.

usage: python3 board_parser.py <board_name> [--out board_info_file]

sample:
	$ sudo python3 board_parser.py apl-up2

v1-v2:
1. allow board parameter for new board

v2-v3:
1. add the usage descriptions for tools
2. add description of kernel cmd line for README
3. output informations to a xml type
4. 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:00:54 +08:00 committed by ACRN System Integration
parent 107c406baa
commit 8adefe26ac
8 changed files with 1275 additions and 0 deletions

View File

@ -0,0 +1,13 @@
board_parser.py will collect all board related info and then generate a board info file for acrn-config host tool usage.
usage: python3 board_parser.py <board_name> [--out board_info_file]
board_name : the name of board that run ACRN hypervisor, like apl-up2/nuc7i7dnb. It will be used as name of the board configurations folder which created by acrn-config host tool.
board_info_file : (optional) the name of board info file. if it is not specified, a name of <board_name>.xml will be generated under ./out/ folder by default.
Please run this script under native Linux environment with root privilege.
OS requirement:
Release: Ubuntu 18.04+ or ClearLinux 30210+
Tools: cpuid, rdmsr, lspci, dmidecode
kernel cmdline: "idle=nomwait intel_idle.max_cstate=0 intel_pstate=disable"

View File

@ -0,0 +1,529 @@
# 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 from /proc/cpuifo"""
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\t"{0}"'.format(model_name), file=config)
break
line = f_node.readline()
def write_reset_reg(space_id, rst_reg_addr, rst_reg_space_id, rst_reg_val, config):
"""Write reset register info"""
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 reg value"""
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(SPACE_ID, 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"""
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"""
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"""
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):
"""Parser and decode the sx pkg"""
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"""
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"""
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)
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\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}},".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]])), file=config)
def store_px_data(sysnode, config):
"""This will get Px data of power and store it to px data"""
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\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}}, /* 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(board_fp):
"""This will parser the sys node form SYS_PATH and generate ACPI info"""
read_pm_sstate(SYS_PATH[1] + 'FACP', board_fp)
print("{0}".format("\t<S3_INFO>"), file=board_fp)
read_pm_sdata(SYS_PATH[1] + 'DSDT', '_S3_', board_fp)
print("{0}".format("\t</S3_INFO>\n"), file=board_fp)
print("{0}".format("\t<S5_INFO>"), file=board_fp)
read_pm_sdata(SYS_PATH[1] + 'DSDT', '_S5_', board_fp)
print("{0}".format("\t</S5_INFO>\n"), file=board_fp)
print("{0}".format("\t<DRHD_INFO>"), file=board_fp)
dmar.write_dmar_data(SYS_PATH[1] + 'DMAR', board_fp)
print("{0}".format("\t</DRHD_INFO>\n"), file=board_fp)
print("{0}".format("\t<CPU_BRAND>"), file=board_fp)
store_cpu_info(SYS_PATH[0], board_fp)
print("{0}".format("\t</CPU_BRAND>\n"), file=board_fp)
print("{0}".format("\t<CX_INFO>"), file=board_fp)
store_cx_data(SYS_PATH[2]+'cpuidle/current_driver', SYS_PATH[2]+'cpu0/cpuidle/', board_fp)
print("{0}".format("\t</CX_INFO>\n"), file=board_fp)
print("{0}".format("\t<PX_INFO>"), file=board_fp)
store_px_data(SYS_PATH[2], board_fp)
print("{0}".format("\t</PX_INFO>\n"), file=board_fp)
def generate_info(board_file):
"""This will generate ACPI info from board file"""
# Generate board info
with open(board_file, 'a+') as board_info:
gen_acpi_info(board_info)

View File

@ -0,0 +1,142 @@
# Copyright (C) 2019 Intel Corporation. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
import os
import sys
import shutil
import argparse
import subprocess
import parser_lib
import pci_dev
import dmi
import acpi
import clos
OUTPUT = "./out/"
PY_CACHE = "__pycache__"
# This file store information which query from hw board
BIN_LIST = ['cpuid', 'rdmsr', 'lspci', ' dmidecode']
PCI_IDS = ["/usr/share/hwdata/pci.ids", "/usr/share/misc/pci.ids"]
CPU_VENDOR = "GenuineIntel"
def check_permission():
"""Check if it is root permission"""
if os.getuid():
parser_lib.print_red("You need run with sudo!")
sys.exit(1)
def native_check():
"""Check if this is natvie os"""
cmd = "cpuid -r -l 0x01"
res = parser_lib.cmd_excute(cmd)
while True:
line = parser_lib.decode_stdout(res)
if line:
if len(line.split()) <= 2:
continue
reg_value = line.split()[4].split('=')[1]
break
return int(reg_value, 16) & 0x80000000 == 0
def vendor_check():
"""Check the CPU vendor"""
with open("/proc/cpuinfo", 'r') as f_node:
while True:
line = f_node.readline()
if len(line.split(':')) == 2:
if line.split(':')[0].strip() == "vendor_id":
vendor_name = line.split(':')[1].strip()
return vendor_name != CPU_VENDOR
def check_env():
"""Check if there is appropriate environment on this system"""
if os.path.exists(PY_CACHE):
shutil.rmtree(PY_CACHE)
# check cpu vendor id
if vendor_check():
parser_lib.print_red("Please run this tools on {}!".format(CPU_VENDOR))
sys.exit(1)
# check if required tools are exists
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:
parser_lib.print_yel("'{}' not found, please install it!".format(excute))
sys.exit(1)
if excute == 'cpuid':
res = subprocess.Popen("cpuid -v",
shell=True, stdout=subprocess.PIPE,
stderr=subprocess.PIPE, close_fds=True)
line = res.stdout.readline().decode('ascii')
version = line.split()[2]
if int(version) < 20170122:
parser_lib.print_yel("Need CPUID version >= 20170122")
sys.exit(1)
if not native_check():
parser_lib.print_red("Please run this tools on natvie OS!")
sys.exit(1)
if not os.path.exists(PCI_IDS[0]) and not os.path.exists(PCI_IDS[1]):
parser_lib.print_yel("pci.ids not found, please make sure lspci is installed correctly!")
sys.exit(1)
if os.path.exists(OUTPUT):
shutil.rmtree(OUTPUT)
if __name__ == '__main__':
check_permission()
check_env()
# arguments to parse
PARSER = argparse.ArgumentParser(usage='%(prog)s <board_name> [--out board_info_file]')
PARSER.add_argument('board_name', help=": the name of board that run ACRN hypervisor")
PARSER.add_argument('--out', help=": the name of board info file.")
ARGS = PARSER.parse_args()
if not ARGS.out:
os.makedirs(OUTPUT)
BOARD_INFO = OUTPUT + ARGS.board_name + ".xml"
else:
BOARD_INFO = ARGS.out
with open(BOARD_INFO, 'w+') as f:
print('<acrn-config board="{}">'.format(ARGS.board_name), file=f)
# Get bios and base board info and store to board info
dmi.generate_info(BOARD_INFO)
# Get pci devicse table and store pci info to board info
pci_dev.generate_info(BOARD_INFO)
# Generate board info
acpi.generate_info(BOARD_INFO)
# Generate clos info
clos.generate_info(BOARD_INFO)
with open(BOARD_INFO, 'a+') as f:
print("</acrn-config>", file=f)
print("{} is generaged successfully!".format(BOARD_INFO))

View File

@ -0,0 +1,81 @@
# Copyright (C) 2019 Intel Corporation. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
import parser_lib
CACHE_TYPE = {
"L2":4,
"L3":2
}
def execute(cmd, reg):
"""Execute the cmd"""
cache_t = ''
res = parser_lib.cmd_excute(cmd)
if reg == "ebx":
idx = 3
if reg == "edx":
idx = 5
while True:
line = parser_lib.decode_stdout(res)
if not line:
break
if len(line.split()) <= 2:
continue
reg_value = line.split()[idx].split('=')[1]
if reg == "ebx":
if int(reg_value, 16) & CACHE_TYPE['L2'] != 0:
cache_t = "L2"
break
elif int(reg_value, 16) & CACHE_TYPE['L3'] != 0:
cache_t = "L3"
break
else:
cache_t = False
break
elif reg == "edx":
cache_t = int(reg_value, 16) + 1
break
return cache_t
def get_clos_info():
"""Get clos max and clos cache type"""
clos_max = 0
clos_cache = False
cmd = "cpuid -r -l 0x10"
clos_cache = execute(cmd, "ebx")
if clos_cache == "L2":
cmd = "cpuid -r -l 0x10 --subleaf 2"
elif clos_cache == "L3":
cmd = "cpuid -r -l 0x10 --subleaf 1"
else:
clos_max = 0
parser_lib.print_yel("CLOS is not supported!")
return (clos_cache, clos_max)
clos_max = execute(cmd, "edx")
return (clos_cache, clos_max)
def generate_info(board_info):
"""Generate clos information"""
(clos_cache, clos_max) = get_clos_info()
with open(board_info, 'a+') as board_fp:
print("\t<CLOS_INFO>", file=board_fp)
print("\tclos supported by cache:{}".format(clos_cache), file=board_fp)
print("\tclos max:{}".format(clos_max), file=board_fp)
print("\t</CLOS_INFO>\n", file=board_fp)

View File

@ -0,0 +1,364 @@
# Copyright (C) 2019 Intel Corporation. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
import ctypes
ACPI_DMAR_TYPE = {
'ACPI_DMAR_TYPE_HARDWARE_UNIT':0,
'ACPI_DMAR_TYPE_RESERVED_MEMORY':1,
'ACPI_DMAR_TYPE_ROOT_ATS':2,
'ACPI_DMAR_TYPE_HARDWARE_AFFINITY':3,
'ACPI_DMAR_TYPE_NAMESPACE':4,
'ACPI_DMAR_TYPE_RESERVED':5,
}
ACPI_DEV_SCOPE_TYPE = {
'ACPI_DMAR_SCOPE_TYPE_NOT_USED':0,
'ACPI_DMAR_SCOPE_TYPE_ENDPOINT':1,
'ACPI_DMAR_SCOPE_TYPE_BRIDGE':2,
'ACPI_DMAR_SCOPE_TYPE_IOAPIC':3,
'ACPI_DMAR_SCOPE_TYPE_HPET':4,
'ACPI_DMAR_SCOPE_TYPE_NAMESPACE':5,
'ACPI_DMAR_SCOPE_TYPE_RESERVED':6,
}
class DmarHeader(ctypes.Structure):
"""DMAR Header"""
_pack_ = 1
_fields_ = [
('signature', ctypes.c_char*4),
('length', ctypes.c_uint32),
('revision', ctypes.c_ubyte),
('checksum', ctypes.c_ubyte),
('oem_id', ctypes.c_char*6),
('oem_table_id', ctypes.c_char*8),
('oem_revision', ctypes.c_uint32),
('asl_compiler_id', ctypes.c_char*4),
('asl_compiler_revision', ctypes.c_uint32),
('host_addr_width', ctypes.c_ubyte),
('flags', ctypes.c_ubyte),
('reserved', ctypes.c_ubyte*10),
]
def style_check_1(self):
"""Style check if have public method"""
self._pack_ = 0
def style_check_2(self):
"""Style check if have public method"""
self._pack_ = 0
class DmarSubtblHeader(ctypes.Structure):
"""DMAR Sub Table Header"""
_pack_ = 1
_fields_ = [
('type', ctypes.c_uint16),
('length', ctypes.c_uint16),
]
def style_check_1(self):
"""Style check if have public method"""
self._pack_ = 0
def style_check_2(self):
"""Style check if have public method"""
self._pack_ = 0
class DmarDevScope(ctypes.Structure):
"""DMAR Device Scope"""
_pack_ = 1
_fields_ = [
('entry_type', ctypes.c_uint8),
('scope_length', ctypes.c_uint8),
('reserved', ctypes.c_uint16),
('enumeration_id', ctypes.c_uint8),
('bus', ctypes.c_uint8),
]
def style_check_1(self):
"""Style check if have public method"""
self._pack_ = 0
def style_check_2(self):
"""Style check if have public method"""
self._pack_ = 0
class DmarHwUnit(ctypes.Structure):
"""DMAR Hardware Unit"""
_pack_ = 1
_fields_ = [
('sub_header', DmarSubtblHeader),
('flags', ctypes.c_uint8),
('reserved', ctypes.c_uint8),
('segment', ctypes.c_uint16),
('address', ctypes.c_uint64),
]
def style_check_1(self):
"""Style check if have public method"""
self._pack_ = 0
def style_check_2(self):
"""Style check if have public method"""
self._pack_ = 0
class DevScopePath(ctypes.Structure):
"""DEVICE Scope Path"""
_pack_ = 1
_fields_ = [
("device", ctypes.c_uint8),
("function", ctypes.c_uint8),
]
def style_check_1(self):
"""Style check if have public method"""
self._pack_ = 0
def style_check_2(self):
"""Style check if have public method"""
self._pack_ = 0
def map_file(sysnode):
"""Map sys node to memory address"""
data = open(sysnode, 'rb').read()
buf = ctypes.create_string_buffer(data, len(data))
addr = ctypes.addressof(buf)
return addr
class DmarHwList:
"""DMAR HW List"""
def __init__(self):
self.hw_segment_list = []
self.hw_flags_list = []
self.hw_address_list = []
self.hw_ignore = {}
def style_check_1(self):
"""Style check if have public method"""
self.hw_ignore = {}
def style_check_2(self):
"""Style check if have public method"""
self.hw_ignore = {}
class DmarDevList:
"""DMAR DEV List"""
def __init__(self):
self.dev_scope_cnt_list = []
self.dev_bus_list = []
self.dev_path_list = []
self.dev_ioapic = {}
def style_check_1(self):
"""Style check if have public method"""
self.dev_bus_list = []
def style_check_2(self):
"""Style check if have public method"""
self.dev_bus_list = []
class DmarTbl:
"""DMAR TBL"""
def __init__(self):
self.sub_tbl_offset = 0
self.dmar_drhd = 0
self.dmar_dev_scope = 0
self.dev_scope_offset = 0
self.dev_scope_cnt = 0
self.path_offset = 0
def style_check_1(self):
"""Style check if have public method"""
self.path_offset = 0
def style_check_2(self):
"""Style check if have public method"""
self.path_offset = 0
class PathDevFun:
"""Path Device Function meta data"""
def __init__(self):
self.path = 0
self.device = 0
self.function = 0
def style_check_1(self):
"""Style check if have public method"""
self.path = 0
def style_check_2(self):
"""Style check if have public method"""
self.path = 0
def walk_pci_bus(tmp_pdf, dmar_tbl, dmar_hw_list, n_cnt, drhd_cnt):
"""Walk Pci bus"""
while n_cnt:
scope_path = DevScopePath.from_address(dmar_tbl.path_offset)
tmp_pdf.device = scope_path.device
tmp_pdf.function = scope_path.function
tmp_pdf.path = (((tmp_pdf.device & 0x1F) << 3) | ((tmp_pdf.function & 0x7)))
dmar_tbl.path_offset += ctypes.sizeof(DevScopePath)
n_cnt -= 1
# this not support to warning if no dedicated iommu for gpu
if ((dmar_tbl.dmar_drhd.segment << 16) | (
dmar_tbl.dmar_dev_scope.bus << 8) | scope_path.function) == 0x10:
dmar_hw_list.hw_ignore[drhd_cnt] = 'true'
else:
dmar_hw_list.hw_ignore[drhd_cnt] = 'false'
return (tmp_pdf, dmar_tbl, dmar_hw_list)
def walk_dev_scope(dmar_tbl, dmar_dev_list, dmar_hw_list, drhd_cnt):
"""Walk device scope"""
dmar_tbl.dev_scope_offset = dmar_tbl.sub_tbl_offset + ctypes.sizeof(DmarHwUnit)
scope_end = dmar_tbl.dev_scope_offset + dmar_tbl.dmar_drhd.sub_header.length
dmar_tbl.dev_scope_cnt = 0
while dmar_tbl.dev_scope_offset < scope_end:
dmar_tbl.dmar_dev_scope = DmarDevScope.from_address(dmar_tbl.dev_scope_offset)
if dmar_tbl.dmar_dev_scope.scope_length <= 0:
break
if dmar_tbl.dmar_dev_scope.entry_type != \
ACPI_DEV_SCOPE_TYPE['ACPI_DMAR_SCOPE_TYPE_NOT_USED'] and \
dmar_tbl.dmar_dev_scope.entry_type < \
ACPI_DEV_SCOPE_TYPE['ACPI_DMAR_SCOPE_TYPE_RESERVED']:
dmar_tbl.dev_scope_cnt += 1
# path offset is in end of device spcope
dmar_tbl.path_offset = dmar_tbl.dev_scope_offset + ctypes.sizeof(DmarDevScope)
# walk the pci bus with path deep, and find the {Device,Function}
tmp_pdf = PathDevFun()
n_cnt = (dmar_tbl.dmar_dev_scope.scope_length - ctypes.sizeof(DmarDevScope)) // 2
(tmp_pdf, dmar_tbl, dmar_hw_list) = walk_pci_bus(tmp_pdf, dmar_tbl, dmar_hw_list,
n_cnt, drhd_cnt)
dmar_dev_list.dev_bus_list.append(dmar_tbl.dmar_dev_scope.bus)
dmar_dev_list.dev_path_list.append(tmp_pdf.path)
# if the scope entry type is ioapic, should address enumeration id
if dmar_tbl.dmar_dev_scope.entry_type ==\
ACPI_DEV_SCOPE_TYPE['ACPI_DMAR_SCOPE_TYPE_IOAPIC']:
dmar_dev_list.dev_ioapic[drhd_cnt] = dmar_tbl.dmar_dev_scope.enumeration_id
dmar_tbl.dev_scope_offset += dmar_tbl.dmar_dev_scope.scope_length
return (dmar_tbl, dmar_dev_list, dmar_hw_list)
def walk_dmar_table(dmar_tbl, dmar_hw_list, dmar_dev_list, sysnode):
"""Walk dmar table and get information"""
data = open(sysnode, 'rb').read()
buf = ctypes.create_string_buffer(data, len(data))
addr = ctypes.addressof(buf)
# contain the dmar tbl_header
dmar_tbl_header = DmarHeader.from_address(addr)
# cytpes.c_int16.from_address(addr) reade int16 from ad1
# in end of tbl header is remapping structure(DRHD/sub tbl)
dmar_tbl.sub_tbl_offset = addr + ctypes.sizeof(DmarHeader)
drhd_cnt = 0
while True:
sub_dmar = DmarSubtblHeader.from_address(dmar_tbl.sub_tbl_offset)
sub_dmar_type = sub_dmar.type
sub_dmar_len = sub_dmar.length
if dmar_tbl.sub_tbl_offset - addr >= dmar_tbl_header.length:
break
if sub_dmar_type != ACPI_DMAR_TYPE['ACPI_DMAR_TYPE_HARDWARE_UNIT']:
dmar_tbl.sub_tbl_offset += sub_dmar.length
continue
# get one DRHD type in sub table
dmar_tbl.dmar_drhd = DmarHwUnit.from_address(dmar_tbl.sub_tbl_offset)
dmar_hw_list.hw_segment_list.append(dmar_tbl.dmar_drhd.segment)
dmar_hw_list.hw_flags_list.append(dmar_tbl.dmar_drhd.flags)
dmar_hw_list.hw_address_list.append(dmar_tbl.dmar_drhd.address)
# in end of DRHD/sub tbl header is devscope
(dmar_tbl, dmar_dev_list, dmar_hw_list) = walk_dev_scope(
dmar_tbl, dmar_dev_list, dmar_hw_list, drhd_cnt)
dmar_dev_list.dev_scope_cnt_list.append(dmar_tbl.dev_scope_cnt)
drhd_cnt += 1
dmar_tbl.sub_tbl_offset += sub_dmar_len
return (dmar_tbl, dmar_hw_list, dmar_dev_list, drhd_cnt)
def write_dmar_data(sysnode, config):
"""Write the DMAR data to board info"""
dmar_hw_list = DmarHwList()
dmar_dev_list = DmarDevList()
dmar_tbl = DmarTbl()
(dmar_tbl, dmar_hw_list, dmar_dev_list, drhd_cnt) = walk_dmar_table(
dmar_tbl, dmar_hw_list, dmar_dev_list, sysnode)
# num drhd and scope are hard coded
drhd_num = 4
scope_num = 4
# padding dev_scope_cnt_list
j = 0
if len(dmar_dev_list.dev_scope_cnt_list) < scope_num:
for j in range(scope_num - dmar_dev_list.dev_scope_cnt_list[j]):
dmar_dev_list.dev_scope_cnt_list.append(0)
# padding dev_bus_list/dev_path_list
for i in range(drhd_num):
for scope_level in range(scope_num - dmar_dev_list.dev_scope_cnt_list[i]):
dmar_dev_list.dev_path_list.insert(i * 4 + dmar_dev_list.dev_scope_cnt_list[i], 0)
dmar_dev_list.dev_bus_list.insert(i * 4 + dmar_dev_list.dev_scope_cnt_list[i], 0)
scope_level = scope_level
# padding the drhd count from hard code drhd_num
for i in range(drhd_num - drhd_cnt):
dmar_dev_list.dev_scope_cnt_list.append(0)
dmar_hw_list.hw_segment_list.append(0)
dmar_hw_list.hw_flags_list.append(0)
dmar_hw_list.hw_address_list.append(0)
dmar_hw_list.hw_ignore[drhd_cnt + i] = 'false'
# output the DRHD macro
print("\t#define DRHD_COUNT {0}U".format(drhd_cnt), file=config)
for drhd_hw_i in range(drhd_num):
print("\t#define DRHD"+str(drhd_hw_i)+"_DEV_CNT {0}U".format(
dmar_dev_list.dev_scope_cnt_list[drhd_hw_i]), file=config)
print("\t#define DRHD"+str(drhd_hw_i)+"_SEGMENT {0}U".format(
dmar_hw_list.hw_segment_list[drhd_hw_i]), file=config)
print("\t#define DRHD"+str(drhd_hw_i)+"_FLAGS {0}U".format(
dmar_hw_list.hw_flags_list[drhd_hw_i]), file=config)
print("\t#define DRHD"+str(drhd_hw_i)+"_REG_BASE 0x{:0>2X}UL".format(
dmar_hw_list.hw_address_list[drhd_hw_i]), file=config)
if drhd_hw_i in dmar_hw_list.hw_ignore.keys():
print("\t#define DRHD"+str(drhd_hw_i)+"_IGNORE {0}".format(
dmar_hw_list.hw_ignore[drhd_hw_i]), file=config)
for dev_scope_i in range(scope_num):
print("\t#define DRHD"+str(drhd_hw_i)+"_DEVSCOPE"+str(dev_scope_i),
file=config, end="")
print("_BUS {0}U".format(hex(
dmar_dev_list.dev_bus_list[drhd_hw_i * scope_num + dev_scope_i])),
file=config)
print("\t#define DRHD"+str(drhd_hw_i)+"_DEVSCOPE"+str(dev_scope_i),
file=config, end="")
print("_PATH {0}U".format(hex(
dmar_dev_list.dev_path_list[drhd_hw_i * scope_num + dev_scope_i])),
file=config)
if drhd_hw_i in dmar_dev_list.dev_ioapic.keys():
print("\t#define DRHD"+str(drhd_hw_i)+"_IOAPIC_ID {0}U".format(
dmar_dev_list.dev_ioapic[drhd_hw_i]), file=config)

View File

@ -0,0 +1,20 @@
# Copyright (C) 2019 Intel Corporation. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
import parser_lib
CMDS = {
'BIOS_INFO':"dmidecode -t 0",
'BASE_BOARD_INFO':"dmidecode -t 2",
}
def generate_info(board_info):
"""Get bios and base board information"""
with open(board_info, 'a+') as config:
parser_lib.dump_excute(CMDS['BIOS_INFO'], 'BIOS_INFO', config)
print("", file=config)
parser_lib.dump_excute(CMDS['BASE_BOARD_INFO'], 'BASE_BOARD_INFO', config)
print("", file=config)

View File

@ -0,0 +1,106 @@
# Copyright (C) 2019 Intel Corporation. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
import os
import subprocess
BIOS_INFO_KEY = ['BIOS Information', 'Vendor:', 'Version:', 'Release Date:', 'BIOS Revision:']
BASE_BOARD_KEY = ['Base Board Information', 'Manufacturer:', 'Product Name:', 'Version:']
def check_dmi():
"""Check if this tool run on native os"""
return os.path.exists("/sys/firmware/dmi")
def print_yel(msg, warn=False):
"""Print the msg wiht 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 msg wiht color of red"""
if err:
print("\033[1;31mError\033[0m:"+msg)
else:
print("\033[1;31m{0}\033[0m".format(msg))
def decode_stdout(resource):
"""Decode stdout"""
line = resource.stdout.readline().decode('ascii')
return line
def handle_hw_info(line, hw_info):
"""handle the hardware information"""
for board_line in hw_info:
if board_line == " ".join(line.split()[0:1]) or \
board_line == " ".join(line.split()[0:2]) or \
board_line == " ".join(line.split()[0:3]):
return True
return False
def handle_pci_dev(line):
"""Handle if it is pci line"""
if "Region" in line and "Memory at" in line:
return True
if line != '\n':
if line.split()[0][2:3] == ':' and line.split()[0][5:6] == '.':
return True
return False
def cmd_excute(cmd):
"""Excute cmd and retrun raw"""
res = subprocess.Popen(cmd, shell=True,
stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True)
return res
def dump_excute(cmd, desc, config):
"""Execute cmd and get information"""
val_dmi = check_dmi()
print("\t<{0}>".format(desc), file=config)
if not val_dmi and "dmidecode" in cmd:
print("\t\t</{0}>".format(desc), file=config)
return
res = cmd_excute(cmd)
while True:
line = res.stdout.readline().decode('ascii')
if not line:
break
if desc == "PCI_DEVICE":
if "prog-if" in line:
line = line.rsplit('(', 1)[0] + '\n'
ret = handle_pci_dev(line)
if not ret:
continue
if desc == "BIOS_INFO":
ret = handle_hw_info(line, BIOS_INFO_KEY)
if not ret:
continue
if desc == "BASE_BOARD_INFO":
ret = handle_hw_info(line, BASE_BOARD_KEY)
if not ret:
continue
print("\t{}".format(line.strip()), file=config)
print("\t</{0}>".format(desc), file=config)

View File

@ -0,0 +1,20 @@
# Copyright (C) 2019 Intel Corporation. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
import parser_lib
CMDS = {
'PCI_DEVICE':"lspci -vv",
'PCI_VID_PID':"lspci -n",
}
def generate_info(board_info):
"""Get the pci info"""
with open(board_info, 'a+') as config:
parser_lib.dump_excute(CMDS['PCI_DEVICE'], 'PCI_DEVICE', config)
print("", file=config)
parser_lib.dump_excute(CMDS['PCI_VID_PID'], 'PCI_VID_PID', config)
print("", file=config)