diff options
-rw-r--r-- | .azure-pipelines.yml | 2 | ||||
-rw-r--r-- | .gitlab-ci.yml | 2 | ||||
-rw-r--r-- | arch/sandbox/dts/test.dts | 2 | ||||
-rw-r--r-- | cmd/fdt.c | 32 | ||||
-rw-r--r-- | doc/arch/sandbox/sandbox.rst | 2 | ||||
-rw-r--r-- | drivers/pinctrl/pinctrl-uclass.c | 47 | ||||
-rw-r--r-- | test/cmd/fdt.c | 1 | ||||
-rw-r--r-- | test/py/tests/test_vbe_vpl.py | 6 | ||||
-rw-r--r-- | test/py/tests/test_vboot.py | 186 | ||||
-rwxr-xr-x | test/run | 5 |
10 files changed, 200 insertions, 85 deletions
diff --git a/.azure-pipelines.yml b/.azure-pipelines.yml index 5594a67..64da11e 100644 --- a/.azure-pipelines.yml +++ b/.azure-pipelines.yml @@ -263,7 +263,7 @@ stages: TEST_PY_TEST_SPEC: "test_ofplatdata or test_handoff or test_spl" sandbox_vpl: TEST_PY_BD: "sandbox_vpl" - TEST_PY_TEST_SPEC: "test_vpl_help or test_spl" + TEST_PY_TEST_SPEC: "vpl or test_spl" sandbox_noinst: TEST_PY_BD: "sandbox_noinst" TEST_PY_TEST_SPEC: "test_ofplatdata or test_handoff or test_spl" diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 5431bf6..2a42374 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -301,7 +301,7 @@ sandbox_noinst_test.py: sandbox_vpl test.py: variables: TEST_PY_BD: "sandbox_vpl" - TEST_PY_TEST_SPEC: "test_vpl_help or test_spl" + TEST_PY_TEST_SPEC: "vpl or test_spl" <<: *buildman_and_testpy_dfn # Enable tracing and disable LTO, to ensure functions are not elided diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts index d72d7a5..7c1ee71 100644 --- a/arch/sandbox/dts/test.dts +++ b/arch/sandbox/dts/test.dts @@ -129,7 +129,7 @@ status = "disabled"; compatible = "fwupd,vbe-simple"; storage = "mmc3"; - skip-offset = <0x400000>; + skip-offset = <0x800000>; area-start = <0>; area-size = <0xe00000>; state-offset = <0xdffc00>; @@ -36,16 +36,21 @@ static int is_printable_string(const void *data, int len); */ struct fdt_header *working_fdt; -void set_working_fdt_addr(ulong addr) +static void set_working_fdt_addr_quiet(ulong addr) { void *buf; - printf("Working FDT set to %lx\n", addr); buf = map_sysmem(addr, 0); working_fdt = buf; env_set_hex("fdtaddr", addr); } +void set_working_fdt_addr(ulong addr) +{ + printf("Working FDT set to %lx\n", addr); + set_working_fdt_addr_quiet(addr); +} + /* * Get a value from the fdt and format it to be set in the environment */ @@ -192,10 +197,14 @@ static int do_fdt(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) if ((quiet && fdt_check_header(blob)) || (!quiet && !fdt_valid(&blob))) return 1; - if (control) + if (control) { gd->fdt_blob = blob; - else - set_working_fdt_addr(addr); + } else { + if (quiet) + set_working_fdt_addr_quiet(addr); + else + set_working_fdt_addr(addr); + } if (argc >= 2) { int len; @@ -475,18 +484,9 @@ static int do_fdt(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) if (ret != 0) return ret; } else if (subcmd[0] == 'a') { - /* Get address */ - char buf[19]; - - snprintf(buf, sizeof(buf), "%lx", - (ulong)map_to_sysmem(nodep)); - env_set(var, buf); + env_set_hex(var, (ulong)map_to_sysmem(nodep)); } else if (subcmd[0] == 's') { - /* Get size */ - char buf[11]; - - sprintf(buf, "0x%08X", len); - env_set(var, buf); + env_set_hex(var, len); } else return CMD_RET_USAGE; return 0; diff --git a/doc/arch/sandbox/sandbox.rst b/doc/arch/sandbox/sandbox.rst index cd7f8a2..77ca6bc 100644 --- a/doc/arch/sandbox/sandbox.rst +++ b/doc/arch/sandbox/sandbox.rst @@ -388,7 +388,7 @@ The device can be marked removeable with 'host bind -r'. A disk image can be created using the following commands:: $> truncate -s 1200M ./disk.raw - $> echo -e "label: gpt\n,64M,U\n,,L" | /usr/sbin/sgdisk ./disk.raw + $> /usr/sbin/sgdisk --new=1:0:+64M --typecode=1:EF00 --new=2:0:0 --typecode=2:8300 disk.raw $> lodev=`sudo losetup -P -f --show ./disk.raw` $> sudo mkfs.vfat -n EFI -v ${lodev}p1 $> sudo mkfs.ext4 -L ROOT -v ${lodev}p2 diff --git a/drivers/pinctrl/pinctrl-uclass.c b/drivers/pinctrl/pinctrl-uclass.c index 8837726..73dd7b1 100644 --- a/drivers/pinctrl/pinctrl-uclass.c +++ b/drivers/pinctrl/pinctrl-uclass.c @@ -169,34 +169,33 @@ pinctrl_gpio_get_pinctrl_and_offset(struct udevice *dev, unsigned offset, { struct ofnode_phandle_args args; unsigned gpio_offset, pfc_base, pfc_pins; - int ret; + int ret = 0; + int i = 0; - ret = dev_read_phandle_with_args(dev, "gpio-ranges", NULL, 3, - 0, &args); - if (ret) { - dev_dbg(dev, "%s: dev_read_phandle_with_args: err=%d\n", - __func__, ret); - return ret; - } + while (ret == 0) { + ret = dev_read_phandle_with_args(dev, "gpio-ranges", NULL, 3, + i++, &args); + if (ret) { + dev_dbg(dev, "%s: dev_read_phandle_with_args: err=%d\n", + __func__, ret); + return ret; + } - ret = uclass_get_device_by_ofnode(UCLASS_PINCTRL, - args.node, pctldev); - if (ret) { - dev_dbg(dev, - "%s: uclass_get_device_by_of_offset failed: err=%d\n", - __func__, ret); - return ret; - } + ret = uclass_get_device_by_ofnode(UCLASS_PINCTRL, + args.node, pctldev); + if (ret) { + dev_dbg(dev, + "%s: uclass_get_device_by_of_offset failed: err=%d\n", + __func__, ret); + return ret; + } - gpio_offset = args.args[0]; - pfc_base = args.args[1]; - pfc_pins = args.args[2]; + gpio_offset = args.args[0]; + pfc_base = args.args[1]; + pfc_pins = args.args[2]; - if (offset < gpio_offset || offset > gpio_offset + pfc_pins) { - dev_dbg(dev, - "%s: GPIO can not be mapped to pincontrol pin\n", - __func__); - return -EINVAL; + if (offset >= gpio_offset && offset <= gpio_offset + pfc_pins) + break; } offset -= gpio_offset; diff --git a/test/cmd/fdt.c b/test/cmd/fdt.c index 597fecb..7835da2 100644 --- a/test/cmd/fdt.c +++ b/test/cmd/fdt.c @@ -236,7 +236,6 @@ static int fdt_test_addr_resize(struct unit_test_state *uts) /* ...quietly */ ut_assertok(run_commandf("fdt addr -q %08lx %zx", addr, sizeof(fdt) / 4)); - ut_assert_nextline("Working FDT set to %lx", addr); ut_assertok(ut_check_console_end(uts)); /* We cannot easily provoke errors in fdt_open_into(), so ignore that */ diff --git a/test/py/tests/test_vbe_vpl.py b/test/py/tests/test_vbe_vpl.py index d1c9d05..ed12d3a 100644 --- a/test/py/tests/test_vbe_vpl.py +++ b/test/py/tests/test_vbe_vpl.py @@ -15,6 +15,7 @@ def test_vbe_vpl(u_boot_console): #cmd = [cons.config.build_dir + fname, '-v'] ram = os.path.join(cons.config.build_dir, 'ram.bin') fdt = os.path.join(cons.config.build_dir, 'arch/sandbox/dts/test.dtb') + image_fname = os.path.join(cons.config.build_dir, 'image.bin') # Enable firmware1 and the mmc that it uses. These are needed for the full # VBE flow. @@ -24,12 +25,13 @@ def test_vbe_vpl(u_boot_console): cons, f'fdtput -t s {fdt} /bootstd/firmware1 status okay') u_boot_utils.run_and_log( cons, f'fdtput -t s {fdt} /mmc3 status okay') + u_boot_utils.run_and_log( + cons, f'fdtput -t s {fdt} /mmc3 filename {image_fname}') # Remove any existing RAM file, so we don't have old data present if os.path.exists(ram): os.remove(ram) - flags = ['-p', os.path.join(cons.config.build_dir, 'image.bin'), '-w', - '-s', 'state.dtb'] + flags = ['-p', image_fname, '-w', '-s', 'state.dtb'] cons.restart_uboot_with_flags(flags) # Make sure that VBE was used in both VPL (to load SPL) and SPL (to load diff --git a/test/py/tests/test_vboot.py b/test/py/tests/test_vboot.py index e3e7ca4..04fa59f 100644 --- a/test/py/tests/test_vboot.py +++ b/test/py/tests/test_vboot.py @@ -30,6 +30,12 @@ For pre-load header verification: - Check that image verification fails Tests run with both SHA1 and SHA256 hashing. + +This also tests fdt_add_pubkey utility in the simple way: +- Create DTB and FIT files +- Add keys with fdt_add_pubkey to DTB +- Sign FIT image +- Check with fit_check_sign that keys properly added to DTB file """ import os @@ -40,6 +46,41 @@ import u_boot_utils as util import vboot_forge import vboot_evil +# Common helper functions +def dtc(dts, cons, dtc_args, datadir, tmpdir, dtb): + """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. + cons: U-Boot console. + dtc_args: DTC arguments. + datadir: Path to data directory. + tmpdir: Path to temp directory. + dtb: Resulting DTB file. + """ + dtb = dts.replace('.dts', '.dtb') + util.run_and_log(cons, 'dtc %s %s%s -O dtb ' + '-o %s%s' % (dtc_args, datadir, dts, tmpdir, dtb)) + +def make_fit(its, cons, mkimage, dtc_args, datadir, fit): + """Make a new FIT from the .its source file. + + This runs 'mkimage -f' to create a new FIT. + + Args: + its: Filename containing .its source. + cons: U-Boot console. + mkimage: Path to mkimage utility. + dtc_args: DTC arguments. + datadir: Path to data directory. + fit: Resulting FIT file. + """ + util.run_and_log(cons, [mkimage, '-D', dtc_args, '-f', + '%s%s' % (datadir, its), fit]) + # Only run the full suite on a few combinations, since it doesn't add any more # test coverage. TESTDATA_IN = [ @@ -82,19 +123,6 @@ def test_vboot(u_boot_console, name, sha_algo, padding, sign_options, required, The SHA1 and SHA256 tests are combined into a single test since the key-generation process is quite slow and we want to avoid doing it twice. """ - def dtc(dts): - """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. - """ - dtb = dts.replace('.dts', '.dtb') - 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 @@ -152,17 +180,6 @@ def test_vboot(u_boot_console, name, sha_algo, padding, sign_options, required, assert('sandbox: continuing, as we cannot run' not in ''.join(output)) - def make_fit(its): - """Make a new FIT from the .its source file. - - This runs 'mkimage -f' to create a new FIT. - - Args: - its: Filename containing .its source. - """ - util.run_and_log(cons, [mkimage, '-D', dtc_args, '-f', - '%s%s' % (datadir, its), fit]) - def sign_fit(sha_algo, options): """Sign the FIT @@ -286,12 +303,12 @@ def test_vboot(u_boot_console, name, sha_algo, padding, sign_options, required, # 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('sandbox-u-boot.dts') + dtc('sandbox-kernel.dts', cons, dtc_args, datadir, tmpdir, dtb) + dtc('sandbox-u-boot.dts', cons, dtc_args, datadir, tmpdir, dtb) # Build the FIT, but don't sign anything yet cons.log.action('%s: Test FIT with signed images' % sha_algo) - make_fit('sign-images-%s%s.its' % (sha_algo, padding)) + make_fit('sign-images-%s%s.its' % (sha_algo, padding), cons, mkimage, dtc_args, datadir, fit) run_bootm(sha_algo, 'unsigned images', ' - OK' if algo_arg else 'dev-', True) # Sign images with our dev keys @@ -299,10 +316,10 @@ def test_vboot(u_boot_console, name, sha_algo, padding, sign_options, required, run_bootm(sha_algo, 'signed images', 'dev+', True) # Create a fresh .dtb without the public keys - dtc('sandbox-u-boot.dts') + dtc('sandbox-u-boot.dts', cons, dtc_args, datadir, tmpdir, dtb) cons.log.action('%s: Test FIT with signed configuration' % sha_algo) - make_fit('sign-configs-%s%s.its' % (sha_algo, padding)) + make_fit('sign-configs-%s%s.its' % (sha_algo, padding), cons, mkimage, dtc_args, datadir, fit) run_bootm(sha_algo, 'unsigned config', '%s+ OK' % ('sha256' if algo_arg else sha_algo), True) # Sign images with our dev keys @@ -352,7 +369,7 @@ def test_vboot(u_boot_console, name, sha_algo, padding, sign_options, required, run_bootm(sha_algo, 'evil kernel@', msg, False, efit) # Create a new properly signed fit and replace header bytes - make_fit('sign-configs-%s%s.its' % (sha_algo, padding)) + make_fit('sign-configs-%s%s.its' % (sha_algo, padding), cons, mkimage, dtc_args, datadir, fit) sign_fit(sha_algo, sign_options) bcfg = u_boot_console.config.buildconfig max_size = int(bcfg.get('config_fit_signature_max_size', 0x10000000), 0) @@ -399,19 +416,19 @@ def test_vboot(u_boot_console, name, sha_algo, padding, sign_options, required, # 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('sandbox-u-boot.dts') + dtc('sandbox-kernel.dts', cons, dtc_args, datadir, tmpdir, dtb) + dtc('sandbox-u-boot.dts', cons, dtc_args, datadir, tmpdir, dtb) cons.log.action('%s: Test FIT with configs images' % sha_algo) # Build the FIT with prod key (keys required) and sign it. This puts the # signature into sandbox-u-boot.dtb, marked 'required' - make_fit('sign-configs-%s%s-prod.its' % (sha_algo, padding)) + make_fit('sign-configs-%s%s-prod.its' % (sha_algo, padding), cons, mkimage, dtc_args, datadir, fit) sign_fit(sha_algo, sign_options) # Build the FIT with dev key (keys NOT required). This adds the # signature into sandbox-u-boot.dtb, NOT marked 'required'. - make_fit('sign-configs-%s%s.its' % (sha_algo, padding)) + make_fit('sign-configs-%s%s.its' % (sha_algo, padding), cons, mkimage, dtc_args, datadir, fit) sign_fit_norequire(sha_algo, sign_options) # So now sandbox-u-boot.dtb two signatures, for the prod and dev keys. @@ -423,7 +440,7 @@ def test_vboot(u_boot_console, name, sha_algo, padding, sign_options, required, # Build the FIT with dev key (keys required) and sign it. This puts the # signature into sandbox-u-boot.dtb, marked 'required'. - make_fit('sign-configs-%s%s.its' % (sha_algo, padding)) + make_fit('sign-configs-%s%s.its' % (sha_algo, padding), cons, mkimage, dtc_args, datadir, fit) sign_fit(sha_algo, sign_options) # Set the required-mode policy to "any". @@ -461,17 +478,17 @@ def test_vboot(u_boot_console, name, sha_algo, padding, sign_options, required, # 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('sandbox-kernel.dts', cons, dtc_args, datadir, tmpdir, dtb) 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') + make_fit('simple-images.its', cons, mkimage, dtc_args, datadir, fit) 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) + dtc('sandbox-binman%s.dts' % padding, cons, dtc_args, datadir, tmpdir, dtb) # Run binman to create the final image with the not signed fit # and the pre-load header that contains the global signature. @@ -531,3 +548,96 @@ def test_vboot(u_boot_console, name, sha_algo, padding, sign_options, required, # Go back to the original U-Boot with the correct dtb. cons.config.dtb = old_dtb cons.restart_uboot() + + +TESTDATA_IN = [ + ['sha1-basic', 'sha1', '', None, False], + ['sha1-pad', 'sha1', '', '-E -p 0x10000', False], + ['sha1-pss', 'sha1', '-pss', None, False], + ['sha1-pss-pad', 'sha1', '-pss', '-E -p 0x10000', False], + ['sha256-basic', 'sha256', '', None, False], + ['sha256-pad', 'sha256', '', '-E -p 0x10000', False], + ['sha256-pss', 'sha256', '-pss', None, False], + ['sha256-pss-pad', 'sha256', '-pss', '-E -p 0x10000', False], + ['sha256-pss-required', 'sha256', '-pss', None, False], + ['sha256-pss-pad-required', 'sha256', '-pss', '-E -p 0x10000', False], + ['sha384-basic', 'sha384', '', None, False], + ['sha384-pad', 'sha384', '', '-E -p 0x10000', False], + ['algo-arg', 'algo-arg', '', '-o sha256,rsa2048', True], + ['sha256-global-sign', 'sha256', '', '', False], + ['sha256-global-sign-pss', 'sha256', '-pss', '', False], +] + +# Mark all but the first test as slow, so they are not run with '-k not slow' +TESTDATA = [TESTDATA_IN[0]] +TESTDATA += [pytest.param(*v, marks=pytest.mark.slow) for v in TESTDATA_IN[1:]] + +@pytest.mark.boardspec('sandbox') +@pytest.mark.buildconfigspec('fit_signature') +@pytest.mark.requiredtool('dtc') +@pytest.mark.requiredtool('openssl') +@pytest.mark.parametrize("name,sha_algo,padding,sign_options,algo_arg", TESTDATA) +def test_fdt_add_pubkey(u_boot_console, name, sha_algo, padding, sign_options, algo_arg): + """Test fdt_add_pubkey utility with bunch of different algo options.""" + + def sign_fit(sha_algo, options): + """Sign the FIT + + Signs the FIT and writes the signature into it. + + Args: + sha_algo: Either 'sha1' or 'sha256', to select the algorithm to + use. + options: Options to provide to mkimage. + """ + args = [mkimage, '-F', '-k', tmpdir, fit] + if options: + args += options.split(' ') + cons.log.action('%s: Sign images' % sha_algo) + util.run_and_log(cons, args) + + def test_add_pubkey(sha_algo, padding, sign_options): + """Test fdt_add_pubkey utility with given hash algorithm and padding. + + This function tests if fdt_add_pubkey utility may add public keys into dtb. + + 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. + sign_options: Options to mkimage when signing a fit image. + """ + + # Create a fresh .dtb without the public keys + dtc('sandbox-u-boot.dts', cons, dtc_args, datadir, tmpdir, dtb) + + cons.log.action('%s: Test fdt_add_pubkey with signed configuration' % sha_algo) + # Then add the dev key via the fdt_add_pubkey tool + util.run_and_log(cons, [fdt_add_pubkey, '-a', '%s,%s' % ('sha256' if algo_arg else sha_algo, \ + 'rsa3072' if sha_algo == 'sha384' else 'rsa2048'), + '-k', tmpdir, '-n', 'dev', '-r', 'conf', dtb]) + + make_fit('sign-configs-%s%s.its' % (sha_algo, padding), cons, mkimage, dtc_args, datadir, fit) + + # Sign images with our dev keys + sign_fit(sha_algo, sign_options) + + # Check with fit_check_sign that FIT is signed with key + util.run_and_log(cons, [fit_check_sign, '-f', fit, '-k', dtb]) + + cons = u_boot_console + tmpdir = os.path.join(cons.config.result_dir, name) + '/' + if not os.path.exists(tmpdir): + os.mkdir(tmpdir) + 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' + fdt_add_pubkey = cons.config.build_dir + '/tools/fdt_add_pubkey' + dtc_args = '-I dts -O dtb -i %s' % tmpdir + dtb = '%ssandbox-u-boot.dtb' % tmpdir + + # keys created in test_vboot test + + test_add_pubkey(sha_algo, padding, sign_options) @@ -56,6 +56,11 @@ echo "${prompt}" run_test "sandbox_noinst" ./test/py/test.py --bd sandbox_noinst --build ${para} \ -k 'test_ofplatdata or test_handoff or test_spl' +# Run tests which require sandbox_vpl +echo "${prompt}" +run_test "sandbox_vpl" ./test/py/test.py --bd sandbox_vpl --build ${para} \ + -k 'vpl or test_spl' + if [ -z "$tools_only" ]; then # Run tests for the flat-device-tree version of sandbox. This is a special # build which does not enable CONFIG_OF_LIVE for the live device tree, so we can |