[PATCH v4 0/9] Handoff bloblist from previous boot stage

This patch set depends on another series: "[PATCH v5 00/11] Support Firmware Handoff spec via bloblist".
This patch set adds/adapts a few bloblist APIs and implements Arm arch custom function to retrieve the bloblist (aka. Transfer List) from previous loader via boot arguments when OF_BOARD option is enabled and all boot arguments are compliant to the register conventions defined in the Firmware Handoff spec v0.9.
FDT library function will load the FDT from the bloblist if it exists. Otherwise it fallbacks to get the FDT from the board custom function.
If an arch wishes to have different behaviors for loading bloblist from the previous boot stage, it is required to implement the custom function xferlist_from_boot_arg().
Raymond Mao (9): bloblist: add API to check the register conventions bloblist: check bloblist with specified buffer size bloblist: refactor of bloblist_reloc() arm: armv7: save boot arguments arm: armv8: save boot arguments arm: Get bloblist from boot arguments bloblist: Load the bloblist from the previous loader fdt: update the document and Kconfig description fdt: get FDT from bloblist
arch/arm/cpu/armv7/start.S | 19 ++++++ arch/arm/cpu/armv8/start.S | 14 +++++ arch/arm/lib/Makefile | 4 ++ arch/arm/lib/xferlist.c | 38 ++++++++++++ common/bloblist.c | 92 +++++++++++++++++++++++------- common/board_f.c | 9 +-- configs/qemu_arm64_defconfig | 3 + doc/develop/devicetree/control.rst | 6 +- dts/Kconfig | 7 ++- include/bloblist.h | 47 ++++++++++++--- lib/fdtdec.c | 9 ++- test/bloblist.c | 8 +-- 12 files changed, 210 insertions(+), 46 deletions(-) create mode 100644 arch/arm/lib/xferlist.c

Add bloblist_check_reg_conv() to check whether the bloblist is compliant to the register conventions defined in Firmware Handoff specification. This API can be used for all Arm platforms.
Signed-off-by: Raymond Mao raymond.mao@linaro.org --- Changes in v2 - Refactor of bloblist_check_reg_conv(). Changes in v3 - bloblist_check_reg_conv() returns -ENOENT if OF_BOARD is disabled. Changes in v4 - Add checking of signature register.
common/bloblist.c | 14 ++++++++++++++ include/bloblist.h | 20 ++++++++++++++++++++ 2 files changed, 34 insertions(+)
diff --git a/common/bloblist.c b/common/bloblist.c index 9daf0d2b13..acf67304d0 100644 --- a/common/bloblist.c +++ b/common/bloblist.c @@ -542,3 +542,17 @@ int bloblist_maybe_init(void)
return 0; } + +int bloblist_check_reg_conv(ulong rfdt, ulong rzero, ulong rsig) +{ + if (!IS_ENABLED(CONFIG_OF_BOARD)) + return -ENOENT; + + if (rzero || rsig != (BLOBLIST_MAGIC | BLOBLIST_REGCONV_VER) || + rfdt != (ulong)bloblist_find(BLOBLISTT_CONTROL_FDT, 0)) { + gd->bloblist = NULL; /* Reset the gd bloblist pointer */ + return -EIO; + } + + return 0; +} diff --git a/include/bloblist.h b/include/bloblist.h index 84fc943819..bf9e12ebf8 100644 --- a/include/bloblist.h +++ b/include/bloblist.h @@ -78,6 +78,13 @@ enum { BLOBLIST_VERSION = 1, BLOBLIST_MAGIC = 0x4a0fb10b,
+ /* + * FIXME: + * Register convention version should be placed into a higher byte + * https://github.com/FirmwareHandoff/firmware_handoff/issues/32 + */ + BLOBLIST_REGCONV_VER = 1 << 24, + BLOBLIST_BLOB_ALIGN_LOG2 = 3, BLOBLIST_BLOB_ALIGN = 1 << BLOBLIST_BLOB_ALIGN_LOG2,
@@ -461,4 +468,17 @@ static inline int bloblist_maybe_init(void) } #endif /* BLOBLIST */
+/** + * bloblist_check_reg_conv() - Check whether the bloblist is compliant to + * the register conventions according to the + * Firmware Handoff spec. + * + * @rfdt: Register that holds the FDT base address. + * @rzero: Register that must be zero. + * @rsig: Register that holds signature and register conventions version. + * Return: 0 if OK, -EIO if the bloblist is not compliant to the register + * conventions, -ENOENT if OF_BOARD is disabled. + */ +int bloblist_check_reg_conv(ulong rfdt, ulong rzero, ulong rsig); + #endif /* __BLOBLIST_H */

Instead of expecting the bloblist total size to be the same as the pre-allocated buffer size, practically we are more interested in whether the pre-allocated buffer size is bigger than the bloblist total size.
Signed-off-by: Raymond Mao raymond.mao@linaro.org --- Changes in v2 - New patch file created for v2. Changes in v4 - Update function header of bloblist_check().
common/bloblist.c | 2 +- include/bloblist.h | 9 +++++---- test/bloblist.c | 2 +- 3 files changed, 7 insertions(+), 6 deletions(-)
diff --git a/common/bloblist.c b/common/bloblist.c index acf67304d0..4039eb3a03 100644 --- a/common/bloblist.c +++ b/common/bloblist.c @@ -384,7 +384,7 @@ int bloblist_check(ulong addr, uint size) return log_msg_ret("Bad magic", -ENOENT); if (hdr->version != BLOBLIST_VERSION) return log_msg_ret("Bad version", -EPROTONOSUPPORT); - if (!hdr->total_size || (size && hdr->total_size != size)) + if (!hdr->total_size || (size && hdr->total_size > size)) return log_msg_ret("Bad total size", -EFBIG); if (hdr->used_size > hdr->total_size) return log_msg_ret("Bad used size", -ENOENT); diff --git a/include/bloblist.h b/include/bloblist.h index bf9e12ebf8..1906847c15 100644 --- a/include/bloblist.h +++ b/include/bloblist.h @@ -348,12 +348,13 @@ int bloblist_new(ulong addr, uint size, uint flags, uint align_log2); * bloblist_check() - Check if a bloblist exists * * @addr: Address of bloblist - * @size: Expected size of blobsize, or 0 to detect the size + * @size: Reserved space size for blobsize, or 0 to use the total size * Return: 0 if OK, -ENOENT if the magic number doesn't match (indicating that - * there problem is no bloblist at the given address), -EPROTONOSUPPORT + * there problem is no bloblist at the given address) or any fields for header + * size, used size and total size do not match, -EPROTONOSUPPORT * if the version does not match, -EIO if the checksum does not match, - * -EFBIG if the expected size does not match the detected size, -ENOSPC - * if the size is not large enough to hold the headers + * -EFBIG if the reserved space size is small than the total size or total size + * is 0 */ int bloblist_check(ulong addr, uint size);
diff --git a/test/bloblist.c b/test/bloblist.c index 17d9dd03d0..7dab9addf8 100644 --- a/test/bloblist.c +++ b/test/bloblist.c @@ -207,7 +207,7 @@ static int bloblist_test_checksum(struct unit_test_state *uts) hdr->flags++;
hdr->total_size--; - ut_asserteq(-EFBIG, bloblist_check(TEST_ADDR, TEST_BLOBLIST_SIZE)); + ut_asserteq(-EIO, bloblist_check(TEST_ADDR, TEST_BLOBLIST_SIZE)); hdr->total_size++;
hdr->spare++;

Hi Raymond
I think my r-b tag got lost across versions
On Wed, 3 Jan 2024 at 00:13, Raymond Mao raymond.mao@linaro.org wrote:
Instead of expecting the bloblist total size to be the same as the pre-allocated buffer size, practically we are more interested in whether the pre-allocated buffer size is bigger than the bloblist total size.
Signed-off-by: Raymond Mao raymond.mao@linaro.org
Changes in v2
- New patch file created for v2.
Changes in v4
- Update function header of bloblist_check().
common/bloblist.c | 2 +- include/bloblist.h | 9 +++++---- test/bloblist.c | 2 +- 3 files changed, 7 insertions(+), 6 deletions(-)
diff --git a/common/bloblist.c b/common/bloblist.c index acf67304d0..4039eb3a03 100644 --- a/common/bloblist.c +++ b/common/bloblist.c @@ -384,7 +384,7 @@ int bloblist_check(ulong addr, uint size) return log_msg_ret("Bad magic", -ENOENT); if (hdr->version != BLOBLIST_VERSION) return log_msg_ret("Bad version", -EPROTONOSUPPORT);
if (!hdr->total_size || (size && hdr->total_size != size))
if (!hdr->total_size || (size && hdr->total_size > size)) return log_msg_ret("Bad total size", -EFBIG); if (hdr->used_size > hdr->total_size) return log_msg_ret("Bad used size", -ENOENT);
diff --git a/include/bloblist.h b/include/bloblist.h index bf9e12ebf8..1906847c15 100644 --- a/include/bloblist.h +++ b/include/bloblist.h @@ -348,12 +348,13 @@ int bloblist_new(ulong addr, uint size, uint flags, uint align_log2);
- bloblist_check() - Check if a bloblist exists
- @addr: Address of bloblist
- @size: Expected size of blobsize, or 0 to detect the size
- @size: Reserved space size for blobsize, or 0 to use the total size
- Return: 0 if OK, -ENOENT if the magic number doesn't match (indicating that
- there problem is no bloblist at the given address), -EPROTONOSUPPORT
- there problem is no bloblist at the given address) or any fields for header
- size, used size and total size do not match, -EPROTONOSUPPORT
- if the version does not match, -EIO if the checksum does not match,
- -EFBIG if the expected size does not match the detected size, -ENOSPC
- if the size is not large enough to hold the headers
- -EFBIG if the reserved space size is small than the total size or total size
*/
- is 0
int bloblist_check(ulong addr, uint size);
diff --git a/test/bloblist.c b/test/bloblist.c index 17d9dd03d0..7dab9addf8 100644 --- a/test/bloblist.c +++ b/test/bloblist.c @@ -207,7 +207,7 @@ static int bloblist_test_checksum(struct unit_test_state *uts) hdr->flags++;
hdr->total_size--;
ut_asserteq(-EFBIG, bloblist_check(TEST_ADDR, TEST_BLOBLIST_SIZE));
ut_asserteq(-EIO, bloblist_check(TEST_ADDR, TEST_BLOBLIST_SIZE)); hdr->total_size++; hdr->spare++;
-- 2.25.1
Reviewed-by: Ilias Apalodimas ilias.apalodimas@linaro.org

The current bloblist pointer and size can be retrieved from global data, so we don't need to pass them from the function arguments. This change also help to remove all external access of gd->bloblist outside of bloblist module.
Signed-off-by: Raymond Mao raymond.mao@linaro.org --- Changes in v2 - New patch file created for v2. Changes in v3 - Check the space size before copying the bloblist. - Add return code of bloblist_reloc(). Changes in v4 - return error code from bloblist_reloc().
common/bloblist.c | 10 ++++++++-- common/board_f.c | 9 +++------ include/bloblist.h | 8 ++++---- test/bloblist.c | 6 ++---- 4 files changed, 17 insertions(+), 16 deletions(-)
diff --git a/common/bloblist.c b/common/bloblist.c index 4039eb3a03..4e76975627 100644 --- a/common/bloblist.c +++ b/common/bloblist.c @@ -472,13 +472,19 @@ void bloblist_show_list(void) } }
-void bloblist_reloc(void *to, uint to_size, void *from, uint from_size) +int bloblist_reloc(void *to, uint to_size) { struct bloblist_hdr *hdr;
- memcpy(to, from, from_size); + if (to_size < gd->bloblist->total_size) + return -ENOSPC; + + memcpy(to, gd->bloblist, gd->bloblist->total_size); hdr = to; hdr->total_size = to_size; + gd->bloblist = to; + + return 0; }
int bloblist_init(void) diff --git a/common/board_f.c b/common/board_f.c index d4d7d01f8f..f4145a2698 100644 --- a/common/board_f.c +++ b/common/board_f.c @@ -676,13 +676,10 @@ static int reloc_bloblist(void) return 0; } if (gd->new_bloblist) { - int size = CONFIG_BLOBLIST_SIZE; - debug("Copying bloblist from %p to %p, size %x\n", - gd->bloblist, gd->new_bloblist, size); - bloblist_reloc(gd->new_bloblist, CONFIG_BLOBLIST_SIZE_RELOC, - gd->bloblist, size); - gd->bloblist = gd->new_bloblist; + gd->bloblist, gd->new_bloblist, gd->bloblist->total_size); + return bloblist_reloc(gd->new_bloblist, + CONFIG_BLOBLIST_SIZE_RELOC); } #endif
diff --git a/include/bloblist.h b/include/bloblist.h index 1906847c15..81f1dfa027 100644 --- a/include/bloblist.h +++ b/include/bloblist.h @@ -426,11 +426,11 @@ const char *bloblist_tag_name(enum bloblist_tag_t tag); * bloblist_reloc() - Relocate the bloblist and optionally resize it * * @to: Pointer to new bloblist location (must not overlap old location) - * @to_size: New size for bloblist (must be larger than from_size) - * @from: Pointer to bloblist to relocate - * @from_size: Size of bloblist to relocate + * @to_size: New size for bloblist + * Return: 0 if OK, -ENOSPC if the new size is small than the bloblist total + * size. */ -void bloblist_reloc(void *to, uint to_size, void *from, uint from_size); +int bloblist_reloc(void *to, uint to_size);
/** * bloblist_init() - Init the bloblist system with a single bloblist diff --git a/test/bloblist.c b/test/bloblist.c index 7dab9addf8..1c60bbac36 100644 --- a/test/bloblist.c +++ b/test/bloblist.c @@ -376,13 +376,12 @@ static int bloblist_test_reloc(struct unit_test_state *uts) { const uint large_size = TEST_BLOBLIST_SIZE; const uint small_size = 0x20; - void *old_ptr, *new_ptr; + void *new_ptr; void *blob1, *blob2; ulong new_addr; ulong new_size;
ut_assertok(bloblist_new(TEST_ADDR, TEST_BLOBLIST_SIZE, 0, 0)); - old_ptr = map_sysmem(TEST_ADDR, TEST_BLOBLIST_SIZE);
/* Add one blob and then one that won't fit */ blob1 = bloblist_add(TEST_TAG, small_size, 0); @@ -394,8 +393,7 @@ static int bloblist_test_reloc(struct unit_test_state *uts) new_addr = TEST_ADDR + TEST_BLOBLIST_SIZE; new_size = TEST_BLOBLIST_SIZE + 0x100; new_ptr = map_sysmem(new_addr, TEST_BLOBLIST_SIZE); - bloblist_reloc(new_ptr, new_size, old_ptr, TEST_BLOBLIST_SIZE); - gd->bloblist = new_ptr; + ut_assertok(bloblist_reloc(new_ptr, new_size));
/* Check the old blob is there and that we can now add the bigger one */ ut_assertnonnull(bloblist_find(TEST_TAG, small_size));

Save boot arguments r[0-3] into an array for handover of bloblist from previous boot stage.
Signed-off-by: Raymond Mao raymond.mao@linaro.org --- Changes in v2 - New patch file created for v2. Changes in v3 - Swap value of r0 with r2. Changes in v4 - Fix a bug when saving the boot args.
arch/arm/cpu/armv7/start.S | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+)
diff --git a/arch/arm/cpu/armv7/start.S b/arch/arm/cpu/armv7/start.S index 69e281b086..66372e4c68 100644 --- a/arch/arm/cpu/armv7/start.S +++ b/arch/arm/cpu/armv7/start.S @@ -152,9 +152,28 @@ ENDPROC(c_runtime_cpu_setup) * *************************************************************************/ WEAK(save_boot_params) +#if (IS_ENABLED(CONFIG_OF_BOARD) && IS_ENABLED(CONFIG_BLOBLIST)) + ldr r12, =saved_args + /* + * Intentionally swapping r0 with r2 in order to simplify the C + * function we use later. + */ + str r2, [r12] + str r1, [r12, #4] + str r0, [r12, #8] + str r3, [r12, #12] +#endif b save_boot_params_ret @ back to my caller ENDPROC(save_boot_params)
+.section .data +.global saved_args +saved_args: + .rept 4 + .word 0 + .endr +END(saved_args) + #ifdef CONFIG_ARMV7_LPAE WEAK(switch_to_hypervisor) b switch_to_hypervisor_ret

On Tue, Jan 02, 2024 at 02:12:29PM -0800, Raymond Mao wrote:
Save boot arguments r[0-3] into an array for handover of bloblist from previous boot stage.
Signed-off-by: Raymond Mao raymond.mao@linaro.org
Changes in v2
- New patch file created for v2.
Changes in v3
- Swap value of r0 with r2.
Changes in v4
- Fix a bug when saving the boot args.
arch/arm/cpu/armv7/start.S | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+)
So on platforms with SAVE_PREV_BL_INITRAMFS_START_ADDR / SAVE_PREV_BL_FDT_ADDR we have this same logic, but in C, and it's working and fine, given what we do. So could we not follow the example of arch/arm/lib/save_prev_bl_data.c and have arch/arm/lib/bloblist.c and have just one implementation for arm32/64?

Hi Tom,
On Wed, 3 Jan 2024 at 14:08, Tom Rini trini@konsulko.com wrote:
On Tue, Jan 02, 2024 at 02:12:29PM -0800, Raymond Mao wrote:
Save boot arguments r[0-3] into an array for handover of bloblist from previous boot stage.
Signed-off-by: Raymond Mao raymond.mao@linaro.org
Changes in v2
- New patch file created for v2.
Changes in v3
- Swap value of r0 with r2.
Changes in v4
- Fix a bug when saving the boot args.
arch/arm/cpu/armv7/start.S | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+)
So on platforms with SAVE_PREV_BL_INITRAMFS_START_ADDR / SAVE_PREV_BL_FDT_ADDR we have this same logic, but in C, and it's working and fine, given what we do. So could we not follow the example of arch/arm/lib/save_prev_bl_data.c and have arch/arm/lib/bloblist.c and have just one implementation for arm32/64?
I went through arch/arm/lib/save_prev_bl_data.c, it looks that this patch
is more straightforward and clean for working together with arch/arm/lib/bloblist.c to support arm FW Handoff spec.
[...]
Thanks and regards, Raymond

Save boot arguments x[0-3] into an array for handover of bloblist from previous boot stage.
Signed-off-by: Raymond Mao raymond.mao@linaro.org Reviewed-by: Simon Glass sjg@chromium.org Reviewed-by: Ilias Apalodimas ilias.apalodimas@linaro.org --- Changes in v2 - New patch file created for v2.
arch/arm/cpu/armv8/start.S | 14 ++++++++++++++ 1 file changed, 14 insertions(+)
diff --git a/arch/arm/cpu/armv8/start.S b/arch/arm/cpu/armv8/start.S index 6cc1d26e5e..8e704f590e 100644 --- a/arch/arm/cpu/armv8/start.S +++ b/arch/arm/cpu/armv8/start.S @@ -370,5 +370,19 @@ ENTRY(c_runtime_cpu_setup) ENDPROC(c_runtime_cpu_setup)
WEAK(save_boot_params) +#if (IS_ENABLED(CONFIG_OF_BOARD) && IS_ENABLED(CONFIG_BLOBLIST)) + adr x9, saved_args + stp x0, x1, [x9] + /* Increment the address by 16 bytes for the next pair of values */ + stp x2, x3, [x9, #16] +#endif b save_boot_params_ret /* back to my caller */ ENDPROC(save_boot_params) + +.section .data +.global saved_args +saved_args: + .rept 4 + .xword 0 + .endr +END(saved_args)

Add arch custom function to get bloblist from boot arguments. Check whether boot arguments aligns with the register conventions defined in FW Handoff spec v0.9. Add bloblist related options into qemu-arm default config.
Signed-off-by: Raymond Mao raymond.mao@linaro.org --- Changes in v2 - Remove low level code for copying boot arguments. - Refactor board_fdt_blob_setup() and remove direct access of gd->bloblist. Changes in v3 - Optimize board_bloblist_from_boot_arg(). Changes in v4 - Move the function as an Arm-arch library instead of a board-specific one.
arch/arm/lib/xferlist.c | 38 ++++++++++++++++++++++++++++++++++++ configs/qemu_arm64_defconfig | 3 +++ 3 files changed, 45 insertions(+) create mode 100644 arch/arm/lib/xferlist.c
diff --git a/arch/arm/lib/Makefile b/arch/arm/lib/Makefile index b1bcd37466..0023c55d0d 100644 --- a/arch/arm/lib/Makefile +++ b/arch/arm/lib/Makefile @@ -85,6 +85,10 @@ obj-y += psci-dt.o
obj-$(CONFIG_DEBUG_LL) += debug.o
+ifdef CONFIG_BLOBLIST +obj-$(CONFIG_OF_BOARD) += xferlist.o +endif + # For EABI conformant tool chains, provide eabi_compat() ifneq (,$(findstring -mabi=aapcs-linux,$(PLATFORM_CPPFLAGS))) extra-y += eabi_compat.o diff --git a/arch/arm/lib/xferlist.c b/arch/arm/lib/xferlist.c new file mode 100644 index 0000000000..163d20c11c --- /dev/null +++ b/arch/arm/lib/xferlist.c @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2023 Linaro Limited + * Author: Raymond Mao raymond.mao@linaro.org + */ +#include <linux/types.h> +#include <errno.h> +#include <bloblist.h> + +/* + * Boot parameters saved from start.S + * saved_args[0]: FDT base address + * saved_args[1]: Bloblist signature + * saved_args[2]: must be 0 + * saved_args[3]: Bloblist base address + */ +extern unsigned long saved_args[]; + +int xferlist_from_boot_arg(ulong addr, ulong size) +{ + int ret = -ENOENT; + + if (!IS_ENABLED(CONFIG_OF_BOARD) || !IS_ENABLED(CONFIG_BLOBLIST)) + return -ENOENT; + + ret = bloblist_check(saved_args[3], size); + if (ret) + return ret; + + /* Check the register conventions */ + ret = bloblist_check_reg_conv(saved_args[0], saved_args[2], + saved_args[1]); + if (!ret) + /* Relocate the bloblist to the fixed address */ + ret = bloblist_reloc((void *)addr, size); + + return ret; +} diff --git a/configs/qemu_arm64_defconfig b/configs/qemu_arm64_defconfig index c010c25a92..418f48001c 100644 --- a/configs/qemu_arm64_defconfig +++ b/configs/qemu_arm64_defconfig @@ -69,3 +69,6 @@ CONFIG_USB_EHCI_HCD=y CONFIG_USB_EHCI_PCI=y CONFIG_SEMIHOSTING=y CONFIG_TPM=y +CONFIG_BLOBLIST=y +CONFIG_BLOBLIST_ADDR=0x40004000 +CONFIG_BLOBLIST_SIZE=0x4000

On 1/2/24 23:12, Raymond Mao wrote:
Add arch custom function to get bloblist from boot arguments. Check whether boot arguments aligns with the register conventions defined in FW Handoff spec v0.9. Add bloblist related options into qemu-arm default config.
Signed-off-by: Raymond Mao raymond.mao@linaro.org
Changes in v2
- Remove low level code for copying boot arguments.
- Refactor board_fdt_blob_setup() and remove direct access of gd->bloblist.
Changes in v3
- Optimize board_bloblist_from_boot_arg().
Changes in v4
Move the function as an Arm-arch library instead of a board-specific one.
arch/arm/lib/xferlist.c | 38 ++++++++++++++++++++++++++++++++++++ configs/qemu_arm64_defconfig | 3 +++ 3 files changed, 45 insertions(+) create mode 100644 arch/arm/lib/xferlist.c
diff --git a/arch/arm/lib/Makefile b/arch/arm/lib/Makefile index b1bcd37466..0023c55d0d 100644 --- a/arch/arm/lib/Makefile +++ b/arch/arm/lib/Makefile @@ -85,6 +85,10 @@ obj-y += psci-dt.o
obj-$(CONFIG_DEBUG_LL) += debug.o
+ifdef CONFIG_BLOBLIST +obj-$(CONFIG_OF_BOARD) += xferlist.o +endif
- # For EABI conformant tool chains, provide eabi_compat() ifneq (,$(findstring -mabi=aapcs-linux,$(PLATFORM_CPPFLAGS))) extra-y += eabi_compat.o
diff --git a/arch/arm/lib/xferlist.c b/arch/arm/lib/xferlist.c new file mode 100644 index 0000000000..163d20c11c --- /dev/null +++ b/arch/arm/lib/xferlist.c @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: GPL-2.0+ +/*
- Copyright (C) 2023 Linaro Limited
- Author: Raymond Mao raymond.mao@linaro.org
- */
+#include <linux/types.h> +#include <errno.h> +#include <bloblist.h>
+/*
- Boot parameters saved from start.S
- saved_args[0]: FDT base address
- saved_args[1]: Bloblist signature
- saved_args[2]: must be 0
- saved_args[3]: Bloblist base address
- */
+extern unsigned long saved_args[];
you should put this to bloblist.h. I would say it should be the part of 4/9 where you define saved_args for armv7.
+int xferlist_from_boot_arg(ulong addr, ulong size) +{
- int ret = -ENOENT;
There is no value to initialize it here.
- if (!IS_ENABLED(CONFIG_OF_BOARD) || !IS_ENABLED(CONFIG_BLOBLIST))
return -ENOENT;
- ret = bloblist_check(saved_args[3], size);
- if (ret)
return ret;
- /* Check the register conventions */
- ret = bloblist_check_reg_conv(saved_args[0], saved_args[2],
saved_args[1]);
- if (!ret)
/* Relocate the bloblist to the fixed address */
ret = bloblist_reloc((void *)addr, size);
- return ret;
+} diff --git a/configs/qemu_arm64_defconfig b/configs/qemu_arm64_defconfig index c010c25a92..418f48001c 100644 --- a/configs/qemu_arm64_defconfig +++ b/configs/qemu_arm64_defconfig @@ -69,3 +69,6 @@ CONFIG_USB_EHCI_HCD=y CONFIG_USB_EHCI_PCI=y CONFIG_SEMIHOSTING=y CONFIG_TPM=y +CONFIG_BLOBLIST=y +CONFIG_BLOBLIST_ADDR=0x40004000 +CONFIG_BLOBLIST_SIZE=0x4000
This is likely not the right position in defconfig. make savedefconfig; cp defconfig configs/qemu_arm64_defconfig.
M

Hi Michal,
On Wed, 3 Jan 2024 at 05:46, Michal Simek michal.simek@amd.com wrote:
On 1/2/24 23:12, Raymond Mao wrote:
Add arch custom function to get bloblist from boot arguments. Check whether boot arguments aligns with the register conventions defined in FW Handoff spec v0.9. Add bloblist related options into qemu-arm default config.
Signed-off-by: Raymond Mao raymond.mao@linaro.org
Changes in v2
- Remove low level code for copying boot arguments.
- Refactor board_fdt_blob_setup() and remove direct access of
gd->bloblist.
Changes in v3
- Optimize board_bloblist_from_boot_arg().
Changes in v4
- Move the function as an Arm-arch library instead of a board-specific
one.
arch/arm/lib/xferlist.c | 38 ++++++++++++++++++++++++++++++++++++ configs/qemu_arm64_defconfig | 3 +++ 3 files changed, 45 insertions(+) create mode 100644 arch/arm/lib/xferlist.c
diff --git a/arch/arm/lib/Makefile b/arch/arm/lib/Makefile index b1bcd37466..0023c55d0d 100644 --- a/arch/arm/lib/Makefile +++ b/arch/arm/lib/Makefile @@ -85,6 +85,10 @@ obj-y += psci-dt.o
obj-$(CONFIG_DEBUG_LL) += debug.o
+ifdef CONFIG_BLOBLIST +obj-$(CONFIG_OF_BOARD) += xferlist.o +endif
- # For EABI conformant tool chains, provide eabi_compat() ifneq (,$(findstring -mabi=aapcs-linux,$(PLATFORM_CPPFLAGS))) extra-y += eabi_compat.o
diff --git a/arch/arm/lib/xferlist.c b/arch/arm/lib/xferlist.c new file mode 100644 index 0000000000..163d20c11c --- /dev/null +++ b/arch/arm/lib/xferlist.c @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: GPL-2.0+ +/*
- Copyright (C) 2023 Linaro Limited
- Author: Raymond Mao raymond.mao@linaro.org
- */
+#include <linux/types.h> +#include <errno.h> +#include <bloblist.h>
+/*
- Boot parameters saved from start.S
- saved_args[0]: FDT base address
- saved_args[1]: Bloblist signature
- saved_args[2]: must be 0
- saved_args[3]: Bloblist base address
- */
+extern unsigned long saved_args[];
you should put this to bloblist.h. I would say it should be the part of 4/9 where you define saved_args for armv7.
Not sure if I understand your point but this part is for Arm only (v7 and
v8) and should not be in bloblist.h. It works following the spec from Arm. Other arches should implement their own way if they want to load the bloblist from the previous loader.
[...]
Thanks and regards, Raymond

Hi Raymond,
On 1/3/24 18:01, Raymond Mao wrote:
Hi Michal,
On Wed, 3 Jan 2024 at 05:46, Michal Simek <michal.simek@amd.com mailto:michal.simek@amd.com> wrote:
On 1/2/24 23:12, Raymond Mao wrote: > Add arch custom function to get bloblist from boot arguments. > Check whether boot arguments aligns with the register conventions > defined in FW Handoff spec v0.9. > Add bloblist related options into qemu-arm default config. > > Signed-off-by: Raymond Mao <raymond.mao@linaro.org <mailto:raymond.mao@linaro.org>> > --- > Changes in v2 > - Remove low level code for copying boot arguments. > - Refactor board_fdt_blob_setup() and remove direct access of gd->bloblist. > Changes in v3 > - Optimize board_bloblist_from_boot_arg(). > Changes in v4 > - Move the function as an Arm-arch library instead of a board-specific one. > > arch/arm/lib/xferlist.c | 38 ++++++++++++++++++++++++++++++++++++ > configs/qemu_arm64_defconfig | 3 +++ > 3 files changed, 45 insertions(+) > create mode 100644 arch/arm/lib/xferlist.c > > diff --git a/arch/arm/lib/Makefile b/arch/arm/lib/Makefile > index b1bcd37466..0023c55d0d 100644 > --- a/arch/arm/lib/Makefile > +++ b/arch/arm/lib/Makefile > @@ -85,6 +85,10 @@ obj-y += psci-dt.o > > obj-$(CONFIG_DEBUG_LL) += debug.o > > +ifdef CONFIG_BLOBLIST > +obj-$(CONFIG_OF_BOARD) += xferlist.o > +endif > + > # For EABI conformant tool chains, provide eabi_compat() > ifneq (,$(findstring -mabi=aapcs-linux,$(PLATFORM_CPPFLAGS))) > extra-y += eabi_compat.o > diff --git a/arch/arm/lib/xferlist.c b/arch/arm/lib/xferlist.c > new file mode 100644 > index 0000000000..163d20c11c > --- /dev/null > +++ b/arch/arm/lib/xferlist.c > @@ -0,0 +1,38 @@ > +// SPDX-License-Identifier: GPL-2.0+ > +/* > + * Copyright (C) 2023 Linaro Limited > + * Author: Raymond Mao <raymond.mao@linaro.org <mailto:raymond.mao@linaro.org>> > + */ > +#include <linux/types.h> > +#include <errno.h> > +#include <bloblist.h> > + > +/* > + * Boot parameters saved from start.S > + * saved_args[0]: FDT base address > + * saved_args[1]: Bloblist signature > + * saved_args[2]: must be 0 > + * saved_args[3]: Bloblist base address > + */ > +extern unsigned long saved_args[]; you should put this to bloblist.h. I would say it should be the part of 4/9 where you define saved_args for armv7.
Not sure if I understand your point but this part is for Arm only (v7 and v8) and should not be in bloblist.h. It works following the spec from Arm. Other arches should implement their own way if they want to load the bloblist from the previous loader.
I am just saying that you shouldn't really have extern in C files. If you need to have reference to it put it to .h file. If this is generic or arch specific that's up to you.
Thanks, Michal

During bloblist initialization, when OF_BOARD is defined, load the bloblist via boot arguments from the previous loader. If a valid bloblist exists in boot arguments, relocate it into the fixed bloblist memory region. If not, fallback to support BLOBLIST_ADDR or BLOBLIST_ALLOC.
Signed-off-by: Raymond Mao raymond.mao@linaro.org --- Changes in v4 - Add weak default function. - Add comments for BLOBLIST_ALLOC. - Add local debug macro. - Refine the commit message.
common/bloblist.c | 66 +++++++++++++++++++++++++++++++++------------- include/bloblist.h | 10 +++++++ 2 files changed, 58 insertions(+), 18 deletions(-)
diff --git a/common/bloblist.c b/common/bloblist.c index 4e76975627..65c3c031d0 100644 --- a/common/bloblist.c +++ b/common/bloblist.c @@ -17,6 +17,9 @@ #include <asm/global_data.h> #include <u-boot/crc.h>
+/* local debug macro */ +#undef BLOBLIST_DEBUG + /* * A bloblist is a single contiguous chunk of memory with a header * (struct bloblist_hdr) and a number of blobs in it. @@ -487,37 +490,58 @@ int bloblist_reloc(void *to, uint to_size) return 0; }
+/* + * Weak default function for getting bloblist from boot args. + */ +int __weak xferlist_from_boot_arg(ulong __always_unused addr, + ulong __always_unused size) +{ + return -ENOENT; +} + int bloblist_init(void) { bool fixed = IS_ENABLED(CONFIG_BLOBLIST_FIXED); int ret = -ENOENT; ulong addr, size; - bool expected; - - /** - * We don't expect to find an existing bloblist in the first phase of - * U-Boot that runs. Also we have no way to receive the address of an - * allocated bloblist from a previous stage, so it must be at a fixed + /* + * If U-Boot is not in the first phase, an existing bloblist must be + * at a fixed address. + */ + bool from_addr = fixed && !u_boot_first_phase(); + /* + * If U-Boot is in the first phase that a board specific routine should + * install the bloblist passed from previous loader to this fixed * address. */ - expected = fixed && !u_boot_first_phase(); + bool from_board = fixed && IS_ENABLED(CONFIG_OF_BOARD) && + u_boot_first_phase(); + if (spl_prev_phase() == PHASE_TPL && !IS_ENABLED(CONFIG_TPL_BLOBLIST)) - expected = false; + from_addr = false; if (fixed) addr = IF_ENABLED_INT(CONFIG_BLOBLIST_FIXED, CONFIG_BLOBLIST_ADDR); size = CONFIG_BLOBLIST_SIZE; - if (expected) { + + if (from_board) + ret = xferlist_from_boot_arg(addr, size); + else if (from_addr) ret = bloblist_check(addr, size); - if (ret) { - log_warning("Expected bloblist at %lx not found (err=%d)\n", - addr, ret); - } else { - /* Get the real size, if it is not what we expected */ - size = gd->bloblist->total_size; - } - } + + if (ret) + log_warning("Bloblist at %lx not found (err=%d)\n", + addr, ret); + else + /* Get the real size */ + size = gd->bloblist->total_size; + if (ret) { + /* + * If we don't have a bloblist from a fixed address, or the one + * in the fixed address is not valid. we must allocate the + * memory for it now. + */ if (CONFIG_IS_ENABLED(BLOBLIST_ALLOC)) { void *ptr = memalign(BLOBLIST_ALIGN, size);
@@ -525,7 +549,8 @@ int bloblist_init(void) return log_msg_ret("alloc", -ENOMEM); addr = map_to_sysmem(ptr); } else if (!fixed) { - return log_msg_ret("!fixed", ret); + return log_msg_ret("BLOBLIST_FIXED is not enabled", + ret); } log_debug("Creating new bloblist size %lx at %lx\n", size, addr); @@ -538,6 +563,11 @@ int bloblist_init(void) return log_msg_ret("ini", ret); gd->flags |= GD_FLG_BLOBLIST_READY;
+#ifdef BLOBLIST_DEBUG + bloblist_show_stats(); + bloblist_show_list(); +#endif + return 0; }
diff --git a/include/bloblist.h b/include/bloblist.h index 81f1dfa027..af215932bc 100644 --- a/include/bloblist.h +++ b/include/bloblist.h @@ -482,4 +482,14 @@ static inline int bloblist_maybe_init(void) */ int bloblist_check_reg_conv(ulong rfdt, ulong rzero, ulong rsig);
+/** + * xferlist_from_boot_arg() - Get bloblist from the boot args and relocate it + * to the specified address. + * + * @addr: Address for the bloblist + * @size: Size of space reserved for the bloblist + * Return: 0 if OK, else on error + */ +int xferlist_from_boot_arg(ulong addr, ulong size); + #endif /* __BLOBLIST_H */

On 1/2/24 23:12, Raymond Mao wrote:
During bloblist initialization, when OF_BOARD is defined, load the bloblist via boot arguments from the previous loader. If a valid bloblist exists in boot arguments, relocate it into the fixed bloblist memory region. If not, fallback to support BLOBLIST_ADDR or BLOBLIST_ALLOC.
Signed-off-by: Raymond Mao raymond.mao@linaro.org
Changes in v4
Add weak default function.
Add comments for BLOBLIST_ALLOC.
Add local debug macro.
Refine the commit message.
common/bloblist.c | 66 +++++++++++++++++++++++++++++++++------------- include/bloblist.h | 10 +++++++ 2 files changed, 58 insertions(+), 18 deletions(-)
diff --git a/common/bloblist.c b/common/bloblist.c index 4e76975627..65c3c031d0 100644 --- a/common/bloblist.c +++ b/common/bloblist.c @@ -17,6 +17,9 @@ #include <asm/global_data.h> #include <u-boot/crc.h>
+/* local debug macro */ +#undef BLOBLIST_DEBUG
What's wrong with standard DEBUG macro that you need to introduce another one?
M

Update the document and Kconfig to describe the behavior of board specific custom functions when CONFIG_OF_BOARD is defined.
Signed-off-by: Raymond Mao raymond.mao@linaro.org --- Changes in v4 - Refine the description.
doc/develop/devicetree/control.rst | 6 +++--- dts/Kconfig | 7 +++++-- 2 files changed, 8 insertions(+), 5 deletions(-)
diff --git a/doc/develop/devicetree/control.rst b/doc/develop/devicetree/control.rst index cbb65c9b17..2b968a6b01 100644 --- a/doc/develop/devicetree/control.rst +++ b/doc/develop/devicetree/control.rst @@ -104,9 +104,9 @@ in u-boot.bin so you can still just flash u-boot.bin onto your board. If you are using CONFIG_SPL_FRAMEWORK, then u-boot.img will be built to include the device tree binary.
-If CONFIG_OF_BOARD is defined, a board-specific routine will provide the -devicetree at runtime, for example if an earlier bootloader stage creates -it and passes it to U-Boot. +If CONFIG_OF_BOARD is defined, arch-specific routine and board-specific routine +will provide the bloblist and devicetree respectively at runtime, for example if +an earlier bootloader stage creates it and passes it to U-Boot.
If CONFIG_SANDBOX is defined, then it will be read from a file on startup. Use the -d flag to U-Boot to specify the file to read, -D for the diff --git a/dts/Kconfig b/dts/Kconfig index 00c0aeff89..ac6e1752bb 100644 --- a/dts/Kconfig +++ b/dts/Kconfig @@ -110,8 +110,11 @@ config OF_BOARD default y if SANDBOX || OF_HAS_PRIOR_STAGE help If this option is enabled, the device tree is provided at runtime by - a custom function called board_fdt_blob_setup(). The board must - implement this function if it wishes to provide special behaviour. + a board custom function called board_fdt_blob_setup(). + If this option is enabled, bloblist is provided at runtime by an + arch custom function called xferlist_from_boot_arg(). + An arch or board must implement these functions if it wishes to + provide special behaviours.
With this option, the device tree build by U-Boot may be overridden or ignored. See OF_HAS_PRIOR_STAGE.

I think this isn't needed anymore after https://lore.kernel.org/u-boot/CAC_iWjJ6=NjqwcFzVvV4DzMWy5nY_QAeD=vfQrRSjodL...
On Wed, 3 Jan 2024 at 00:14, Raymond Mao raymond.mao@linaro.org wrote:
Update the document and Kconfig to describe the behavior of board specific custom functions when CONFIG_OF_BOARD is defined.
Signed-off-by: Raymond Mao raymond.mao@linaro.org
Changes in v4
- Refine the description.
doc/develop/devicetree/control.rst | 6 +++--- dts/Kconfig | 7 +++++-- 2 files changed, 8 insertions(+), 5 deletions(-)
diff --git a/doc/develop/devicetree/control.rst b/doc/develop/devicetree/control.rst index cbb65c9b17..2b968a6b01 100644 --- a/doc/develop/devicetree/control.rst +++ b/doc/develop/devicetree/control.rst @@ -104,9 +104,9 @@ in u-boot.bin so you can still just flash u-boot.bin onto your board. If you are using CONFIG_SPL_FRAMEWORK, then u-boot.img will be built to include the device tree binary.
-If CONFIG_OF_BOARD is defined, a board-specific routine will provide the -devicetree at runtime, for example if an earlier bootloader stage creates -it and passes it to U-Boot. +If CONFIG_OF_BOARD is defined, arch-specific routine and board-specific routine +will provide the bloblist and devicetree respectively at runtime, for example if +an earlier bootloader stage creates it and passes it to U-Boot.
If CONFIG_SANDBOX is defined, then it will be read from a file on startup. Use the -d flag to U-Boot to specify the file to read, -D for the diff --git a/dts/Kconfig b/dts/Kconfig index 00c0aeff89..ac6e1752bb 100644 --- a/dts/Kconfig +++ b/dts/Kconfig @@ -110,8 +110,11 @@ config OF_BOARD default y if SANDBOX || OF_HAS_PRIOR_STAGE help If this option is enabled, the device tree is provided at runtime by
a custom function called board_fdt_blob_setup(). The board must
implement this function if it wishes to provide special behaviour.
a board custom function called board_fdt_blob_setup().
If this option is enabled, bloblist is provided at runtime by an
arch custom function called xferlist_from_boot_arg().
An arch or board must implement these functions if it wishes to
provide special behaviours. With this option, the device tree build by U-Boot may be overridden or ignored. See OF_HAS_PRIOR_STAGE.
-- 2.25.1

Hi Ilias,
On Wed, 10 Jan 2024 at 09:12, Ilias Apalodimas ilias.apalodimas@linaro.org wrote:
I think this isn't needed anymore after
https://lore.kernel.org/u-boot/CAC_iWjJ6=NjqwcFzVvV4DzMWy5nY_QAeD=vfQrRSjodL...
I think Simon's patch is missing the description on OF_BOARD, a FDT from
the previous stage via transfer list depends on both OF_BOARD and BLOBLIST. And also I think we need to describe about the arch-specific function here, in case that other arches want to follow the same FW handoff spec in the future.
[...]
Regards, Raymond

Get devicetree from a bloblist if it exists. If not, fallback to get FDT from the board custom function.
Signed-off-by: Raymond Mao raymond.mao@linaro.org --- Changes in v2 - Refactor of board_fdt_blob_setup(). Changes in v4 - Move the logics from board custom function to fdt library.
lib/fdtdec.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/lib/fdtdec.c b/lib/fdtdec.c index 7a69167648..02a0504fad 100644 --- a/lib/fdtdec.c +++ b/lib/fdtdec.c @@ -8,6 +8,7 @@
#ifndef USE_HOSTCC #include <common.h> +#include <bloblist.h> #include <boot_fit.h> #include <display_options.h> #include <dm.h> @@ -1676,7 +1677,13 @@ int fdtdec_setup(void)
/* Allow the board to override the fdt address. */ if (IS_ENABLED(CONFIG_OF_BOARD)) { - gd->fdt_blob = board_fdt_blob_setup(&ret); + void *fdt = NULL; + + /* Check if a fdt exists in bloblist */ + if (IS_ENABLED(CONFIG_BLOBLIST) && !bloblist_maybe_init()) + fdt = bloblist_find(BLOBLISTT_CONTROL_FDT, 0); + + gd->fdt_blob = fdt ? fdt : board_fdt_blob_setup(&ret); if (ret) return ret; gd->fdt_src = FDTSRC_BOARD;
participants (4)
-
Ilias Apalodimas
-
Michal Simek
-
Raymond Mao
-
Tom Rini