From: Ahmad Fatoum <a.fatoum@pengutronix.de>
To: SCHNEIDER Johannes <johannes.schneider@leica-geosystems.com>
Cc: "barebox@lists.infradead.org" <barebox@lists.infradead.org>
Subject: Re: [PATCH v1] firmware: choose PBL fw-external verify algorithm via Kconfig
Date: Tue, 16 Jun 2026 10:14:46 +0200 [thread overview]
Message-ID: <ad9006dd-08c6-4c9f-be0c-a97a673e2117@pengutronix.de> (raw)
In-Reply-To: <AM0PR06MB41485EC4B2403D9B22037A6FBCE52@AM0PR06MB4148.eurprd06.prod.outlook.com>
Hello Johannes,
On 6/16/26 7:46 AM, SCHNEIDER Johannes wrote:
>> On 6/13/26 9:56 PM, Johannes Schneider wrote:
>>
>>> it
>>> only re-checks the BootROM->DRAM copy against a value baked into the
>>> PBL itself, not against an external trust anchor. A 32-bit CRC over
>>> the same window catches the realistic failure mode (a corrupted copy
>>> into DRAM) at ~200x lower wall-clock cost.
>>
>> Give recent commit f2ae1a4a85d0 ("ARM: rockchip: atf: enable MMU in
>> PBL") and its follow-up a look.
>>
>
> thanks for the hint, i'm "toying" with the code now, and am wondering: instead
> of enabling the MMU to speed up the software sha256, would you have any concerns
> if i would enable and use the hardware sha256 that lives inside the imx8?
>
> from my first couple of measurements i get:
> | Variant | bl32-verify | Delta vs prev | Cumulative drop |
> | Pre-MMU-on (generic C, uncached) | 2190 ms | -- | -- |
> | Post-MMU-on (generic C, cached) | 451 ms | -1739 ms | -1739 ms |
> | Crypto-ext, per 64bytes block | 192 ms | -259 ms | -1998 ms |
> | Crypto-ext, batched | **5 ms** | -187 ms | -2185 ms |
>
> i could send either the "enable mmu" or the "enable hardware hashing" a better follow up to this patch - opinions/preferences?
Por qué no los dos? :-)
>> I'd suggest you do the same: Keep the hash as-is, but set up MMU as soon
>> as you have the memory size.
>>
>> You can also play around with mimicking compression of firmware blobs
>> like we have on Rockchip. Depending on CPU vs I/O speed, this can also
>> reduce your startup time.
>
> compressing the optee tee.bin (~720KiB) and having PBL uncompress it again would
> (probably) work, i have some code that does this - but for some reason the way
> we build and sign the whole barebox binary now doesn't agree with the imx8m*
> bootrom, and it drops me back into serial-dl mode = it refuses the image
> completly.
That's strange. You can continue booting via serial download mode and
run the bootrom command. Maybe there's some useful info there on why the
boot failed.
> Any hints for what i need to look out for when adding such feature to the PBL?
I haven't implemented it myself yet, but saw Sascha's patches for
Rockchip. I'd suggest you to follow that.
Cheers,
Ahmad
>
>
> gruß
> Johannes
>
>
>>
>> Cheers,
>> Ahmad
>>
>>>
>>> Make the verify algorithm a Kconfig choice:
>>>
>>> PBL_FIRMWARE_EXT_VERIFY_NONE no verify
>>> PBL_FIRMWARE_EXT_VERIFY_CRC32 4-byte CRC, cheap corruption check
>>> PBL_FIRMWARE_EXT_VERIFY_SHA256 current behaviour, default
>>>
>>> firmware/Makefile selects an algorithm and passes it to gen-fw-s,
>>> which emits nothing for NONE, a 4-byte .long for CRC32, or 32 bytes
>>> for SHA-256 in the per-blob .rodata.<fwstr>.sha section. The macro
>>> in include/firmware.h declares the verify symbols only when actually
>>> used (offset != 0, i.e. fw-external blobs), so NONE is a true no-op
>>> and in-tree firmware never grew a section dependency.
>>> firmware_ext_verify() dispatches via IS_ENABLED() at compile time.
>>>
>>> The verify-section symbol names (_fw_*_sha_*) are kept as-is rather
>>> than renamed, since firmware_next_image_verify() also references
>>> them for the FIRMWARE_VERIFY_NEXT_IMAGE path; under CRC32 the name
>>> no longer describes the contents, but renaming would expand the
>>> patch scope unnecessarily.
>>>
>>> Default stays at SHA-256 so existing defconfigs keep their current
>>> semantics.
>>>
>>> Assisted-by: Claude:claude-opus-4-7
>>> Signed-off-by: Johannes Schneider <johannes.schneider@leica-geosystems.com>
>>> ---
>>> firmware/Kconfig | 33 +++++++++++++++++++++++++++
>>> firmware/Makefile | 15 ++++++++++--
>>> include/firmware.h | 41 +++++++++++++++++++++++----------
>>> include/pbl.h | 2 ++
>>> pbl/decomp.c | 35 ++++++++++++++++++++++++++++
>>> scripts/gen-fw-s | 57 +++++++++++++++++++++++++++++++++-------------
>>> 6 files changed, 153 insertions(+), 30 deletions(-)
>>>
>>> diff --git a/firmware/Kconfig b/firmware/Kconfig
>>> index b9b4556dbd..f745819a67 100644
>>> --- a/firmware/Kconfig
>>> +++ b/firmware/Kconfig
>>> @@ -151,4 +151,37 @@ config FIRMWARE_VERIFY_NEXT_IMAGE
>>> verified images. The function to check the next stage image hash is
>>> firmware_next_image_verify(), make sure your SoC code uses it.
>>>
>>> +choice
>>> + prompt "PBL fw-external blob verification"
>>> + default PBL_FIRMWARE_EXT_VERIFY_SHA256
>>> + help
>>> + Algorithm used by the PBL to verify an fw-external blob against a
>>> + value embedded at build time, before handoff to TF-A. Runs with
>>> + the MMU off and DRAM reads uncached, so cost scales sharply with
>>> + blob size and algorithm. This checks integrity vs the build-time
>>> + value; it is not authentication against an external trust anchor.
>>> +
>>> +config PBL_FIRMWARE_EXT_VERIFY_NONE
>>> + bool "none"
>>> + help
>>> + Skip the verify. Appropriate when the boot chain authenticates the
>>> + blob upstream of the PBL (HAB, AHAB, signed FIT, ...) -- the
>>> + in-PBL check is then redundant.
>>> +
>>> +config PBL_FIRMWARE_EXT_VERIFY_CRC32
>>> + bool "CRC32"
>>> + select CRC32
>>> + help
>>> + 4-byte CRC32 (zlib polynomial). Catches accidental corruption
>>> + of the BootROM->DRAM copy; not cryptographic.
>>> +
>>> +config PBL_FIRMWARE_EXT_VERIFY_SHA256
>>> + bool "SHA-256"
>>> + help
>>> + Cryptographic hash, software-computed with MMU off. Strongest
>>> + option but by far the slowest -- prefer NONE or CRC32 when the
>>> + blob is already authenticated upstream of the PBL.
>>> +
>>> +endchoice
>>> +
>>> endmenu
>>> diff --git a/firmware/Makefile b/firmware/Makefile
>>> index 7e433a1824..1590bed9f1 100644
>>> --- a/firmware/Makefile
>>> +++ b/firmware/Makefile
>>> @@ -61,8 +61,19 @@ pbl-fwext-y := $(addsuffix .extgen.o, $(fw-external-y))
>>>
>>> FWNAME = $(patsubst $(obj)/%.extgen.S,%,$(patsubst $(obj)/%.gen.S,%,$@))
>>>
>>> -filechk_fwbin = $(srctree)/scripts/gen-fw-s $(FWNAME) $(FIRMWARE_DIR) .rodata '' $(fwobjdir)
>>> -filechk_fwbin_ext = $(srctree)/scripts/gen-fw-s $(FWNAME) $(FIRMWARE_DIR) .pblext a $(fwobjdir)
>>> +# Verify algorithm passed to gen-fw-s for fw-external blobs. Drives the
>>> +# verify metadata section emitted into .extgen.S and matched by
>>> +# firmware_ext_verify() in include/firmware.h.
>>> +ifdef CONFIG_PBL_FIRMWARE_EXT_VERIFY_NONE
>>> +fw_verify_algo := none
>>> +else ifdef CONFIG_PBL_FIRMWARE_EXT_VERIFY_CRC32
>>> +fw_verify_algo := crc32
>>> +else
>>> +fw_verify_algo := sha256
>>> +endif
>>> +
>>> +filechk_fwbin = $(srctree)/scripts/gen-fw-s $(FWNAME) $(FIRMWARE_DIR) .rodata '' $(fwobjdir) sha256
>>> +filechk_fwbin_ext = $(srctree)/scripts/gen-fw-s $(FWNAME) $(FIRMWARE_DIR) .pblext a $(fwobjdir) $(fw_verify_algo)
>>>
>>> $(obj)/%.gen.S: FORCE
>>> $(call filechk,fwbin)
>>> diff --git a/include/firmware.h b/include/firmware.h
>>> index 6511d56b2e..72a47f24e3 100644
>>> --- a/include/firmware.h
>>> +++ b/include/firmware.h
>>> @@ -80,13 +80,21 @@ static inline void release_firmware(const struct firmware *fw)
>>>
>>> void firmwaremgr_list_handlers(void);
>>>
>>> -static inline void firmware_ext_verify(const void *data_start, size_t data_size,
>>> - const void *hash_start, size_t hash_size)
>>> +static inline void firmware_ext_verify(const void *data, size_t data_size,
>>> + const void *verify, size_t verify_size)
>>> {
>>> - if (pbl_barebox_verify(data_start, data_size,
>>> - hash_start, hash_size) != 0) {
>>> + int ret;
>>> +
>>> + if (IS_ENABLED(CONFIG_PBL_FIRMWARE_EXT_VERIFY_CRC32))
>>> + ret = pbl_barebox_verify_crc32(data, data_size,
>>> + verify, verify_size);
>>> + else
>>> + ret = pbl_barebox_verify(data, data_size,
>>> + verify, verify_size);
>>> +
>>> + if (ret != 0) {
>>> putc_ll('!');
>>> - panic("hash mismatch, refusing to decompress");
>>> + panic("firmware verify mismatch, refusing to decompress");
>>> }
>>> }
>>>
>>> @@ -96,22 +104,31 @@ struct fwobj {
>>> void *data;
>>> };
>>>
>>> +#if defined(CONFIG_PBL_FIRMWARE_EXT_VERIFY_NONE)
>>> +# define __fw_ext_verify(name, fwobj) do { } while (0)
>>> +#else
>>> +# define __fw_ext_verify(name, fwobj) \
>>> + do { \
>>> + extern char _fw_##name##_sha_start[]; \
>>> + extern char _fw_##name##_sha_end[]; \
>>> + firmware_ext_verify( \
>>> + (fwobj)->data, (fwobj)->size, \
>>> + _fw_##name##_sha_start, \
>>> + _fw_##name##_sha_end - \
>>> + _fw_##name##_sha_start); \
>>> + } while (0)
>>> +#endif
>>> +
>>> #define __get_builtin_firmware(name, offset, fwobj) \
>>> do { \
>>> extern char _fw_##name##_start[]; \
>>> extern char _fw_##name##_end[]; \
>>> - extern char _fw_##name##_sha_start[]; \
>>> - extern char _fw_##name##_sha_end[]; \
>>> (fwobj)->data = _fw_##name##_start; \
>>> (fwobj)->size = _fw_##name##_end - _fw_##name##_start; \
>>> if (!(offset)) \
>>> break; \
>>> (fwobj)->data += (offset); \
>>> - firmware_ext_verify( \
>>> - (fwobj)->data, (fwobj)->size, \
>>> - _fw_##name##_sha_start, \
>>> - _fw_##name##_sha_end - _fw_##name##_sha_start \
>>> - ); \
>>> + __fw_ext_verify(name, fwobj); \
>>> } while (0)
>>>
>>>
>>> diff --git a/include/pbl.h b/include/pbl.h
>>> index fe4367825c..57ca8b4eb3 100644
>>> --- a/include/pbl.h
>>> +++ b/include/pbl.h
>>> @@ -29,6 +29,8 @@ fdt_device_get_match_data(const void *fdt, const char *nodepath,
>>>
>>> int pbl_barebox_verify(const void *compressed_start, unsigned int len,
>>> const void *hash, unsigned int hash_len);
>>> +int pbl_barebox_verify_crc32(const void *data_start, unsigned int len,
>>> + const void *crc, unsigned int crc_len);
>>> int pbl_load_fdt(const void *fdt, void *dest, int destsize);
>>>
>>> #define PBL_MALLOC_SIZE SZ_128K
>>> diff --git a/pbl/decomp.c b/pbl/decomp.c
>>> index 1539a6b67e..ace121eac6 100644
>>> --- a/pbl/decomp.c
>>> +++ b/pbl/decomp.c
>>> @@ -13,6 +13,10 @@
>>> #include <asm/sections.h>
>>> #include <pbl.h>
>>> #include <debug_ll.h>
>>> +#ifdef CONFIG_PBL_FIRMWARE_EXT_VERIFY_CRC32
>>> +#include <crc.h>
>>> +#include <asm/unaligned.h>
>>> +#endif
>>>
>>> #define STATIC static
>>>
>>> @@ -90,6 +94,37 @@ int pbl_barebox_verify(const void *compressed_start, unsigned int len,
>>> return memcmp(hash, computed_hash, SHA256_DIGEST_SIZE);
>>> }
>>>
>>> +#ifdef CONFIG_PBL_FIRMWARE_EXT_VERIFY_CRC32
>>> +int pbl_barebox_verify_crc32(const void *data_start, unsigned int len,
>>> + const void *crc, unsigned int crc_len)
>>> +{
>>> + uint32_t expected, computed;
>>> +
>>> + if (crc_len != sizeof(uint32_t))
>>> + return -1;
>>> +
>>> + /* Stored little-endian by .long in the .rodata.*.sha section. */
>>> + expected = get_unaligned_le32(crc);
>>> + computed = crc32(0, data_start, len);
>>> +
>>> + if (IS_ENABLED(CONFIG_DEBUG_LL)) {
>>> + puts_ll("CRC ");
>>> + puthexc_ll((computed >> 24) & 0xff);
>>> + puthexc_ll((computed >> 16) & 0xff);
>>> + puthexc_ll((computed >> 8) & 0xff);
>>> + puthexc_ll(computed & 0xff);
>>> + puts_ll(" vs ");
>>> + puthexc_ll((expected >> 24) & 0xff);
>>> + puthexc_ll((expected >> 16) & 0xff);
>>> + puthexc_ll((expected >> 8) & 0xff);
>>> + puthexc_ll(expected & 0xff);
>>> + putc_ll('\n');
>>> + }
>>> +
>>> + return computed == expected ? 0 : -1;
>>> +}
>>> +#endif
>>> +
>>> void pbl_barebox_uncompress(void *dest, void *compressed_start, unsigned int len)
>>> {
>>> uint32_t pbl_hash_len;
>>> diff --git a/scripts/gen-fw-s b/scripts/gen-fw-s
>>> index 78c3193479..d7d7d15824 100755
>>> --- a/scripts/gen-fw-s
>>> +++ b/scripts/gen-fw-s
>>> @@ -3,13 +3,20 @@
>>> #
>>> # Generate assembly source to embed firmware binary
>>> #
>>> -# Usage: gen-fw-s <fwname> <fwdir> <secprefix> [secflags] [fwobjdir]
>>> +# Usage: gen-fw-s <fwname> <fwdir> <secprefix> [secflags] [fwobjdir] [verify-algo]
>>> +#
>>> +# verify-algo selects the metadata emitted in the .rodata.<fwstr>.sha
>>> +# section, matched by firmware_ext_verify() in include/firmware.h:
>>> +# sha256 (default) -- 32-byte SHA-256
>>> +# crc32 -- 4-byte CRC32 (zlib polynomial)
>>> +# none -- no section, no symbols
>>>
>>> fwname=$1
>>> fwdir=$2
>>> secprefix=$3
>>> secflags=$4
>>> fwobjdir=$5
>>> +verify_algo=${6:-sha256}
>>>
>>> fwstr=$(echo "$fwname" | tr '/.-' '___')
>>> fwpath="$fwdir/$fwname"
>>> @@ -19,8 +26,6 @@ if [ -f "$fwpath" ]; then
>>> fw_uncompressed=$(stat -c %s "$fwpath")
>>> fi
>>>
>>> -sha=$(sha256sum "$fwpath" 2>/dev/null | sed 's/ .*$//;s/../0x&, /g;s/, $//')
>>> -
>>> echo "/* Generated by scripts/gen-fw-s */"
>>> echo "#include <asm-generic/pointer.h>"
>>> echo ".section .note.GNU-stack,\"\",%progbits"
>>> @@ -59,19 +64,39 @@ echo ".global _fw_z_${fwstr}_end"
>>> echo "_fw_z_${fwstr}_end:"
>>> echo "#endif"
>>>
>>> -# include sha256, needed for external firmware
>>> -echo " .section .rodata.${fwstr}.sha"
>>> -echo " .p2align ASM_LGPTR"
>>> -echo ".global _fw_${fwstr}_sha_start"
>>> -echo "_fw_${fwstr}_sha_start:"
>>> -echo " .byte ${sha}"
>>> -echo ".global _fw_${fwstr}_sha_end"
>>> -echo "_fw_${fwstr}_sha_end:"
>>> -if [ -f "$fwpath" ]; then
>>> - echo ".if _fw_${fwstr}_sha_start + 32 - _fw_${fwstr}_sha_end"
>>> - echo ".error \"sha256sum invalid\""
>>> - echo ".endif"
>>> -fi
>>> +# verify metadata for fw-external blobs, consumed by firmware_ext_verify()
>>> +# in include/firmware.h. Driven by the PBL_FIRMWARE_EXT_VERIFY Kconfig
>>> +# choice (passed in from firmware/Makefile).
>>> +case "$verify_algo" in
>>> +none)
>>> + ;;
>>> +crc32)
>>> + crc=$(python3 -c 'import sys,zlib; sys.stdout.write("0x%08x" % zlib.crc32(open(sys.argv[1],"rb").read()))' \
>>> + "$fwpath" 2>/dev/null || echo "0x00000000")
>>> + echo " .section .rodata.${fwstr}.sha"
>>> + echo " .p2align 2"
>>> + echo ".global _fw_${fwstr}_sha_start"
>>> + echo "_fw_${fwstr}_sha_start:"
>>> + echo " .long ${crc}"
>>> + echo ".global _fw_${fwstr}_sha_end"
>>> + echo "_fw_${fwstr}_sha_end:"
>>> + ;;
>>> +sha256|*)
>>> + sha=$(sha256sum "$fwpath" 2>/dev/null | sed 's/ .*$//;s/../0x&, /g;s/, $//')
>>> + echo " .section .rodata.${fwstr}.sha"
>>> + echo " .p2align ASM_LGPTR"
>>> + echo ".global _fw_${fwstr}_sha_start"
>>> + echo "_fw_${fwstr}_sha_start:"
>>> + echo " .byte ${sha}"
>>> + echo ".global _fw_${fwstr}_sha_end"
>>> + echo "_fw_${fwstr}_sha_end:"
>>> + if [ -f "$fwpath" ]; then
>>> + echo ".if _fw_${fwstr}_sha_start + 32 - _fw_${fwstr}_sha_end"
>>> + echo ".error \"sha256sum invalid\""
>>> + echo ".endif"
>>> + fi
>>> + ;;
>>> +esac
>>>
>>> # include a string containing the firmware name. When a non existing
>>> # firmware is referenced in the PBL then _fwname_${fwstr} is referenced
>>>
>>> base-commit: 6c70fb327d486376c1f2e37dfff2212cb9eebb1b
>>
>> --
>> Pengutronix e.K. | |
>> Steuerwalder Str. 21 | http://www.pengutronix.de/ |
>> 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 |
>> Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
>>
>
>
--
Pengutronix e.K. | |
Steuerwalder Str. 21 | http://www.pengutronix.de/ |
31137 Hildesheim, Germany | Phone: +49-5121-206917-0 |
Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
next prev parent reply other threads:[~2026-06-16 8:15 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-06-13 19:56 Johannes Schneider
2026-06-15 9:49 ` Ahmad Fatoum
2026-06-16 5:46 ` SCHNEIDER Johannes
2026-06-16 8:14 ` Ahmad Fatoum [this message]
2026-06-16 14:59 ` SCHNEIDER Johannes
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=ad9006dd-08c6-4c9f-be0c-a97a673e2117@pengutronix.de \
--to=a.fatoum@pengutronix.de \
--cc=barebox@lists.infradead.org \
--cc=johannes.schneider@leica-geosystems.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox