Merge branch 'next'

This commit is contained in:
Tom Rini
2026-04-06 12:16:57 -06:00
3248 changed files with 120724 additions and 31617 deletions

View File

@@ -15,6 +15,7 @@ config SPL_UNIT_TEST
bool "Unit tests in SPL"
depends on SPL
# We need to be able to unbind devices for tests to work
select SPL_DM
select SPL_DM_DEVICE_REMOVE
help
Select this to enable unit tests in SPL. Most test are designed for

View File

@@ -31,6 +31,7 @@ DECLARE_GLOBAL_DATA_PTR;
extern U_BOOT_DRIVER(bootmeth_android);
extern U_BOOT_DRIVER(bootmeth_cros);
extern U_BOOT_DRIVER(bootmeth_rauc);
extern U_BOOT_DRIVER(bootmeth_2script);
/* Use this as the vendor for EFI to tell the app to exit boot services */
@@ -1392,6 +1393,62 @@ static int bootflow_efi(struct unit_test_state *uts)
}
BOOTSTD_TEST(bootflow_efi, UTF_CONSOLE);
/* Test RAUC bootmeth */
static int bootflow_rauc(struct unit_test_state *uts)
{
const char *mmc_dev = "mmc10";
struct bootstd_priv *std;
struct udevice *bootstd;
static const char *order[] = {NULL, NULL};
const char **old_order;
ofnode root;
ofnode node;
order[0] = mmc_dev;
if (!CONFIG_IS_ENABLED(BOOTMETH_RAUC))
return -EAGAIN;
/* Enable the requested mmc node since we need a different bootflow */
root = oftree_root(oftree_default());
node = ofnode_find_subnode(root, mmc_dev);
ut_assert(ofnode_valid(node));
ut_assertok(lists_bind_fdt(gd->dm_root, node, NULL, NULL, false));
/* Enable the rauc bootmeth */
ut_assertok(uclass_first_device_err(UCLASS_BOOTSTD, &bootstd));
ut_assertok(device_bind(bootstd, DM_DRIVER_REF(bootmeth_rauc),
"rauc", 0, ofnode_null(), NULL));
/* Change the device and bootmeth order */
std = dev_get_priv(bootstd);
old_order = std->bootdev_order;
std->bootdev_order = order;
ut_assertok(bootmeth_set_order("rauc"));
/* Run scan and list */
ut_assertok(run_command("bootflow scan", 0));
ut_assert_console_end();
ut_assertok(run_command("bootflow list", 0));
ut_assert_nextlinen("Showing all");
ut_assert_nextlinen("Seq");
ut_assert_nextlinen("---");
ut_assert_nextlinen(" 0 rauc ready mmc 0 mmc10.bootdev.whole ");
ut_assert_nextlinen("---");
ut_assert_skip_to_line("(1 bootflow, 1 valid)");
ut_assert_console_end();
/* Restore the order used by the device tree */
std->bootdev_order = old_order;
return 0;
}
BOOTSTD_TEST(bootflow_rauc, UTF_CONSOLE | UTF_DM | UTF_SCAN_FDT);
/* Check 'bootflow scan' provides a list of images */
static int bootstd_images(struct unit_test_state *uts)
{

View File

@@ -7,11 +7,8 @@
#include <console.h>
#include <mapmem.h>
#include <asm/global_data.h>
#include <test/ut.h>
DECLARE_GLOBAL_DATA_PTR;
/* Declare a new exit test */
#define EXIT_TEST(_name, _flags) UNIT_TEST(_name, _flags, exit)

View File

@@ -6,14 +6,11 @@
*/
#include <command.h>
#include <asm/global_data.h>
#include <display_options.h>
#include <test/lib.h>
#include <test/test.h>
#include <test/ut.h>
DECLARE_GLOBAL_DATA_PTR;
struct test_data {
char *cmd;
char *expected;

View File

@@ -5,12 +5,9 @@
* Copyright 2022, Samuel Dionne-Riel <samuel@dionne-riel.com>
*/
#include <asm/global_data.h>
#include <test/lib.h>
#include <test/ut.h>
DECLARE_GLOBAL_DATA_PTR;
static int lib_test_hush_pause(struct unit_test_state *uts)
{
/* Test default message */

View File

@@ -8,14 +8,11 @@
#include <part.h>
#include <sandbox_host.h>
#include <usb.h>
#include <asm/global_data.h>
#include <asm/state.h>
#include <dm/test.h>
#include <test/test.h>
#include <test/ut.h>
DECLARE_GLOBAL_DATA_PTR;
/* Test that block devices can be created */
static int dm_test_blk_base(struct unit_test_state *uts)
{

View File

@@ -8,8 +8,6 @@
#include <dm/test.h>
#include <test/ut.h>
DECLARE_GLOBAL_DATA_PTR;
/* Basic test of the i3c uclass */
static int dm_test_i3c_base(struct unit_test_state *uts)
{

View File

@@ -40,6 +40,7 @@ static int dm_test_virtio_base(struct unit_test_state *uts)
ut_assertok(virtio_get_status(dev, &status));
ut_asserteq(VIRTIO_CONFIG_S_DRIVER |
VIRTIO_CONFIG_S_DRIVER_OK |
VIRTIO_CONFIG_S_ACKNOWLEDGE |
VIRTIO_CONFIG_S_FEATURES_OK, status);
return 0;

View File

@@ -19,12 +19,19 @@ struct virtio_rng_priv {
struct virtqueue *rng_vq;
};
#define BUFFER_SIZE 16
#define CANARY "CANARYCANARYCANARYCANARY"
/* Test the virtio-rng driver validates the used size */
static int dm_test_virtio_rng_check_len(struct unit_test_state *uts)
{
struct udevice *bus, *dev;
struct virtio_rng_priv *priv;
u8 buffer[16];
u8 buffer[BUFFER_SIZE + sizeof(CANARY)];
/* write known data to buffer */
memset(buffer, 0xaa, BUFFER_SIZE);
memcpy(buffer + BUFFER_SIZE, CANARY, sizeof(CANARY));
/* check probe success */
ut_assertok(uclass_first_device_err(UCLASS_VIRTIO, &bus));
@@ -44,7 +51,10 @@ static int dm_test_virtio_rng_check_len(struct unit_test_state *uts)
priv->rng_vq->vring.used->ring[0].len = U32_MAX;
/* check the driver gracefully handles the error */
ut_asserteq(-EIO, dm_rng_read(dev, buffer, sizeof(buffer)));
dm_rng_read(dev, buffer, BUFFER_SIZE);
/* check for the canary bytes behind the real buffer */
ut_asserteq_mem(buffer + BUFFER_SIZE, CANARY, sizeof(CANARY));
return 0;
}

View File

@@ -32,6 +32,19 @@ static int hush_test_if_base(struct unit_test_state *uts)
sprintf(if_formatted, if_format, "false");
ut_asserteq(1, run_command(if_formatted, 0));
sprintf(if_formatted, if_format, "test");
ut_asserteq(1, run_command(if_formatted, 0));
sprintf(if_formatted, if_format, "test ''");
ut_asserteq(1, run_command(if_formatted, 0));
sprintf(if_formatted, if_format, "test 'abc'");
ut_assertok(run_command(if_formatted, 0));
/* Special case: 'test -n' interpreted as 'test -n ""'. */
sprintf(if_formatted, if_format, "test '-n'");
ut_asserteq(1, run_command(if_formatted, 0));
return 0;
}
HUSH_TEST(hush_test_if_base, 0);
@@ -315,3 +328,71 @@ static int hush_test_if_z_operator(struct unit_test_state *uts)
return 0;
}
HUSH_TEST(hush_test_if_z_operator, 0);
static int hush_test_lbracket_alias(struct unit_test_state *uts)
{
char if_formatted[128];
const char *missing_rbracket_error = "[: missing terminating ]";
sprintf(if_formatted, if_format, "[ aaa = aaa ]");
ut_assertok(run_command(if_formatted, 0));
sprintf(if_formatted, if_format, "[ aaa = bbb ]");
ut_asserteq(1, run_command(if_formatted, 0));
sprintf(if_formatted, if_format, "[ aaa = aaa");
ut_asserteq(1, run_command(if_formatted, 0));
ut_assert_nextline(missing_rbracket_error);
sprintf(if_formatted, if_format, "[ aaa = bbb");
ut_asserteq(1, run_command(if_formatted, 0));
ut_assert_nextline(missing_rbracket_error);
sprintf(if_formatted, if_format, "[ aaa = aaa]");
ut_asserteq(1, run_command(if_formatted, 0));
ut_assert_nextline(missing_rbracket_error);
sprintf(if_formatted, if_format, "[ aaa = bbb]");
ut_asserteq(1, run_command(if_formatted, 0));
ut_assert_nextline(missing_rbracket_error);
sprintf(if_formatted, if_format, "[ aaa != aaa -o bbb != bbb ]");
ut_asserteq(1, run_command(if_formatted, 0));
sprintf(if_formatted, if_format, "[ aaa != aaa -o bbb = bbb ]");
ut_assertok(run_command(if_formatted, 0));
sprintf(if_formatted, if_format, "[ ! aaa != aaa -o ! bbb != bbb ]");
ut_assertok(run_command(if_formatted, 0));
sprintf(if_formatted, if_format, "[ ! aaa != aaa -o ! bbb = bbb ]");
ut_assertok(run_command(if_formatted, 0));
sprintf(if_formatted, if_format, "[ ]");
ut_asserteq(1, run_command(if_formatted, 0));
sprintf(if_formatted, if_format, "[");
ut_asserteq(1, run_command(if_formatted, 0));
ut_assert_nextline(missing_rbracket_error);
sprintf(if_formatted, if_format, "[ '' ]");
ut_asserteq(1, run_command(if_formatted, 0));
sprintf(if_formatted, if_format, "[ ''");
ut_asserteq(1, run_command(if_formatted, 0));
ut_assert_nextline(missing_rbracket_error);
sprintf(if_formatted, if_format, "[ 'abc' ]");
ut_assertok(run_command(if_formatted, 0));
sprintf(if_formatted, if_format, "[ 'abc'");
ut_asserteq(1, run_command(if_formatted, 0));
ut_assert_nextline(missing_rbracket_error);
/* Special case: '[ -n ]' interpreted as '[ -n "" ]'. */
sprintf(if_formatted, if_format, "[ -n ]");
ut_asserteq(1, run_command(if_formatted, 0));
return 0;
}
HUSH_TEST(hush_test_lbracket_alias, UTF_CONSOLE);

View File

@@ -7,13 +7,10 @@
#include <command.h>
#include <display_options.h>
#include <asm/global_data.h>
#include <test/lib.h>
#include <test/test.h>
#include <test/ut.h>
DECLARE_GLOBAL_DATA_PTR;
static int test_print_freq(struct unit_test_state *uts,
uint64_t freq, char *expected)
{

View File

@@ -5,12 +5,10 @@
#include <console.h>
#include <log.h>
#include <asm/global_data.h>
#include <vsprintf.h>
#include <test/log.h>
#include <test/ut.h>
DECLARE_GLOBAL_DATA_PTR;
/* Test invalid options */
static int log_test_filter_invalid(struct unit_test_state *uts)
{

View File

@@ -7,9 +7,97 @@
import re
import os
import shutil
from subprocess import call, check_call, check_output, CalledProcessError
from subprocess import DEVNULL
import tempfile
def mk_fs(config, fs_type, size, prefix, src_dir=None, size_gran = 0x100000):
# size_gran (int): Size granularity of file system image in bytes
SIZE_GRAN = 1 << 20
class FsHelper:
"""Creating a filesystem containing test files
Usage:
with FsHelper(ubman.config, 'ext4', 10, 'mmc1') as fsh:
# create files in the self.srcdir directory
fsh.mk_fs()
# Now use the filesystem
# The filesystem and srcdir are erased after the 'with' statement.
It is also possible to use an existing srcdir:
with FsHelper(ubman.config, 'fat32', 10, 'usb2') as fsh:
fsh.srcdir = src_dir
fsh.mk_fs()
...
Properties:
fs_img (str): Filename for the filesystem image
"""
def __init__(self, config, fs_type, size_mb, prefix):
"""Set up a new object
Args:
config (u_boot_config): U-Boot configuration
fs_type (str): File system type: one of ext2, ext3, ext4, vfat,
fat12, fat16, fat32, exfat, fs_generic (which means vfat)
size_mb (int): Size of file system in MB
prefix (str): Prefix string of volume's file name
"""
if fs_type not in ['fat12', 'fat16', 'fat32', 'vfat',
'ext2', 'ext3', 'ext4',
'exfat', 'fs_generic']:
raise ValueError(f"Unsupported filesystem type '{fs_type}'")
self.config = config
self.fs_type = fs_type
self.size_mb = size_mb
self.prefix = prefix
self.quiet = True
self.fs_img = None
self.tmpdir = None
self.srcdir = None
self._do_cleanup = False
def mk_fs(self):
"""Make a new filesystem and copy in the files"""
self.setup()
self._do_cleanup = True
self.fs_img = mk_fs(self.config, self.fs_type, self.size_mb << 20,
self.prefix, self.srcdir, quiet=self.quiet)
def setup(self):
"""Set up the srcdir ready to receive files"""
if not self.srcdir:
if self.config:
self.srcdir = os.path.join(self.config.persistent_data_dir,
f'{self.prefix}.{self.fs_type}.tmp')
if os.path.exists(self.srcdir):
shutil.rmtree(self.srcdir)
os.mkdir(self.srcdir)
else:
self.tmpdir = tempfile.TemporaryDirectory('fs_helper')
self.srcdir = self.tmpdir.name
def cleanup(self):
"""Remove created image"""
if self.tmpdir:
self.tmpdir.cleanup()
if self._do_cleanup:
os.remove(self.fs_img)
def __enter__(self):
self.setup()
return self
def __exit__(self, extype, value, traceback):
self.cleanup()
def mk_fs(config, fs_type, size, prefix, src_dir=None, fs_img=None, quiet=False):
"""Create a file system volume
Args:
@@ -18,12 +106,16 @@ def mk_fs(config, fs_type, size, prefix, src_dir=None, size_gran = 0x100000):
size (int): Size of file system in bytes
prefix (str): Prefix string of volume's file name
src_dir (str): Root directory to use, or None for none
size_gran (int): Size granularity of file system image in bytes
fs_img (str or None): Leaf filename for image, or None to use a
default name. The image is always placed under
persistent_data_dir.
quiet (bool): Suppress non-error output
Raises:
CalledProcessError: if any error occurs when creating the filesystem
"""
fs_img = f'{prefix}.{fs_type}.img'
if not fs_img:
fs_img = f'{prefix}.{fs_type}.img'
fs_img = os.path.join(config.persistent_data_dir, fs_img)
if fs_type == 'fat12':
@@ -48,7 +140,7 @@ def mk_fs(config, fs_type, size, prefix, src_dir=None, size_gran = 0x100000):
elif fs_lnxtype != 'vfat' and fs_lnxtype != 'exfat':
raise ValueError(f'src_dir not implemented for fs {fs_lnxtype}')
count = (size + size_gran - 1) // size_gran
count = (size + SIZE_GRAN - 1) // SIZE_GRAN
# Some distributions do not add /sbin to the default PATH, where mkfs lives
if '/sbin' not in os.environ["PATH"].split(os.pathsep):
@@ -56,16 +148,19 @@ def mk_fs(config, fs_type, size, prefix, src_dir=None, size_gran = 0x100000):
try:
check_call(f'rm -f {fs_img}', shell=True)
check_call(f'truncate -s $(( {size_gran} * {count} )) {fs_img}',
check_call(f'truncate -s $(( {SIZE_GRAN} * {count} )) {fs_img}',
shell=True)
check_call(f'mkfs.{fs_lnxtype} {mkfs_opt} {fs_img}', shell=True)
check_call(f'mkfs.{fs_lnxtype} {mkfs_opt} {fs_img}', shell=True,
stdout=DEVNULL if quiet else None)
if fs_type == 'ext4':
sb_content = check_output(f'tune2fs -l {fs_img}',
shell=True).decode()
if 'metadata_csum' in sb_content:
check_call(f'tune2fs -O ^metadata_csum {fs_img}', shell=True)
elif fs_lnxtype == 'vfat' and src_dir:
check_call(f'mcopy -i {fs_img} -vsmpQ {src_dir}/* ::/', shell=True)
flags = f"-smpQ{'' if quiet else 'v'}"
check_call(f'mcopy -i {fs_img} {flags} {src_dir}/* ::/',
shell=True)
elif fs_lnxtype == 'exfat' and src_dir:
check_call(f'fattools cp {src_dir}/* {fs_img}', shell=True)
return fs_img
@@ -75,7 +170,7 @@ def mk_fs(config, fs_type, size, prefix, src_dir=None, size_gran = 0x100000):
def setup_image(ubman, devnum, part_type, img_size=20, second_part=False,
basename='mmc'):
"""Create a disk image with a single partition
"""Create a disk image with one or two partitions
Args:
ubman (ConsoleBase): Console to use

View File

@@ -0,0 +1,42 @@
# SPDX-License-Identifier: GPL-2.0-or-later
""" Unit test for the EFI Conformance Profiles Table (ECPT)
"""
import pytest
@pytest.mark.buildconfigspec('cmd_efidebug')
@pytest.mark.buildconfigspec('efi_ecpt')
def test_efi_ecpt(ubman) -> None:
""" Unit test for the ECPT
This test assumes nothing about the ECPT contents, it just checks that the
ECPT table is there and that the efidebug ecpt command does not fail.
Args:
ubman -- U-Boot console
"""
response = ubman.run_command('efidebug tables')
assert ('36122546-f7e7-4c8f-bd9b-eb8525b50c0b '
'EFI Conformance Profiles Table') in response
response = ubman.run_command('efidebug ecpt')
assert 'Unknown command' not in response
assert 'Configure UEFI environment' not in response
assert 'Usage:' not in response
assert 'table missing' not in response
@pytest.mark.buildconfigspec('cmd_efidebug')
@pytest.mark.buildconfigspec('efi_ecpt')
@pytest.mark.buildconfigspec('efi_ebbr_2_1_conformance')
def test_efi_ecpt_ebbr_2_1(ubman) -> None:
""" Unit test for the ECPT, with EBBR 2.1 profile
This test uses the efidebug ecpt command to dump the ECPT and check that
the EBBR 2.1 conformance profile is there.
Args:
ubman -- U-Boot console
"""
response = ubman.run_command('efidebug ecpt')
assert ('cce33c35-74ac-4087-bce7-8b29b02eeb27 '
'EFI EBBR 2.1 Conformance Profile') in response

View File

@@ -4,8 +4,6 @@
# Copyright (c) 2020 Alex Kiernan <alex.kiernan@gmail.com>
import pytest
import time
import utils
"""
test_gpio_input is intended to test the fix 4dbc107f4683.
@@ -136,8 +134,12 @@ def test_gpio_set_generic(ubman):
if not f:
pytest.skip("gpio not configured")
gpio_pin_adr = f['gpio_op_pin'];
gpio_set_value = f['gpio_set_value'];
gpio_pin_adr = f.get('gpio_op_pin')
if gpio_pin_adr is None:
pytest.skip("gpio_op_pin is not configured")
gpio_set_value = f['gpio_set_value']
cmd = 'gpio set ' + gpio_pin_adr
@@ -160,8 +162,12 @@ def test_gpio_clear_generic(ubman):
if not f:
pytest.skip("gpio not configured")
gpio_pin_adr = f['gpio_op_pin'];
gpio_clear_value = f['gpio_clear_value'];
gpio_pin_adr = f.get('gpio_op_pin')
if gpio_pin_adr is None:
pytest.skip("gpio_op_pin is not configured")
gpio_clear_value = f['gpio_clear_value']
cmd = 'gpio clear ' + gpio_pin_adr
@@ -184,9 +190,13 @@ def test_gpio_toggle_generic(ubman):
if not f:
pytest.skip("gpio not configured")
gpio_pin_adr = f['gpio_op_pin'];
gpio_set_value = f['gpio_set_value'];
gpio_clear_value = f['gpio_clear_value'];
gpio_pin_adr = f.get('gpio_op_pin')
if gpio_pin_adr is None:
pytest.skip("gpio_op_pin is not configured")
gpio_set_value = f['gpio_set_value']
gpio_clear_value = f['gpio_clear_value']
cmd = 'gpio set ' + gpio_pin_adr
response = ubman.run_command(cmd)
@@ -212,8 +222,8 @@ def test_gpio_input_generic(ubman):
if not f:
pytest.skip("gpio not configured")
gpio_pin_adr = f['gpio_ip_pin_clear'];
gpio_clear_value = f['gpio_clear_value'];
gpio_pin_adr = f['gpio_ip_pin_clear']
gpio_clear_value = f['gpio_clear_value']
cmd = 'gpio input ' + gpio_pin_adr
@@ -222,8 +232,8 @@ def test_gpio_input_generic(ubman):
assert good_response in response
gpio_pin_adr = f['gpio_ip_pin_set'];
gpio_set_value = f['gpio_set_value'];
gpio_pin_adr = f['gpio_ip_pin_set']
gpio_set_value = f['gpio_set_value']
cmd = 'gpio input ' + gpio_pin_adr

View File

@@ -554,6 +554,52 @@ def setup_efi_image(ubman):
utils.run_and_log(ubman, f'rm -rf {mnt}')
utils.run_and_log(ubman, f'rm -f {fsfile}')
def setup_rauc_image(ubman):
"""Create a 40MB disk image with an A/B RAUC system on it"""
mmc_dev = 10
fname = os.path.join(ubman.config.source_dir, f'mmc{mmc_dev}.img')
mnt = ubman.config.persistent_data_dir
spec = 'type=c, size=8M, start=1M, bootable\n' \
'type=83, size=10M\n' \
'type=c, size=8M, bootable\n' \
'type=83, size=10M'
utils.run_and_log(ubman, f'qemu-img create {fname} 40M')
utils.run_and_log(ubman, ['sh', '-c', f'printf "{spec}" | sfdisk {fname}'])
# Generate boot script
script = '# dummy boot script'
bootdir = os.path.join(mnt, 'boot')
utils.run_and_log(ubman, f'mkdir -p {bootdir}')
cmd_fname = os.path.join(bootdir, 'boot.cmd')
scr_fname = os.path.join(bootdir, 'boot.scr')
with open(cmd_fname, 'w', encoding='ascii') as outf:
print(script, file=outf)
mkimage = os.path.join(ubman.config.build_dir, 'tools/mkimage')
utils.run_and_log(
ubman, f'{mkimage} -C none -A arm -T script -d {cmd_fname} {scr_fname}')
utils.run_and_log(ubman, f'rm -f {cmd_fname}')
# Generate empty rootfs
rootdir = os.path.join(mnt, 'root')
utils.run_and_log(ubman, f'mkdir -p {rootdir}')
# Create boot filesystem image with boot script in it and copy to disk image
fsfile = f'rauc_boot.fat32.img'
fs_helper.mk_fs(ubman.config, 'fat32', 0x800000, fsfile.split('.')[0], bootdir)
utils.run_and_log(ubman, f'dd if={mnt}/{fsfile} of=mmc{mmc_dev}.img bs=1M seek=1 conv=notrunc')
utils.run_and_log(ubman, f'dd if={mnt}/{fsfile} of=mmc{mmc_dev}.img bs=1M seek=19 conv=notrunc')
utils.run_and_log(ubman, f'rm -f {scr_fname}')
# Create empty root filesystem image and copy to disk image
fsfile = f'rauc_root.ext4.img'
fs_helper.mk_fs(ubman.config, 'ext4', 0xa00000, fsfile.split('.')[0], rootdir)
utils.run_and_log(ubman, f'dd if={mnt}/{fsfile} of=mmc{mmc_dev}.img bs=1M seek=9 conv=notrunc')
utils.run_and_log(ubman, f'dd if={mnt}/{fsfile} of=mmc{mmc_dev}.img bs=1M seek=27 conv=notrunc')
utils.run_and_log(ubman, f'rm -f {fsfile}')
@pytest.mark.buildconfigspec('cmd_bootflow')
@pytest.mark.buildconfigspec('sandbox')
def test_ut_dm_init_bootstd(ubman):
@@ -565,6 +611,7 @@ def test_ut_dm_init_bootstd(ubman):
setup_cros_image(ubman)
setup_android_image(ubman)
setup_efi_image(ubman)
setup_rauc_image(ubman)
# Restart so that the new mmc1.img is picked up
ubman.restart_uboot()