Create transfer lists with header version 2, and accept lists with header version 1 or 2.
Version 1.0 of the Firmware Handoff specification is withdrawn, because it specified an XOR checksum while implementations used an additive one. Version 2.0 went back to the additive checksum, which U-Boot already uses, and changed the header version to 2 without changing the layout of the header or the entries. Since TF-A v2.15, its transfer list library creates version 2 lists, which U-Boot rejects, so it loses everything that the earlier boot stage passed in the list. Lists with version 1 are still accepted, since existing firmware creates them. Link: https://github.com/FirmwareHandoff/firmware_handoff/commit/dfb62d83c735064291a249d802aabcf48bffb8a0 Link: https://github.com/TF-Shared/transfer-list-library/commit/81d7f820853aa117a0458ada3b9892c619233db1 Signed-off-by: David Lechner <[email protected]> --- common/bloblist.c | 10 +++++++++- include/bloblist.h | 8 ++++++-- test/common/bloblist.c | 21 ++++++++++++++++++++- 3 files changed, 35 insertions(+), 4 deletions(-) diff --git a/common/bloblist.c b/common/bloblist.c index 4ddb4a56944..90b70b06826 100644 --- a/common/bloblist.c +++ b/common/bloblist.c @@ -467,7 +467,15 @@ int bloblist_check(ulong addr, uint size) hdr = map_sysmem(addr, sizeof(*hdr)); if (hdr->magic != BLOBLIST_MAGIC) return log_msg_ret("Bad magic", -ENOENT); - if (hdr->version != BLOBLIST_VERSION) + /* + * Lists of version 1 and 2 are implemented the same way. Version 1.0 + * of the Firmware Handoff specification was withdrawn because it + * specified an XOR checksum while implementations used the additive + * checksum that version 2.0 specifies. Both are accepted for backwards + * compatibility. + */ + if (hdr->version != BLOBLIST_VERSION && + hdr->version != BLOBLIST_VERSION_WITHDRAWN) return log_msg_ret("Bad version", -EPROTONOSUPPORT); if (!hdr->total_size || (size && hdr->total_size > size)) return log_msg_ret("Bad total size", -EFBIG); diff --git a/include/bloblist.h b/include/bloblist.h index fcd290eeb16..f368a6acb85 100644 --- a/include/bloblist.h +++ b/include/bloblist.h @@ -76,7 +76,10 @@ #include <linux/errno.h> enum { - BLOBLIST_VERSION = 1, + /* Version of the lists supported here */ + BLOBLIST_VERSION = 2, + /* Withdrawn version 1.0 of the specification, still accepted */ + BLOBLIST_VERSION_WITHDRAWN = 1, BLOBLIST_MAGIC = 0x4a0fb10b, BLOBLIST_REGCONV_SHIFT_64 = 32, @@ -179,7 +182,8 @@ enum bloblist_tag_t { * blobs can be altered after being created, this checksum is only valid * when the bloblist is finalized before jumping to the next stage of boot. * This is the value needed to make all checksummed bytes sum to 0 - * @version: BLOBLIST_VERSION + * @version: BLOBLIST_VERSION, or BLOBLIST_VERSION_WITHDRAWN when created by + * another boot stage * @hdr_size: Size of this header, normally sizeof(struct bloblist_hdr). The * first bloblist_rec starts at this offset from the start of the header * @align_log2: Power of two of the maximum alignment required by this list diff --git a/test/common/bloblist.c b/test/common/bloblist.c index ef410ca62fc..3ae5eef3859 100644 --- a/test/common/bloblist.c +++ b/test/common/bloblist.c @@ -69,7 +69,10 @@ static int bloblist_test_init(struct unit_test_state *uts) ut_asserteq_ptr(NULL, bloblist_check_magic(TEST_ADDR)); ut_assertok(bloblist_new(TEST_ADDR, TEST_BLOBLIST_SIZE, 0, 0)); ut_asserteq_ptr(hdr, bloblist_check_magic(TEST_ADDR)); - hdr->version++; + hdr->version = BLOBLIST_VERSION + 1; + ut_asserteq(-EPROTONOSUPPORT, bloblist_check(TEST_ADDR, + TEST_BLOBLIST_SIZE)); + hdr->version = 0; ut_asserteq(-EPROTONOSUPPORT, bloblist_check(TEST_ADDR, TEST_BLOBLIST_SIZE)); @@ -92,6 +95,22 @@ static int bloblist_test_init(struct unit_test_state *uts) } BLOBLIST_TEST(bloblist_test_init, UFT_BLOBLIST); +/* Test that a list of the withdrawn version is still accepted */ +static int bloblist_test_version(struct unit_test_state *uts) +{ + struct bloblist_hdr *hdr; + + hdr = clear_bloblist(); + ut_assertok(bloblist_new(TEST_ADDR, TEST_BLOBLIST_SIZE, 0, 0)); + hdr->version = BLOBLIST_VERSION_WITHDRAWN; + ut_assertok(bloblist_finish()); + ut_assertok(bloblist_check(TEST_ADDR, TEST_BLOBLIST_SIZE)); + ut_assertnonnull(bloblist_add(TEST_TAG, TEST_SIZE, 0)); + + return 0; +} +BLOBLIST_TEST(bloblist_test_version, UFT_BLOBLIST); + static int bloblist_test_blob(struct unit_test_state *uts) { struct bloblist_hdr *hdr; -- 2.53.0
