From patchwork Fri Jan 9 01:53:08 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 1369 Return-Path: X-Original-To: u-boot-concept@u-boot.org Delivered-To: u-boot-concept@u-boot.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1767923656; bh=xiwEnvyrZWTXM4j5lvo+1X6JkLdsBGw7+fdiykEzNjc=; h=From:To:Date:In-Reply-To:References:CC:Subject:List-Id: List-Archive:List-Help:List-Owner:List-Post:List-Subscribe: List-Unsubscribe:From; b=d8vdRaskRqueNP1MYoYfFgwh0jsoiEj3MkiMS/3zjj2CtwVoRxtPLKPnsXWtjm8SX UYkW9eu4fKSVWXyF01J+vApP02L2gPF37zVZA0l9qCydgtGN1zRRUYlrI4h+EeqbHH KOaNY0tAmDL1WTwKNo5A4cdJ5u9KkUh+IQk6f7sZqlbehFzz8GwPamA1+by0LHkRW+ J55vjOizmuO8XQ1dU4N+C1Q1YM/+9m+xDoFKZcwqH6L3KMGuPuUL3Tb+IMSmUoawV7 ygkL15Mua3YdRL12hw1y9afy7zuReUz9ePCqA0xq1vio5+UPzhCLbpy8qaaBACzlyI N1hvMTi7Jg/+g== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 54ECC691E9 for ; Thu, 8 Jan 2026 18:54:16 -0700 (MST) X-Virus-Scanned: Debian amavis at Received: from mail.u-boot.org ([127.0.0.1]) by localhost (mail.u-boot.org [127.0.0.1]) (amavis, port 10024) with ESMTP id 5Hg7_zYkCDjt for ; Thu, 8 Jan 2026 18:54:16 -0700 (MST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1767923656; bh=xiwEnvyrZWTXM4j5lvo+1X6JkLdsBGw7+fdiykEzNjc=; h=From:To:Date:In-Reply-To:References:CC:Subject:List-Id: List-Archive:List-Help:List-Owner:List-Post:List-Subscribe: List-Unsubscribe:From; b=d8vdRaskRqueNP1MYoYfFgwh0jsoiEj3MkiMS/3zjj2CtwVoRxtPLKPnsXWtjm8SX UYkW9eu4fKSVWXyF01J+vApP02L2gPF37zVZA0l9qCydgtGN1zRRUYlrI4h+EeqbHH KOaNY0tAmDL1WTwKNo5A4cdJ5u9KkUh+IQk6f7sZqlbehFzz8GwPamA1+by0LHkRW+ J55vjOizmuO8XQ1dU4N+C1Q1YM/+9m+xDoFKZcwqH6L3KMGuPuUL3Tb+IMSmUoawV7 ygkL15Mua3YdRL12hw1y9afy7zuReUz9ePCqA0xq1vio5+UPzhCLbpy8qaaBACzlyI N1hvMTi7Jg/+g== Received: from mail.u-boot.org (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 4294D69130 for ; Thu, 8 Jan 2026 18:54:16 -0700 (MST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1767923653; bh=/CXcsP9pIrPrwRMLCwHoAsOZOqUUwQNEsv5QMnHqKJk=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=JQZQlrhm61DfV/I+e0lXdiEKJ3zIN2YAE1aPEN9EGz0ksrYbq112Tct4qEpGyvOL5 /cPEroigY/t/yPRx3J83bGtvrUP+keuENHwANCDm3xhtE1mpALUIc333jZzgHPGNSn b63EUhvwxd9QxHNBSakD685DK47jtAGgS51jOP+iIM/4VXFo24OAoT45uWD8ay8oiY cngTFB5HYUeWbGKq9mfBBLHNH87wPXvayBBL74+MCpg140Quzla+uA56VCMibIqlsi giYOup8lKMRogyUtfsMrD1lw4I/TeLNBw72hYx0a3+fU9rfAfkSdtoCkxrWwgn0e63 aRzxPsSgRQkKA== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 7175F691E6; Thu, 8 Jan 2026 18:54:13 -0700 (MST) X-Virus-Scanned: Debian amavis at Received: from mail.u-boot.org ([127.0.0.1]) by localhost (mail.u-boot.org [127.0.0.1]) (amavis, port 10026) with ESMTP id 2-5EGI5zlJHH; Thu, 8 Jan 2026 18:54:13 -0700 (MST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1767923649; bh=3grnabYcdIae9LvApaQ9FqxKvF9qjCzMmxEF3BWoDkc=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=I1HEm0MrEeF5eLgHyO15oYoO8yVSEE2vVGWlJjPSOA5f9ztCJZHoSWY5yL2sR6rJ+ slXFq99X2TfsqkGo6jPyfozoH+3iKEwcYu927iOWva8EK1BjWW0Z4zrAFAQPLdgXs4 aGTiEU2+SuoBgRSb0MYB0K896U4l5fg3WRCrhpjeHzXwCCM4PVPQk4+B1MMID+N7c8 mcwNMFJ4N8WiTRu5mdPhpvVbCmYAUrjmj2ieYDcfhUrdE0rMDjm0hix+P0U6qQ0WqJ +vuUVVTrbciSN9/3dqKFvZtsERRgFv87neM5Q5I740wAVhguPT/RYFcuPchHe93aH8 Cmwv0ef13yclw== Received: from u-boot.org (unknown [73.34.74.121]) by mail.u-boot.org (Postfix) with ESMTPSA id B1ACB69130; Thu, 8 Jan 2026 18:54:08 -0700 (MST) From: Simon Glass To: U-Boot Concept Date: Thu, 8 Jan 2026 18:53:08 -0700 Message-ID: <20260109015323.3411528-8-sjg@u-boot.org> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260109015323.3411528-1-sjg@u-boot.org> References: <20260109015323.3411528-1-sjg@u-boot.org> MIME-Version: 1.0 Message-ID-Hash: JSYHRB7F3ZHZTAUJSYY6HK32UUDMY7K5 X-Message-ID-Hash: JSYHRB7F3ZHZTAUJSYY6HK32UUDMY7K5 X-MailFrom: sjg@u-boot.org X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; emergency; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header CC: Simon Glass , "Claude Opus 4 . 5" X-Mailman-Version: 3.3.10 Precedence: list Subject: [Concept] [PATCH 07/16] boot: pxe: Add a test for the sysboot command List-Id: Discussion and patches related to U-Boot Concept Archived-At: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: From: Simon Glass Add a test that uses the sysboot command to boot a label and verifies that files are loaded to the correct memory addresses. - Run sysboot with an extlinux.conf containing multiple labels - Verify console output shows files being retrieved - Check kernel, initrd, and FDT are at expected addresses - Verifiy file contents match what was written to the filesystem Use simple strings for the dummy kernel and initrd files so we can check that the correct files are loaded. Co-developed-by: Claude Opus 4.5 Signed-off-by: Simon Glass --- test/boot/pxe.c | 85 ++++++++++++++++++++++++++++++++ test/py/tests/test_pxe_parser.py | 77 +++++++++++++++++++++++++++++ 2 files changed, 162 insertions(+) diff --git a/test/boot/pxe.c b/test/boot/pxe.c index 778c7d62816..3d560fd9ade 100644 --- a/test/boot/pxe.c +++ b/test/boot/pxe.c @@ -9,7 +9,9 @@ #include #include +#include #include +#include #include #include #include @@ -25,6 +27,10 @@ /* Memory address for loading files */ #define PXE_LOAD_ADDR 0x01000000 +#define PXE_KERNEL_ADDR 0x02000000 +#define PXE_INITRD_ADDR 0x02800000 +#define PXE_FDT_ADDR 0x03000000 +#define PXE_OVERLAY_ADDR 0x03100000 /** * struct pxe_test_info - context for the test getfile callback @@ -233,3 +239,82 @@ static int pxe_test_parse_norun(struct unit_test_state *uts) PXE_TEST_ARGS(pxe_test_parse_norun, UTF_CONSOLE | UTF_MANUAL, { "fs_image", UT_ARG_STR }, { "cfg_path", UT_ARG_STR }); + +/** + * Test booting via sysboot command + * + * This test: + * 1. Binds a filesystem image containing extlinux.conf + * 2. Sets up environment variables for file loading + * 3. Runs sysboot to boot the default label + * 4. Verifies files were loaded by checking console output + */ +static int pxe_test_sysboot_norun(struct unit_test_state *uts) +{ + const char *fs_image = ut_str(PXE_ARG_FS_IMAGE); + const char *cfg_path = ut_str(PXE_ARG_CFG_PATH); + void *kernel, *initrd, *fdt; + + ut_assertnonnull(fs_image); + ut_assertnonnull(cfg_path); + + /* Bind the filesystem image */ + ut_assertok(run_commandf("host bind 0 %s", fs_image)); + + /* Set environment variables for file loading */ + ut_assertok(env_set_hex("pxefile_addr_r", PXE_LOAD_ADDR)); + ut_assertok(env_set_hex("kernel_addr_r", PXE_KERNEL_ADDR)); + ut_assertok(env_set_hex("ramdisk_addr_r", PXE_INITRD_ADDR)); + ut_assertok(env_set_hex("fdt_addr_r", PXE_FDT_ADDR)); + ut_assertok(env_set_hex("fdtoverlay_addr_r", PXE_OVERLAY_ADDR)); + ut_assertok(env_set("bootfile", cfg_path)); + + /* + * Run sysboot - it will try all labels and return 0 after failing + * to boot them all (since sandbox can't actually boot Linux) + */ + ut_assertok(run_commandf("sysboot host 0:0 any %x %s", + PXE_LOAD_ADDR, cfg_path)); + + /* Skip menu output and find the first label boot attempt */ + ut_assert_skip_to_line("Enter choice: 1:\tBoot Linux"); + + /* Verify files were loaded in order */ + ut_assert_nextline("Retrieving file: /vmlinuz"); + ut_assert_nextline("Retrieving file: /initrd.img"); + ut_assert_nextline("append: root=/dev/sda1 quiet"); + ut_assert_nextline("Retrieving file: /dtb/board.dtb"); + ut_assert_nextline("Retrieving file: /dtb/overlay1.dtbo"); + ut_assert_nextline("Retrieving file: /dtb/overlay2.dtbo"); + + /* Boot fails on sandbox */ + ut_assert_nextline("Unrecognized zImage"); + ut_assert_nextlinen(" unmap_physmem"); + + /* Verify files were loaded at the correct addresses */ + kernel = map_sysmem(PXE_KERNEL_ADDR, 0); + initrd = map_sysmem(PXE_INITRD_ADDR, 0); + fdt = map_sysmem(PXE_FDT_ADDR, 0); + + /* Kernel should contain "kernel" at start */ + ut_asserteq_mem("kernel", kernel, 6); + + /* Initrd should contain "ramdisk" at start */ + ut_asserteq_mem("ramdisk", initrd, 7); + + /* FDT should have valid magic number */ + ut_assertok(fdt_check_header(fdt)); + + /* Verify overlays were applied - check for properties added by overlays */ + ut_asserteq_str("from-overlay1", + fdt_getprop(fdt, fdt_path_offset(fdt, "/test-node"), + "overlay1-property", NULL)); + ut_asserteq_str("from-overlay2", + fdt_getprop(fdt, fdt_path_offset(fdt, "/test-node"), + "overlay2-property", NULL)); + + return 0; +} +PXE_TEST_ARGS(pxe_test_sysboot_norun, UTF_CONSOLE | UTF_MANUAL, + { "fs_image", UT_ARG_STR }, + { "cfg_path", UT_ARG_STR }); diff --git a/test/py/tests/test_pxe_parser.py b/test/py/tests/test_pxe_parser.py index 614252a444f..c2467f70f5d 100644 --- a/test/py/tests/test_pxe_parser.py +++ b/test/py/tests/test_pxe_parser.py @@ -13,10 +13,64 @@ Python handles filesystem image setup and configuration. import os import pytest +import subprocess from fs_helper import FsHelper +# Simple base DTS with symbols enabled (for overlay support) +BASE_DTS = """\ +/dts-v1/; + +/ { + model = "Test Board"; + compatible = "test,board"; + + test: test-node { + test-property = <42>; + status = "okay"; + }; +}; +""" + +# Simple overlay that modifies the test node +OVERLAY1_DTS = """\ +/dts-v1/; +/plugin/; + +&test { + overlay1-property = "from-overlay1"; +}; +""" + +# Another overlay that adds a different property +OVERLAY2_DTS = """\ +/dts-v1/; +/plugin/; + +&test { + overlay2-property = "from-overlay2"; +}; +""" + + +def compile_dts(dts_content, output_path, is_overlay=False): + """Compile DTS content to DTB/DTBO file + + Args: + dts_content (str): DTS source content + output_path (str): Path to output DTB/DTBO file + is_overlay (bool): True if this is an overlay (needs -@) + + Raises: + subprocess.CalledProcessError: If dtc fails + """ + # Use -@ for both base (to generate __symbols__) and overlays + cmd = ['dtc', '-@', '-I', 'dts', '-O', 'dtb', '-o', output_path] + subprocess.run(cmd, input=dts_content.encode(), check=True, + capture_output=True) + + def create_extlinux_conf(srcdir, labels, menu_opts=None): """Create an extlinux.conf file with the given labels @@ -190,6 +244,21 @@ def pxe_image(u_boot_config): next_fname = f'nest{level + 1}.conf' fd.write(f"\ninclude /extlinux/{next_fname}\n") + # Create DTB and overlay files for testing + dtbdir = os.path.join(fsh.srcdir, 'dtb') + os.makedirs(dtbdir, exist_ok=True) + compile_dts(BASE_DTS, os.path.join(dtbdir, 'board.dtb')) + compile_dts(OVERLAY1_DTS, os.path.join(dtbdir, 'overlay1.dtbo'), + is_overlay=True) + compile_dts(OVERLAY2_DTS, os.path.join(dtbdir, 'overlay2.dtbo'), + is_overlay=True) + + # Create dummy kernel and initrd files with identifiable content + with open(os.path.join(fsh.srcdir, 'vmlinuz'), 'wb') as fd: + fd.write(b'kernel') + with open(os.path.join(fsh.srcdir, 'initrd.img'), 'wb') as fd: + fd.write(b'ramdisk') + # Create the filesystem fsh.mk_fs() @@ -201,6 +270,7 @@ def pxe_image(u_boot_config): @pytest.mark.boardspec('sandbox') +@pytest.mark.requiredtool('dtc') class TestPxeParser: """Test PXE/extlinux parser APIs via C unit tests""" @@ -210,3 +280,10 @@ class TestPxeParser: with ubman.log.section('Test PXE parse'): ubman.run_ut('pxe', 'pxe_test_parse', fs_image=fs_img, cfg_path=cfg_path) + + def test_pxe_sysboot(self, ubman, pxe_image): + """Test booting via sysboot command""" + fs_img, cfg_path = pxe_image + with ubman.log.section('Test PXE sysboot'): + ubman.run_ut('pxe', 'pxe_test_sysboot', + fs_image=fs_img, cfg_path=cfg_path)