From: Simon Glass <simon.glass@canonical.com>
The code for printing FITs is quite messy, with lots of separate
printf() calls, an indentation string, etc.
It also has no tests.
In preparation for refactoring this code, add a test. Use Python code
to create the test image and C code to test it.
The test covers FIT description, image details (type, architecture, OS,
addresses), and configuration details.
Co-developed-by: Claude <noreply@anthropic.com>
Signed-off-by: Simon Glass <simon.glass@canonical.com>
---
test/boot/Makefile | 1 +
test/boot/fit_print.c | 93 +++++++++++++++++++++++++
test/py/tests/test_fit_print.py | 120 ++++++++++++++++++++++++++++++++
3 files changed, 214 insertions(+)
create mode 100644 test/boot/fit_print.c
create mode 100644 test/py/tests/test_fit_print.py
@@ -5,6 +5,7 @@
ifdef CONFIG_UT_BOOTSTD
obj-$(CONFIG_BOOTSTD) += bootdev.o bootstd_common.o bootflow.o bootmeth.o
obj-$(CONFIG_FIT) += image.o
+obj-$(CONFIG_$(PHASE_)FIT_PRINT) += fit_print.o
obj-$(CONFIG_BLK_LUKS) += luks.o
obj-$(CONFIG_EXPO) += expo.o expo_common.o
new file mode 100644
@@ -0,0 +1,93 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Test for FIT image printing
+ *
+ * Copyright 2025 Canonical Ltd
+ * Written by Simon Glass <simon.glass@canonical.com>
+ */
+
+#include <image.h>
+#include <mapmem.h>
+#include <os.h>
+#include <test/ut.h>
+#include <linux/libfdt.h>
+#include "bootstd_common.h"
+
+/* Test fit_print_contents() output */
+static int test_fit_print_norun(struct unit_test_state *uts)
+{
+ char fname[256];
+ void *fit;
+ void *buf;
+ ulong addr;
+ int size;
+
+ /* Load the FIT created by the Python test */
+ ut_assertok(os_persistent_file(fname, sizeof(fname), "test-fit.fit"));
+ ut_assertok(os_read_file(fname, &buf, &size));
+
+ /* Copy to address 0x10000 and print from there */
+ addr = 0x10000;
+ fit = map_sysmem(addr, size);
+ memcpy(fit, buf, size);
+
+ /* Print it and check output line by line */
+ console_record_reset_enable();
+ fit_print_contents(fit);
+
+ /* Check every line of output */
+ ut_assert_nextline(" FIT description: Test FIT image for printing");
+ ut_assert_nextline(" Created: 2009-02-13 23:31:30 UTC");
+ ut_assert_nextline(" Image 0 (kernel)");
+ ut_assert_nextline(" Description: Test kernel");
+ ut_assert_nextline(" Created: 2009-02-13 23:31:30 UTC");
+ ut_assert_nextline(" Type: Kernel Image");
+ ut_assert_nextline(" Compression: gzip compressed");
+ ut_assert_nextline(" Data Start: 0x000100c4");
+ ut_assert_nextline(" Data Size: 327 Bytes = 327 Bytes");
+ ut_assert_nextline(" Architecture: Sandbox");
+ ut_assert_nextline(" OS: Linux");
+ ut_assert_nextline(" Load Address: 0x01000000");
+ ut_assert_nextline(" Entry Point: 0x01000000");
+ ut_assert_nextline(" Hash algo: sha256");
+ ut_assert_nextline(" Hash value: fad998b94ef12fdac0c347915d8b9b6069a4011399e1a2097638a2cb33244cee");
+ ut_assert_nextline(" Image 1 (ramdisk)");
+ ut_assert_nextline(" Description: Test ramdisk");
+ ut_assert_nextline(" Created: 2009-02-13 23:31:30 UTC");
+ ut_assert_nextline(" Type: RAMDisk Image");
+ ut_assert_nextline(" Compression: uncompressed");
+ ut_assert_nextline(" Data Start: 0x00010304");
+ ut_assert_nextline(" Data Size: 301 Bytes = 301 Bytes");
+ ut_assert_nextline(" Architecture: Sandbox");
+ ut_assert_nextline(" OS: Linux");
+ ut_assert_nextline(" Load Address: 0x02000000");
+ ut_assert_nextline(" Entry Point: unavailable");
+ ut_assert_nextline(" Hash algo: sha256");
+ ut_assert_nextline(" Hash value: 53e2a65d92ad890dcd89d83a1f95ad6b8206e0e4889548b035062fc494e7f655");
+ ut_assert_nextline(" Image 2 (fdt)");
+ ut_assert_nextline(" Description: Test FDT");
+ ut_assert_nextline(" Created: 2009-02-13 23:31:30 UTC");
+ ut_assert_nextline(" Type: Flat Device Tree");
+ ut_assert_nextline(" Compression: uncompressed");
+ ut_assert_nextline(" Data Start: 0x00010514");
+ ut_assert_nextline(" Data Size: 157 Bytes = 157 Bytes");
+ ut_assert_nextline(" Architecture: Sandbox");
+ ut_assert_nextline(" Hash algo: sha256");
+ ut_assert_nextline(" Hash value: 51918524b06745cae06331047c7e566909431bf71338e5f703dffba1823274f4");
+ ut_assert_nextline(" Default Configuration: 'conf-1'");
+ ut_assert_nextline(" Configuration 0 (conf-1)");
+ ut_assert_nextline(" Description: Test configuration");
+ ut_assert_nextline(" Kernel: kernel");
+ ut_assert_nextline(" Init Ramdisk: ramdisk");
+ ut_assert_nextline(" FDT: fdt");
+ ut_assert_nextline(" Configuration 1 (conf-2)");
+ ut_assert_nextline(" Description: Alternate configuration");
+ ut_assert_nextline(" Kernel: kernel");
+ ut_assert_nextline(" FDT: fdt");
+ ut_assert_console_end();
+
+ os_free(buf);
+
+ return 0;
+}
+BOOTSTD_TEST(test_fit_print_norun, UTF_CONSOLE | UTF_MANUAL);
new file mode 100644
@@ -0,0 +1,120 @@
+# SPDX-License-Identifier: GPL-2.0+
+# Copyright 2025 Canonical Ltd
+# Written by Simon Glass <simon.glass@canonical.com>
+
+"""Test for FIT image printing"""
+
+import os
+
+import pytest
+
+import fit_util
+import utils
+
+# ITS for testing FIT printing with hashes, ramdisk, and multiple configs
+PRINT_ITS = '''
+/dts-v1/;
+
+/ {
+ description = "Test FIT image for printing";
+ #address-cells = <1>;
+
+ images {
+ kernel {
+ description = "Test kernel";
+ data = /incbin/("%(kernel)s");
+ type = "kernel";
+ arch = "sandbox";
+ os = "linux";
+ compression = "gzip";
+ load = <0x1000000>;
+ entry = <0x1000000>;
+ hash-1 {
+ algo = "sha256";
+ };
+ };
+ ramdisk {
+ description = "Test ramdisk";
+ data = /incbin/("%(ramdisk)s");
+ type = "ramdisk";
+ arch = "sandbox";
+ os = "linux";
+ compression = "none";
+ load = <0x2000000>;
+ hash-1 {
+ algo = "sha256";
+ };
+ };
+ fdt {
+ description = "Test FDT";
+ data = /incbin/("%(fdt)s");
+ type = "flat_dt";
+ arch = "sandbox";
+ compression = "none";
+ hash-1 {
+ algo = "sha256";
+ };
+ };
+ };
+ configurations {
+ default = "conf-1";
+ conf-1 {
+ description = "Test configuration";
+ kernel = "kernel";
+ fdt = "fdt";
+ ramdisk = "ramdisk";
+ };
+ conf-2 {
+ description = "Alternate configuration";
+ kernel = "kernel";
+ fdt = "fdt";
+ };
+ };
+};
+'''
+
+@pytest.mark.boardspec('sandbox')
+@pytest.mark.buildconfigspec('fit_print')
+@pytest.mark.requiredtool('dtc')
+def test_fit_print(ubman):
+ """Test fit_print_contents() via C unit test"""
+ mkimage = os.path.join(ubman.config.build_dir, 'tools/mkimage')
+
+ # Create test files (make kernel ~6.3K)
+ kernel = fit_util.make_kernel(ubman, 'test-kernel.bin',
+ 'kernel with some extra test data')
+
+ # Compress the kernel (with -n to avoid timestamps for reproducibility)
+ kernel_gz = kernel + '.gz'
+ utils.run_and_log(ubman, ['gzip', '-f', '-n', '-k', kernel])
+
+ fdt = fit_util.make_dtb(ubman, '''
+/dts-v1/;
+/ {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ model = "Test";
+};
+''', 'test-fdt')
+ ramdisk = fit_util.make_kernel(ubman, 'test-ramdisk.bin', 'ramdisk')
+
+ # Compress the ramdisk (with -n to avoid timestamps for reproducibility)
+ ramdisk_gz = ramdisk + '.gz'
+ utils.run_and_log(ubman, ['gzip', '-f', '-n', '-k', ramdisk])
+
+ # Create FIT image with fixed timestamp for reproducible output
+ params = {
+ 'kernel': kernel_gz,
+ 'fdt': fdt,
+ 'ramdisk': ramdisk_gz,
+ }
+ env = os.environ.copy()
+ env['SOURCE_DATE_EPOCH'] = '1234567890' # 2009-02-13 23:31:30 UTC
+ fit = os.path.join(ubman.config.persistent_data_dir, 'test-fit.fit')
+ its = fit_util.make_its(ubman, PRINT_ITS, params)
+ utils.run_and_log(ubman, [mkimage, '-f', its, fit], env=env)
+
+ # Run the C test which will load and verify this FIT
+ ubman.run_command('ut -f bootstd test_fit_print_norun')
+ result = ubman.run_command('echo $?')
+ assert '0' == result