blob: 593efa4aaeb67796364c20314929e66e6ad46c49 [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
34
Andrew Scull7fd4bb72018-12-08 23:40:12 +000035def qemu(image, initrd, args, log):
Andrew Scullbc7189d2018-08-14 09:35:13 +010036 qemu_args = [
Andrew Walbranbc342d42019-02-05 16:56:02 +000037 "timeout", "--foreground", "10s",
Andrew Scullf0551c82018-12-15 20:38:47 +000038 "./prebuilts/linux-x64/qemu/qemu-system-aarch64", "-M", "virt,gic_version=3",
Andrew Walbranbc342d42019-02-05 16:56:02 +000039 "-cpu", "cortex-a57", "-smp", "4", "-m", "64M", "-machine", "virtualization=true",
Andrew Scull7fd4bb72018-12-08 23:40:12 +000040 "-nographic", "-nodefaults", "-serial", "stdio", "-kernel", image,
Andrew Scullbc7189d2018-08-14 09:35:13 +010041 ]
Andrew Scull7fd4bb72018-12-08 23:40:12 +000042 if initrd:
Andrew Scullf0551c82018-12-15 20:38:47 +000043 qemu_args += ["-initrd", initrd]
Andrew Scullbc7189d2018-08-14 09:35:13 +010044 if args:
45 qemu_args += ["-append", args]
46 # Save the log to a file.
47 with open(log, "w") as f:
48 f.write("$ {}\r\n".format(" ".join(qemu_args)))
49 f.flush()
50 subprocess.check_call(qemu_args, stdout=f, stderr=f)
51 # Return that log for processing.
52 with open(log, "r") as f:
53 return f.read()
54
55
Andrew Walbran98656252019-03-14 14:52:29 +000056def fvp(image, initrd, args, log):
57 uart0_log = log + ".uart0"
58 uart1_log = log + ".uart1"
59 fdt = log + ".dtb"
60 dtc_args = [
61 "dtc", "-I", "dts", "-O", "dtb",
62 "-o", fdt,
63 ]
64 fvp_args = [
65 "timeout", "--foreground", "10s",
66 "../fvp/Base_RevC_AEMv8A_pkg/models/Linux64_GCC-4.9/FVP_Base_RevC-2xAEMv8A",
67 "-C", "pctl.startup=0.0.0.0",
68 "-C", "bp.secure_memory=0",
69 "-C", "cluster0.NUM_CORES=4",
70 "-C", "cluster1.NUM_CORES=4",
71 "-C", "cache_state_modelled=0",
72 "-C", "bp.vis.disable_visualisation=true",
73 "-C", "bp.vis.rate_limit-enable=false",
74 "-C", "bp.terminal_0.start_telnet=false",
75 "-C", "bp.terminal_1.start_telnet=false",
76 "-C", "bp.terminal_2.start_telnet=false",
77 "-C", "bp.terminal_3.start_telnet=false",
78 "-C", "bp.pl011_uart0.untimed_fifos=1",
79 "-C", "bp.pl011_uart0.unbuffered_output=1",
80 "-C", "bp.pl011_uart0.out_file=" + uart0_log,
81 "-C", "bp.pl011_uart1.out_file=" + uart1_log,
82 "-C", "cluster0.cpu0.RVBAR=0x04020000",
83 "-C", "cluster0.cpu1.RVBAR=0x04020000",
84 "-C", "cluster0.cpu2.RVBAR=0x04020000",
85 "-C", "cluster0.cpu3.RVBAR=0x04020000",
86 "-C", "cluster1.cpu0.RVBAR=0x04020000",
87 "-C", "cluster1.cpu1.RVBAR=0x04020000",
88 "-C", "cluster1.cpu2.RVBAR=0x04020000",
89 "-C", "cluster1.cpu3.RVBAR=0x04020000",
90 "--data", "cluster0.cpu0=prebuilts/linux-aarch64/arm-trusted-firmware/bl31.bin@0x04020000",
91 "--data", "cluster0.cpu0=" + fdt + "@0x82000000",
92 "--data", "cluster0.cpu0=" + image + "@0x80000000",
93 "-C", "bp.ve_sysregs.mmbSiteDefault=0",
94 "-C", "bp.ve_sysregs.exit_on_shutdown=1",
95 ]
96 if initrd:
97 fvp_args += ["--data", "cluster0.cpu0=" + initrd + "@0x84000000"]
98
99 with open(log, "w") as f:
100 f.write("$ {}\r\n".format(" ".join(dtc_args)))
101 f.flush()
102 dtc = subprocess.Popen(dtc_args, stdout=f, stderr=f, stdin=subprocess.PIPE)
103 with open("prebuilts/linux-aarch64/arm-trusted-firmware/fvp-base-gicv3-psci-1t.dts", "r") as base_dts:
104 dtc.stdin.write(base_dts.read())
105 dtc.stdin.write("/ {\n")
106 dtc.stdin.write(" chosen {\n")
107 dtc.stdin.write(" bootargs = \"" + args + "\";\n")
108 dtc.stdin.write(" stdout-path = \"serial0:115200n8\";\n")
109 dtc.stdin.write(" linux,initrd-start = <0x84000000>;\n")
110 dtc.stdin.write(" linux,initrd-end = <0x85000000>;\n")
111 dtc.stdin.write(" };\n")
112 dtc.stdin.write("};\n")
113 dtc.stdin.close()
114 dtc.wait()
115
116 f.write("$ {}\r\n".format(" ".join(fvp_args)))
117 f.flush()
118 subprocess.call(fvp_args, stdout=f, stderr=f)
119 with open(uart0_log, "r") as g:
120 f.write(g.read())
121
122 with open(log, "r") as f:
123 return f.read()
124
125
126def emulator(use_fvp, image, initrd, args, log):
127 if use_fvp:
128 return fvp(image, initrd, args, log)
129 else:
130 return qemu(image, initrd, args, log)
131
132
Andrew Scullbc7189d2018-08-14 09:35:13 +0100133def ensure_dir(path):
134 try:
135 os.makedirs(path)
136 except OSError:
137 if not os.path.isdir(path):
138 raise
139
140
141def hftest_lines(raw):
142 prefix = "[hftest] "
143 return [
144 line[len(prefix):]
145 for line in raw.splitlines()
146 if line.startswith(prefix)
147 ]
148
149
150def Main():
151 parser = argparse.ArgumentParser()
Andrew Scull7fd4bb72018-12-08 23:40:12 +0000152 parser.add_argument("image")
Andrew Scullbc7189d2018-08-14 09:35:13 +0100153 parser.add_argument("--out", required=True)
Andrew Scull23e93a82018-10-26 14:56:04 +0100154 parser.add_argument("--log", required=True)
Andrew Scull7fd4bb72018-12-08 23:40:12 +0000155 parser.add_argument("--initrd")
Andrew Scullbc7189d2018-08-14 09:35:13 +0100156 parser.add_argument("--suite")
157 parser.add_argument("--test")
Andrew Walbranbc342d42019-02-05 16:56:02 +0000158 parser.add_argument("--vm_args")
Andrew Walbran98656252019-03-14 14:52:29 +0000159 parser.add_argument("--fvp", type=bool)
Andrew Scullbc7189d2018-08-14 09:35:13 +0100160 args = parser.parse_args()
161 # Resolve some paths.
Andrew Scull7fd4bb72018-12-08 23:40:12 +0000162 image = os.path.join(args.out, args.image + ".bin")
163 initrd = None
164 suite = args.image
165 if args.initrd:
Andrew Walbran377bd8b2019-02-04 17:51:04 +0000166 initrd = os.path.join(args.out, "obj", args.initrd, "initrd.img")
Andrew Scull7fd4bb72018-12-08 23:40:12 +0000167 suite += "_" + args.initrd
Andrew Walbranbc342d42019-02-05 16:56:02 +0000168 vm_args = args.vm_args or ""
Andrew Scull7fd4bb72018-12-08 23:40:12 +0000169 log = os.path.join(args.log, suite)
Andrew Scullbc7189d2018-08-14 09:35:13 +0100170 ensure_dir(log)
171 print("Logs saved under", log)
Andrew Scull3b62f2b2018-08-21 14:26:12 +0100172 log_file = os.path.join(log, "sponge_log.log")
173 with open(log_file, "w") as sponge_log:
174 # Query the tests in the image.
Andrew Walbran98656252019-03-14 14:52:29 +0000175 out = emulator(args.fvp, image, initrd, vm_args + " json", os.path.join(log, "json.log"))
Andrew Scull3b62f2b2018-08-21 14:26:12 +0100176 sponge_log.write(out)
177 sponge_log.write("\r\n\r\n")
178 hftest_json = "\n".join(hftest_lines(out))
179 tests = json.loads(hftest_json)
180 # Run the selected tests.
181 tests_run = 0
182 failures = 0
183 suite_re = re.compile(args.suite or ".*")
184 test_re = re.compile(args.test or ".*")
185 sponge = ET.Element("testsuites")
Andrew Scull7fd4bb72018-12-08 23:40:12 +0000186 sponge.set("name", suite)
Andrew Scull04502e42018-09-03 14:54:52 +0100187 sponge.set(
188 "timestamp",
189 datetime.datetime.now().replace(microsecond=0).isoformat())
Andrew Scull3b62f2b2018-08-21 14:26:12 +0100190 for suite in tests["suites"]:
191 if not suite_re.match(suite["name"]):
Andrew Scullbc7189d2018-08-14 09:35:13 +0100192 continue
Andrew Scull3b62f2b2018-08-21 14:26:12 +0100193 tests_run_from_suite = 0
194 failures_from_suite = 0
195 sponge_suite = ET.SubElement(sponge, "testsuite")
196 sponge_suite.set("name", suite["name"])
197 for test in suite["tests"]:
198 if not test_re.match(test):
199 continue
200 sponge_test = ET.SubElement(sponge_suite, "testcase")
201 sponge_test.set("name", test)
Andrew Scull04502e42018-09-03 14:54:52 +0100202 sponge_test.set("classname", suite['name'])
Andrew Scull3b62f2b2018-08-21 14:26:12 +0100203 sponge_test.set("status", "run")
204 tests_run_from_suite += 1
205 if tests_run_from_suite == 1:
206 print(" SUITE", suite["name"])
207 print(" RUN", test)
208 test_log = os.path.join(log,
209 suite["name"] + "." + test + ".log")
Andrew Walbran98656252019-03-14 14:52:29 +0000210 out = emulator(args.fvp, image, initrd, vm_args + " run {} {}".format(
Andrew Scull3b62f2b2018-08-21 14:26:12 +0100211 suite["name"], test), test_log)
212 sponge_log.write(out)
213 sponge_log.write("\r\n\r\n")
214 hftest_out = hftest_lines(out)
Andrew Walbran6bc52b22019-02-08 14:35:00 +0000215 if len(hftest_out) > 0 and hftest_out[-1] == "FINISHED" and not any(
Andrew Scullf0551c82018-12-15 20:38:47 +0000216 l.startswith('Failure:') for l in hftest_out):
Andrew Scull3b62f2b2018-08-21 14:26:12 +0100217 print(" PASS")
218 else:
219 failures_from_suite += 1
220 sponge_failure = ET.SubElement(sponge_test, "failure")
221 # TODO: set a meaningful message and put log in CDATA
222 sponge_failure.set("message", "Test failed")
223 print("[x] FAIL --", test_log)
224 tests_run += tests_run_from_suite
225 failures += failures_from_suite
226 sponge_suite.set("tests", str(tests_run_from_suite))
227 sponge_suite.set("failures", str(failures_from_suite))
228 sponge.set("tests", str(tests_run))
229 sponge.set("failures", str(failures))
230 with open(os.path.join(log, "sponge_log.xml"), "w") as f:
231 ET.ElementTree(sponge).write(f, encoding='utf-8', xml_declaration=True)
Andrew Scullbc7189d2018-08-14 09:35:13 +0100232 # If none were run, this is probably a mistake.
233 if tests_run == 0:
234 print("Error: no tests match")
235 return 10
236 # Exit with 0 on success and 1 if any test failed.
237 if failures:
238 print("[x] FAIL:", failures, "of", tests_run, "tests failed")
239 return 1
240 else:
241 print(" PASS: all", tests_run, "tests passed")
242 return 0
243
244
245if __name__ == "__main__":
246 sys.exit(Main())