diff --git a/arch/arm/lib/xferlist.c b/arch/arm/lib/xferlist.c index f9c5d88bd47..6425936d354 100644 --- a/arch/arm/lib/xferlist.c +++ b/arch/arm/lib/xferlist.c @@ -8,18 +8,16 @@ #include #include "xferlist.h" -int xferlist_from_boot_arg(ulong addr, ulong size) +int xferlist_from_boot_arg(ulong *addr) { int ret; - ret = bloblist_check(saved_args[3], size); - if (ret) - return ret; - ret = bloblist_check_reg_conv(saved_args[0], saved_args[2], - saved_args[1]); + saved_args[1], saved_args[3]); if (ret) return ret; - return bloblist_reloc((void *)addr, size); + *addr = bloblist_get_base(); + + return 0; } diff --git a/common/Kconfig b/common/Kconfig index 7b2db46ef06..1d6de8badf7 100644 --- a/common/Kconfig +++ b/common/Kconfig @@ -1066,11 +1066,15 @@ config BLOBLIST_ALLOC specify a fixed address on systems where this is unknown or can change at runtime. -config BLOBLIST_PASSAGE - bool "Use bloblist in-place" +config BLOBLIST_PASSAGE_MANDATORY + bool "Use bloblist in-place mandatorily" help - Use a bloblist in the incoming standard passage. The size is detected - automatically so CONFIG_BLOBLIST_SIZE can be 0. + By default U-Boot will use a bloblist in the incoming standard passage. + This option controls whether U-Boot tries to load a static bloblist or + allocate one if a valid incoming bloblist does not exist. + Select this option to mark incoming standard passage as mandatory and + U-Boot will report an error when a valid incoming bloblist does not + exist. endchoice @@ -1086,7 +1090,7 @@ config BLOBLIST_ADDR config BLOBLIST_SIZE hex "Size of bloblist" - default 0x0 if BLOBLIST_PASSAGE + default 0x0 if BLOBLIST_PASSAGE_MANDATORY default 0x400 help Sets the size of the bloblist in bytes. This must include all diff --git a/common/bloblist.c b/common/bloblist.c index 31ba0311090..6e4f020d7c4 100644 --- a/common/bloblist.c +++ b/common/bloblist.c @@ -505,8 +505,7 @@ int bloblist_reloc(void *to, uint to_size) /* * Weak default function for getting bloblist from boot args. */ -int __weak xferlist_from_boot_arg(ulong __always_unused addr, - ulong __always_unused size) +int __weak xferlist_from_boot_arg(ulong __always_unused *addr) { return -ENOENT; } @@ -514,37 +513,46 @@ int __weak xferlist_from_boot_arg(ulong __always_unused addr, int bloblist_init(void) { bool fixed = IS_ENABLED(CONFIG_BLOBLIST_FIXED); - int ret = -ENOENT; + int ret = 0; ulong addr = 0, size; - /* - * If U-Boot is not in the first phase, an existing bloblist must be - * at a fixed address. - */ - bool from_addr = fixed && !xpl_is_first_phase(); - if (xpl_prev_phase() == PHASE_TPL && !IS_ENABLED(CONFIG_TPL_BLOBLIST)) - from_addr = false; - if (fixed) - addr = IF_ENABLED_INT(CONFIG_BLOBLIST_FIXED, - CONFIG_BLOBLIST_ADDR); - size = CONFIG_BLOBLIST_SIZE; + /* Check if a valid transfer list passed in */ + if (!xferlist_from_boot_arg(&addr)) { + size = bloblist_get_total_size(); + } else { + /* + * If U-Boot is not in the first phase, an existing bloblist must + * be at a fixed address. + */ + bool from_addr = fixed && !xpl_is_first_phase(); - /* - * If the current boot stage is the first phase of U-Boot, then an - * architecture-specific routine should be used to handle the bloblist - * passed from the previous boot loader - */ - if (xpl_is_first_phase() && !IS_ENABLED(CONFIG_BLOBLIST_ALLOC)) - ret = xferlist_from_boot_arg(addr, size); - else if (from_addr) - ret = bloblist_check(addr, size); + /* + * If Firmware Handoff is mandatory but no transfer list is + * observed, report it as an error. + */ + if (IS_ENABLED(CONFIG_BLOBLIST_PASSAGE_MANDATORY)) + return -ENOENT; - if (ret) - log_warning("Bloblist at %lx not found (err=%d)\n", - addr, ret); - else - /* Get the real size */ - size = gd->bloblist->total_size; + ret = -ENOENT; + + if (xpl_prev_phase() == PHASE_TPL && + !IS_ENABLED(CONFIG_TPL_BLOBLIST)) + from_addr = false; + if (fixed) + addr = IF_ENABLED_INT(CONFIG_BLOBLIST_FIXED, + CONFIG_BLOBLIST_ADDR); + size = CONFIG_BLOBLIST_SIZE; + + if (from_addr) + ret = bloblist_check(addr, 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) { /* @@ -569,6 +577,7 @@ int bloblist_init(void) log_debug("Found existing bloblist size %lx at %lx\n", size, addr); } + if (ret) return log_msg_ret("ini", ret); gd->flags |= GD_FLG_BLOBLIST_READY; @@ -589,10 +598,11 @@ int bloblist_maybe_init(void) return 0; } -int bloblist_check_reg_conv(ulong rfdt, ulong rzero, ulong rsig) +int bloblist_check_reg_conv(ulong rfdt, ulong rzero, ulong rsig, ulong xlist) { u64 version = BLOBLIST_REGCONV_VER; ulong sigval; + int ret; if ((IS_ENABLED(CONFIG_64BIT) && !IS_ENABLED(CONFIG_SPL_BUILD)) || (IS_ENABLED(CONFIG_SPL_64BIT) && IS_ENABLED(CONFIG_SPL_BUILD))) { @@ -603,8 +613,14 @@ int bloblist_check_reg_conv(ulong rfdt, ulong rzero, ulong rsig) ((version & BLOBLIST_REGCONV_MASK) << BLOBLIST_REGCONV_SHIFT_32)); } - if (rzero || rsig != sigval || - rfdt != (ulong)bloblist_find(BLOBLISTT_CONTROL_FDT, 0)) { + if (rzero || rsig != sigval) + return -EIO; + + ret = bloblist_check(xlist, 0); + if (ret) + return ret; + + if (rfdt != (ulong)bloblist_find(BLOBLISTT_CONTROL_FDT, 0)) { gd->bloblist = NULL; /* Reset the gd bloblist pointer */ return -EIO; } diff --git a/common/board_f.c b/common/board_f.c index 6c5c3bfab48..2912320054f 100644 --- a/common/board_f.c +++ b/common/board_f.c @@ -624,11 +624,14 @@ static int reserve_stacks(void) static int reserve_bloblist(void) { #ifdef CONFIG_BLOBLIST + ulong size = bloblist_get_total_size(); + + if (size < CONFIG_BLOBLIST_SIZE_RELOC) + size = CONFIG_BLOBLIST_SIZE_RELOC; + /* Align to a 4KB boundary for easier reading of addresses */ - gd->start_addr_sp = ALIGN_DOWN(gd->start_addr_sp - - CONFIG_BLOBLIST_SIZE_RELOC, 0x1000); - gd->boardf->new_bloblist = map_sysmem(gd->start_addr_sp, - CONFIG_BLOBLIST_SIZE_RELOC); + gd->start_addr_sp = ALIGN_DOWN(gd->start_addr_sp - size, 0x1000); + gd->boardf->new_bloblist = map_sysmem(gd->start_addr_sp, size); #endif return 0; @@ -698,11 +701,14 @@ static int reloc_bloblist(void) return 0; } if (gd->boardf->new_bloblist) { - debug("Copying bloblist from %p to %p, size %x\n", - gd->bloblist, gd->boardf->new_bloblist, - gd->bloblist->total_size); - return bloblist_reloc(gd->boardf->new_bloblist, - CONFIG_BLOBLIST_SIZE_RELOC); + ulong size = bloblist_get_total_size(); + + if (size < CONFIG_BLOBLIST_SIZE_RELOC) + size = CONFIG_BLOBLIST_SIZE_RELOC; + + debug("Copying bloblist from %p to %p, size %lx\n", + gd->bloblist, gd->boardf->new_bloblist, size); + return bloblist_reloc(gd->boardf->new_bloblist, size); } #endif diff --git a/configs/vexpress_fvp_bloblist_defconfig b/configs/vexpress_fvp_bloblist_defconfig index dcc87db8723..4d52b96202b 100644 --- a/configs/vexpress_fvp_bloblist_defconfig +++ b/configs/vexpress_fvp_bloblist_defconfig @@ -1,5 +1,5 @@ #include CONFIG_BLOBLIST=y -CONFIG_BLOBLIST_PASSAGE=y +CONFIG_BLOBLIST_PASSAGE_MANDATORY=y CONFIG_BLOBLIST_SIZE_RELOC=0x10000 diff --git a/doc/board/armltd/vexpress64.rst b/doc/board/armltd/vexpress64.rst index 4dadadb53dc..a732fac899d 100644 --- a/doc/board/armltd/vexpress64.rst +++ b/doc/board/armltd/vexpress64.rst @@ -53,8 +53,8 @@ predefined bloblist at a specified address, dynamically allocating memory for a bloblist, or utilizing a standard passage-provided bloblist with automatic size detection. -By default, ``vexpress_fvp_bloblist_defconfig`` uses the standard passage method -(CONFIG_BLOBLIST_PASSAGE) because TF-A provides a Transfer List in non-secure +By default, ``vexpress_fvp_bloblist_defconfig`` uses the standard passage method mandatorily +(CONFIG_BLOBLIST_PASSAGE_MANDATORY) because TF-A provides a Transfer List in non-secure memory that U-Boot can utilise. This Bloblist, which is referred to as a Transfer List in TF-A, contains all necessary data for the handoff process, including DT and ACPI tables. diff --git a/include/bloblist.h b/include/bloblist.h index 98aacf52733..f32faf78560 100644 --- a/include/bloblist.h +++ b/include/bloblist.h @@ -467,9 +467,8 @@ int bloblist_reloc(void *to, uint to_size); * If CONFIG_BLOBLIST_ALLOC is selected, it allocates memory for a bloblist of * size CONFIG_BLOBLIST_SIZE. * - * If CONFIG_BLOBLIST_PASSAGE is selected, it uses the bloblist in the incoming - * standard passage. The size is detected automatically so CONFIG_BLOBLIST_SIZE - * can be 0. + * If CONFIG_BLOBLIST_PASSAGE_MANDATORY is selected, bloblist in the incoming + * standard passage is mandatorily required. * * Sets GD_FLG_BLOBLIST_READY in global_data flags on success * @@ -501,19 +500,18 @@ static inline int bloblist_maybe_init(void) * @rfdt: Register that holds the FDT base address. * @rzero: Register that must be zero. * @rsig: Register that holds signature and register conventions version. + * @xlist: Register that holds the transfer list. * Return: 0 if OK, -EIO if the bloblist is not compliant to the register * conventions. */ -int bloblist_check_reg_conv(ulong rfdt, ulong rzero, ulong rsig); +int bloblist_check_reg_conv(ulong rfdt, ulong rzero, ulong rsig, ulong xlist); /** - * xferlist_from_boot_arg() - Get bloblist from the boot args and relocate it - * to the specified address. + * xferlist_from_boot_arg() - Get bloblist from the boot args. * - * @addr: Address for the bloblist - * @size: Size of space reserved for the bloblist + * @addr: Address of the bloblist * Return: 0 if OK, else on error */ -int xferlist_from_boot_arg(ulong addr, ulong size); +int xferlist_from_boot_arg(ulong *addr); #endif /* __BLOBLIST_H */