From: Simon Glass <simon.glass@canonical.com>
Add build infrastructure to compile and link the ulib demo for ARM64.
In this case, arch/arm/Makefile re-links U-Boot with example objects
using the u-boot-link helper, so the example's strong main() overrides
the weak default, then creates demo-nodtb.bin and appends the
devicetree to produce demo.bin
Unlike x86 which uses a ROM image, ARM64 produces a binary that is
loaded directly via QEMU's -bios parameter.
Enable CONFIG_EXAMPLES in qemu_arm64_defconfig so the demo is built
by default. Add a pytest which boots demo.bin under
qemu-system-aarch64 and verifies the expected output.
Also refactor the test code to share QEMU demo helpers between x86
and ARM64: run_qemu_demo() handles subprocess execution with timeout,
and assert_demo_output() validates the expected output strings.
Co-developed-by: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Simon Glass <simon.glass@canonical.com>
---
arch/arm/Makefile | 6 ++++
configs/qemu_arm64_defconfig | 2 ++
examples/ulib/Kbuild | 2 +-
test/py/tests/test_ulib.py | 68 +++++++++++++++++++++++++++---------
4 files changed, 60 insertions(+), 18 deletions(-)
@@ -124,5 +124,11 @@ ifneq (,$(filter $(SOC), kirkwood))
libs-y += arch/arm/mach-mvebu/
endif
+ifdef CONFIG_EXAMPLES
+EXAMPLE_ARCH := arm
+EXAMPLE_APPEND_DTB := y
+include scripts/Makefile.ulib-example
+endif
+
# deprecated
-include $(machdirs)/config.mk
@@ -76,3 +76,5 @@ CONFIG_TPM_PCR_ALLOCATE=y
CONFIG_GENERATE_SMBIOS_TABLE_VERBOSE=y
CONFIG_UTHREAD=y
CONFIG_UNIT_TEST=y
+CONFIG_ULIB=y
+CONFIG_EXAMPLES=y
@@ -1,6 +1,6 @@
# SPDX-License-Identifier: GPL-2.0+
#
-# Example objects for x86 platforms (compiled via kbuild, not linked into
+# Example objects for platform builds (compiled via kbuild, not linked into
# u-boot). The standalone Makefile is used for sandbox builds instead.
extra-y += demo.o demo_helper.o
@@ -221,6 +221,39 @@ def test_ulib_api_header(ubman):
assert 'ub_snprintf(char *buf, size_t size, const char *fmt, ...)' in out
assert 'ub_vprintf(const char *fmt, va_list args)' in out
+def assert_demo_output(out):
+ """Assert that demo output contains expected strings.
+
+ Args:
+ out (str): Decoded output string from QEMU
+ """
+ assert 'U-Boot Library Demo Helper' in out
+ assert '==========================' in out
+ assert 'U-Boot version:' in out
+ assert 'helper: Adding 42 + 13 = 55' in out
+ assert '=================================' in out
+ assert 'Demo complete' in out
+
+def run_qemu_demo(qemu_cmd):
+ """Run a ulib demo under QEMU and return output.
+
+ Args:
+ qemu_cmd (list): QEMU command and arguments (e.g.
+ ['qemu-system-i386', '-bios', 'demo.rom', ...])
+
+ Returns:
+ str: Decoded stdout from QEMU
+ """
+ with subprocess.Popen(qemu_cmd, stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE) as proc:
+ try:
+ stdout, _ = proc.communicate(timeout=5)
+ except subprocess.TimeoutExpired:
+ proc.kill()
+ stdout, _ = proc.communicate()
+
+ return stdout.decode('utf-8', errors='replace')
+
def run_x86_rom_demo(ubman, qemu_binary):
"""Boot the demo ROM image under QEMU and check for expected output.
@@ -240,23 +273,8 @@ def run_x86_rom_demo(ubman, qemu_binary):
assert shutil.which(qemu_binary), f'{qemu_binary} not found'
cmd = [qemu_binary, '-bios', demo_rom, '-nographic', '-no-reboot']
-
- with subprocess.Popen(cmd, stdout=subprocess.PIPE,
- stderr=subprocess.PIPE) as proc:
- try:
- stdout, _ = proc.communicate(timeout=5)
- except subprocess.TimeoutExpired:
- proc.kill()
- stdout, _ = proc.communicate()
-
- out = stdout.decode('utf-8', errors='replace')
-
- assert 'U-Boot Library Demo Helper' in out
- assert '==========================' in out
- assert 'U-Boot version:' in out
- assert 'helper: Adding 42 + 13 = 55' in out
- assert '=================================' in out
- assert 'Demo complete' in out
+ out = run_qemu_demo(cmd)
+ assert_demo_output(out)
@pytest.mark.localqemu
@pytest.mark.boardspec('qemu-x86')
@@ -271,3 +289,19 @@ def test_ulib_demo_rom(ubman):
def test_ulib_demo_rom_64(ubman):
"""Test the ulib demo ROM image under QEMU x86_64."""
run_x86_rom_demo(ubman, 'qemu-system-x86_64')
+
+@pytest.mark.localqemu
+@pytest.mark.boardspec('qemu_arm64')
+@pytest.mark.buildconfigspec("examples")
+def test_ulib_demo_arm64(ubman):
+ """Test the ulib demo binary under QEMU ARM64."""
+ build = ubman.config.build_dir
+ demo_bin = os.path.join(build, 'examples', 'ulib', 'demo.bin')
+
+ assert os.path.exists(demo_bin), 'demo.bin not found in build directory'
+ assert shutil.which('qemu-system-aarch64'), 'qemu-system-aarch64 not found'
+
+ cmd = ['qemu-system-aarch64', '-machine', 'virt', '-cpu', 'cortex-a57',
+ '-nographic', '-no-reboot', '-bios', demo_bin]
+ out = run_qemu_demo(cmd)
+ assert_demo_output(out)