Tests: Decouple Hypervisor and SPMC test drivers
Going forward it is intended to support a test set-up that encompasses
the Hypervisor and the SPMC. This patch intends to facilitate the
support of such test set-up. Added arguments to the script that are
specific to Hypervisor or SPMC driver, and slightly refactored the
FVP driver so that they can be used simultaneously.
Change-Id: Ic83f09bcb873d4cdea88ec1d1a7268d322816ba3
Signed-off-by: J-Alves <joao.alves@arm.com>
diff --git a/test/hftest/hftest.py b/test/hftest/hftest.py
index fde1bd8..c4fe016 100755
--- a/test/hftest/hftest.py
+++ b/test/hftest/hftest.py
@@ -63,6 +63,8 @@
def join_if_not_None(*args):
return " ".join(filter(lambda x: x, args))
+DT = collections.namedtuple("DT", ["dts", "dtb"])
+
class ArtifactsManager:
"""Class which manages folder with test artifacts."""
@@ -115,7 +117,8 @@
# This is to avoid having to pass arguments from subclasses to superclasses.
DriverArgs = collections.namedtuple("DriverArgs", [
"artifacts",
- "kernel",
+ "hypervisor",
+ "spmc",
"initrd",
"vm_args",
"cpu",
@@ -208,7 +211,7 @@
"-machine", "virt,virtualization=on,gic-version=3",
"-cpu", cpu, "-smp", "4", "-m", "1G",
"-nographic", "-nodefaults", "-serial", "stdio",
- "-d", "unimp", "-kernel", os.path.abspath(self.args.kernel),
+ "-d", "unimp", "-kernel", os.path.abspath(self.args.hypervisor),
]
if self.tfa:
@@ -278,13 +281,13 @@
def create_dt(self, run_name : str):
"""Create DT related files, and return respective paths in a tuple
(dts,dtb)"""
- return self.args.artifacts.create_file(run_name, ".dts"), \
- self.args.artifacts.create_file(run_name, ".dtb")
+ return DT(self.args.artifacts.create_file(run_name, ".dts"),
+ self.args.artifacts.create_file(run_name, ".dtb"))
- def compile_dt(self, run_state, dts_path, dtb_path):
+ def compile_dt(self, run_state, dt : DT):
"""Compile DT calling dtc."""
dtc_args = [
- DTC_SCRIPT, "compile", "-i", dts_path, "-o", dtb_path,
+ DTC_SCRIPT, "compile", "-i", dt.dts, "-o", dt.dtb,
]
self.exec_logged(run_state, dtc_args)
@@ -310,14 +313,14 @@
return manifests
@abstractmethod
- def gen_dts(self, dts_path, test_args):
+ def gen_dts(self, dt, test_args):
"""Abstract method to generate dts file. This specific to the use case
so should be implemented within derived driver"""
pass
@abstractmethod
def gen_fvp_args(
- self, is_long_running, uart0_log_path, uart1_log_path, dtb_path):
+ self, is_long_running, uart0_log_path, uart1_log_path, dt):
"""Generate command line arguments for FVP."""
time_limit = "80s" if is_long_running else "40s"
fvp_args = [
@@ -356,8 +359,6 @@
"-C", f"cluster1.cpu3.RVBAR={self.CPU_START_ADDRESS}",
"--data",
f"cluster0.cpu0={self.FVP_PREBUILT_BL31}@{self.CPU_START_ADDRESS}",
- "--data", f"cluster0.cpu0={dtb_path}@{self.DTB_ADDRESS}",
- "--data", f"cluster0.cpu0={self.args.kernel}@{self.KERNEL_ADDRESS}",
"-C", "bp.ve_sysregs.mmbSiteDefault=0",
"-C", "bp.ve_sysregs.exit_on_shutdown=1",
]
@@ -366,15 +367,15 @@
def run(self, run_name, test_args, is_long_running):
""" Run test """
run_state = self.start_run(run_name)
- dts_path, dtb_path = self.create_dt(run_name)
+ dt = self.create_dt(run_name)
uart0_log_path = self.create_uart_log(run_name, ".uart0.log")
uart1_log_path = self.create_uart_log(run_name, ".uart1.log")
try:
- self.gen_dts(dts_path, test_args)
- self.compile_dt(run_state, dts_path, dtb_path)
+ self.gen_dts(dt, test_args)
+ self.compile_dt(run_state, dt)
fvp_args = self.gen_fvp_args(is_long_running, uart0_log_path,
- uart1_log_path, dtb_path)
+ uart1_log_path, dt)
self.exec_logged(run_state, fvp_args)
except DriverRunException:
pass
@@ -414,12 +415,12 @@
def KERNEL_ADDRESS(self):
return "0x80000000"
- def gen_dts(self, dts_path, test_args):
+ def gen_dts(self, dt, test_args):
"""Create a DeviceTree source which will be compiled into a DTB and
passed to FVP for a test run."""
vm_args = join_if_not_None(self.args.vm_args, test_args)
- write_file(dts_path, read_file(FVP_PREBUILT_DTS))
+ write_file(dt.dts, read_file(FVP_PREBUILT_DTS))
# Write the vm arguments to the partition manifest
to_append = f"""
@@ -434,14 +435,18 @@
if self.vms_in_partitions_json:
to_append += self.get_manifests_from_json(self.args.partitions["VMs"])
- append_file(dts_path, to_append)
+ append_file(dt.dts, to_append)
def gen_fvp_args(
- self, is_long_running, uart0_log_path, uart1_log_path, dtb_path):
+ self, is_long_running, uart0_log_path, uart1_log_path, dt, call_super = True):
"""Generate command line arguments for FVP."""
+ common_args = (is_long_running, uart0_log_path, uart1_log_path, dt)
+ fvp_args = super().gen_fvp_args(*common_args) if call_super else []
- fvp_args = super().gen_fvp_args(
- is_long_running, uart0_log_path, uart1_log_path, dtb_path)
+ fvp_args += [
+ "--data", f"cluster0.cpu0={dt.dtb}@{self.DTB_ADDRESS}",
+ "--data", f"cluster0.cpu0={self.args.hypervisor}@{self.KERNEL_ADDRESS}",
+ ]
if self.vms_in_partitions_json:
img_ldadd = self.get_img_and_ldadd(self.args.partitions["VMs"])
@@ -484,19 +489,27 @@
def KERNEL_ADDRESS(self):
return "0x6000000"
- def gen_dts(self, dts_path, test_args):
+ def gen_dts(self, dt, test_args):
"""Create a DeviceTree source which will be compiled into a DTB and
passed to FVP for a test run."""
to_append = self.get_manifests_from_json(self.args.partitions["SPs"])
- write_file(dts_path, read_file(FvpDriverSPMC.FVP_PREBUILT_SECURE_DTS))
- append_file(dts_path, to_append)
+ write_file(dt.dts, read_file(FvpDriverSPMC.FVP_PREBUILT_SECURE_DTS))
+ append_file(dt.dts, to_append)
def gen_fvp_args(
- self, is_long_running, uart0_log_path, uart1_log_path, dtb_path):
+ self, is_long_running, uart0_log_path, uart1_log_path, dt,
+ call_super = True, secure_hfctrl = True):
"""Generate command line arguments for FVP."""
- fvp_args = super().gen_fvp_args(
- is_long_running, uart0_log_path, uart1_log_path, dtb_path)
+ common_args = (is_long_running, uart0_log_path, uart1_log_path, dt.dtb)
+ fvp_args = super().gen_fvp_args(*common_args) if call_super else []
+
fvp_args += [
+ "--data", f"cluster0.cpu0={dt.dtb}@{self.DTB_ADDRESS}",
+ "--data", f"cluster0.cpu0={self.args.spmc}@{self.KERNEL_ADDRESS}",
+ ]
+
+ if secure_hfctrl:
+ fvp_args += [
"-C", f"bp.pl011_uart0.in_file={FvpDriverSPMC.HFTEST_CMD_FILE}",
"-C", f"bp.pl011_uart0.shutdown_tag=\"{HFTEST_CTRL_FINISHED}\"",
"-C", "cluster0.has_arm_v8-5=1",
@@ -506,6 +519,7 @@
"-C", "cluster0.restriction_on_speculative_execution=2",
"-C", "cluster1.restriction_on_speculative_execution=2",
]
+
img_ldadd = self.get_img_and_ldadd(self.args.partitions["SPs"])
for img, ldadd in img_ldadd:
fvp_args += ["--data", f"cluster0.cpu0={img}@{hex(ldadd)}"]
@@ -577,7 +591,6 @@
ser.write(b'\r')
break
-
# Tuple used to return information about the results of running a set of tests.
TestRunnerResult = collections.namedtuple("TestRunnerResult", [
"tests_run",
@@ -590,11 +603,11 @@
"""Class which communicates with a test platform to obtain a list of
available tests and driving their execution."""
- def __init__(self, artifacts, driver, image_name, suite_regex, test_regex,
+ def __init__(self, artifacts, driver, test_set_up, suite_regex, test_regex,
skip_long_running_tests, force_long_running):
self.artifacts = artifacts
self.driver = driver
- self.image_name = image_name
+ self.test_set_up = test_set_up
self.skip_long_running_tests = skip_long_running_tests
self.force_long_running = force_long_running
@@ -769,7 +782,7 @@
timestamp = datetime.datetime.now().replace(microsecond=0).isoformat()
xml = ET.Element("testsuites")
- xml.set("name", self.image_name)
+ xml.set("name", self.test_set_up)
xml.set("timestamp", timestamp)
result = self.collect_results(
@@ -794,8 +807,8 @@
def Main():
parser = argparse.ArgumentParser()
- parser.add_argument("image")
- parser.add_argument("--out", required=True)
+ parser.add_argument("--hypervisor")
+ parser.add_argument("--spmc")
parser.add_argument("--log", required=True)
parser.add_argument("--out_initrd")
parser.add_argument("--out_partitions")
@@ -813,18 +826,23 @@
parser.add_argument("--cpu",
help="Selects the CPU configuration for the run environment.")
parser.add_argument("--tfa", action="store_true")
- parser.add_argument("--secure", action="store_true")
args = parser.parse_args()
- # Resolve some paths.
- image = os.path.join(args.out, args.image + ".bin")
- initrd = None
- image_name = args.image
+ # Create class which will manage all test artifacts.
+ if args.hypervisor and args.spmc:
+ test_set_up = "hypervisor_and_spmc"
+ elif args.hypervisor:
+ test_set_up = "hypervisor"
+ elif args.spmc:
+ test_set_up = "spmc"
+ else:
+ raise Exception("No Hafnium image provided!\n")
- if not args.secure and args.initrd:
+ initrd = None
+ if args.hypervisor and args.initrd:
initrd_dir = os.path.join(args.out_initrd, "obj", args.initrd)
initrd = os.path.join(initrd_dir, "initrd.img")
- image_name += "_" + args.initrd
+ test_set_up += "_" + args.initrd
vm_args = args.vm_args or ""
partitions = None
@@ -833,20 +851,21 @@
partitions = json.load(open(partitions_dir, "r"))
# Create class which will manage all test artifacts.
- log_dir = os.path.join(args.log, "hafnium" if not args.secure else "spmc")
+ log_dir = os.path.join(args.log, test_set_up)
artifacts = ArtifactsManager(log_dir)
# Create a driver for the platform we want to test on.
- driver_args = DriverArgs(artifacts, image, initrd, vm_args, args.cpu,
- partitions)
+ driver_args = DriverArgs(artifacts, args.hypervisor, args.spmc, initrd,
+ vm_args, args.cpu, partitions)
- if args.secure:
+ if args.spmc:
if args.driver != "fvp":
raise Exception("Secure tests can only run with fvp driver")
driver = FvpDriverSPMC(driver_args)
- else:
+ elif args.hypervisor:
if args.driver == "qemu":
- driver = QemuDriver(driver_args, args.out, args.tfa)
+ out = os.path.dirname(args.hypervisor)
+ driver = QemuDriver(driver_args, out, args.tfa)
elif args.driver == "fvp":
driver = FvpDriverHypervisor(driver_args)
elif args.driver == "serial":
@@ -854,9 +873,11 @@
args.serial_baudrate, not args.serial_no_init_wait)
else:
raise Exception("Unknown driver name: {}".format(args.driver))
+ else:
+ raise Exception("No Hafnium image provided!\n")
# Create class which will drive test execution.
- runner = TestRunner(artifacts, driver, image_name, args.suite, args.test,
+ runner = TestRunner(artifacts, driver, test_set_up, args.suite, args.test,
args.skip_long_running_tests, args.force_long_running)
# Run tests.