config_tools: board_inspector: record all details from RTCT in board XML

Today users still need to manually copy the RTCT binary file when they want
to passthrough software SRAM to a pre-launched RTVM, which is far from
being user friendly.

To get rid of that step, this patch extracts all information from the RTCT
table and format them in the board XML which is the only file users need to
copy from their target platform to build the hypervisor. The patch that
immediately follows will then use such information to generate vRTCT for
the pre-launched VM.

A side effect of this change is that more ranges, which represents those
reported by RTCT such as the CRL binary or the error log area, will be
added to the `memory` section of the board XML. The `id` attributes of
those range will be used to identify what that range is for. As a result,
getting RAM of the physical platform from the board XML requires additional
conditions on the `id` attributes to avoid counting non-RAM regions
unintendedly.

Tracked-On: #7947
Signed-off-by: Junjie Mao <junjie.mao@intel.com>
This commit is contained in:
Junjie Mao 2022-07-29 22:59:39 +08:00 committed by acrnsi-robot
parent d7bac88e5e
commit 89d54aa5d1
4 changed files with 106 additions and 47 deletions

View File

@ -67,39 +67,10 @@ def extract_topology(root_node, caches_node):
return (level, id, type)
caches_node[:] = sorted(caches_node, key=getkey)
def extract_tcc_capabilities(caches_node):
try:
rtct = parse_rtct()
if rtct.version == 1:
for entry in rtct.entries:
if entry.type == acpiparser.rtct.ACPI_RTCT_V1_TYPE_SoftwareSRAM:
cache_node = get_node(caches_node, f"cache[@level='{entry.cache_level}' and processors/processor='{hex(entry.apic_id_tbl[0])}']")
if cache_node is None:
logging.debug(f"Cannot find the level {entry.cache_level} cache of physical processor with apic ID {entry.apic_id_tbl[0]}")
continue
cap = add_child(cache_node, "capability", None, id="Software SRAM")
add_child(cap, "start", "0x{:08x}".format(entry.base))
add_child(cap, "end", "0x{:08x}".format(entry.base + entry.size - 1))
add_child(cap, "size", str(entry.size))
elif rtct.version == 2:
for entry in rtct.entries:
if entry.type == acpiparser.rtct.ACPI_RTCT_V2_TYPE_SoftwareSRAM:
cache_node = get_node(caches_node, f"cache[@level='{entry.level}' and @id='{hex(entry.cache_id)}']")
if cache_node is None:
logging.debug(f"Cannot find the level {entry.level} cache with cache ID {entry.cache_id}")
continue
cap = add_child(cache_node, "capability", None, id="Software SRAM")
add_child(cap, "start", "0x{:08x}".format(entry.base))
add_child(cap, "end", "0x{:08x}".format(entry.base + entry.size - 1))
add_child(cap, "size", str(entry.size))
except FileNotFoundError:
pass
def extract(args, board_etree):
root_node = board_etree.getroot()
caches_node = get_node(board_etree, "//caches")
extract_topology(root_node, caches_node)
extract_tcc_capabilities(caches_node)
# Inject the explicitly specified CAT capability if exists
if args.add_llc_cat:

View File

@ -9,7 +9,7 @@ import re, os, fcntl, errno
import lxml.etree
from extractors.helpers import add_child, get_node
from acpiparser import parse_apic, apic
import acpiparser
DEFAULT_MAX_IOAPIC_LINES = 240
@ -40,16 +40,113 @@ def extract_gsi_number(ioapic_node, apic_id):
def extract_topology(ioapics_node, tables):
for subtable in tables.interrupt_controller_structures:
if subtable.subtype == apic.MADT_TYPE_IO_APIC:
if subtable.subtype == acpiparser.apic.MADT_TYPE_IO_APIC:
apic_id = subtable.io_apic_id
ioapic_node = add_child(ioapics_node, "ioapic", None, id=hex(apic_id))
add_child(ioapic_node, "address", hex(subtable.io_apic_addr))
add_child(ioapic_node, "gsi_base", hex(subtable.global_sys_int_base))
extract_gsi_number(ioapic_node, apic_id)
def extract_tcc_capabilities_from_rtct_v1(board_etree, rtct):
caches_node = get_node(board_etree, "//caches")
for entry in rtct.entries:
if entry.type == acpiparser.rtct.ACPI_RTCT_V1_TYPE_SoftwareSRAM:
cache_node = get_node(caches_node, f"cache[@level='{entry.cache_level}' and processors/processor='{hex(entry.apic_id_tbl[0])}']")
if cache_node is None:
logging.debug(f"Cannot find the level {entry.cache_level} cache of physical processor with apic ID {entry.apic_id_tbl[0]}")
continue
cap = add_child(cache_node, "capability", None, id="Software SRAM")
add_child(cap, "start", "0x{:08x}".format(entry.base))
add_child(cap, "end", "0x{:08x}".format(entry.base + entry.size - 1))
add_child(cap, "size", str(entry.size))
def extract_tcc_capabilities_from_rtct_v2(board_etree, rtct):
def get_or_create_ssram_node(cache_node):
ssram_node = get_node(cache_node, "capability[@id = 'Software SRAM']")
if ssram_node is None:
ssram_node = add_child(cache_node, "capability", None, id="Software SRAM")
return ssram_node
caches_node = get_node(board_etree, "//caches")
memory_node = get_node(board_etree, "//memory")
devices_node = get_node(board_etree, "//devices")
for entry in rtct.entries:
cache_node = None
if hasattr(entry, "level") and hasattr(entry, "cache_id"):
cache_node = get_node(caches_node, f"cache[@level='{entry.level}' and @id='{hex(entry.cache_id)}']")
if cache_node is None:
logging.debug(f"Cannot find the level {entry.level} cache with cache ID {entry.cache_id}")
continue
if entry.type == acpiparser.rtct.ACPI_RTCT_TYPE_COMPATIBILITY:
rtct_version_node = add_child(caches_node, "parameter", None, id="RTCT Version")
add_child(rtct_version_node, "major", str(entry.rtct_version_major))
add_child(rtct_version_node, "minor", str(entry.rtct_version_minor))
rtcd_version_node = add_child(caches_node, "parameter", None, id="RTCD Version")
add_child(rtcd_version_node, "major", str(entry.rtcd_version_major))
add_child(rtcd_version_node, "minor", str(entry.rtcd_version_minor))
elif entry.type == acpiparser.rtct.ACPI_RTCT_V2_TYPE_RTCD_Limits:
add_child(caches_node, "parameter", str(entry.total_ia_l2_clos), id="Total IA L2 CLOS")
add_child(caches_node, "parameter", str(entry.total_ia_l3_clos), id="Total IA L3 CLOS")
add_child(caches_node, "parameter", str(entry.total_l2_instances), id="Total IA L2 Instances")
add_child(caches_node, "parameter", str(entry.total_l3_instances), id="Total IA L2 Instances")
add_child(caches_node, "parameter", str(entry.total_gt_clos), id="Total GT CLOS")
add_child(caches_node, "parameter", str(entry.total_wrc_clos), id="Total WRC CLOS")
add_child(devices_node, "parameter", str(entry.max_tcc_streams), id="Maximum TCC Streams")
add_child(devices_node, "parameter", str(entry.max_tcc_registers), id="Maximum TCC Registers")
elif entry.type == acpiparser.rtct.ACPI_RTCT_V2_TYPE_CRL_Binary:
start = "0x{:016x}".format(entry.address)
end = "0x{:016x}".format(entry.address + entry.size - 1)
size = str(entry.size)
region = add_child(memory_node, "range", None, id="CRL Binary", start=start, end=end, size=size)
elif entry.type == acpiparser.rtct.ACPI_RTCT_V2_TYPE_IA_WayMasks:
cap = add_child(cache_node, "parameter", None, id="IA Waymask")
for waymask in entry.waymask:
add_child(cap, "waymask", hex(waymask))
elif entry.type == acpiparser.rtct.ACPI_RTCT_V2_TYPE_WRC_WayMasks:
cap = add_child(cache_node, "parameter", None, id="WRC Waymask")
add_child(cap, "waymask", hex(entry.waymask))
elif entry.type == acpiparser.rtct.ACPI_RTCT_V2_TYPE_GT_WayMasks:
cap = add_child(cache_node, "parameter", None, id="GT Waymask")
for waymask in entry.waymask:
add_child(cap, "waymask", hex(waymask))
elif entry.type == acpiparser.rtct.ACPI_RTCT_V2_TYPE_SSRAM_WayMask:
ssram_node = get_or_create_ssram_node(cache_node)
add_child(ssram_node, "waymask", hex(entry.waymask))
elif entry.type == acpiparser.rtct.ACPI_RTCT_V2_TYPE_SoftwareSRAM:
ssram_node = get_or_create_ssram_node(cache_node)
add_child(ssram_node, "start", "0x{:08x}".format(entry.base))
add_child(ssram_node, "end", "0x{:08x}".format(entry.base + entry.size - 1))
add_child(ssram_node, "size", str(entry.size))
elif entry.type == acpiparser.rtct.ACPI_RTCT_V2_TYPE_MemoryHierarchyLatency:
for cache_id in entry.cache_id:
cache_node = get_node(caches_node, f"cache[@level='{entry.hierarchy}' and @id='{hex(cache_id)}']")
if cache_node is None:
logging.debug(f"Cannot find the level {entry.hierarchy} cache with cache ID {cache_id}")
continue
param = add_child(cache_node, "parameter", None, id="Worst Case Access Latency")
add_child(param, "native", str(entry.clock_cycles))
elif entry.type == acpiparser.rtct.ACPI_RTCT_V2_TYPE_ErrorLogAddress:
start = "0x{:016x}".format(entry.address)
end = "0x{:016x}".format(entry.address + entry.size - 1)
size = str(entry.size)
region = add_child(memory_node, "range", None, id="TCC Error Log", start=start, end=end, size=size)
def extract_tcc_capabilities(board_etree):
try:
rtct = acpiparser.parse_rtct()
if rtct.version == 1:
extract_tcc_capabilities_from_rtct_v1(board_etree, rtct)
elif rtct.version == 2:
extract_tcc_capabilities_from_rtct_v2(board_etree, rtct)
except FileNotFoundError:
pass
def extract(args, board_etree):
try:
tables = parse_apic()
tables = acpiparser.parse_apic()
except Exception as e:
logging.warning(f"Parse ACPI tables failed: {str(e)}")
logging.warning(f"Will not extract information from ACPI tables")
@ -57,3 +154,5 @@ def extract(args, board_etree):
ioapics_node = get_node(board_etree, "//ioapics")
extract_topology(ioapics_node, tables)
extract_tcc_capabilities(board_etree)

View File

@ -656,12 +656,3 @@ def generate_info(board_file):
# Generate board info
with open(board_file, 'a+') as config:
gen_acpi_info(config)
# get the PTCT/RTCT table from native environment
out_dir = os.path.dirname(board_file)
if os.path.isfile(SYS_PATH[1] + 'PTCT'):
shutil.copy(SYS_PATH[1] + 'PTCT', out_dir if out_dir != "" else "./")
logging.info("PTCT table has been saved to {} successfully!".format(os.path.join(out_dir, 'PTCT')))
if os.path.isfile(SYS_PATH[1] + 'RTCT'):
shutil.copy(SYS_PATH[1] + 'RTCT', out_dir if out_dir != "" else "./")
logging.info("RTCT table has been saved to {} successfully!".format(os.path.join(out_dir, 'RTCT')))

View File

@ -13,12 +13,10 @@ import common, math, logging
def import_memory_info(board_etree):
ram_range = {}
start = board_etree.xpath("/acrn-config/memory/range/@start")
size = board_etree.xpath("/acrn-config/memory/range/@size")
for i in range(len(start)):
start_hex = int(start[i], 16)
size_hex = int(size[i], 10)
ram_range[start_hex] = size_hex
for memory_range in board_etree.xpath("/acrn-config/memory/range[not(@id) or @id = 'RAM']"):
start = int(memory_range.get("start"), base=16)
size = int(memory_range.get("size"), base=10)
ram_range[start] = size
return ram_range