@samitouri / QOSamiQemu / commits / da10beeb8a

tests/functional: add VBSA linux tests

This extends the VBSA test to run the linux tests. The sysarch-acs test suite does provide some pre-built images which is good because the tests require a patched kernel. However due to the structure of the image we need to jump one or two hoops to get something useful: - download and double decompress (zip then xz) the image - navigate grub to launch the Linux Execution Environment - shutdown the system once tests are done - extract the logs from the MSDOS file system and parse them It does make the code a bit ugly but it works for me at least. So far the subset of tests run is limited but that might be solved by adding some more devices to the PCIe bus to exercise the SMMU behaviour. Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org> Message-ID: <20260320155107.2143191-5-alex.bennee@linaro.org> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>

Alex Bennée committed Mar 20, 2026 at 15:51 UTC da10beeb8a0c81124a4c873724acc0dfaff887b6
1 file changed +111 -11
tests/functional/aarch64/test_virt_vbsa.py
+111 -11
@@ -10,7 +10,8 @@
10 # SPDX-License-Identifier: GPL-2.0-or-later
11
12 import shutil
13 -from subprocess import check_call, DEVNULL
13 +import re
14 +from subprocess import check_call, check_output, DEVNULL
15
16 from qemu_test import QemuSystemTest, Asset
17 from qemu_test import get_qemu_img, skipIfMissingCommands
@@ -28,6 +29,20 @@ class Aarch64VirtMachine(QemuSystemTest):
29 failure_message='FAILED',
30 vm=vm)
31
32 + def append_firmware_blobs(self):
33 + """
34 + Setup QEMU firmware blobs for boot.
35 + """
36 + code_path = self.build_file('pc-bios', 'edk2-aarch64-code.fd')
37 + vars_source = self.build_file('pc-bios', 'edk2-arm-vars.fd')
38 + vars_path = self.scratch_file('vars.fd')
39 + shutil.copy(vars_source, vars_path)
40 +
41 + self.vm.add_args('-drive',
42 + f'if=pflash,format=raw,readonly=on,file={code_path}')
43 + self.vm.add_args('-drive', f'if=pflash,format=raw,file={vars_path}')
44 +
45 +
46 ASSET_VBSA_EFI = Asset(
47 'https://github.com/ARM-software/sysarch-acs/raw/refs/heads/main'
48 '/prebuilt_images/VBSA/v25.12_VBSA_0.7.0/Vbsa.efi',
@@ -45,20 +60,12 @@ class Aarch64VirtMachine(QemuSystemTest):
60
61 self.vm.set_console()
62
48 - # virt machine wi
63 + # virt machine
64 self.set_machine('virt')
65 self.vm.add_args('-M', 'virt,gic-version=max,virtualization=on')
66 self.vm.add_args('-cpu', 'max', '-m', '1024')
67
53 - # We will use the QEMU firmware blobs to boot
54 - code_path = self.build_file('pc-bios', 'edk2-aarch64-code.fd')
55 - vars_source = self.build_file('pc-bios', 'edk2-arm-vars.fd')
56 - vars_path = self.scratch_file('vars.fd')
57 - shutil.copy(vars_source, vars_path)
58 -
59 - self.vm.add_args('-drive',
60 - f'if=pflash,format=raw,readonly=on,file={code_path}')
61 - self.vm.add_args('-drive', f'if=pflash,format=raw,file={vars_path}')
68 + self.append_firmware_blobs()
69
70 # Build an EFI FAT32 file-system for the UEFI tests
71 vbsa_efi = self.ASSET_VBSA_EFI.fetch()
@@ -102,5 +109,98 @@ class Aarch64VirtMachine(QemuSystemTest):
109 self.wait_for_console_pattern('VBSA tests complete. Reset the system.')
110
111
112 + ASSET_SYSREADY_IMAGE = Asset(
113 + 'https://github.com/ARM-software/arm-systemready/'
114 + 'releases/download/v25.10_SR_3.1.0/systemready_acs_live_image.img.xz.zip',
115 + 'df2c359de15784b1da6a8e6f3c98a053ee38ac0b3f241ccea62e17db092eb03a')
116 +
117 + ROOT_PROMPT = '/ # '
118 +
119 + @skipIfMissingCommands("sfdisk", "jq", "sed")
120 + def test_aarch64_vbsa_linux_tests(self):
121 + """
122 + Launch the Linux based VBSA test from the ACS prebuilt images.
123 +
124 + We can use the pre-built images and then trigger the Linux
125 + build and run the tests. We then need to slurp the results
126 + from the partition.
127 + """
128 +
129 + self.vm.set_console()
130 +
131 + # Plain virt machine
132 + self.set_machine('virt')
133 + self.vm.add_args('-M', 'virt,gic-version=max')
134 + self.vm.add_args('-cpu', 'max', '-m', '1024', '-smp', '4')
135 +
136 + self.append_firmware_blobs()
137 +
138 + # First fetch, decompress (twice) and prepare the disk image
139 + # on an NVME device (the kernel only has drivers for that).
140 + self.archive_extract(self.ASSET_SYSREADY_IMAGE, format="zip")
141 + disk_image_xz = self.scratch_file("systemready_acs_live_image.img.xz")
142 + disk_image = self.uncompress(disk_image_xz)
143 +
144 + self.vm.add_args('-device',
145 + 'nvme,drive=hd,serial=QEMU_ROOT_SSD')
146 + self.vm.add_args('-blockdev',
147 + f'driver=raw,node-name=hd,file.driver=file,file.filename={disk_image}')
148 +
149 + # Tweak grub.cfg default to avoid manually navigating grub
150 + grub_cfg = self.scratch_file("grub.cfg")
151 + offset = int(check_output(f"sfdisk --json {disk_image} |"
152 + "jq '.partitiontable.partitions[0].start * 512'",
153 + shell=True))
154 + check_call(["mcopy", "-i", f"{disk_image}@@{offset}",
155 + "::/EFI/BOOT/grub.cfg", grub_cfg])
156 +
157 + with open(grub_cfg, 'a', encoding="utf8") as f:
158 + f.write("set default='Linux Execution Enviroment'")
159 +
160 + check_call(["mcopy", "-D", "o", "-i", f"{disk_image}@@{offset}",
161 + grub_cfg, "::/EFI/BOOT/grub.cfg"])
162 +
163 + # Launch QEMU and wait for grub and select the "Linux
164 + # Execution Environment" so we can launch the test.
165 +
166 + self.vm.launch()
167 + self.wait_for_console_pattern(self.ROOT_PROMPT)
168 + ec_and_wait(self, "/usr/bin/bsa.sh --skip "
169 + "B_REP_1,B_IEP_1,B_PCIe_11,B_MEM_06",
170 + self.ROOT_PROMPT)
171 +
172 + # Now we can shutdown
173 + ec_and_wait(self, "halt -f", "reboot: System halted")
174 + self.vm.shutdown()
175 +
176 + # and extract the test logs
177 + bsa_app_res = self.scratch_file("BsaResultsApp.log")
178 + bsa_kern_res = self.scratch_file("BsaResultsKernel.log")
179 +
180 + check_call(["mcopy", "-i", f"{disk_image}@@{offset}",
181 + "::acs_results/Linux/BsaResultsApp.log", bsa_app_res])
182 + check_call(["mcopy", "-i", f"{disk_image}@@{offset}",
183 + "::acs_results/Linux/BsaResultsKernel.log", bsa_kern_res])
184 +
185 + # for now just check the kernel log for the result summary
186 + test_result_re = re.compile(r"\[.*\]\s+(.+): Result:\s+(\w+)")
187 + summary_re = re.compile(r"Total Tests Run =\s*(\d+), Tests Passed =\s*(\d+), Tests Failed =\s*(\d+)")
188 +
189 + with open(bsa_kern_res, 'r', encoding="utf8") as f:
190 + for line in f:
191 + test_match = test_result_re.search(line)
192 + if test_match:
193 + desc = test_match.group(1)
194 + status = test_match.group(2)
195 + self.log.info(f"Test: {desc} status: {status}")
196 +
197 + match = summary_re.search(line)
198 + if match:
199 + total, passed, failed = match.groups()
200 +
201 + if int(failed) > 0:
202 + self.fail(f"{failed} tests failed ({total})")
203 +
204 +
205 if __name__ == '__main__':
206 QemuSystemTest.main()