From 9d89fc4054faa7b5a9422b97b756b2cf63a91ad8 Mon Sep 17 00:00:00 2001 From: Raymond Mao Date: Fri, 18 Jul 2025 07:16:14 -0700 Subject: [PATCH 1/6] bloblist: add blob type for DT overlay Add blob type for DT overlay according to the update of Firmware Handoff spec[1]. Add an inline header to represent the 'subtype' in a DT overlay blob payload. [1] Add Transfer Entry for Devicetree Overlay https://github.com/FirmwareHandoff/firmware_handoff/pull/74 Signed-off-by: Raymond Mao Reviewed-by: Tom Rini Tested-by: Michal Simek --- common/bloblist.c | 1 + include/bloblist.h | 13 ++++++++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/common/bloblist.c b/common/bloblist.c index 6e4f020d7c4..1c690f58b56 100644 --- a/common/bloblist.c +++ b/common/bloblist.c @@ -43,6 +43,7 @@ static struct tag_name { { BLOBLISTT_ACPI_TABLES, "ACPI tables for x86" }, { BLOBLISTT_TPM_EVLOG, "TPM event log defined by TCG EFI" }, { BLOBLISTT_TPM_CRB_BASE, "TPM Command Response Buffer address" }, + { BLOBLISTT_FDT_OVERLAY, "DT overlay" }, /* BLOBLISTT_AREA_FIRMWARE */ { BLOBLISTT_TPM2_TCG_LOG, "TPM v2 log space" }, diff --git a/include/bloblist.h b/include/bloblist.h index f32faf78560..c2d3065a43c 100644 --- a/include/bloblist.h +++ b/include/bloblist.h @@ -110,7 +110,8 @@ enum bloblist_tag_t { BLOBLISTT_ACPI_TABLES = 4, BLOBLISTT_TPM_EVLOG = 5, BLOBLISTT_TPM_CRB_BASE = 6, - BLOBLISTT_ACPI_PP = 7, + BLOBLISTT_FDT_OVERLAY = 7, + BLOBLISTT_ACPI_PP = 8, /* Standard area to allocate blobs used across firmware components */ BLOBLISTT_AREA_FIRMWARE = 0x10, @@ -231,6 +232,16 @@ enum { BLOBLIST_REC_HDR_SIZE = sizeof(struct bloblist_rec), }; +/* + * struct dto_blob_hdr - Blob inline header for BLOBLISTT_FDT_OVERLAY + * + * @subtype: IMP-DEF per the agreement between the DT overlay producer and + * consumer. Default value is 0. + */ +struct dto_blob_hdr { + u64 subtype; +}; + /** * bloblist_check_magic() - return a bloblist if the magic matches * From ad82e750fd2af6d7f098e78e70cbba1678e84b2f Mon Sep 17 00:00:00 2001 From: Raymond Mao Date: Fri, 18 Jul 2025 07:16:15 -0700 Subject: [PATCH 2/6] bloblist: add helper functions Add two helper functions for: 1. marking a blob void 2. getting blob record from a given blob data pointer. Signed-off-by: Raymond Mao Reviewed-by: Tom Rini Tested-by: Michal Simek --- common/bloblist.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/common/bloblist.c b/common/bloblist.c index 1c690f58b56..488908f605e 100644 --- a/common/bloblist.c +++ b/common/bloblist.c @@ -97,6 +97,19 @@ static inline uint rec_tag(struct bloblist_rec *rec) BLOBLISTR_TAG_SHIFT; } +static inline void void_blob(struct bloblist_rec *rec) +{ + if (rec_tag(rec) == BLOBLISTT_VOID) + return; + rec->tag_and_hdr_size = BLOBLISTT_VOID | + sizeof(*rec) << BLOBLISTR_HDR_SIZE_SHIFT; +} + +static inline struct bloblist_rec *rec_from_blob(void *blob) +{ + return (blob - sizeof(struct bloblist_rec)); +} + static ulong bloblist_blob_end_ofs(struct bloblist_hdr *hdr, struct bloblist_rec *rec) { From 63cc797a7e89a2543c9997a271ad8f02b04a6777 Mon Sep 17 00:00:00 2001 From: Raymond Mao Date: Fri, 18 Jul 2025 07:16:16 -0700 Subject: [PATCH 3/6] bloblist: fix a potential negative size for memmove It causes a panic when blob is shrunk and 'new_alloced' is less than 'next_ofs'. The data area that needs to be moved should end up at 'hdr->used_size'. Fixes: 1fe59375498f ("bloblist: Support resizing a blob") Signed-off-by: Raymond Mao Reviewed-by: Tom Rini Tested-by: Michal Simek --- common/bloblist.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/bloblist.c b/common/bloblist.c index 488908f605e..550c0c78ffc 100644 --- a/common/bloblist.c +++ b/common/bloblist.c @@ -335,7 +335,7 @@ static int bloblist_resize_rec(struct bloblist_hdr *hdr, next_ofs = bloblist_blob_end_ofs(hdr, rec); if (next_ofs != hdr->used_size) { memmove((void *)hdr + next_ofs + expand_by, - (void *)hdr + next_ofs, new_alloced - next_ofs); + (void *)hdr + next_ofs, hdr->used_size - next_ofs); } hdr->used_size = new_alloced; From 25baace94298bbe50a91f7b1b7470bf0eb5688fa Mon Sep 17 00:00:00 2001 From: Raymond Mao Date: Fri, 18 Jul 2025 07:16:17 -0700 Subject: [PATCH 4/6] bloblist: add API for applying blobs with specified tag Add an API to search for the blobs with specified tag and use the hook function to apply the blob data. Add a helper function to return the inline header size as according to recent spec[1] updates, the actual data can be following an inline header instead of following the TE header immediately. [1] Firmware Handoff spec: https://github.com/FirmwareHandoff/firmware_handoff Signed-off-by: Raymond Mao Reviewed-by: Tom Rini Tested-by: Michal Simek --- common/bloblist.c | 51 ++++++++++++++++++++++++++++++++++++++++++++++ include/bloblist.h | 21 +++++++++++++++++++ 2 files changed, 72 insertions(+) diff --git a/common/bloblist.c b/common/bloblist.c index 550c0c78ffc..2b5026e00da 100644 --- a/common/bloblist.c +++ b/common/bloblist.c @@ -235,6 +235,19 @@ static int bloblist_ensurerec(uint tag, struct bloblist_rec **recp, int size, return 0; } +static int bloblist_get_blob_data_offset(uint tag) +{ + switch (tag) { + case BLOBLISTT_FDT_OVERLAY: + return sizeof(struct dto_blob_hdr); + /* + * return the data offset if it is not following the blob + * header immediately. + */ + } + return 0; +} + void *bloblist_find(uint tag, int size) { void *blob = NULL; @@ -261,6 +274,44 @@ void *bloblist_get_blob(uint tag, int *sizep) return (void *)rec + rec_hdr_size(rec); } +int bloblist_apply_blobs(uint tag, int (*func)(void **data, int size)) +{ + struct bloblist_hdr *hdr = gd->bloblist; + struct bloblist_rec *rec; + + if (!func || !hdr) + return -ENOENT; + + foreach_rec(rec, hdr) { + /* Apply all blobs with the specified tag */ + if (rec_tag(rec) == tag) { + int ret; + int tag = rec_tag(rec); + void *blob = (void *)rec + rec_hdr_size(rec); + int dat_off = bloblist_get_blob_data_offset(tag); + + blob += dat_off; + ret = func(&blob, rec->size - dat_off); + if (ret) { + log_err("Failed to apply blob with tag %d\n", + tag); + return ret; + } + + rec = rec_from_blob(blob - dat_off); + if (rec <= 0) { + log_err("Blob corrupted\n"); + return -ENOENT; + } + + /* Mark applied blob record as void */ + void_blob(rec); + } + } + + return 0; +} + void *bloblist_add(uint tag, int size, int align_log2) { struct bloblist_rec *rec; diff --git a/include/bloblist.h b/include/bloblist.h index c2d3065a43c..e67b2a76358 100644 --- a/include/bloblist.h +++ b/include/bloblist.h @@ -73,6 +73,7 @@ #define __BLOBLIST_H #include +#include enum { BLOBLIST_VERSION = 1, @@ -279,6 +280,26 @@ static inline void *bloblist_get_blob(uint tag, int *sizep) } #endif +#if CONFIG_IS_ENABLED(BLOBLIST) +/** + * bloblist_apply_blobs() - Apply the data of blobs by tag + * + * Scan the bloblist, find the blobs with the matching tag and apply the data + * of blobs + * + * @tag: Tag to search for (enum bloblist_tag_t) + * @func: Function to apply the data of blobs + * Return: 0 if OK, otherwise error. + */ +int bloblist_apply_blobs(uint tag, int (*func)(void **data, int size)); +#else +static inline int bloblist_apply_blobs(uint tag, + int (*func)(void **data, int size)) +{ + return -EPERM; +} +#endif + /** * bloblist_find() - Find a blob * From b70cbbfbf94fdb50367a0884a9c44770b4c3bddc Mon Sep 17 00:00:00 2001 From: Raymond Mao Date: Fri, 18 Jul 2025 07:16:18 -0700 Subject: [PATCH 5/6] fdtdec: apply DT overlays from bloblist During FDT setup, apply all existing DT overlays from the bloblist to the base FDT if bloblist is being used for handoff from previous boot stage. According to the Firmware Handoff spec update to support DT overlay [1], an overlay must have the same top-level compatible string as its target base DT has. Before applying the overlays, check whether sufficient space is reserved in the base DT blob, if not, resize the blob to the allowed padded size, which is limited by CONFIG_SYS_FDT_PAD and the bloblist spare space size. After all overlays are applied, resize the merged DT to its actual size. [1] Add Transfer Entry for Devicetree Overlay https://github.com/FirmwareHandoff/firmware_handoff/pull/74 Signed-off-by: Raymond Mao Reviewed-by: Tom Rini Tested-by: Michal Simek --- lib/fdtdec.c | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/lib/fdtdec.c b/lib/fdtdec.c index c38738b48c7..630b7d2bd69 100644 --- a/lib/fdtdec.c +++ b/lib/fdtdec.c @@ -1687,6 +1687,83 @@ void fdtdec_setup_embed(void) gd->fdt_src = FDTSRC_EMBED; } +static int fdtdec_match_dto_compatible(const void *base, const void *dto) +{ + const char *compat_base; + const char *compat_dto; + int len; + + compat_base = (const char *)fdt_getprop(base, 0, "compatible", &len); + if (!compat_base || len <= 0) + return -ENOENT; + + compat_dto = (const char *)fdt_getprop(dto, 0, "compatible", &len); + if (!compat_dto || len <= 0) + return -ENOENT; + + if (strcmp(compat_base, compat_dto)) + return -EPERM; + + return 0; +} + +static int fdtdec_apply_dto_blob(void **blob, __maybe_unused int size) +{ + int ret; + + ret = fdt_check_header(*blob); + if (ret) + return ret; + + ret = fdtdec_match_dto_compatible(gd->fdt_blob, *blob); + if (ret) + return ret; + + return fdt_overlay_apply_verbose((void *)gd->fdt_blob, *blob); +} + +static int fdtdec_apply_bloblist_dtos(void) +{ + int ret; + struct fdt_header *live_fdt; + int blob_size; + size_t padded_size, max_size; + + if (!CONFIG_IS_ENABLED(OF_LIBFDT_OVERLAY) || + !CONFIG_IS_ENABLED(BLOBLIST)) + return 0; + + /* Get the total space reserved for FDT in blob */ + live_fdt = bloblist_get_blob(BLOBLISTT_CONTROL_FDT, &blob_size); + if (live_fdt != gd->fdt_blob) + return -ENOENT; + + /* Calculate the allowed padded size */ + padded_size = fdt_totalsize(live_fdt) + CONFIG_SYS_FDT_PAD; + max_size = bloblist_get_total_size() - bloblist_get_size() + blob_size; + if (padded_size > max_size) + padded_size = max_size; + + /* Resize if the current space is not sufficient */ + if (blob_size < padded_size) { + ret = bloblist_resize(BLOBLISTT_CONTROL_FDT, padded_size); + if (ret) + return ret; + + ret = fdt_open_into(live_fdt, live_fdt, padded_size); + if (ret) + return ret; + } + + ret = bloblist_apply_blobs(BLOBLISTT_FDT_OVERLAY, fdtdec_apply_dto_blob); + if (ret) + return ret; + + /* Shink the blob to the actual FDT size */ + fdt_pack(live_fdt); + return bloblist_resize(BLOBLISTT_CONTROL_FDT, fdt_totalsize(live_fdt)); +} + int fdtdec_setup(void) { int ret = -ENOENT; @@ -1708,6 +1785,9 @@ int fdtdec_setup(void) gd->fdt_src = FDTSRC_BLOBLIST; log_debug("Devicetree is in bloblist at %p\n", gd->fdt_blob); + ret = fdtdec_apply_bloblist_dtos(); + if (ret) + return ret; goto setup_fdt; } else { log_debug("No FDT found in bloblist\n"); From d3935134c9d597b57cebb954615cf3b80eaf85d7 Mon Sep 17 00:00:00 2001 From: Raymond Mao Date: Fri, 18 Jul 2025 07:16:19 -0700 Subject: [PATCH 6/6] configs: Select OF_LIBFDT_OVERLAY to hand over DTO via bloblist Select OF_LIBFDT_OVERLAY for qemu_arm64 and vexpress_fvp_bloblist to hand over DTO via bloblist. Signed-off-by: Raymond Mao Tested-by: Michal Simek --- configs/qemu_arm64_defconfig | 1 + configs/vexpress_fvp_bloblist_defconfig | 1 + 2 files changed, 2 insertions(+) diff --git a/configs/qemu_arm64_defconfig b/configs/qemu_arm64_defconfig index 39afb837e41..a63cef0c1ea 100644 --- a/configs/qemu_arm64_defconfig +++ b/configs/qemu_arm64_defconfig @@ -7,6 +7,7 @@ CONFIG_CUSTOM_SYS_INIT_SP_ADDR=0x40200000 CONFIG_ENV_SIZE=0x40000 CONFIG_ENV_SECT_SIZE=0x40000 CONFIG_DEFAULT_DEVICE_TREE="qemu-arm64" +CONFIG_OF_LIBFDT_OVERLAY=y CONFIG_SYS_LOAD_ADDR=0x40200000 CONFIG_DEBUG_UART_BASE=0x9000000 CONFIG_DEBUG_UART_CLOCK=0 diff --git a/configs/vexpress_fvp_bloblist_defconfig b/configs/vexpress_fvp_bloblist_defconfig index 4d52b96202b..6cd0365ec68 100644 --- a/configs/vexpress_fvp_bloblist_defconfig +++ b/configs/vexpress_fvp_bloblist_defconfig @@ -1,5 +1,6 @@ #include +CONFIG_OF_LIBFDT_OVERLAY=y CONFIG_BLOBLIST=y CONFIG_BLOBLIST_PASSAGE_MANDATORY=y CONFIG_BLOBLIST_SIZE_RELOC=0x10000