diff options
author | Tom Rini <trini@konsulko.com> | 2022-04-04 10:45:33 -0400 |
---|---|---|
committer | Tom Rini <trini@konsulko.com> | 2022-04-04 10:48:44 -0400 |
commit | 01f1ab67f38882dc7665a0a6eca4bbeba6d84f81 (patch) | |
tree | 31b1febefe82731d94571f7442877c039efb602c /test | |
parent | e4b6ebd3de982ae7185dbf689a030e73fd06e0d2 (diff) | |
parent | 8221c52d88fbe84ca9692dc23827e21403c952e8 (diff) | |
download | u-boot-01f1ab67f38882dc7665a0a6eca4bbeba6d84f81.zip u-boot-01f1ab67f38882dc7665a0a6eca4bbeba6d84f81.tar.gz u-boot-01f1ab67f38882dc7665a0a6eca4bbeba6d84f81.tar.bz2 |
Merge branch 'next'
Signed-off-by: Tom Rini <trini@konsulko.com>
Diffstat (limited to 'test')
-rw-r--r-- | test/cmd/pinmux.c | 8 | ||||
-rw-r--r-- | test/common/Makefile | 1 | ||||
-rw-r--r-- | test/common/event.c | 85 | ||||
-rw-r--r-- | test/dm/scmi.c | 119 | ||||
-rw-r--r-- | test/image/spl_load.c | 6 | ||||
-rw-r--r-- | test/py/tests/test_android/test_avb.py | 2 | ||||
-rw-r--r-- | test/py/tests/test_bind.py | 8 | ||||
-rw-r--r-- | test/py/tests/test_event_dump.py | 20 | ||||
-rwxr-xr-x | test/py/tests/test_fit.py | 3 | ||||
-rw-r--r-- | test/py/tests/test_fs/test_erofs.py | 211 | ||||
-rw-r--r-- | test/py/tests/test_vboot.py | 148 | ||||
-rw-r--r-- | test/py/tests/vboot/sandbox-binman-pss.dts | 25 | ||||
-rw-r--r-- | test/py/tests/vboot/sandbox-binman.dts | 24 | ||||
-rw-r--r-- | test/py/tests/vboot/sandbox-u-boot-global-pss.dts | 28 | ||||
-rw-r--r-- | test/py/tests/vboot/sandbox-u-boot-global.dts | 27 | ||||
-rw-r--r-- | test/py/tests/vboot/sandbox-u-boot.dts | 3 | ||||
-rw-r--r-- | test/py/tests/vboot/simple-images.its | 36 | ||||
-rw-r--r-- | test/py/tests/vboot_evil.py | 3 | ||||
-rw-r--r-- | test/py/u_boot_console_base.py | 8 | ||||
-rw-r--r-- | test/test-main.c | 4 |
20 files changed, 677 insertions, 92 deletions
diff --git a/test/cmd/pinmux.c b/test/cmd/pinmux.c index 8ae807b..ba338b8 100644 --- a/test/cmd/pinmux.c +++ b/test/cmd/pinmux.c @@ -16,18 +16,18 @@ static int dm_test_cmd_pinmux_status_pinname(struct unit_test_state *uts) /* Test that 'pinmux status <pinname>' displays the selected pin. */ console_record_reset(); run_command("pinmux status a5", 0); - ut_assert_nextline("a5 : gpio input . "); + ut_assert_nextlinen("a5 : gpio input ."); ut_assert_console_end(); console_record_reset(); run_command("pinmux status P7", 0); - ut_assert_nextline("P7 : GPIO2 bias-pull-down input-enable. "); + ut_assert_nextlinen("P7 : GPIO2 bias-pull-down input-enable."); ut_assert_console_end(); console_record_reset(); run_command("pinmux status P9", 0); - ut_assert_nextline("single-pinctrl pinctrl-single-no-width: missing register width"); - ut_assert_nextline("P9 not found"); + ut_assert_nextlinen("single-pinctrl pinctrl-single-no-width: missing register width"); + ut_assert_nextlinen("P9 not found"); ut_assert_console_end(); return 0; diff --git a/test/common/Makefile b/test/common/Makefile index 24c9145..9087788 100644 --- a/test/common/Makefile +++ b/test/common/Makefile @@ -1,3 +1,4 @@ # SPDX-License-Identifier: GPL-2.0+ obj-y += cmd_ut_common.o obj-$(CONFIG_AUTOBOOT) += test_autoboot.o +obj-$(CONFIG_EVENT) += event.o diff --git a/test/common/event.c b/test/common/event.c new file mode 100644 index 0000000..6037ae2 --- /dev/null +++ b/test/common/event.c @@ -0,0 +1,85 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Unit tests for event handling + * + * Copyright 2021 Google LLC + * Written by Simon Glass <sjg@chromium.org> + */ + +#include <common.h> +#include <dm.h> +#include <event.h> +#include <test/common.h> +#include <test/test.h> +#include <test/ut.h> + +struct test_state { + struct udevice *dev; + int val; +}; + +static int h_adder(void *ctx, struct event *event) +{ + struct event_data_test *data = &event->data.test; + struct test_state *test_state = ctx; + + test_state->val += data->signal; + + return 0; +} + +static int test_event_base(struct unit_test_state *uts) +{ + struct test_state state; + int signal; + + state.val = 12; + ut_assertok(event_register("wibble", EVT_TEST, h_adder, &state)); + + signal = 17; + + /* Check that the handler is called */ + ut_assertok(event_notify(EVT_TEST, &signal, sizeof(signal))); + ut_asserteq(12 + 17, state.val); + + return 0; +} +COMMON_TEST(test_event_base, 0); + +static int h_probe(void *ctx, struct event *event) +{ + struct test_state *test_state = ctx; + + test_state->dev = event->data.dm.dev; + switch (event->type) { + case EVT_DM_PRE_PROBE: + test_state->val |= 1; + break; + case EVT_DM_POST_PROBE: + test_state->val |= 2; + break; + default: + break; + } + + return 0; +} + +static int test_event_probe(struct unit_test_state *uts) +{ + struct test_state state; + struct udevice *dev; + + state.val = 0; + ut_assertok(event_register("pre", EVT_DM_PRE_PROBE, h_probe, &state)); + ut_assertok(event_register("post", EVT_DM_POST_PROBE, h_probe, &state)); + + /* Probe a device */ + ut_assertok(uclass_first_device_err(UCLASS_TEST_FDT, &dev)); + + /* Check that the handler is called */ + ut_asserteq(3, state.val); + + return 0; +} +COMMON_TEST(test_event_probe, UT_TESTF_DM | UT_TESTF_SCAN_FDT); diff --git a/test/dm/scmi.c b/test/dm/scmi.c index c938e6d..795f207 100644 --- a/test/dm/scmi.c +++ b/test/dm/scmi.c @@ -5,7 +5,7 @@ * Tests scmi_agent uclass and the SCMI drivers implemented in other * uclass devices probe when a SCMI server exposes resources. * - * Note in test.dts the protocol@10 node in agent 1. Protocol 0x10 is not + * Note in test.dts the protocol@10 node in scmi node. Protocol 0x10 is not * implemented in U-Boot SCMI components but the implementation is exepected * to not complain on unknown protocol IDs, as long as it is not used. Note * in test.dts tests that SCMI drivers probing does not fail for such an @@ -28,8 +28,7 @@ static int ut_assert_scmi_state_preprobe(struct unit_test_state *uts) struct sandbox_scmi_service *scmi_ctx = sandbox_scmi_service_ctx(); ut_assertnonnull(scmi_ctx); - if (scmi_ctx->agent_count) - ut_asserteq(2, scmi_ctx->agent_count); + ut_assertnull(scmi_ctx->agent); return 0; } @@ -39,35 +38,26 @@ static int ut_assert_scmi_state_postprobe(struct unit_test_state *uts, { struct sandbox_scmi_devices *scmi_devices; struct sandbox_scmi_service *scmi_ctx; - struct sandbox_scmi_agent *agent0; - struct sandbox_scmi_agent *agent1; + struct sandbox_scmi_agent *agent; /* Device references to check context against test sequence */ scmi_devices = sandbox_scmi_devices_ctx(dev); - ut_assertnonnull(scmi_devices); - ut_asserteq(3, scmi_devices->clk_count); + ut_asserteq(2, scmi_devices->clk_count); ut_asserteq(1, scmi_devices->reset_count); ut_asserteq(2, scmi_devices->regul_count); /* State of the simulated SCMI server exposed */ scmi_ctx = sandbox_scmi_service_ctx(); - agent0 = scmi_ctx->agent[0]; - agent1 = scmi_ctx->agent[1]; - - ut_asserteq(2, scmi_ctx->agent_count); - - ut_assertnonnull(agent0); - ut_asserteq(2, agent0->clk_count); - ut_assertnonnull(agent0->clk); - ut_asserteq(1, agent0->reset_count); - ut_assertnonnull(agent0->reset); - ut_asserteq(2, agent0->voltd_count); - ut_assertnonnull(agent0->voltd); - - ut_assertnonnull(agent1); - ut_assertnonnull(agent1->clk); - ut_asserteq(1, agent1->clk_count); + ut_assertnonnull(scmi_ctx); + agent = scmi_ctx->agent; + ut_assertnonnull(agent); + ut_asserteq(3, agent->clk_count); + ut_assertnonnull(agent->clk); + ut_asserteq(1, agent->reset_count); + ut_assertnonnull(agent->reset); + ut_asserteq(2, agent->voltd_count); + ut_assertnonnull(agent->voltd); return 0; } @@ -118,9 +108,8 @@ static int dm_test_scmi_clocks(struct unit_test_state *uts) { struct sandbox_scmi_devices *scmi_devices; struct sandbox_scmi_service *scmi_ctx; - struct sandbox_scmi_agent *agent0; - struct sandbox_scmi_agent *agent1; - struct udevice *dev = NULL; + struct sandbox_scmi_agent *agent; + struct udevice *dev; int ret_dev; int ret; @@ -129,48 +118,50 @@ static int dm_test_scmi_clocks(struct unit_test_state *uts) return ret; scmi_devices = sandbox_scmi_devices_ctx(dev); + ut_assertnonnull(scmi_devices); scmi_ctx = sandbox_scmi_service_ctx(); - agent0 = scmi_ctx->agent[0]; - agent1 = scmi_ctx->agent[1]; + ut_assertnonnull(scmi_ctx); + agent = scmi_ctx->agent; + ut_assertnonnull(agent); /* Test SCMI clocks rate manipulation */ + ut_asserteq(333, agent->clk[0].rate); + ut_asserteq(200, agent->clk[1].rate); + ut_asserteq(1000, agent->clk[2].rate); + ut_asserteq(1000, clk_get_rate(&scmi_devices->clk[0])); ut_asserteq(333, clk_get_rate(&scmi_devices->clk[1])); - ut_asserteq(44, clk_get_rate(&scmi_devices->clk[2])); ret_dev = clk_set_rate(&scmi_devices->clk[1], 1088); ut_assert(!ret_dev || ret_dev == 1088); - ut_asserteq(1000, agent0->clk[0].rate); - ut_asserteq(1088, agent0->clk[1].rate); - ut_asserteq(44, agent1->clk[0].rate); + ut_asserteq(1088, agent->clk[0].rate); + ut_asserteq(200, agent->clk[1].rate); + ut_asserteq(1000, agent->clk[2].rate); ut_asserteq(1000, clk_get_rate(&scmi_devices->clk[0])); ut_asserteq(1088, clk_get_rate(&scmi_devices->clk[1])); - ut_asserteq(44, clk_get_rate(&scmi_devices->clk[2])); /* restore original rate for further tests */ ret_dev = clk_set_rate(&scmi_devices->clk[1], 333); ut_assert(!ret_dev || ret_dev == 333); /* Test SCMI clocks gating manipulation */ - ut_assert(!agent0->clk[0].enabled); - ut_assert(!agent0->clk[1].enabled); - ut_assert(!agent1->clk[0].enabled); + ut_assert(!agent->clk[0].enabled); + ut_assert(!agent->clk[1].enabled); + ut_assert(!agent->clk[2].enabled); ut_asserteq(0, clk_enable(&scmi_devices->clk[1])); - ut_asserteq(0, clk_enable(&scmi_devices->clk[2])); - ut_assert(!agent0->clk[0].enabled); - ut_assert(agent0->clk[1].enabled); - ut_assert(agent1->clk[0].enabled); + ut_assert(agent->clk[0].enabled); + ut_assert(!agent->clk[1].enabled); + ut_assert(!agent->clk[2].enabled); ut_assertok(clk_disable(&scmi_devices->clk[1])); - ut_assertok(clk_disable(&scmi_devices->clk[2])); - ut_assert(!agent0->clk[0].enabled); - ut_assert(!agent0->clk[1].enabled); - ut_assert(!agent1->clk[0].enabled); + ut_assert(!agent->clk[0].enabled); + ut_assert(!agent->clk[1].enabled); + ut_assert(!agent->clk[2].enabled); return release_sandbox_scmi_test_devices(uts, dev); } @@ -180,7 +171,7 @@ static int dm_test_scmi_resets(struct unit_test_state *uts) { struct sandbox_scmi_devices *scmi_devices; struct sandbox_scmi_service *scmi_ctx; - struct sandbox_scmi_agent *agent0; + struct sandbox_scmi_agent *agent; struct udevice *dev = NULL; int ret; @@ -189,17 +180,20 @@ static int dm_test_scmi_resets(struct unit_test_state *uts) return ret; scmi_devices = sandbox_scmi_devices_ctx(dev); + ut_assertnonnull(scmi_devices); scmi_ctx = sandbox_scmi_service_ctx(); - agent0 = scmi_ctx->agent[0]; + ut_assertnonnull(scmi_ctx); + agent = scmi_ctx->agent; + ut_assertnonnull(agent); /* Test SCMI resect controller manipulation */ - ut_assert(!agent0->reset[0].asserted) + ut_assert(!agent->reset[0].asserted) ut_assertok(reset_assert(&scmi_devices->reset[0])); - ut_assert(agent0->reset[0].asserted) + ut_assert(agent->reset[0].asserted) ut_assertok(reset_deassert(&scmi_devices->reset[0])); - ut_assert(!agent0->reset[0].asserted); + ut_assert(!agent->reset[0].asserted); return release_sandbox_scmi_test_devices(uts, dev); } @@ -209,7 +203,7 @@ static int dm_test_scmi_voltage_domains(struct unit_test_state *uts) { struct sandbox_scmi_devices *scmi_devices; struct sandbox_scmi_service *scmi_ctx; - struct sandbox_scmi_agent *agent0; + struct sandbox_scmi_agent *agent; struct dm_regulator_uclass_plat *uc_pdata; struct udevice *dev; struct udevice *regul0_dev; @@ -217,8 +211,11 @@ static int dm_test_scmi_voltage_domains(struct unit_test_state *uts) ut_assertok(load_sandbox_scmi_test_devices(uts, &dev)); scmi_devices = sandbox_scmi_devices_ctx(dev); + ut_assertnonnull(scmi_devices); scmi_ctx = sandbox_scmi_service_ctx(); - agent0 = scmi_ctx->agent[0]; + ut_assertnonnull(scmi_ctx); + agent = scmi_ctx->agent; + ut_assertnonnull(agent); /* Set/Get an SCMI voltage domain level */ regul0_dev = scmi_devices->regul[0]; @@ -228,32 +225,32 @@ static int dm_test_scmi_voltage_domains(struct unit_test_state *uts) ut_assert(uc_pdata); ut_assertok(regulator_set_value(regul0_dev, uc_pdata->min_uV)); - ut_asserteq(agent0->voltd[0].voltage_uv, uc_pdata->min_uV); + ut_asserteq(agent->voltd[0].voltage_uv, uc_pdata->min_uV); ut_assert(regulator_get_value(regul0_dev) == uc_pdata->min_uV); ut_assertok(regulator_set_value(regul0_dev, uc_pdata->max_uV)); - ut_asserteq(agent0->voltd[0].voltage_uv, uc_pdata->max_uV); + ut_asserteq(agent->voltd[0].voltage_uv, uc_pdata->max_uV); ut_assert(regulator_get_value(regul0_dev) == uc_pdata->max_uV); /* Enable/disable SCMI voltage domains */ ut_assertok(regulator_set_enable(scmi_devices->regul[0], false)); ut_assertok(regulator_set_enable(scmi_devices->regul[1], false)); - ut_assert(!agent0->voltd[0].enabled); - ut_assert(!agent0->voltd[1].enabled); + ut_assert(!agent->voltd[0].enabled); + ut_assert(!agent->voltd[1].enabled); ut_assertok(regulator_set_enable(scmi_devices->regul[0], true)); - ut_assert(agent0->voltd[0].enabled); - ut_assert(!agent0->voltd[1].enabled); + ut_assert(agent->voltd[0].enabled); + ut_assert(!agent->voltd[1].enabled); ut_assertok(regulator_set_enable(scmi_devices->regul[1], true)); - ut_assert(agent0->voltd[0].enabled); - ut_assert(agent0->voltd[1].enabled); + ut_assert(agent->voltd[0].enabled); + ut_assert(agent->voltd[1].enabled); ut_assertok(regulator_set_enable(scmi_devices->regul[0], false)); - ut_assert(!agent0->voltd[0].enabled); - ut_assert(agent0->voltd[1].enabled); + ut_assert(!agent->voltd[0].enabled); + ut_assert(agent->voltd[1].enabled); return release_sandbox_scmi_test_devices(uts, dev); } diff --git a/test/image/spl_load.c b/test/image/spl_load.c index e7cabf5..df389e2 100644 --- a/test/image/spl_load.c +++ b/test/image/spl_load.c @@ -56,7 +56,6 @@ struct image_header *spl_get_load_buffer(ssize_t offset, size_t size) static int spl_test_load(struct unit_test_state *uts) { - const char *cur_prefix, *next_prefix; struct spl_image_info image; struct image_header *header; struct text_ctx text_ctx; @@ -69,10 +68,7 @@ static int spl_test_load(struct unit_test_state *uts) load.bl_len = 512; load.read = read_fit_image; - cur_prefix = spl_phase_prefix(spl_phase()); - next_prefix = spl_phase_prefix(spl_next_phase()); - ret = os_find_u_boot(fname, sizeof(fname), true, cur_prefix, - next_prefix); + ret = sandbox_find_next_phase(fname, sizeof(fname), true); if (ret) { printf("(%s not found, error %d)\n", fname, ret); return ret; diff --git a/test/py/tests/test_android/test_avb.py b/test/py/tests/test_android/test_avb.py index a04a7ff..a3f8831 100644 --- a/test/py/tests/test_android/test_avb.py +++ b/test/py/tests/test_android/test_avb.py @@ -66,7 +66,7 @@ def test_avb_mmc_uuid(u_boot_console): part_list[cur_partname] = guid_to_check[1] # lets check all guids with avb get_guid - for part, guid in part_list.iteritems(): + for part, guid in part_list.items(): avb_guid_resp = u_boot_console.run_command('avb get_uuid %s' % part) assert guid == avb_guid_resp.split('UUID: ')[1] diff --git a/test/py/tests/test_bind.py b/test/py/tests/test_bind.py index 9f234fb6..8ad277d 100644 --- a/test/py/tests/test_bind.py +++ b/test/py/tests/test_bind.py @@ -131,7 +131,7 @@ def test_bind_unbind_with_uclass(u_boot_console): child2_index = int(child2_line[0].split()[1]) #bind simple_bus as a child of bind-test-child2 - response = u_boot_console.run_command('bind {} {} simple_bus'.format(child2_uclass, child2_index, 'simple_bus')) + response = u_boot_console.run_command('bind {} {} simple_bus'.format(child2_uclass, child2_index)) #check that the child is there and its uclass/index pair is right tree = u_boot_console.run_command('dm tree') @@ -152,7 +152,7 @@ def test_bind_unbind_with_uclass(u_boot_console): assert child_of_child2_line == '' #bind simple_bus as a child of bind-test-child2 - response = u_boot_console.run_command('bind {} {} simple_bus'.format(child2_uclass, child2_index, 'simple_bus')) + response = u_boot_console.run_command('bind {} {} simple_bus'.format(child2_uclass, child2_index)) #check that the child is there and its uclass/index pair is right tree = u_boot_console.run_command('dm tree') @@ -165,7 +165,7 @@ def test_bind_unbind_with_uclass(u_boot_console): assert child_of_child2_index == child2_index + 1 #unbind the child and check it has been removed - response = u_boot_console.run_command('unbind {} {} simple_bus'.format(child2_uclass, child2_index, 'simple_bus')) + response = u_boot_console.run_command('unbind {} {} simple_bus'.format(child2_uclass, child2_index)) assert response == '' tree = u_boot_console.run_command('dm tree') @@ -176,7 +176,7 @@ def test_bind_unbind_with_uclass(u_boot_console): #unbind the child again and check it doesn't change the tree tree_old = u_boot_console.run_command('dm tree') - response = u_boot_console.run_command('unbind {} {} simple_bus'.format(child2_uclass, child2_index, 'simple_bus')) + response = u_boot_console.run_command('unbind {} {} simple_bus'.format(child2_uclass, child2_index)) tree_new = u_boot_console.run_command('dm tree') assert response == '' diff --git a/test/py/tests/test_event_dump.py b/test/py/tests/test_event_dump.py new file mode 100644 index 0000000..b753e80 --- /dev/null +++ b/test/py/tests/test_event_dump.py @@ -0,0 +1,20 @@ +# SPDX-License-Identifier: GPL-2.0+ +# Copyright 2021 Google LLC +# Written by Simon Glass <sjg@chromium.org> + +import pytest +import re +import u_boot_utils as util + +# This is only a partial test - coverting 64-bit sandbox. It does not test +# big-endian images, nor 32-bit images +@pytest.mark.boardspec('sandbox') +def test_event_dump(u_boot_console): + """Test that the "help" command can be executed.""" + cons = u_boot_console + sandbox = cons.config.build_dir + '/u-boot' + out = util.run_and_log(cons, ['scripts/event_dump.py', sandbox]) + expect = '''.*Event type Id Source location +-------------------- ------------------------------ ------------------------------ +EVT_MISC_INIT_F sandbox_misc_init_f .*arch/sandbox/cpu/start.c:''' + assert re.match(expect, out, re.MULTILINE) is not None diff --git a/test/py/tests/test_fit.py b/test/py/tests/test_fit.py index 6d5b43c..5856960 100755 --- a/test/py/tests/test_fit.py +++ b/test/py/tests/test_fit.py @@ -89,6 +89,9 @@ base_fdt = ''' model = "Sandbox Verified Boot Test"; compatible = "sandbox"; + binman { + }; + reset@0 { compatible = "sandbox,reset"; reg = <0>; diff --git a/test/py/tests/test_fs/test_erofs.py b/test/py/tests/test_fs/test_erofs.py new file mode 100644 index 0000000..458a52b --- /dev/null +++ b/test/py/tests/test_fs/test_erofs.py @@ -0,0 +1,211 @@ +# SPDX-License-Identifier: GPL-2.0+ +# Copyright (C) 2022 Huang Jianan <jnhuang95@gmail.com> +# Author: Huang Jianan <jnhuang95@gmail.com> + +import os +import pytest +import shutil +import subprocess + +EROFS_SRC_DIR = 'erofs_src_dir' +EROFS_IMAGE_NAME = 'erofs.img' + +def generate_file(name, size): + """ + Generates a file filled with 'x'. + """ + content = 'x' * size + file = open(name, 'w') + file.write(content) + file.close() + +def make_erofs_image(build_dir): + """ + Makes the EROFS images used for the test. + + The image is generated at build_dir with the following structure: + erofs_src_dir/ + ├── f4096 + ├── f7812 + ├── subdir/ + │ └── subdir-file + ├── symdir -> subdir + └── symfile -> f5096 + """ + root = os.path.join(build_dir, EROFS_SRC_DIR) + os.makedirs(root) + + # 4096: uncompressed file + generate_file(os.path.join(root, 'f4096'), 4096) + + # 7812: Compressed file + generate_file(os.path.join(root, 'f7812'), 7812) + + # sub-directory with a single file inside + subdir_path = os.path.join(root, 'subdir') + os.makedirs(subdir_path) + generate_file(os.path.join(subdir_path, 'subdir-file'), 100) + + # symlink + os.symlink('subdir', os.path.join(root, 'symdir')) + os.symlink('f7812', os.path.join(root, 'symfile')) + + input_path = os.path.join(build_dir, EROFS_SRC_DIR) + output_path = os.path.join(build_dir, EROFS_IMAGE_NAME) + args = ' '.join([output_path, input_path]) + subprocess.run(['mkfs.erofs -zlz4 ' + args], shell=True, check=True, + stdout=subprocess.DEVNULL) + +def clean_erofs_image(build_dir): + """ + Deletes the image and src_dir at build_dir. + """ + path = os.path.join(build_dir, EROFS_SRC_DIR) + shutil.rmtree(path) + image_path = os.path.join(build_dir, EROFS_IMAGE_NAME) + os.remove(image_path) + +def erofs_ls_at_root(u_boot_console): + """ + Test if all the present files and directories were listed. + """ + no_slash = u_boot_console.run_command('erofsls host 0') + slash = u_boot_console.run_command('erofsls host 0 /') + assert no_slash == slash + + expected_lines = ['./', '../', '4096 f4096', '7812 f7812', 'subdir/', + '<SYM> symdir', '<SYM> symfile', '4 file(s), 3 dir(s)'] + + output = u_boot_console.run_command('erofsls host 0') + for line in expected_lines: + assert line in output + +def erofs_ls_at_subdir(u_boot_console): + """ + Test if the path resolution works. + """ + expected_lines = ['./', '../', '100 subdir-file', '1 file(s), 2 dir(s)'] + output = u_boot_console.run_command('erofsls host 0 subdir') + for line in expected_lines: + assert line in output + +def erofs_ls_at_symlink(u_boot_console): + """ + Test if the symbolic link's target resolution works. + """ + output = u_boot_console.run_command('erofsls host 0 symdir') + output_subdir = u_boot_console.run_command('erofsls host 0 subdir') + assert output == output_subdir + + expected_lines = ['./', '../', '100 subdir-file', '1 file(s), 2 dir(s)'] + for line in expected_lines: + assert line in output + +def erofs_ls_at_non_existent_dir(u_boot_console): + """ + Test if the EROFS support will crash when get a nonexistent directory. + """ + out_non_existent = u_boot_console.run_command('erofsls host 0 fff') + out_not_dir = u_boot_console.run_command('erofsls host 0 f1000') + assert out_non_existent == out_not_dir + assert '' in out_non_existent + +def erofs_load_files(u_boot_console, files, sizes, address): + """ + Loads files and asserts their checksums. + """ + build_dir = u_boot_console.config.build_dir + for (file, size) in zip(files, sizes): + out = u_boot_console.run_command('erofsload host 0 {} {}'.format(address, file)) + + # check if the right amount of bytes was read + assert size in out + + # calculate u-boot file's checksum + out = u_boot_console.run_command('md5sum {} {}'.format(address, hex(int(size)))) + u_boot_checksum = out.split()[-1] + + # calculate original file's checksum + original_file_path = os.path.join(build_dir, EROFS_SRC_DIR + '/' + file) + out = subprocess.run(['md5sum ' + original_file_path], shell=True, check=True, + capture_output=True, text=True) + original_checksum = out.stdout.split()[0] + + # compare checksum + assert u_boot_checksum == original_checksum + +def erofs_load_files_at_root(u_boot_console): + """ + Test load file from the root directory. + """ + files = ['f4096', 'f7812'] + sizes = ['4096', '7812'] + address = '$kernel_addr_r' + erofs_load_files(u_boot_console, files, sizes, address) + +def erofs_load_files_at_subdir(u_boot_console): + """ + Test load file from the subdirectory. + """ + files = ['subdir/subdir-file'] + sizes = ['100'] + address = '$kernel_addr_r' + erofs_load_files(u_boot_console, files, sizes, address) + +def erofs_load_files_at_symlink(u_boot_console): + """ + Test load file from the symlink. + """ + files = ['symfile'] + sizes = ['7812'] + address = '$kernel_addr_r' + erofs_load_files(u_boot_console, files, sizes, address) + +def erofs_load_non_existent_file(u_boot_console): + """ + Test if the EROFS support will crash when load a nonexistent file. + """ + address = '$kernel_addr_r' + file = 'non-existent' + out = u_boot_console.run_command('erofsload host 0 {} {}'.format(address, file)) + assert 'Failed to load' in out + +def erofs_run_all_tests(u_boot_console): + """ + Runs all test cases. + """ + erofs_ls_at_root(u_boot_console) + erofs_ls_at_subdir(u_boot_console) + erofs_ls_at_symlink(u_boot_console) + erofs_ls_at_non_existent_dir(u_boot_console) + erofs_load_files_at_root(u_boot_console) + erofs_load_files_at_subdir(u_boot_console) + erofs_load_files_at_symlink(u_boot_console) + erofs_load_non_existent_file(u_boot_console) + +@pytest.mark.boardspec('sandbox') +@pytest.mark.buildconfigspec('cmd_fs_generic') +@pytest.mark.buildconfigspec('cmd_erofs') +@pytest.mark.buildconfigspec('fs_erofs') +@pytest.mark.requiredtool('mkfs.erofs') +@pytest.mark.requiredtool('md5sum') + +def test_erofs(u_boot_console): + """ + Executes the erofs test suite. + """ + build_dir = u_boot_console.config.build_dir + + try: + # setup test environment + make_erofs_image(build_dir) + image_path = os.path.join(build_dir, EROFS_IMAGE_NAME) + u_boot_console.run_command('host bind 0 {}'.format(image_path)) + # run all tests + erofs_run_all_tests(u_boot_console) + except: + clean_erofs_image(build_dir) + raise AssertionError + + # clean test environment + clean_erofs_image(build_dir) diff --git a/test/py/tests/test_vboot.py b/test/py/tests/test_vboot.py index ac8ed9f..040147d 100644 --- a/test/py/tests/test_vboot.py +++ b/test/py/tests/test_vboot.py @@ -21,6 +21,14 @@ For configuration verification: - Corrupt the signature - Check that image verification no-longer works +For pre-load header verification: +- Create FIT image with a pre-load header +- Check that signature verification succeeds +- Corrupt the FIT image +- Check that signature verification fails +- Launch an FIT image without a pre-load header +- Check that image verification fails + Tests run with both SHA1 and SHA256 hashing. """ @@ -35,19 +43,21 @@ import vboot_evil # Only run the full suite on a few combinations, since it doesn't add any more # test coverage. TESTDATA = [ - ['sha1-basic', 'sha1', '', None, False, True, False], - ['sha1-pad', 'sha1', '', '-E -p 0x10000', False, False, False], - ['sha1-pss', 'sha1', '-pss', None, False, False, False], - ['sha1-pss-pad', 'sha1', '-pss', '-E -p 0x10000', False, False, False], - ['sha256-basic', 'sha256', '', None, False, False, False], - ['sha256-pad', 'sha256', '', '-E -p 0x10000', False, False, False], - ['sha256-pss', 'sha256', '-pss', None, False, False, False], - ['sha256-pss-pad', 'sha256', '-pss', '-E -p 0x10000', False, False, False], - ['sha256-pss-required', 'sha256', '-pss', None, True, False, False], - ['sha256-pss-pad-required', 'sha256', '-pss', '-E -p 0x10000', True, True, False], - ['sha384-basic', 'sha384', '', None, False, False, False], - ['sha384-pad', 'sha384', '', '-E -p 0x10000', False, False, False], - ['algo-arg', 'algo-arg', '', '-o sha256,rsa2048', False, False, True], + ['sha1-basic', 'sha1', '', None, False, True, False, False], + ['sha1-pad', 'sha1', '', '-E -p 0x10000', False, False, False, False], + ['sha1-pss', 'sha1', '-pss', None, False, False, False, False], + ['sha1-pss-pad', 'sha1', '-pss', '-E -p 0x10000', False, False, False, False], + ['sha256-basic', 'sha256', '', None, False, False, False, False], + ['sha256-pad', 'sha256', '', '-E -p 0x10000', False, False, False, False], + ['sha256-pss', 'sha256', '-pss', None, False, False, False, False], + ['sha256-pss-pad', 'sha256', '-pss', '-E -p 0x10000', False, False, False, False], + ['sha256-pss-required', 'sha256', '-pss', None, True, False, False, False], + ['sha256-pss-pad-required', 'sha256', '-pss', '-E -p 0x10000', True, True, False, False], + ['sha384-basic', 'sha384', '', None, False, False, False, False], + ['sha384-pad', 'sha384', '', '-E -p 0x10000', False, False, False, False], + ['algo-arg', 'algo-arg', '', '-o sha256,rsa2048', False, False, True, False], + ['sha256-global-sign', 'sha256', '', '', False, False, False, True], + ['sha256-global-sign-pss', 'sha256', '-pss', '', False, False, False, True], ] @pytest.mark.boardspec('sandbox') @@ -56,10 +66,10 @@ TESTDATA = [ @pytest.mark.requiredtool('fdtget') @pytest.mark.requiredtool('fdtput') @pytest.mark.requiredtool('openssl') -@pytest.mark.parametrize("name,sha_algo,padding,sign_options,required,full_test,algo_arg", +@pytest.mark.parametrize("name,sha_algo,padding,sign_options,required,full_test,algo_arg,global_sign", TESTDATA) def test_vboot(u_boot_console, name, sha_algo, padding, sign_options, required, - full_test, algo_arg): + full_test, algo_arg, global_sign): """Test verified boot signing with mkimage and verification with 'bootm'. This works using sandbox only as it needs to update the device tree used @@ -81,6 +91,33 @@ def test_vboot(u_boot_console, name, sha_algo, padding, sign_options, required, util.run_and_log(cons, 'dtc %s %s%s -O dtb ' '-o %s%s' % (dtc_args, datadir, dts, tmpdir, dtb)) + def dtc_options(dts, options): + """Run the device tree compiler to compile a .dts file + + The output file will be the same as the input file but with a .dtb + extension. + + Args: + dts: Device tree file to compile. + options: Options provided to the compiler. + """ + dtb = dts.replace('.dts', '.dtb') + util.run_and_log(cons, 'dtc %s %s%s -O dtb ' + '-o %s%s %s' % (dtc_args, datadir, dts, tmpdir, dtb, options)) + + def run_binman(dtb): + """Run binman to build an image + + Args: + dtb: Device tree file used as input file. + """ + pythonpath = os.environ.get('PYTHONPATH', '') + os.environ['PYTHONPATH'] = pythonpath + ':' + '%s/../scripts/dtc/pylibfdt' % tmpdir + util.run_and_log(cons, [binman, 'build', '-d', "%s/%s" % (tmpdir,dtb), + '-a', "pre-load-key-path=%s" % tmpdir, '-O', + tmpdir, '-I', tmpdir]) + os.environ['PYTHONPATH'] = pythonpath + def run_bootm(sha_algo, test_type, expect_string, boots, fit=None): """Run a 'bootm' command U-Boot. @@ -139,6 +176,23 @@ def test_vboot(u_boot_console, name, sha_algo, padding, sign_options, required, cons.log.action('%s: Sign images' % sha_algo) util.run_and_log(cons, args) + def sign_fit_dtb(sha_algo, options, dtb): + """Sign the FIT + + Signs the FIT and writes the signature into it. It also writes the + public key into the dtb. + + Args: + sha_algo: Either 'sha1' or 'sha256', to select the algorithm to + use. + options: Options to provide to mkimage. + """ + args = [mkimage, '-F', '-k', tmpdir, '-K', dtb, '-r', fit] + if options: + args += options.split(' ') + cons.log.action('%s: Sign images' % sha_algo) + util.run_and_log(cons, args) + def sign_fit_norequire(sha_algo, options): """Sign the FIT @@ -176,6 +230,20 @@ def test_vboot(u_boot_console, name, sha_algo, padding, sign_options, required, handle.write(struct.pack(">I", size)) return struct.unpack(">I", total_size)[0] + def corrupt_file(fit, offset, value): + """Corrupt a file + + To corrupt a file, a value is written at the specified offset + + Args: + fit: The file to corrupt + offset: Offset to write + value: Value written + """ + with open(fit, 'r+b') as handle: + handle.seek(offset) + handle.write(struct.pack(">I", value)) + def create_rsa_pair(name): """Generate a new RSA key paid and certificate @@ -374,6 +442,51 @@ def test_vboot(u_boot_console, name, sha_algo, padding, sign_options, required, (dtb)) run_bootm(sha_algo, 'multi required key', '', False) + def test_global_sign(sha_algo, padding, sign_options): + """Test global image signature with the given hash algorithm and padding. + + Args: + sha_algo: Either 'sha1' or 'sha256', to select the algorithm to use + padding: Either '' or '-pss', to select the padding to use for the + rsa signature algorithm. + """ + + dtb = '%ssandbox-u-boot-global%s.dtb' % (tmpdir, padding) + cons.config.dtb = dtb + + # Compile our device tree files for kernel and U-Boot. These are + # regenerated here since mkimage will modify them (by adding a + # public key) below. + dtc('sandbox-kernel.dts') + dtc_options('sandbox-u-boot-global%s.dts' % padding, '-p 1024') + + # Build the FIT with dev key (keys NOT required). This adds the + # signature into sandbox-u-boot.dtb, NOT marked 'required'. + make_fit('simple-images.its') + sign_fit_dtb(sha_algo, '', dtb) + + # Build the dtb for binman that define the pre-load header + # with the global sigature. + dtc('sandbox-binman%s.dts' % padding) + + # Run binman to create the final image with the not signed fit + # and the pre-load header that contains the global signature. + run_binman('sandbox-binman%s.dtb' % padding) + + # Check that the signature is correctly verified by u-boot + run_bootm(sha_algo, 'global image signature', + 'signature check has succeed', True, "%ssandbox.img" % tmpdir) + + # Corrupt the image (just one byte after the pre-load header) + corrupt_file("%ssandbox.img" % tmpdir, 4096, 255); + + # Check that the signature verification fails + run_bootm(sha_algo, 'global image signature', + 'signature check has failed', False, "%ssandbox.img" % tmpdir) + + # Check that the boot fails if the global signature is not provided + run_bootm(sha_algo, 'global image signature', 'signature is mandatory', False) + cons = u_boot_console tmpdir = os.path.join(cons.config.result_dir, name) + '/' if not os.path.exists(tmpdir): @@ -381,6 +494,7 @@ def test_vboot(u_boot_console, name, sha_algo, padding, sign_options, required, datadir = cons.config.source_dir + '/test/py/tests/vboot/' fit = '%stest.fit' % tmpdir mkimage = cons.config.build_dir + '/tools/mkimage' + binman = cons.config.source_dir + '/tools/binman/binman' fit_check_sign = cons.config.build_dir + '/tools/fit_check_sign' dtc_args = '-I dts -O dtb -i %s' % tmpdir dtb = '%ssandbox-u-boot.dtb' % tmpdir @@ -403,7 +517,9 @@ def test_vboot(u_boot_console, name, sha_algo, padding, sign_options, required, # afterwards. old_dtb = cons.config.dtb cons.config.dtb = dtb - if required: + if global_sign: + test_global_sign(sha_algo, padding, sign_options) + elif required: test_required_key(sha_algo, padding, sign_options) else: test_with_algo(sha_algo, padding, sign_options) diff --git a/test/py/tests/vboot/sandbox-binman-pss.dts b/test/py/tests/vboot/sandbox-binman-pss.dts new file mode 100644 index 0000000..56e3a42 --- /dev/null +++ b/test/py/tests/vboot/sandbox-binman-pss.dts @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: GPL-2.0+ + +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + binman { + filename = "sandbox.img"; + + pre-load { + content = <&image>; + algo-name = "sha256,rsa2048"; + padding-name = "pss"; + key-name = "dev.key"; + header-size = <4096>; + version = <1>; + }; + + image: blob-ext { + filename = "test.fit"; + }; + }; +}; diff --git a/test/py/tests/vboot/sandbox-binman.dts b/test/py/tests/vboot/sandbox-binman.dts new file mode 100644 index 0000000..b24aeba --- /dev/null +++ b/test/py/tests/vboot/sandbox-binman.dts @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: GPL-2.0+ + +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + binman { + filename = "sandbox.img"; + + pre-load { + content = <&image>; + algo-name = "sha256,rsa2048"; + key-name = "dev.key"; + header-size = <4096>; + version = <1>; + }; + + image: blob-ext { + filename = "test.fit"; + }; + }; +}; diff --git a/test/py/tests/vboot/sandbox-u-boot-global-pss.dts b/test/py/tests/vboot/sandbox-u-boot-global-pss.dts new file mode 100644 index 0000000..c59a682 --- /dev/null +++ b/test/py/tests/vboot/sandbox-u-boot-global-pss.dts @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: GPL-2.0+ + +/dts-v1/; + +/ { + model = "Sandbox Verified Boot Test"; + compatible = "sandbox"; + + binman { + }; + + reset@0 { + compatible = "sandbox,reset"; + }; + + image { + pre-load { + sig { + algo-name = "sha256,rsa2048"; + padding-name = "pss"; + signature-size = <256>; + mandatory = "yes"; + + key-name = "dev"; + }; + }; + }; +}; diff --git a/test/py/tests/vboot/sandbox-u-boot-global.dts b/test/py/tests/vboot/sandbox-u-boot-global.dts new file mode 100644 index 0000000..1409f9e --- /dev/null +++ b/test/py/tests/vboot/sandbox-u-boot-global.dts @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: GPL-2.0+ + +/dts-v1/; + +/ { + model = "Sandbox Verified Boot Test"; + compatible = "sandbox"; + + binman { + }; + + reset@0 { + compatible = "sandbox,reset"; + }; + + image { + pre-load { + sig { + algo-name = "sha256,rsa2048"; + signature-size = <256>; + mandatory = "yes"; + + key-name = "dev"; + }; + }; + }; +}; diff --git a/test/py/tests/vboot/sandbox-u-boot.dts b/test/py/tests/vboot/sandbox-u-boot.dts index 63f8f40..5809c62 100644 --- a/test/py/tests/vboot/sandbox-u-boot.dts +++ b/test/py/tests/vboot/sandbox-u-boot.dts @@ -4,6 +4,9 @@ model = "Sandbox Verified Boot Test"; compatible = "sandbox"; + binman { + }; + reset@0 { compatible = "sandbox,reset"; }; diff --git a/test/py/tests/vboot/simple-images.its b/test/py/tests/vboot/simple-images.its new file mode 100644 index 0000000..f627864 --- /dev/null +++ b/test/py/tests/vboot/simple-images.its @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: GPL-2.0+ + +/dts-v1/; + +/ { + description = "Chrome OS kernel image with one or more FDT blobs"; + #address-cells = <1>; + + images { + kernel { + data = /incbin/("test-kernel.bin"); + type = "kernel_noload"; + arch = "sandbox"; + os = "linux"; + compression = "none"; + load = <0x4>; + entry = <0x8>; + kernel-version = <1>; + }; + fdt-1 { + description = "snow"; + data = /incbin/("sandbox-kernel.dtb"); + type = "flat_dt"; + arch = "sandbox"; + compression = "none"; + fdt-version = <1>; + }; + }; + configurations { + default = "conf-1"; + conf-1 { + kernel = "kernel"; + fdt = "fdt-1"; + }; + }; +}; diff --git a/test/py/tests/vboot_evil.py b/test/py/tests/vboot_evil.py index 9825c21..e2b0cd6 100644 --- a/test/py/tests/vboot_evil.py +++ b/test/py/tests/vboot_evil.py @@ -482,4 +482,5 @@ if __name__ == '__main__': print('valid attack names: [fakeroot, kernel@]') sys.exit(1) - add_evil_node(sys.argv[1:]) + in_fname, out_fname, kernel_fname, attack = sys.argv[1:] + add_evil_node(in_fname, out_fname, kernel_fname, attack) diff --git a/test/py/u_boot_console_base.py b/test/py/u_boot_console_base.py index 3938ec1..58ec859 100644 --- a/test/py/u_boot_console_base.py +++ b/test/py/u_boot_console_base.py @@ -115,6 +115,14 @@ class ConsoleBase(object): self.at_prompt = False self.at_prompt_logevt = None + def get_spawn(self): + # This is not called, ssubclass must define this. + # Return a value to avoid: + # u_boot_console_base.py:348:12: E1128: Assigning result of a function + # call, where the function returns None (assignment-from-none) + return u_boot_spawn.Spawn([]) + + def eval_bad_patterns(self): self.bad_patterns = [pat[PAT_RE] for pat in bad_pattern_defs \ if self.disable_check_count[pat[PAT_ID]] == 0] diff --git a/test/test-main.c b/test/test-main.c index 8fcb02e..ee38d1f 100644 --- a/test/test-main.c +++ b/test/test-main.c @@ -7,6 +7,7 @@ #include <common.h> #include <console.h> #include <dm.h> +#include <event.h> #include <dm/root.h> #include <dm/test.h> #include <dm/uclass-internal.h> @@ -218,6 +219,8 @@ static int dm_test_restore(struct device_node *of_root) */ static int test_pre_run(struct unit_test_state *uts, struct unit_test *test) { + ut_assertok(event_init()); + if (test->flags & UT_TESTF_DM) ut_assertok(dm_test_pre_run(uts)); @@ -260,6 +263,7 @@ static int test_post_run(struct unit_test_state *uts, struct unit_test *test) ut_unsilence_console(uts); if (test->flags & UT_TESTF_DM) ut_assertok(dm_test_post_run(uts)); + ut_assertok(event_uninit()); return 0; } |