blob: 9a9019c780fb51b5c7f80248e1ff922450456370 [file] [log] [blame]
Andrew Scullbc7189d2018-08-14 09:35:13 +01001#!/usr/bin/env python
Andrew Scull18834872018-10-12 11:48:09 +01002#
Andrew Walbran692b3252019-03-07 15:51:31 +00003# Copyright 2018 The Hafnium Authors.
Andrew Scull18834872018-10-12 11:48:09 +01004#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9# https://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16
Andrew Scullbc7189d2018-08-14 09:35:13 +010017"""Run tests.
18
19Runs tests on QEMU.
20"""
21
22from __future__ import print_function
23
Andrew Scull3b62f2b2018-08-21 14:26:12 +010024import xml.etree.ElementTree as ET
25
Andrew Scullbc7189d2018-08-14 09:35:13 +010026import argparse
Andrew Scull04502e42018-09-03 14:54:52 +010027import datetime
Andrew Scullbc7189d2018-08-14 09:35:13 +010028import json
29import os
30import re
31import subprocess
32import sys
33
Andrew Scull845fc9b2019-04-03 12:44:26 +010034HFTEST_LOG_PREFIX = "[hftest] "
35HFTEST_LOG_FAILURE_PREFIX = "Failure:"
36HFTEST_LOG_FINISHED = "FINISHED"
37
David Brazdil5715f042019-08-27 11:11:51 +010038HF_ROOT = os.path.dirname(os.path.dirname(os.path.dirname(__file__)))
39DTC_SCRIPT = os.path.join(HF_ROOT, "build", "image", "dtc.py")
Andrew Scull845fc9b2019-04-03 12:44:26 +010040
41def log_timeout_returncode(f, returncode):
42 if returncode == 0:
43 return
44 elif returncode == 124:
45 f.write("\r\n{}{} timed out\r\n".format(HFTEST_LOG_PREFIX,
46 HFTEST_LOG_FAILURE_PREFIX))
47 else:
48 f.write("\r\n{}{} process return code {}\r\n".format(
49 HFTEST_LOG_PREFIX, HFTEST_LOG_FAILURE_PREFIX, returncode))
50
Andrew Scull7fd4bb72018-12-08 23:40:12 +000051def qemu(image, initrd, args, log):
Andrew Scullbc7189d2018-08-14 09:35:13 +010052 qemu_args = [
Andrew Walbranbc342d42019-02-05 16:56:02 +000053 "timeout", "--foreground", "10s",
Andrew Scullf0551c82018-12-15 20:38:47 +000054 "./prebuilts/linux-x64/qemu/qemu-system-aarch64", "-M", "virt,gic_version=3",
Andrew Walbranbc342d42019-02-05 16:56:02 +000055 "-cpu", "cortex-a57", "-smp", "4", "-m", "64M", "-machine", "virtualization=true",
Andrew Scull7fd4bb72018-12-08 23:40:12 +000056 "-nographic", "-nodefaults", "-serial", "stdio", "-kernel", image,
Andrew Scullbc7189d2018-08-14 09:35:13 +010057 ]
Andrew Scull7fd4bb72018-12-08 23:40:12 +000058 if initrd:
Andrew Scullf0551c82018-12-15 20:38:47 +000059 qemu_args += ["-initrd", initrd]
Andrew Scullbc7189d2018-08-14 09:35:13 +010060 if args:
61 qemu_args += ["-append", args]
62 # Save the log to a file.
63 with open(log, "w") as f:
64 f.write("$ {}\r\n".format(" ".join(qemu_args)))
65 f.flush()
Andrew Scull845fc9b2019-04-03 12:44:26 +010066 try:
67 subprocess.check_call(qemu_args, stdout=f, stderr=f)
68 except subprocess.CalledProcessError as e:
69 log_timeout_returncode(f, e.returncode)
Andrew Scullbc7189d2018-08-14 09:35:13 +010070 # Return that log for processing.
71 with open(log, "r") as f:
72 return f.read()
73
74
Andrew Walbran98656252019-03-14 14:52:29 +000075def fvp(image, initrd, args, log):
76 uart0_log = log + ".uart0"
77 uart1_log = log + ".uart1"
78 fdt = log + ".dtb"
David Brazdil5715f042019-08-27 11:11:51 +010079 dtc_args = [ DTC_SCRIPT, "-o", fdt ]
Andrew Walbran98656252019-03-14 14:52:29 +000080 fvp_args = [
Marc Bonnici0a125632019-04-01 13:46:52 +010081 "timeout", "--foreground", "40s",
Andrew Walbran98656252019-03-14 14:52:29 +000082 "../fvp/Base_RevC_AEMv8A_pkg/models/Linux64_GCC-4.9/FVP_Base_RevC-2xAEMv8A",
83 "-C", "pctl.startup=0.0.0.0",
84 "-C", "bp.secure_memory=0",
85 "-C", "cluster0.NUM_CORES=4",
86 "-C", "cluster1.NUM_CORES=4",
87 "-C", "cache_state_modelled=0",
88 "-C", "bp.vis.disable_visualisation=true",
89 "-C", "bp.vis.rate_limit-enable=false",
90 "-C", "bp.terminal_0.start_telnet=false",
91 "-C", "bp.terminal_1.start_telnet=false",
92 "-C", "bp.terminal_2.start_telnet=false",
93 "-C", "bp.terminal_3.start_telnet=false",
94 "-C", "bp.pl011_uart0.untimed_fifos=1",
95 "-C", "bp.pl011_uart0.unbuffered_output=1",
96 "-C", "bp.pl011_uart0.out_file=" + uart0_log,
97 "-C", "bp.pl011_uart1.out_file=" + uart1_log,
98 "-C", "cluster0.cpu0.RVBAR=0x04020000",
99 "-C", "cluster0.cpu1.RVBAR=0x04020000",
100 "-C", "cluster0.cpu2.RVBAR=0x04020000",
101 "-C", "cluster0.cpu3.RVBAR=0x04020000",
102 "-C", "cluster1.cpu0.RVBAR=0x04020000",
103 "-C", "cluster1.cpu1.RVBAR=0x04020000",
104 "-C", "cluster1.cpu2.RVBAR=0x04020000",
105 "-C", "cluster1.cpu3.RVBAR=0x04020000",
106 "--data", "cluster0.cpu0=prebuilts/linux-aarch64/arm-trusted-firmware/bl31.bin@0x04020000",
107 "--data", "cluster0.cpu0=" + fdt + "@0x82000000",
108 "--data", "cluster0.cpu0=" + image + "@0x80000000",
109 "-C", "bp.ve_sysregs.mmbSiteDefault=0",
110 "-C", "bp.ve_sysregs.exit_on_shutdown=1",
111 ]
Marc Bonnici0a125632019-04-01 13:46:52 +0100112 initrd_start = 0x84000000
113 initrd_end = 0x85000000 # Default value
Andrew Walbran98656252019-03-14 14:52:29 +0000114 if initrd:
Marc Bonnici0a125632019-04-01 13:46:52 +0100115 fvp_args += ["--data", "cluster0.cpu0={}@{}".format(initrd, hex(initrd_start))]
116 initrd_end = initrd_start + os.path.getsize(initrd)
117
Andrew Walbran98656252019-03-14 14:52:29 +0000118
119 with open(log, "w") as f:
120 f.write("$ {}\r\n".format(" ".join(dtc_args)))
121 f.flush()
Andrew Scull845fc9b2019-04-03 12:44:26 +0100122 dtc = subprocess.Popen(
123 dtc_args, stdout=f, stderr=f, stdin=subprocess.PIPE)
124 with open(
125 "prebuilts/linux-aarch64/arm-trusted-firmware/fvp-base-gicv3-psci-1t.dts",
126 "r") as base_dts:
Andrew Walbran98656252019-03-14 14:52:29 +0000127 dtc.stdin.write(base_dts.read())
128 dtc.stdin.write("/ {\n")
129 dtc.stdin.write(" chosen {\n")
130 dtc.stdin.write(" bootargs = \"" + args + "\";\n")
131 dtc.stdin.write(" stdout-path = \"serial0:115200n8\";\n")
Marc Bonnici0a125632019-04-01 13:46:52 +0100132 dtc.stdin.write(" linux,initrd-start = <{}>;\n".format(initrd_start))
133 dtc.stdin.write(" linux,initrd-end = <{}>;\n".format(initrd_end))
Andrew Walbran98656252019-03-14 14:52:29 +0000134 dtc.stdin.write(" };\n")
135 dtc.stdin.write("};\n")
136 dtc.stdin.close()
137 dtc.wait()
138
139 f.write("$ {}\r\n".format(" ".join(fvp_args)))
140 f.flush()
Andrew Scull845fc9b2019-04-03 12:44:26 +0100141 returncode = subprocess.call(fvp_args, stdout=f, stderr=f)
Andrew Walbran98656252019-03-14 14:52:29 +0000142 with open(uart0_log, "r") as g:
143 f.write(g.read())
Andrew Scull845fc9b2019-04-03 12:44:26 +0100144 log_timeout_returncode(f, returncode)
Andrew Walbran98656252019-03-14 14:52:29 +0000145
146 with open(log, "r") as f:
147 return f.read()
148
149
150def emulator(use_fvp, image, initrd, args, log):
151 if use_fvp:
152 return fvp(image, initrd, args, log)
153 else:
154 return qemu(image, initrd, args, log)
155
156
Andrew Scullbc7189d2018-08-14 09:35:13 +0100157def ensure_dir(path):
158 try:
159 os.makedirs(path)
160 except OSError:
161 if not os.path.isdir(path):
162 raise
163
164
165def hftest_lines(raw):
Andrew Walbran58954f92019-05-09 17:11:20 +0100166 lines = []
167 for line in raw.splitlines():
168 if line.startswith("VM "):
169 line = line[len("VM 0: "):]
170 if line.startswith(HFTEST_LOG_PREFIX):
171 lines.append(line[len(HFTEST_LOG_PREFIX):])
172 return lines
Andrew Scullbc7189d2018-08-14 09:35:13 +0100173
174
175def Main():
176 parser = argparse.ArgumentParser()
Andrew Scull7fd4bb72018-12-08 23:40:12 +0000177 parser.add_argument("image")
Andrew Scullbc7189d2018-08-14 09:35:13 +0100178 parser.add_argument("--out", required=True)
Andrew Scull23e93a82018-10-26 14:56:04 +0100179 parser.add_argument("--log", required=True)
Andrew Walbran7559fcf2019-05-09 17:11:20 +0100180 parser.add_argument("--out_initrd")
Andrew Scull7fd4bb72018-12-08 23:40:12 +0000181 parser.add_argument("--initrd")
Andrew Scullbc7189d2018-08-14 09:35:13 +0100182 parser.add_argument("--suite")
183 parser.add_argument("--test")
Andrew Walbranbc342d42019-02-05 16:56:02 +0000184 parser.add_argument("--vm_args")
Andrew Walbran98656252019-03-14 14:52:29 +0000185 parser.add_argument("--fvp", type=bool)
Andrew Scullbc7189d2018-08-14 09:35:13 +0100186 args = parser.parse_args()
187 # Resolve some paths.
Andrew Scull7fd4bb72018-12-08 23:40:12 +0000188 image = os.path.join(args.out, args.image + ".bin")
189 initrd = None
190 suite = args.image
191 if args.initrd:
Andrew Walbran7559fcf2019-05-09 17:11:20 +0100192 initrd = os.path.join(args.out_initrd, "obj", args.initrd, "initrd.img")
Andrew Scull7fd4bb72018-12-08 23:40:12 +0000193 suite += "_" + args.initrd
Andrew Walbranbc342d42019-02-05 16:56:02 +0000194 vm_args = args.vm_args or ""
Andrew Scull7fd4bb72018-12-08 23:40:12 +0000195 log = os.path.join(args.log, suite)
Andrew Scullbc7189d2018-08-14 09:35:13 +0100196 ensure_dir(log)
197 print("Logs saved under", log)
Andrew Scull3b62f2b2018-08-21 14:26:12 +0100198 log_file = os.path.join(log, "sponge_log.log")
Andrew Scull845fc9b2019-04-03 12:44:26 +0100199 with open(log_file, "w") as full_log:
Andrew Scull3b62f2b2018-08-21 14:26:12 +0100200 # Query the tests in the image.
Andrew Scull845fc9b2019-04-03 12:44:26 +0100201 out = emulator(args.fvp, image, initrd, vm_args + " json",
202 os.path.join(log, "json.log"))
203 full_log.write(out)
204 full_log.write("\r\n\r\n")
Andrew Scull3b62f2b2018-08-21 14:26:12 +0100205 hftest_json = "\n".join(hftest_lines(out))
Fuad Tabbaa1b550c2019-08-02 14:14:30 +0100206 try:
207 tests = json.loads(hftest_json)
208 except ValueError:
209 print(hftest_json)
210 return 2
Andrew Scull3b62f2b2018-08-21 14:26:12 +0100211 # Run the selected tests.
212 tests_run = 0
213 failures = 0
214 suite_re = re.compile(args.suite or ".*")
215 test_re = re.compile(args.test or ".*")
Andrew Scull845fc9b2019-04-03 12:44:26 +0100216 suites_xml = ET.Element("testsuites")
217 suites_xml.set("name", suite)
218 suites_xml.set(
Andrew Scull04502e42018-09-03 14:54:52 +0100219 "timestamp",
220 datetime.datetime.now().replace(microsecond=0).isoformat())
Andrew Scull3b62f2b2018-08-21 14:26:12 +0100221 for suite in tests["suites"]:
222 if not suite_re.match(suite["name"]):
Andrew Scullbc7189d2018-08-14 09:35:13 +0100223 continue
Andrew Scull3b62f2b2018-08-21 14:26:12 +0100224 tests_run_from_suite = 0
225 failures_from_suite = 0
Andrew Scull845fc9b2019-04-03 12:44:26 +0100226 suite_xml = ET.SubElement(suites_xml, "testsuite")
227 suite_xml.set("name", suite["name"])
Andrew Scull3b62f2b2018-08-21 14:26:12 +0100228 for test in suite["tests"]:
229 if not test_re.match(test):
230 continue
Andrew Scull845fc9b2019-04-03 12:44:26 +0100231 test_xml = ET.SubElement(suite_xml, "testcase")
232 test_xml.set("name", test)
233 test_xml.set("classname", suite['name'])
234 test_xml.set("status", "run")
Andrew Scull3b62f2b2018-08-21 14:26:12 +0100235 tests_run_from_suite += 1
236 if tests_run_from_suite == 1:
237 print(" SUITE", suite["name"])
238 print(" RUN", test)
239 test_log = os.path.join(log,
240 suite["name"] + "." + test + ".log")
Andrew Scull845fc9b2019-04-03 12:44:26 +0100241 out = emulator(
242 args.fvp, image, initrd,
243 vm_args + " run {} {}".format(suite["name"], test),
244 test_log)
245 full_log.write(out)
246 full_log.write("\r\n\r\n")
Andrew Scull3b62f2b2018-08-21 14:26:12 +0100247 hftest_out = hftest_lines(out)
Andrew Scull845fc9b2019-04-03 12:44:26 +0100248 if len(
249 hftest_out
250 ) > 0 and hftest_out[-1] == HFTEST_LOG_FINISHED and not any(
251 l.startswith(HFTEST_LOG_FAILURE_PREFIX)
252 for l in hftest_out):
Andrew Scull3b62f2b2018-08-21 14:26:12 +0100253 print(" PASS")
254 else:
255 failures_from_suite += 1
Andrew Scull845fc9b2019-04-03 12:44:26 +0100256 failure_xml = ET.SubElement(test_xml, "failure")
Andrew Scull3b62f2b2018-08-21 14:26:12 +0100257 # TODO: set a meaningful message and put log in CDATA
Andrew Scull845fc9b2019-04-03 12:44:26 +0100258 failure_xml.set("message", "Test failed")
Andrew Scull3b62f2b2018-08-21 14:26:12 +0100259 print("[x] FAIL --", test_log)
260 tests_run += tests_run_from_suite
261 failures += failures_from_suite
Andrew Scull845fc9b2019-04-03 12:44:26 +0100262 suite_xml.set("tests", str(tests_run_from_suite))
263 suite_xml.set("failures", str(failures_from_suite))
264 suites_xml.set("tests", str(tests_run))
265 suites_xml.set("failures", str(failures))
Andrew Scull3b62f2b2018-08-21 14:26:12 +0100266 with open(os.path.join(log, "sponge_log.xml"), "w") as f:
Andrew Scull845fc9b2019-04-03 12:44:26 +0100267 ET.ElementTree(suites_xml).write(
268 f, encoding='utf-8', xml_declaration=True)
Andrew Scullbc7189d2018-08-14 09:35:13 +0100269 # If none were run, this is probably a mistake.
270 if tests_run == 0:
271 print("Error: no tests match")
272 return 10
273 # Exit with 0 on success and 1 if any test failed.
274 if failures:
275 print("[x] FAIL:", failures, "of", tests_run, "tests failed")
276 return 1
277 else:
278 print(" PASS: all", tests_run, "tests passed")
279 return 0
280
281
282if __name__ == "__main__":
283 sys.exit(Main())