[PATCH 00/67] upl: Align with the updated spec

The current UPL spec[1] has been tidied up and improved over the last year, since U-Boot's original UPL support was written.
This series addresses various issues, with a goal of having U-Boot boot EDK2.
There is still more work to do, but this series gets to the point (on QEMU) where the ACPI tables are required. Further work will be needed to relocate the tables out of the QEMU firmware-filesystem.
[1] git@github.com:UniversalPayload/spec.git commit 3f1450d
Simon Glass (67): bloblist: Make BLOBLIST_ALLOC the default abuf: Provide a way to get the buffer address abuf: Allow use in host tools abuf: Provide a constant buffer cpu: Provide a way to get the physical-address size serial: Support info() method in ns16550 xPL with UPL mkimage: Update map_to_sysmem() to match its prototype x86: Emable meminfo command x86: Show the timestamp counter with bdinfo ofnode: Use 4K for a default tree-size ofnode: Indicate when out of space in a few places ofnode: Update of_add_subnode() to indicate name is alloced boot: Rename fit_image_get_data() boot: Rename fit_image_get_data_and_size() boot: Update fit_image_get_emb_data to use abuf boot: Use fit_image_get_data() to get data boot: Update fit_image_get_data() to use abuf test: Fix inpected typo in upl test emulation: fdt: Relax condition for OF_HAS_PRIOR_STAGE emulation: Use bloblist to hold tables x86: Create more space for SPL with qemu-x86_64 upl: Create a function to create a memory node upl: Update add_upl_memmap() to use write_mem_node() upl: Update add_upl_memres() to use write_mem_node() upl: Support writing a UPL only for testing upl: Drop enum upl_serial_access_type upl: Init serial and graphics alists in upl_init() upl: Move serial and graphics addition-code to upl_common pci: video: Set up the pixel-format field x86: Show an error if video fails x86: Support jumping to a UPL image x86: Enable UPL handoff for SPL x86: Align the SMBIOS table to a 4K boundary upl: Require OFNODE_MULTI_TREE when writing a UPL handoff upl: Drop the argument to spl_write_upl_handoff() x86: emulation: Enable UPL upl: Correct comment and condition in add_upl_memres() upl: Add addr/size tags in the reserved-memory node upl: Update upl_add_graphics() to return framebuffer upl: Add a function to write a UPL handoff to an abuf upl: Use a 64-bit value for a memregion base-address upl: Set bit 32 of the address when using ISA upl: Add RAM to the memory region upl: Add a compatible string for the upl-params node upl: Move buffer_addr_size() higher and rename upl: Factor out part of encode_reg() to new function upl: Move decode_addr_size() higher and rename upl: Factor out part of decode_reg() to new function upl: Correct name of upl-images dm: core: Clarify behaviour of ofnode_name_eq() dm: core: Allow ofnode_name_eq() to accept a unit address dm: core: Rewrite ofnode_find_subnode() to use ofnode API upl: test: Show the handoff FDT when debugging upl: Use a reg property to specify the FIT address and size upl: Update and tidy writing of images upl: Make use of alist_for_each() upl: Correct use of sizeof() upl: Drop acpi_nvs_size upl: Improve uniqueness of log_msg_ret() strings upl: Add PCI information upl: Handle serial on an ISA bus with /chosen node upl: Add missing word in comment for upl_write_handoff() upl: Add a command to execute a UPL payload scripts: Update qemu script to use 64-bit on x86 always scripts: Update qemu script to support specifying a UPL upl: Add reserved memory for the ACPI and SMBIOS tables upl: Add an 'addr' property for Tianocore
arch/Kconfig | 2 + arch/arm/cpu/armv8/sec_firmware.c | 13 +- arch/arm/mach-k3/r5/sysfw-loader.c | 11 +- arch/x86/include/asm/cpu.h | 9 - arch/x86/lib/bdinfo.c | 3 + arch/x86/lib/bootm.c | 18 +- arch/x86/lib/spl.c | 12 +- arch/x86/lib/tables.c | 9 +- boot/Kconfig | 9 + boot/Makefile | 1 + boot/image-board.c | 11 +- boot/image-fit.c | 98 ++---- boot/upl_common.c | 191 ++++++++++ boot/upl_exec.c | 130 +++++++ boot/upl_read.c | 220 ++++++------ boot/upl_write.c | 464 ++++++++++++++++--------- cmd/upl.c | 36 +- cmd/ximg.c | 14 +- common/Kconfig | 15 +- common/spl/spl.c | 2 +- common/spl/spl_fit.c | 8 +- common/spl/spl_upl.c | 114 +----- common/splash_source.c | 18 +- common/update.c | 7 +- configs/chromebook_bob_defconfig | 1 + configs/chromebook_coral_defconfig | 1 + configs/chromebook_kevin_defconfig | 1 + configs/chromebook_samus_tpl_defconfig | 1 + configs/qemu-x86_64_defconfig | 9 +- configs/qemu-x86_defconfig | 2 + configs/qemu_arm64_defconfig | 2 + configs/qemu_arm_defconfig | 2 + drivers/core/ofnode.c | 57 +-- drivers/misc/qfw_acpi.c | 37 +- drivers/misc/qfw_smbios.c | 45 ++- drivers/pci/pci_rom.c | 3 + drivers/serial/ns16550.c | 2 +- drivers/video/bochs.c | 1 + drivers/video/video-uclass.c | 1 + dts/Kconfig | 2 +- include/abuf.h | 25 ++ include/alist.h | 2 +- include/cpu.h | 14 + include/dm/ofnode.h | 15 +- include/image.h | 39 ++- include/spl.h | 3 +- include/upl.h | 211 +++++++++-- include/video.h | 2 + lib/Kconfig | 1 + lib/Makefile | 5 + lib/abuf.c | 21 +- lib/alist.c | 2 +- scripts/build-qemu.sh | 28 +- test/boot/upl.c | 72 ++-- test/common/Makefile | 4 + test/dm/core.c | 5 + test/dm/ofnode.c | 19 + test/lib/abuf.c | 27 +- test/py/tests/test_upl.py | 2 +- tools/Makefile | 3 +- tools/fit_image.c | 8 +- tools/image-host.c | 23 +- tools/mkimage.h | 2 +- 63 files changed, 1445 insertions(+), 670 deletions(-) create mode 100644 boot/upl_exec.c

We want to encourage people to use an allocated bloblist since it is more flexible than a fixed one. Make this the default, being sure not to change existing users.
The unit tests require BLOBLIST_FIXED so add a dependency in the Makefile to avoid build errors.
Signed-off-by: Simon Glass sjg@chromium.org ---
common/Kconfig | 15 ++++++++------- configs/chromebook_bob_defconfig | 1 + configs/chromebook_coral_defconfig | 1 + configs/chromebook_kevin_defconfig | 1 + configs/chromebook_samus_tpl_defconfig | 1 + configs/qemu-x86_64_defconfig | 1 + test/common/Makefile | 4 ++++ 7 files changed, 17 insertions(+), 7 deletions(-)
diff --git a/common/Kconfig b/common/Kconfig index e8d89bf6eb9..a00387a4609 100644 --- a/common/Kconfig +++ b/common/Kconfig @@ -1039,16 +1039,10 @@ if BLOBLIST
choice prompt "Bloblist location" + default BLOBLIST_FIXED if SANDBOX help Select the location of the bloblist, via various means.
-config BLOBLIST_FIXED - bool "Place bloblist at a fixed address in memory" - help - Select this to used a fixed memory address for the bloblist. If the - bloblist exists at this address from a previous phase, it used as is. - If not it is created at this address in U-Boot. - config BLOBLIST_ALLOC bool "Allocate bloblist" help @@ -1056,6 +1050,13 @@ config BLOBLIST_ALLOC specify a fixed address on systems where this is unknown or can change at runtime.
+config BLOBLIST_FIXED + bool "Place bloblist at a fixed address in memory" + help + Select this to used a fixed memory address for the bloblist. If the + bloblist exists at this address from a previous phase, it used as is. + If not it is created at this address in U-Boot. + endchoice
config BLOBLIST_ADDR diff --git a/configs/chromebook_bob_defconfig b/configs/chromebook_bob_defconfig index decac2e1935..072311465d9 100644 --- a/configs/chromebook_bob_defconfig +++ b/configs/chromebook_bob_defconfig @@ -36,6 +36,7 @@ CONFIG_DEFAULT_FDT_FILE="rockchip/rk3399-gru-bob.dtb" CONFIG_DISPLAY_BOARDINFO_LATE=y CONFIG_BOARD_EARLY_INIT_R=y CONFIG_BLOBLIST=y +CONFIG_BLOBLIST_FIXED=y CONFIG_BLOBLIST_ADDR=0x100000 CONFIG_BLOBLIST_SIZE=0x1000 CONFIG_SPL_MAX_SIZE=0x1e000 diff --git a/configs/chromebook_coral_defconfig b/configs/chromebook_coral_defconfig index 0fb73049738..b1999b4ef20 100644 --- a/configs/chromebook_coral_defconfig +++ b/configs/chromebook_coral_defconfig @@ -44,6 +44,7 @@ CONFIG_LOGF_FUNC=y CONFIG_DISPLAY_BOARDINFO_LATE=y CONFIG_BLOBLIST=y # CONFIG_TPL_BLOBLIST is not set +CONFIG_BLOBLIST_FIXED=y CONFIG_BLOBLIST_ADDR=0x100000 CONFIG_BLOBLIST_SIZE=0x30000 CONFIG_SPL_NO_BSS_LIMIT=y diff --git a/configs/chromebook_kevin_defconfig b/configs/chromebook_kevin_defconfig index 5bbea6c42a8..13c0998dbab 100644 --- a/configs/chromebook_kevin_defconfig +++ b/configs/chromebook_kevin_defconfig @@ -37,6 +37,7 @@ CONFIG_DEFAULT_FDT_FILE="rockchip/rk3399-gru-kevin.dtb" CONFIG_DISPLAY_BOARDINFO_LATE=y CONFIG_BOARD_EARLY_INIT_R=y CONFIG_BLOBLIST=y +CONFIG_BLOBLIST_FIXED=y CONFIG_BLOBLIST_ADDR=0x100000 CONFIG_BLOBLIST_SIZE=0x1000 CONFIG_SPL_MAX_SIZE=0x1e000 diff --git a/configs/chromebook_samus_tpl_defconfig b/configs/chromebook_samus_tpl_defconfig index fc524da5480..42337d7a11e 100644 --- a/configs/chromebook_samus_tpl_defconfig +++ b/configs/chromebook_samus_tpl_defconfig @@ -34,6 +34,7 @@ CONFIG_SYS_CONSOLE_INFO_QUIET=y CONFIG_DISPLAY_BOARDINFO_LATE=y CONFIG_MISC_INIT_R=y CONFIG_BLOBLIST=y +CONFIG_BLOBLIST_FIXED=y CONFIG_BLOBLIST_ADDR=0xff7c0000 CONFIG_BLOBLIST_SIZE=0x1000 CONFIG_SPL_NO_BSS_LIMIT=y diff --git a/configs/qemu-x86_64_defconfig b/configs/qemu-x86_64_defconfig index 812b20687e5..f93721fceb8 100644 --- a/configs/qemu-x86_64_defconfig +++ b/configs/qemu-x86_64_defconfig @@ -34,6 +34,7 @@ CONFIG_SPL_LOG=y CONFIG_DISPLAY_BOARDINFO_LATE=y CONFIG_PCI_INIT_R=y CONFIG_BLOBLIST=y +CONFIG_BLOBLIST_FIXED=y CONFIG_BLOBLIST_ADDR=0x10000 CONFIG_SPL_NO_BSS_LIMIT=y CONFIG_SPL_BOARD_INIT=y diff --git a/test/common/Makefile b/test/common/Makefile index 53c4f16164d..95bd00741a3 100644 --- a/test/common/Makefile +++ b/test/common/Makefile @@ -1,9 +1,13 @@ # SPDX-License-Identifier: GPL-2.0+ obj-y += cmd_ut_common.o obj-$(CONFIG_AUTOBOOT) += test_autoboot.o + ifneq ($(CONFIG_$(XPL_)BLOBLIST),) +ifdef CONFIG_BLOBLIST_FIXED obj-$(CONFIG_$(XPL_)CMDLINE) += bloblist.o endif +endif + obj-$(CONFIG_CYCLIC) += cyclic.o obj-$(CONFIG_EVENT_DYNAMIC) += event.o obj-y += cread.o

In many cases it is useful to get the address of a buffer, e.g. when booting from it. Add a function to handle this.
Signed-off-by: Simon Glass sjg@chromium.org ---
include/abuf.h | 8 ++++++++ lib/abuf.c | 6 ++++++ test/lib/abuf.c | 4 +++- 3 files changed, 17 insertions(+), 1 deletion(-)
diff --git a/include/abuf.h b/include/abuf.h index be98ec78c86..76e314b9a47 100644 --- a/include/abuf.h +++ b/include/abuf.h @@ -42,6 +42,14 @@ static inline size_t abuf_size(const struct abuf *abuf) return abuf->size; }
+/** + * abuf_addr() - Get the address of a buffer's data + * + * @abuf: Buffer to check + * Return: address of buffer + */ +ulong abuf_addr(const struct abuf *abuf); + /** * abuf_set() - set the (unallocated) data in a buffer * diff --git a/lib/abuf.c b/lib/abuf.c index 937c3df351e..8156177c773 100644 --- a/lib/abuf.c +++ b/lib/abuf.c @@ -26,6 +26,12 @@ void abuf_map_sysmem(struct abuf *abuf, ulong addr, size_t size) { abuf_set(abuf, map_sysmem(addr, size), size); } + +ulong abuf_addr(const struct abuf *abuf) +{ + return map_to_sysmem(abuf->data); +} + #else /* copied from lib/string.c for convenience */ static char *memdup(const void *src, size_t len) diff --git a/test/lib/abuf.c b/test/lib/abuf.c index 7c0481ab610..5d61f9261c6 100644 --- a/test/lib/abuf.c +++ b/test/lib/abuf.c @@ -46,7 +46,7 @@ static int lib_test_abuf_set(struct unit_test_state *uts) } LIB_TEST(lib_test_abuf_set, 0);
-/* Test abuf_map_sysmem() */ +/* Test abuf_map_sysmem() and abuf_addr() */ static int lib_test_abuf_map_sysmem(struct unit_test_state *uts) { struct abuf buf; @@ -60,6 +60,8 @@ static int lib_test_abuf_map_sysmem(struct unit_test_state *uts) ut_asserteq(TEST_DATA_LEN, buf.size); ut_asserteq(false, buf.alloced);
+ ut_asserteq(addr, abuf_addr(&buf)); + return 0; } LIB_TEST(lib_test_abuf_map_sysmem, 0);

Some header files included on the host are moving to use abuf, so adjust the header-inclusion to bring in size_t correctly.
Signed-off-by: Simon Glass sjg@chromium.org ---
include/abuf.h | 4 ++++ 1 file changed, 4 insertions(+)
diff --git a/include/abuf.h b/include/abuf.h index 76e314b9a47..de21cefade4 100644 --- a/include/abuf.h +++ b/include/abuf.h @@ -9,7 +9,11 @@ #ifndef __ABUF_H #define __ABUF_H
+#ifdef USE_HOSTCC +#include <sys/types.h> +#else #include <linux/types.h> +#endif
/** * struct abuf - buffer that can be allocated and freed

Add a new initialiser which can accept a constant pointer.
Signed-off-by: Simon Glass sjg@chromium.org ---
include/abuf.h | 13 +++++++++++++ lib/abuf.c | 6 ++++++ test/lib/abuf.c | 23 +++++++++++++++++++++++ 3 files changed, 42 insertions(+)
diff --git a/include/abuf.h b/include/abuf.h index de21cefade4..62ff6499a0c 100644 --- a/include/abuf.h +++ b/include/abuf.h @@ -157,6 +157,19 @@ void abuf_init_move(struct abuf *abuf, void *data, size_t size); */ void abuf_init_set(struct abuf *abuf, void *data, size_t size);
+/** + * abuf_init_const() - Set up a new const abuf + * + * Inits a new abuf and sets up its (unallocated) data. The only current + * difference between this and abuf_init_set() is the 'data' parameter is a + * const pointer. At some point a flag could be used to indicate const-ness. + * + * @abuf: abuf to set up + * @data: New contents of abuf + * @size: New size of abuf + */ +void abuf_init_const(struct abuf *abuf, const void *data, size_t size); + /** * abuf_uninit() - Free any memory used by an abuf * diff --git a/lib/abuf.c b/lib/abuf.c index 8156177c773..61adf7fc6b1 100644 --- a/lib/abuf.c +++ b/lib/abuf.c @@ -119,6 +119,12 @@ void abuf_init_set(struct abuf *abuf, void *data, size_t size) abuf_set(abuf, data, size); }
+void abuf_init_const(struct abuf *abuf, const void *data, size_t size) +{ + /* for now there is no flag indicating that the abuf data is constant */ + abuf_init_set(abuf, (void *)data, size); +} + void abuf_init_move(struct abuf *abuf, void *data, size_t size) { abuf_init_set(abuf, data, size); diff --git a/test/lib/abuf.c b/test/lib/abuf.c index 5d61f9261c6..f954ae16da1 100644 --- a/test/lib/abuf.c +++ b/test/lib/abuf.c @@ -46,6 +46,29 @@ static int lib_test_abuf_set(struct unit_test_state *uts) } LIB_TEST(lib_test_abuf_set, 0);
+/* Test abuf_init_const() */ +static int lib_test_abuf_init_const(struct unit_test_state *uts) +{ + struct abuf buf; + ulong start; + void *ptr; + + start = ut_check_free(); + + ptr = map_sysmem(0x100, 0); + + abuf_init_const(&buf, ptr, 10); + ut_asserteq_ptr(ptr, buf.data); + ut_asserteq(10, buf.size); + + /* No memory should have been allocated */ + ut_assertok(ut_check_delta(start)); + + return 0; +} +LIB_TEST(lib_test_abuf_init_const, 0); + + /* Test abuf_map_sysmem() and abuf_addr() */ static int lib_test_abuf_map_sysmem(struct unit_test_state *uts) {

This concept exists on x86. Declare it as a generic function so that the value can be accessed by UPL.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/x86/include/asm/cpu.h | 9 --------- arch/x86/lib/bdinfo.c | 1 + include/cpu.h | 14 ++++++++++++++ 3 files changed, 15 insertions(+), 9 deletions(-)
diff --git a/arch/x86/include/asm/cpu.h b/arch/x86/include/asm/cpu.h index 8c1ef4c8cc1..fd389d4024c 100644 --- a/arch/x86/include/asm/cpu.h +++ b/arch/x86/include/asm/cpu.h @@ -284,15 +284,6 @@ u32 cpu_get_family_model(void); */ u32 cpu_get_stepping(void);
-/** - * cpu_phys_address_size() - Get the physical address size in bits - * - * This is 32 for older CPUs but newer ones may support 36. - * - * Return: address size (typically 32 or 36) - */ -int cpu_phys_address_size(void); - void board_final_init(void); void board_final_cleanup(void);
diff --git a/arch/x86/lib/bdinfo.c b/arch/x86/lib/bdinfo.c index 2a78f578dee..bd2cf0b9fcb 100644 --- a/arch/x86/lib/bdinfo.c +++ b/arch/x86/lib/bdinfo.c @@ -5,6 +5,7 @@ * Copyright 2021 Google LLC */
+#include <cpu.h> #include <efi.h> #include <init.h> #include <asm/cpu.h> diff --git a/include/cpu.h b/include/cpu.h index 0018910d61f..d0cd104c05a 100644 --- a/include/cpu.h +++ b/include/cpu.h @@ -179,4 +179,18 @@ struct udevice *cpu_get_current_dev(void); * @return 0 if OK, -ve on error */ int cpu_release_core(const struct udevice *dev, phys_addr_t addr); + +/** + * cpu_phys_address_size() - Get the physical-address size for the CPU + * + * x86 CPUs have a setting which indicates how many bits of address space are + * available on the CPU. This is 32 for older CPUs but newer ones may support 36 + * or more. + * + * For non-x86 CPUs the result may simply be 32 for 32-bit CPUS or 64 for 64-bit + * + * Return: address size (typically 32 or 36) + */ +int cpu_phys_address_size(void); + #endif

UPL needs to pass the serial details onto the next stage, so adjust the condition to support this.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/serial/ns16550.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/serial/ns16550.c b/drivers/serial/ns16550.c index 3f6860f3916..5126cf8bc1a 100644 --- a/drivers/serial/ns16550.c +++ b/drivers/serial/ns16550.c @@ -473,7 +473,7 @@ static int ns16550_serial_getinfo(struct udevice *dev, struct ns16550_plat *plat = com_port->plat;
/* save code size */ - if (!not_xpl()) + if (!not_xpl() && !CONFIG_IS_ENABLED(UPL_OUT)) return -ENOSYS;
info->type = SERIAL_CHIP_16550_COMPATIBLE;

Update the version of this function in mkimage so that it uses a const pointer, as is done in the mapmem.h header file.
Signed-off-by: Simon Glass sjg@chromium.org ---
tools/mkimage.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tools/mkimage.h b/tools/mkimage.h index d92a3ff8117..15741f250fd 100644 --- a/tools/mkimage.h +++ b/tools/mkimage.h @@ -37,7 +37,7 @@ static inline void *map_sysmem(ulong paddr, unsigned long len) return (void *)(uintptr_t)paddr; }
-static inline ulong map_to_sysmem(void *ptr) +static inline ulong map_to_sysmem(const void *ptr) { return (ulong)(uintptr_t)ptr; }

Enable this command for x86 boards as it is quite useful for seeing where memory is.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/Kconfig | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/arch/Kconfig b/arch/Kconfig index 6258788f53f..2fb247d04b3 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -310,6 +310,8 @@ config X86 imply SYSINFO if GENERATE_SMBIOS_TABLE imply SYSINFO_SMBIOS if GENERATE_SMBIOS_TABLE imply TIMESTAMP + imply CMD_MEMINFO + imply CMD_MEMINFO_MAP
# Thing to enable for when SPL/TPL are enabled: SPL imply SPL_DM

Nits: %s/Emable/Enable/
On 01.01.25 23:08, Simon Glass wrote:
Enable this command for x86 boards as it is quite useful for seeing where memory is.
Signed-off-by: Simon Glass sjg@chromium.org
Enabling the option by default for the sandbox in cmd/Kconfig and for x86 in arch/Kconfig is confusing. Please, use the same approach for all concerned architectures.
Why do we need symbol CMD_MEMINFO_MAP? The meminfo command is worthless without it. Both the greeting header and bdinfo already show the memory size. Can we remove that over-engineering?
Sending standalone patches separately from a bulky patch series would avoid hesitation to review and merge (see Tom's mail).
Best regards
Heinrich
arch/Kconfig | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/arch/Kconfig b/arch/Kconfig index 6258788f53f..2fb247d04b3 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -310,6 +310,8 @@ config X86 imply SYSINFO if GENERATE_SMBIOS_TABLE imply SYSINFO_SMBIOS if GENERATE_SMBIOS_TABLE imply TIMESTAMP
imply CMD_MEMINFO
imply CMD_MEMINFO_MAP
# Thing to enable for when SPL/TPL are enabled: SPL imply SPL_DM

Hi Heinrich,
On Sat, 4 Jan 2025 at 03:51, Heinrich Schuchardt xypron.glpk@gmx.de wrote:
Nits: %s/Emable/Enable/
On 01.01.25 23:08, Simon Glass wrote:
Enable this command for x86 boards as it is quite useful for seeing where memory is.
Signed-off-by: Simon Glass sjg@chromium.org
Enabling the option by default for the sandbox in cmd/Kconfig and for x86 in arch/Kconfig is confusing. Please, use the same approach for all concerned architectures.
OK.
Why do we need symbol CMD_MEMINFO_MAP? The meminfo command is worthless without it. Both the greeting header and bdinfo already show the memory size. Can we remove that over-engineering?
I have no objection to that, but please check with Tom and Ilias[1] [2]
Sending standalone patches separately from a bulky patch series would avoid hesitation to review and merge (see Tom's mail).
Well, thank you for reviewing. I'm going to figure out some tooling to help, when I get a chance. Then I hope to be able to keep track of lots of independent patches. Tom has suggested that I just send less, as well. Another solution might be for me to adopt several aliases so I am three different people?
Regards, Simon
[1] https://patchwork.ozlabs.org/project/uboot/patch/20241011214032.760072-7-sjg... [2] https://patchwork.ozlabs.org/project/uboot/patch/20241009015020.25817-7-sjg@...

Add a line to the 'bdinfo' command which shows the current value of the TSC.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/x86/lib/bdinfo.c | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/arch/x86/lib/bdinfo.c b/arch/x86/lib/bdinfo.c index bd2cf0b9fcb..4b016d4a0fc 100644 --- a/arch/x86/lib/bdinfo.c +++ b/arch/x86/lib/bdinfo.c @@ -33,6 +33,8 @@ void arch_print_bdinfo(void) bdinfo_print_num_l(" high start", gd->arch.table_start_high); bdinfo_print_num_l(" high end", gd->arch.table_end_high);
+ bdinfo_print_num_ll("tsc", rdtsc()); + if (IS_ENABLED(CONFIG_EFI_STUB)) efi_show_bdinfo(); }

At some point it would be nice to have the ofnode API automatically expand the tree as required, to accommodate new nodes. For now, expand the default size so that UPL can be supported.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/core/ofnode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/core/ofnode.c b/drivers/core/ofnode.c index 950895e72a9..ec03f6f550d 100644 --- a/drivers/core/ofnode.c +++ b/drivers/core/ofnode.c @@ -118,7 +118,7 @@ int oftree_new(oftree *treep) return log_msg_ret("liv", ret); tree = oftree_from_np(root); } else { - const int size = 1024; + const int size = 4096; void *fdt;
ret = check_tree_count();

Update ofnode_add_subnode() and ofnode_add_prop() to return a suitable error when space is exhausted in the FDT. This makes it easier to see what is going wrong.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/core/ofnode.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-)
diff --git a/drivers/core/ofnode.c b/drivers/core/ofnode.c index ec03f6f550d..5b8be218d3b 100644 --- a/drivers/core/ofnode.c +++ b/drivers/core/ofnode.c @@ -1607,9 +1607,10 @@ ofnode ofnode_by_prop_value(ofnode from, const char *propname, int ofnode_write_prop(ofnode node, const char *propname, const void *value, int len, bool copy) { + int ret; + if (of_live_active()) { void *newval; - int ret;
if (copy) { newval = malloc(len); @@ -1623,8 +1624,12 @@ int ofnode_write_prop(ofnode node, const char *propname, const void *value, free(newval); return ret; } else { - return fdt_setprop(ofnode_to_fdt(node), ofnode_to_offset(node), - propname, value, len); + ret = fdt_setprop(ofnode_to_fdt(node), ofnode_to_offset(node), + propname, value, len); + if (ret) + return ret == -FDT_ERR_NOSPACE ? -ENOSPC : -EINVAL; + + return 0; } }
@@ -1897,7 +1902,7 @@ int ofnode_add_subnode(ofnode node, const char *name, ofnode *subnodep) ret = -EEXIST; } if (offset < 0) - return -EINVAL; + return offset == -FDT_ERR_NOSPACE ? -ENOSPC : -EINVAL; subnode = noffset_to_ofnode(node, offset); }

This function allocates memory for the node name, so mention this in the function comment.
Signed-off-by: Simon Glass sjg@chromium.org ---
include/dm/ofnode.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/include/dm/ofnode.h b/include/dm/ofnode.h index 0787758926f..024ae4cd289 100644 --- a/include/dm/ofnode.h +++ b/include/dm/ofnode.h @@ -1702,7 +1702,7 @@ static inline int ofnode_read_bootscript_flash(u64 *bootscr_flash_offset, * of_add_subnode() - add a new subnode to a node * * @parent: parent node to add to - * @name: name of subnode + * @name: name of subnode (allocated by this function) * @nodep: returns pointer to new subnode (valid if the function returns 0 * or -EEXIST) * Returns 0 if OK, -EEXIST if already exists, -ENOMEM if out of memory, other

This function can only be used with FITs that use embedded data. Rename it so this is clear.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/arm/cpu/armv8/sec_firmware.c | 4 ++-- arch/arm/mach-k3/r5/sysfw-loader.c | 2 +- arch/x86/lib/bootm.c | 6 +++--- boot/image-fit.c | 10 +++++----- common/spl/spl_fit.c | 2 +- common/splash_source.c | 4 +++- common/update.c | 2 +- include/image.h | 4 ++-- tools/image-host.c | 4 ++-- 9 files changed, 20 insertions(+), 18 deletions(-)
diff --git a/arch/arm/cpu/armv8/sec_firmware.c b/arch/arm/cpu/armv8/sec_firmware.c index 44372cbe4a1..b7c73f288bd 100644 --- a/arch/arm/cpu/armv8/sec_firmware.c +++ b/arch/arm/cpu/armv8/sec_firmware.c @@ -128,8 +128,8 @@ static int sec_firmware_check_copy_loadable(const void *sec_firmware_img, return -EINVAL; }
- if (fit_image_get_data(sec_firmware_img, ld_node_off, - &data, &size)) { + if (fit_image_get_emb_data(sec_firmware_img, ld_node_off, + &data, &size)) { printf("SEC Loadable: Can't get subimage data/size"); return -ENOENT; } diff --git a/arch/arm/mach-k3/r5/sysfw-loader.c b/arch/arm/mach-k3/r5/sysfw-loader.c index 188731e673d..c323d2f78f8 100644 --- a/arch/arm/mach-k3/r5/sysfw-loader.c +++ b/arch/arm/mach-k3/r5/sysfw-loader.c @@ -115,7 +115,7 @@ static int fit_get_data_by_name(const void *fit, int images, const char *name, if (node_offset < 0) return -ENOENT;
- return fit_image_get_data(fit, node_offset, addr, size); + return fit_image_get_emb_data(fit, node_offset, addr, size); }
static void k3_start_system_controller(int rproc_id, bool rproc_loaded, diff --git a/arch/x86/lib/bootm.c b/arch/x86/lib/bootm.c index 5fb46112ccb..3305560aa06 100644 --- a/arch/x86/lib/bootm.c +++ b/arch/x86/lib/bootm.c @@ -106,9 +106,9 @@ static int boot_prep_linux(struct bootm_headers *images) is_zimage = 1; #if defined(CONFIG_FIT) } else if (images->fit_uname_os && is_zimage) { - ret = fit_image_get_data(images->fit_hdr_os, - images->fit_noffset_os, - (const void **)&data, &len); + ret = fit_image_get_emb_data(images->fit_hdr_os, + images->fit_noffset_os, + (const void **)&data, &len); if (ret) { puts("Can't get image data/size!\n"); goto error; diff --git a/boot/image-fit.c b/boot/image-fit.c index 7d56f0b5e6e..4b116ba5891 100644 --- a/boot/image-fit.c +++ b/boot/image-fit.c @@ -902,13 +902,13 @@ int fit_image_get_entry(const void *fit, int noffset, ulong *entry) }
/** - * fit_image_get_data - get data property and its size for a given component image node + * fit_image_get_emb_data - get data property and its size for a given component image node * @fit: pointer to the FIT format image header * @noffset: component image node offset * @data: double pointer to void, will hold data property's data address * @size: pointer to size_t, will hold data property's data size * - * fit_image_get_data() finds data property in a given component image node. + * fit_image_get_emb_data() finds data property in a given component image node. * If the property is found its data start address and size are returned to * the caller. * @@ -916,8 +916,8 @@ int fit_image_get_entry(const void *fit, int noffset, ulong *entry) * 0, on success * -1, on failure */ -int fit_image_get_data(const void *fit, int noffset, - const void **data, size_t *size) +int fit_image_get_emb_data(const void *fit, int noffset, const void **data, + size_t *size) { int len;
@@ -1074,7 +1074,7 @@ int fit_image_get_data_and_size(const void *fit, int noffset, *size = len; } } else { - ret = fit_image_get_data(fit, noffset, data, size); + ret = fit_image_get_emb_data(fit, noffset, data, size); }
return ret; diff --git a/common/spl/spl_fit.c b/common/spl/spl_fit.c index 3160f573bfb..097c731d9a3 100644 --- a/common/spl/spl_fit.c +++ b/common/spl/spl_fit.c @@ -282,7 +282,7 @@ static int load_simple_fit(struct spl_load_info *info, ulong fit_offset, src = src_ptr + overhead; } else { /* Embedded data */ - if (fit_image_get_data(fit, node, &data, &length)) { + if (fit_image_get_emb_data(fit, node, &data, &length)) { puts("Cannot get image data/size\n"); return -ENOENT; } diff --git a/common/splash_source.c b/common/splash_source.c index f43e7cc1be7..5ac32a2f995 100644 --- a/common/splash_source.c +++ b/common/splash_source.c @@ -396,7 +396,9 @@ static int splash_load_fit(struct splash_location *location, u32 bmp_load_addr)
/* Extract the splash data from FIT */ /* 1. Test if splash is in FIT internal data. */ - if (!fit_image_get_data(fit_header, node_offset, &internal_splash_data, &internal_splash_size)) + if (!fit_image_get_emb_data(fit_header, node_offset, + &internal_splash_data, + &internal_splash_size)) memmove((void *)(uintptr_t)bmp_load_addr, internal_splash_data, internal_splash_size); /* 2. Test if splash is in FIT external data with fixed position. */ else if (!fit_image_get_data_position(fit_header, node_offset, &external_splash_addr)) diff --git a/common/update.c b/common/update.c index 6801b49479d..d149ca18e78 100644 --- a/common/update.c +++ b/common/update.c @@ -200,7 +200,7 @@ static int update_fit_getparams(const void *fit, int noffset, ulong *addr, { const void *data;
- if (fit_image_get_data(fit, noffset, &data, (size_t *)size)) + if (fit_image_get_emb_data(fit, noffset, &data, (size_t *)size)) return 1;
if (fit_image_get_load(fit, noffset, (ulong *)fladdr)) diff --git a/include/image.h b/include/image.h index de44dc09d07..e5241648b5e 100644 --- a/include/image.h +++ b/include/image.h @@ -1196,8 +1196,8 @@ int fit_image_get_type(const void *fit, int noffset, uint8_t *type); int fit_image_get_comp(const void *fit, int noffset, uint8_t *comp); int fit_image_get_load(const void *fit, int noffset, ulong *load); int fit_image_get_entry(const void *fit, int noffset, ulong *entry); -int fit_image_get_data(const void *fit, int noffset, - const void **data, size_t *size); +int fit_image_get_emb_data(const void *fit, int noffset, const void **data, + size_t *size); int fit_image_get_data_offset(const void *fit, int noffset, int *data_offset); int fit_image_get_data_position(const void *fit, int noffset, int *data_position); diff --git a/tools/image-host.c b/tools/image-host.c index 5e01b853c50..007a94f72d5 100644 --- a/tools/image-host.c +++ b/tools/image-host.c @@ -574,7 +574,7 @@ int fit_image_cipher_data(const char *keydir, void *keydest, }
/* Get image data and data length */ - if (fit_image_get_data(fit, image_noffset, &data, &size)) { + if (fit_image_get_emb_data(fit, image_noffset, &data, &size)) { fprintf(stderr, "Can't get image data/size\n"); return -1; } @@ -654,7 +654,7 @@ int fit_image_add_verification_data(const char *keydir, const char *keyfile, int noffset;
/* Get image data and data length */ - if (fit_image_get_data(fit, image_noffset, &data, &size)) { + if (fit_image_get_emb_data(fit, image_noffset, &data, &size)) { fprintf(stderr, "Can't get image data/size\n"); return -1; }

On 01.01.25 23:08, Simon Glass wrote:
This function can only be used with FITs that use embedded data. Rename it so this is clear.
Signed-off-by: Simon Glass sjg@chromium.org
Acked-by: Heinrich Schuchardt xypron.glpk@gmx.de
arch/arm/cpu/armv8/sec_firmware.c | 4 ++-- arch/arm/mach-k3/r5/sysfw-loader.c | 2 +- arch/x86/lib/bootm.c | 6 +++--- boot/image-fit.c | 10 +++++----- common/spl/spl_fit.c | 2 +- common/splash_source.c | 4 +++- common/update.c | 2 +- include/image.h | 4 ++-- tools/image-host.c | 4 ++-- 9 files changed, 20 insertions(+), 18 deletions(-)
diff --git a/arch/arm/cpu/armv8/sec_firmware.c b/arch/arm/cpu/armv8/sec_firmware.c index 44372cbe4a1..b7c73f288bd 100644 --- a/arch/arm/cpu/armv8/sec_firmware.c +++ b/arch/arm/cpu/armv8/sec_firmware.c @@ -128,8 +128,8 @@ static int sec_firmware_check_copy_loadable(const void *sec_firmware_img, return -EINVAL; }
if (fit_image_get_data(sec_firmware_img, ld_node_off,
&data, &size)) {
if (fit_image_get_emb_data(sec_firmware_img, ld_node_off,
}&data, &size)) { printf("SEC Loadable: Can't get subimage data/size"); return -ENOENT;
diff --git a/arch/arm/mach-k3/r5/sysfw-loader.c b/arch/arm/mach-k3/r5/sysfw-loader.c index 188731e673d..c323d2f78f8 100644 --- a/arch/arm/mach-k3/r5/sysfw-loader.c +++ b/arch/arm/mach-k3/r5/sysfw-loader.c @@ -115,7 +115,7 @@ static int fit_get_data_by_name(const void *fit, int images, const char *name, if (node_offset < 0) return -ENOENT;
- return fit_image_get_data(fit, node_offset, addr, size);
return fit_image_get_emb_data(fit, node_offset, addr, size); }
static void k3_start_system_controller(int rproc_id, bool rproc_loaded,
diff --git a/arch/x86/lib/bootm.c b/arch/x86/lib/bootm.c index 5fb46112ccb..3305560aa06 100644 --- a/arch/x86/lib/bootm.c +++ b/arch/x86/lib/bootm.c @@ -106,9 +106,9 @@ static int boot_prep_linux(struct bootm_headers *images) is_zimage = 1; #if defined(CONFIG_FIT) } else if (images->fit_uname_os && is_zimage) {
ret = fit_image_get_data(images->fit_hdr_os,
images->fit_noffset_os,
(const void **)&data, &len);
ret = fit_image_get_emb_data(images->fit_hdr_os,
images->fit_noffset_os,
if (ret) { puts("Can't get image data/size!\n"); goto error;(const void **)&data, &len);
diff --git a/boot/image-fit.c b/boot/image-fit.c index 7d56f0b5e6e..4b116ba5891 100644 --- a/boot/image-fit.c +++ b/boot/image-fit.c @@ -902,13 +902,13 @@ int fit_image_get_entry(const void *fit, int noffset, ulong *entry) }
/**
- fit_image_get_data - get data property and its size for a given component image node
- fit_image_get_emb_data - get data property and its size for a given component image node
- @fit: pointer to the FIT format image header
- @noffset: component image node offset
- @data: double pointer to void, will hold data property's data address
- @size: pointer to size_t, will hold data property's data size
- fit_image_get_data() finds data property in a given component image node.
- fit_image_get_emb_data() finds data property in a given component image node.
- If the property is found its data start address and size are returned to
- the caller.
@@ -916,8 +916,8 @@ int fit_image_get_entry(const void *fit, int noffset, ulong *entry)
0, on success
-1, on failure
*/ -int fit_image_get_data(const void *fit, int noffset,
const void **data, size_t *size)
+int fit_image_get_emb_data(const void *fit, int noffset, const void **data,
{ int len;size_t *size)
@@ -1074,7 +1074,7 @@ int fit_image_get_data_and_size(const void *fit, int noffset, *size = len; } } else {
ret = fit_image_get_data(fit, noffset, data, size);
ret = fit_image_get_emb_data(fit, noffset, data, size);
}
return ret;
diff --git a/common/spl/spl_fit.c b/common/spl/spl_fit.c index 3160f573bfb..097c731d9a3 100644 --- a/common/spl/spl_fit.c +++ b/common/spl/spl_fit.c @@ -282,7 +282,7 @@ static int load_simple_fit(struct spl_load_info *info, ulong fit_offset, src = src_ptr + overhead; } else { /* Embedded data */
if (fit_image_get_data(fit, node, &data, &length)) {
}if (fit_image_get_emb_data(fit, node, &data, &length)) { puts("Cannot get image data/size\n"); return -ENOENT;
diff --git a/common/splash_source.c b/common/splash_source.c index f43e7cc1be7..5ac32a2f995 100644 --- a/common/splash_source.c +++ b/common/splash_source.c @@ -396,7 +396,9 @@ static int splash_load_fit(struct splash_location *location, u32 bmp_load_addr)
/* Extract the splash data from FIT */ /* 1. Test if splash is in FIT internal data. */
- if (!fit_image_get_data(fit_header, node_offset, &internal_splash_data, &internal_splash_size))
- if (!fit_image_get_emb_data(fit_header, node_offset,
&internal_splash_data,
memmove((void *)(uintptr_t)bmp_load_addr, internal_splash_data, internal_splash_size); /* 2. Test if splash is in FIT external data with fixed position. */ else if (!fit_image_get_data_position(fit_header, node_offset, &external_splash_addr))&internal_splash_size))
diff --git a/common/update.c b/common/update.c index 6801b49479d..d149ca18e78 100644 --- a/common/update.c +++ b/common/update.c @@ -200,7 +200,7 @@ static int update_fit_getparams(const void *fit, int noffset, ulong *addr, { const void *data;
- if (fit_image_get_data(fit, noffset, &data, (size_t *)size))
if (fit_image_get_emb_data(fit, noffset, &data, (size_t *)size)) return 1;
if (fit_image_get_load(fit, noffset, (ulong *)fladdr))
diff --git a/include/image.h b/include/image.h index de44dc09d07..e5241648b5e 100644 --- a/include/image.h +++ b/include/image.h @@ -1196,8 +1196,8 @@ int fit_image_get_type(const void *fit, int noffset, uint8_t *type); int fit_image_get_comp(const void *fit, int noffset, uint8_t *comp); int fit_image_get_load(const void *fit, int noffset, ulong *load); int fit_image_get_entry(const void *fit, int noffset, ulong *entry); -int fit_image_get_data(const void *fit, int noffset,
const void **data, size_t *size);
+int fit_image_get_emb_data(const void *fit, int noffset, const void **data,
int fit_image_get_data_offset(const void *fit, int noffset, int *data_offset); int fit_image_get_data_position(const void *fit, int noffset, int *data_position);size_t *size);
diff --git a/tools/image-host.c b/tools/image-host.c index 5e01b853c50..007a94f72d5 100644 --- a/tools/image-host.c +++ b/tools/image-host.c @@ -574,7 +574,7 @@ int fit_image_cipher_data(const char *keydir, void *keydest, }
/* Get image data and data length */
- if (fit_image_get_data(fit, image_noffset, &data, &size)) {
- if (fit_image_get_emb_data(fit, image_noffset, &data, &size)) { fprintf(stderr, "Can't get image data/size\n"); return -1; }
@@ -654,7 +654,7 @@ int fit_image_add_verification_data(const char *keydir, const char *keyfile, int noffset;
/* Get image data and data length */
- if (fit_image_get_data(fit, image_noffset, &data, &size)) {
- if (fit_image_get_emb_data(fit, image_noffset, &data, &size)) { fprintf(stderr, "Can't get image data/size\n"); return -1; }

This function is really just getting the data. The size comes along for the ride. In fact this function is only reliable way to obtain the data for an image in a FIT, since the FIT may use external data.
Rename it to fit_image_get_data()
Signed-off-by: Simon Glass sjg@chromium.org ---
boot/image-board.c | 4 ++-- boot/image-fit.c | 20 +++++++++----------- cmd/ximg.c | 3 +-- include/image.h | 4 ++-- tools/fit_image.c | 2 +- 5 files changed, 15 insertions(+), 18 deletions(-)
diff --git a/boot/image-board.c b/boot/image-board.c index d018d790a49..8e6b2974dcf 100644 --- a/boot/image-board.c +++ b/boot/image-board.c @@ -1087,8 +1087,8 @@ fallback: }
/* get script subimage data address and length */ - if (fit_image_get_data_and_size(fit_hdr, noffset, - &fit_data, &fit_len)) { + if (fit_image_get_data(fit_hdr, noffset, &fit_data, + &fit_len)) { puts("Could not find script subimage data\n"); return 1; } diff --git a/boot/image-fit.c b/boot/image-fit.c index 4b116ba5891..e9653452eae 100644 --- a/boot/image-fit.c +++ b/boot/image-fit.c @@ -509,7 +509,7 @@ void fit_image_print(const void *fit, int image_noffset, const char *p) fit_image_get_comp(fit, image_noffset, &comp); printf("%s Compression: %s\n", p, genimg_get_comp_name(comp));
- ret = fit_image_get_data_and_size(fit, image_noffset, &data, &size); + ret = fit_image_get_data(fit, image_noffset, &data, &size);
if (!tools_build()) { printf("%s Data Start: ", p); @@ -1031,14 +1031,14 @@ int fit_image_get_data_size_unciphered(const void *fit, int noffset, }
/** - * fit_image_get_data_and_size - get data and its size including + * fit_image_get_data - get data and its size including * both embedded and external data * @fit: pointer to the FIT format image header * @noffset: component image node offset * @data: double pointer to void, will hold data property's data address * @size: pointer to size_t, will hold data property's data size * - * fit_image_get_data_and_size() finds data and its size including + * fit_image_get_data() finds data and its size including * both embedded and external data. If the property is found * its data start address and size are returned to the caller. * @@ -1046,8 +1046,8 @@ int fit_image_get_data_size_unciphered(const void *fit, int noffset, * 0, on success * otherwise, on failure */ -int fit_image_get_data_and_size(const void *fit, int noffset, - const void **data, size_t *size) +int fit_image_get_data(const void *fit, int noffset, const void **data, + size_t *size) { bool external_data = false; int offset; @@ -1432,7 +1432,7 @@ int fit_image_verify(const void *fit, int image_noffset) goto err; } /* Get image data and data length */ - if (fit_image_get_data_and_size(fit, image_noffset, &data, &size)) { + if (fit_image_get_data(fit, image_noffset, &data, &size)) { err_msg = "Can't get image data/size"; goto err; } @@ -1781,8 +1781,7 @@ int fit_conf_find_compat(const void *fit, const void *fdt) }
/* search in this config's kernel FDT */ - if (fit_image_get_data_and_size(fit, kfdt_noffset, - &fdt, &sz)) { + if (fit_image_get_data(fit, kfdt_noffset, &fdt, &sz)) { debug("Failed to get fdt "%s".\n", kfdt_name); continue; } @@ -1941,7 +1940,7 @@ static int fit_get_data_tail(const void *fit, int noffset, if (!fit_image_verify(fit, noffset)) return -EINVAL;
- if (fit_image_get_data_and_size(fit, noffset, data, size)) + if (fit_image_get_data(fit, noffset, data, size)) return -ENOENT;
if (!fit_get_desc(fit, noffset, &desc)) @@ -2197,8 +2196,7 @@ int fit_image_load(struct bootm_headers *images, ulong addr, bootstage_mark(bootstage_id + BOOTSTAGE_SUB_CHECK_ALL_OK);
/* get image data address and length */ - if (fit_image_get_data_and_size(fit, noffset, - (const void **)&buf, &size)) { + if (fit_image_get_data(fit, noffset, (const void **)&buf, &size)) { printf("Could not find %s subimage data!\n", prop_name); bootstage_error(bootstage_id + BOOTSTAGE_SUB_GET_DATA); return -ENOENT; diff --git a/cmd/ximg.c b/cmd/ximg.c index 1c96f5a0a1f..29d7c3279b3 100644 --- a/cmd/ximg.c +++ b/cmd/ximg.c @@ -161,8 +161,7 @@ do_imgextract(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) }
/* get subimage/external data address and length */ - if (fit_image_get_data_and_size(fit_hdr, noffset, - &fit_data, &fit_len)) { + if (fit_image_get_data(fit_hdr, noffset, &fit_data, &fit_len)) { puts("Could not find script subimage data\n"); return 1; } diff --git a/include/image.h b/include/image.h index e5241648b5e..12f52919812 100644 --- a/include/image.h +++ b/include/image.h @@ -1204,8 +1204,8 @@ int fit_image_get_data_position(const void *fit, int noffset, int fit_image_get_data_size(const void *fit, int noffset, int *data_size); int fit_image_get_data_size_unciphered(const void *fit, int noffset, size_t *data_size); -int fit_image_get_data_and_size(const void *fit, int noffset, - const void **data, size_t *size); +int fit_image_get_data(const void *fit, int noffset, const void **data, + size_t *size);
/** * fit_get_data_node() - Get verified image data for an image diff --git a/tools/fit_image.c b/tools/fit_image.c index 0fccfbb4ebd..caed8d5f901 100644 --- a/tools/fit_image.c +++ b/tools/fit_image.c @@ -876,7 +876,7 @@ static int fit_image_extract( int ret;
/* get the data address and size of component at offset "image_noffset" */ - ret = fit_image_get_data_and_size(fit, image_noffset, &file_data, &file_size); + ret = fit_image_get_data(fit, image_noffset, &file_data, &file_size); if (ret) { fprintf(stderr, "Could not get component information\n"); return ret;

This function uses separate arguments for data and size. Use the new abuf instead, so that they are paired and in one place. In some cases it also saves an argument, thus potentially reducing code size.
Move the prototype to the header file while here.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/arm/cpu/armv8/sec_firmware.c | 12 +++++----- arch/arm/mach-k3/r5/sysfw-loader.c | 11 +++++++++- arch/x86/lib/bootm.c | 7 ++++-- boot/image-fit.c | 35 +++++++++++------------------- common/spl/spl_fit.c | 8 ++++--- common/splash_source.c | 11 ++++------ include/image.h | 20 +++++++++++++++-- tools/Makefile | 3 ++- tools/image-host.c | 23 ++++++++++---------- 9 files changed, 74 insertions(+), 56 deletions(-)
diff --git a/arch/arm/cpu/armv8/sec_firmware.c b/arch/arm/cpu/armv8/sec_firmware.c index b7c73f288bd..e768859acfb 100644 --- a/arch/arm/cpu/armv8/sec_firmware.c +++ b/arch/arm/cpu/armv8/sec_firmware.c @@ -83,10 +83,8 @@ static int sec_firmware_check_copy_loadable(const void *sec_firmware_img, { phys_addr_t sec_firmware_loadable_addr = 0; int conf_node_off, ld_node_off, images; - const void *data; - size_t size; - ulong load; const char *name, *str, *type; + ulong load; int len;
conf_node_off = fit_conf_get_node(sec_firmware_img, NULL); @@ -114,6 +112,8 @@ static int sec_firmware_check_copy_loadable(const void *sec_firmware_img,
for (str = name; str && ((str - name) < len); str = strchr(str, '\0') + 1) { + struct abuf buf; + printf("%s: '%s'\n", type, str); ld_node_off = fdt_subnode_offset(sec_firmware_img, images, str); if (ld_node_off < 0) { @@ -129,7 +129,7 @@ static int sec_firmware_check_copy_loadable(const void *sec_firmware_img, }
if (fit_image_get_emb_data(sec_firmware_img, ld_node_off, - &data, &size)) { + &buf)) { printf("SEC Loadable: Can't get subimage data/size"); return -ENOENT; } @@ -147,9 +147,9 @@ static int sec_firmware_check_copy_loadable(const void *sec_firmware_img, /* Copy loadable to secure memory and flush dcache */ debug("%s copied to address 0x%p\n", FIT_LOADABLE_PROP, (void *)sec_firmware_loadable_addr); - memcpy((void *)sec_firmware_loadable_addr, data, size); + memcpy((void *)sec_firmware_loadable_addr, buf.data, buf.size); flush_dcache_range(sec_firmware_loadable_addr, - sec_firmware_loadable_addr + size); + sec_firmware_loadable_addr + buf.size);
/* Populate loadable address only for Trusted OS */ if (!strcmp(str, "trustedOS@1")) { diff --git a/arch/arm/mach-k3/r5/sysfw-loader.c b/arch/arm/mach-k3/r5/sysfw-loader.c index c323d2f78f8..1895fb385a5 100644 --- a/arch/arm/mach-k3/r5/sysfw-loader.c +++ b/arch/arm/mach-k3/r5/sysfw-loader.c @@ -110,12 +110,21 @@ static int fit_get_data_by_name(const void *fit, int images, const char *name, const void **addr, size_t *size) { int node_offset; + struct abuf buf; + int ret;
node_offset = fdt_subnode_offset(fit, images, name); if (node_offset < 0) return -ENOENT;
- return fit_image_get_emb_data(fit, node_offset, addr, size); + ret = fit_image_get_emb_data(fit, node_offset, &buf); + if (ret) + return ret; + + *addr = buf.data; + *size = buf.size; + + return 0; }
static void k3_start_system_controller(int rproc_id, bool rproc_loaded, diff --git a/arch/x86/lib/bootm.c b/arch/x86/lib/bootm.c index 3305560aa06..16980c15081 100644 --- a/arch/x86/lib/bootm.c +++ b/arch/x86/lib/bootm.c @@ -106,13 +106,16 @@ static int boot_prep_linux(struct bootm_headers *images) is_zimage = 1; #if defined(CONFIG_FIT) } else if (images->fit_uname_os && is_zimage) { + struct abuf buf; + ret = fit_image_get_emb_data(images->fit_hdr_os, - images->fit_noffset_os, - (const void **)&data, &len); + images->fit_noffset_os, &buf); if (ret) { puts("Can't get image data/size!\n"); goto error; } + data = buf.data; + len = buf.size; is_zimage = 1; #endif } diff --git a/boot/image-fit.c b/boot/image-fit.c index e9653452eae..e9b4152eb84 100644 --- a/boot/image-fit.c +++ b/boot/image-fit.c @@ -33,6 +33,7 @@ DECLARE_GLOBAL_DATA_PTR; #endif /* !USE_HOSTCC*/
+#include <abuf.h> #include <bootm.h> #include <image.h> #include <bootstage.h> @@ -901,34 +902,20 @@ int fit_image_get_entry(const void *fit, int noffset, ulong *entry) return fit_image_get_address(fit, noffset, FIT_ENTRY_PROP, entry); }
-/** - * fit_image_get_emb_data - get data property and its size for a given component image node - * @fit: pointer to the FIT format image header - * @noffset: component image node offset - * @data: double pointer to void, will hold data property's data address - * @size: pointer to size_t, will hold data property's data size - * - * fit_image_get_emb_data() finds data property in a given component image node. - * If the property is found its data start address and size are returned to - * the caller. - * - * returns: - * 0, on success - * -1, on failure - */ -int fit_image_get_emb_data(const void *fit, int noffset, const void **data, - size_t *size) +int fit_image_get_emb_data(const void *fit, int noffset, struct abuf *buf) { + const void *data; int len;
- *data = fdt_getprop(fit, noffset, FIT_DATA_PROP, &len); - if (*data == NULL) { + data = fdt_getprop(fit, noffset, FIT_DATA_PROP, &len); + if (!data) { fit_get_debug(fit, noffset, FIT_DATA_PROP, len); - *size = 0; + abuf_init(buf); return -1; }
- *size = len; + abuf_init_const(buf, data, len); + return 0; }
@@ -1074,7 +1061,11 @@ int fit_image_get_data(const void *fit, int noffset, const void **data, *size = len; } } else { - ret = fit_image_get_emb_data(fit, noffset, data, size); + struct abuf buf; + + ret = fit_image_get_emb_data(fit, noffset, &buf); + *data = buf.data; + *size = buf.size; }
return ret; diff --git a/common/spl/spl_fit.c b/common/spl/spl_fit.c index 097c731d9a3..172153b75c2 100644 --- a/common/spl/spl_fit.c +++ b/common/spl/spl_fit.c @@ -214,7 +214,6 @@ static int load_simple_fit(struct spl_load_info *info, ulong fit_offset, void *src; ulong overhead; uint8_t image_comp = -1, type = -1; - const void *data; const void *fit = ctx->fit; bool external_data = false;
@@ -281,14 +280,17 @@ static int load_simple_fit(struct spl_load_info *info, ulong fit_offset, src_ptr, offset, (unsigned long)length); src = src_ptr + overhead; } else { + struct abuf buf; + /* Embedded data */ - if (fit_image_get_emb_data(fit, node, &data, &length)) { + if (fit_image_get_emb_data(fit, node, &buf)) { puts("Cannot get image data/size\n"); return -ENOENT; } + src = buf.data; + length = buf.size; debug("Embedded data: dst=%lx, size=%lx\n", load_addr, (unsigned long)length); - src = (void *)data; /* cast away const */ }
if (CONFIG_IS_ENABLED(FIT_SIGNATURE)) { diff --git a/common/splash_source.c b/common/splash_source.c index 5ac32a2f995..37648b8b9f3 100644 --- a/common/splash_source.c +++ b/common/splash_source.c @@ -347,8 +347,6 @@ static int splash_load_fit(struct splash_location *location, u32 bmp_load_addr) int res; int node_offset; const char *splash_file; - const void *internal_splash_data; - size_t internal_splash_size; int external_splash_addr; int external_splash_size; bool is_splash_external = false; @@ -356,6 +354,7 @@ static int splash_load_fit(struct splash_location *location, u32 bmp_load_addr) const u32 *fit_header; u32 fit_size; const size_t header_size = sizeof(struct legacy_img_hdr); + struct abuf buf;
/* Read in image header */ res = splash_storage_read_raw(location, bmp_load_addr, header_size); @@ -396,12 +395,10 @@ static int splash_load_fit(struct splash_location *location, u32 bmp_load_addr)
/* Extract the splash data from FIT */ /* 1. Test if splash is in FIT internal data. */ - if (!fit_image_get_emb_data(fit_header, node_offset, - &internal_splash_data, - &internal_splash_size)) - memmove((void *)(uintptr_t)bmp_load_addr, internal_splash_data, internal_splash_size); + if (!fit_image_get_emb_data(fit_header, node_offset, &buf)) { + memmove((void *)(uintptr_t)bmp_load_addr, buf.data, buf.size); /* 2. Test if splash is in FIT external data with fixed position. */ - else if (!fit_image_get_data_position(fit_header, node_offset, &external_splash_addr)) + } else if (!fit_image_get_data_position(fit_header, node_offset, &external_splash_addr)) is_splash_external = true; /* 3. Test if splash is in FIT external data with offset. */ else if (!fit_image_get_data_offset(fit_header, node_offset, &external_splash_addr)) { diff --git a/include/image.h b/include/image.h index 12f52919812..29ac7a69ae9 100644 --- a/include/image.h +++ b/include/image.h @@ -20,6 +20,7 @@ #include <stdbool.h>
/* Define this to avoid #ifdefs later on */ +struct abuf; struct fdt_region;
#ifdef USE_HOSTCC @@ -1196,8 +1197,23 @@ int fit_image_get_type(const void *fit, int noffset, uint8_t *type); int fit_image_get_comp(const void *fit, int noffset, uint8_t *comp); int fit_image_get_load(const void *fit, int noffset, ulong *load); int fit_image_get_entry(const void *fit, int noffset, ulong *entry); -int fit_image_get_emb_data(const void *fit, int noffset, const void **data, - size_t *size); + +/** + * fit_image_get_emb_data() - get embedded data for a component-image node + * @fit: pointer to the FIT format image header + * @noffset: component image node offset + * @buf: returns data (inited by this function) + * + * fit_image_get_emb_data() finds data property in a given component image node. + * If the property is found its data start address and size are returned to + * the caller. + * + * returns: + * 0, on success + * -1, on failure + */ +int fit_image_get_emb_data(const void *fit, int noffset, struct abuf *buf); + int fit_image_get_data_offset(const void *fit, int noffset, int *data_offset); int fit_image_get_data_position(const void *fit, int noffset, int *data_position); diff --git a/tools/Makefile b/tools/Makefile index ee08a9675df..d0adfe1f58d 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -71,7 +71,8 @@ ifneq ($(CONFIG_CMD_BOOTEFI_SELFTEST)$(CONFIG_FWU_MDATA_GPT_BLK),) hostprogs-y += file2include endif
-FIT_OBJS-y := fit_common.o fit_image.o image-host.o generated/boot/image-fit.o +FIT_OBJS-y := fit_common.o fit_image.o image-host.o generated/boot/image-fit.o \ + generated/lib/abuf.o FIT_SIG_OBJS-$(CONFIG_TOOLS_LIBCRYPTO) := image-sig-host.o generated/boot/image-fit-sig.o FIT_CIPHER_OBJS-$(CONFIG_TOOLS_LIBCRYPTO) := generated/boot/image-cipher.o
diff --git a/tools/image-host.c b/tools/image-host.c index 007a94f72d5..d428f655591 100644 --- a/tools/image-host.c +++ b/tools/image-host.c @@ -9,6 +9,7 @@ */
#include "mkimage.h" +#include <abuf.h> #include <bootm.h> #include <fdt_region.h> #include <image.h> @@ -509,7 +510,7 @@ int fit_image_write_cipher(void *fit, int image_noffset, int noffset, static int fit_image_process_cipher(const char *keydir, void *keydest, void *fit, const char *image_name, int image_noffset, - int node_noffset, const void *data, size_t size, + int node_noffset, struct abuf *buf, const char *cmdname) { struct image_cipher_info info; @@ -524,7 +525,7 @@ fit_image_process_cipher(const char *keydir, void *keydest, void *fit, if (ret) goto out;
- ret = info.cipher->encrypt(&info, data, size, + ret = info.cipher->encrypt(&info, buf->data, buf->size, &data_ciphered, &data_ciphered_len); if (ret) goto out; @@ -546,7 +547,7 @@ fit_image_process_cipher(const char *keydir, void *keydest, void *fit, }
ret = fit_image_write_cipher(fit, image_noffset, node_noffset, - data, size, + buf->data, buf->size, data_ciphered, data_ciphered_len);
out: @@ -562,9 +563,8 @@ int fit_image_cipher_data(const char *keydir, void *keydest, const char *cmdname) { const char *image_name; - const void *data; - size_t size; int cipher_node_offset, len; + struct abuf buf;
/* Get image name */ image_name = fit_get_name(fit, image_noffset, NULL); @@ -574,7 +574,7 @@ int fit_image_cipher_data(const char *keydir, void *keydest, }
/* Get image data and data length */ - if (fit_image_get_emb_data(fit, image_noffset, &data, &size)) { + if (fit_image_get_emb_data(fit, image_noffset, &buf)) { fprintf(stderr, "Can't get image data/size\n"); return -1; } @@ -605,7 +605,7 @@ int fit_image_cipher_data(const char *keydir, void *keydest, if (!IMAGE_ENABLE_ENCRYPT || !keydir) return 0; return fit_image_process_cipher(keydir, keydest, fit, image_name, - image_noffset, cipher_node_offset, data, size, cmdname); + image_noffset, cipher_node_offset, &buf, cmdname); }
/** @@ -649,12 +649,11 @@ int fit_image_add_verification_data(const char *keydir, const char *keyfile, const char *cmdname, const char* algo_name) { const char *image_name; - const void *data; - size_t size; + struct abuf buf; int noffset;
/* Get image data and data length */ - if (fit_image_get_emb_data(fit, image_noffset, &data, &size)) { + if (fit_image_get_emb_data(fit, image_noffset, &buf)) { fprintf(stderr, "Can't get image data/size\n"); return -1; } @@ -677,12 +676,12 @@ int fit_image_add_verification_data(const char *keydir, const char *keyfile, if (!strncmp(node_name, FIT_HASH_NODENAME, strlen(FIT_HASH_NODENAME))) { ret = fit_image_process_hash(fit, image_name, noffset, - data, size); + buf.data, buf.size); } else if (IMAGE_ENABLE_SIGN && (keydir || keyfile) && !strncmp(node_name, FIT_SIG_NODENAME, strlen(FIT_SIG_NODENAME))) { ret = fit_image_process_sig(keydir, keyfile, keydest, - fit, image_name, noffset, data, size, + fit, image_name, noffset, buf.data, buf.size, comment, require_keys, engine_id, cmdname, algo_name); }

Use this function instead of fit_image_get_emb_data() data, since it works will FITs that use external data.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/arm/cpu/armv8/sec_firmware.c | 12 ++++++------ arch/arm/mach-k3/r5/sysfw-loader.c | 9 +-------- arch/x86/lib/bootm.c | 9 +++------ common/splash_source.c | 22 +++++++--------------- common/update.c | 2 +- 5 files changed, 18 insertions(+), 36 deletions(-)
diff --git a/arch/arm/cpu/armv8/sec_firmware.c b/arch/arm/cpu/armv8/sec_firmware.c index e768859acfb..e3f8a6dcd60 100644 --- a/arch/arm/cpu/armv8/sec_firmware.c +++ b/arch/arm/cpu/armv8/sec_firmware.c @@ -83,6 +83,8 @@ static int sec_firmware_check_copy_loadable(const void *sec_firmware_img, { phys_addr_t sec_firmware_loadable_addr = 0; int conf_node_off, ld_node_off, images; + const void *data; + size_t size; const char *name, *str, *type; ulong load; int len; @@ -112,8 +114,6 @@ static int sec_firmware_check_copy_loadable(const void *sec_firmware_img,
for (str = name; str && ((str - name) < len); str = strchr(str, '\0') + 1) { - struct abuf buf; - printf("%s: '%s'\n", type, str); ld_node_off = fdt_subnode_offset(sec_firmware_img, images, str); if (ld_node_off < 0) { @@ -128,8 +128,8 @@ static int sec_firmware_check_copy_loadable(const void *sec_firmware_img, return -EINVAL; }
- if (fit_image_get_emb_data(sec_firmware_img, ld_node_off, - &buf)) { + if (fit_image_get_data(sec_firmware_img, ld_node_off, + &data, &size)) { printf("SEC Loadable: Can't get subimage data/size"); return -ENOENT; } @@ -147,9 +147,9 @@ static int sec_firmware_check_copy_loadable(const void *sec_firmware_img, /* Copy loadable to secure memory and flush dcache */ debug("%s copied to address 0x%p\n", FIT_LOADABLE_PROP, (void *)sec_firmware_loadable_addr); - memcpy((void *)sec_firmware_loadable_addr, buf.data, buf.size); + memcpy((void *)sec_firmware_loadable_addr, data, size); flush_dcache_range(sec_firmware_loadable_addr, - sec_firmware_loadable_addr + buf.size); + sec_firmware_loadable_addr + size);
/* Populate loadable address only for Trusted OS */ if (!strcmp(str, "trustedOS@1")) { diff --git a/arch/arm/mach-k3/r5/sysfw-loader.c b/arch/arm/mach-k3/r5/sysfw-loader.c index 1895fb385a5..f0ad7559b97 100644 --- a/arch/arm/mach-k3/r5/sysfw-loader.c +++ b/arch/arm/mach-k3/r5/sysfw-loader.c @@ -117,14 +117,7 @@ static int fit_get_data_by_name(const void *fit, int images, const char *name, if (node_offset < 0) return -ENOENT;
- ret = fit_image_get_emb_data(fit, node_offset, &buf); - if (ret) - return ret; - - *addr = buf.data; - *size = buf.size; - - return 0; + return fit_image_get_data(fit, node_offset, addr, size); }
static void k3_start_system_controller(int rproc_id, bool rproc_loaded, diff --git a/arch/x86/lib/bootm.c b/arch/x86/lib/bootm.c index 16980c15081..2a7933cdaf8 100644 --- a/arch/x86/lib/bootm.c +++ b/arch/x86/lib/bootm.c @@ -106,16 +106,13 @@ static int boot_prep_linux(struct bootm_headers *images) is_zimage = 1; #if defined(CONFIG_FIT) } else if (images->fit_uname_os && is_zimage) { - struct abuf buf; - - ret = fit_image_get_emb_data(images->fit_hdr_os, - images->fit_noffset_os, &buf); + ret = fit_image_get_data(images->fit_hdr_os, + images->fit_noffset_os, + (const void **)&data, &len); if (ret) { puts("Can't get image data/size!\n"); goto error; } - data = buf.data; - len = buf.size; is_zimage = 1; #endif } diff --git a/common/splash_source.c b/common/splash_source.c index 37648b8b9f3..9972a1b2a08 100644 --- a/common/splash_source.c +++ b/common/splash_source.c @@ -347,6 +347,8 @@ static int splash_load_fit(struct splash_location *location, u32 bmp_load_addr) int res; int node_offset; const char *splash_file; + const void *internal_splash_data; + size_t internal_splash_size; int external_splash_addr; int external_splash_size; bool is_splash_external = false; @@ -354,7 +356,6 @@ static int splash_load_fit(struct splash_location *location, u32 bmp_load_addr) const u32 *fit_header; u32 fit_size; const size_t header_size = sizeof(struct legacy_img_hdr); - struct abuf buf;
/* Read in image header */ res = splash_storage_read_raw(location, bmp_load_addr, header_size); @@ -394,20 +395,11 @@ static int splash_load_fit(struct splash_location *location, u32 bmp_load_addr) }
/* Extract the splash data from FIT */ - /* 1. Test if splash is in FIT internal data. */ - if (!fit_image_get_emb_data(fit_header, node_offset, &buf)) { - memmove((void *)(uintptr_t)bmp_load_addr, buf.data, buf.size); - /* 2. Test if splash is in FIT external data with fixed position. */ - } else if (!fit_image_get_data_position(fit_header, node_offset, &external_splash_addr)) - is_splash_external = true; - /* 3. Test if splash is in FIT external data with offset. */ - else if (!fit_image_get_data_offset(fit_header, node_offset, &external_splash_addr)) { - /* Align data offset to 4-byte boundary */ - fit_size = ALIGN(fdt_totalsize(fit_header), 4); - /* External splash offset means the offset by end of FIT header */ - external_splash_addr += location->offset + fit_size; - is_splash_external = true; - } else { + if (!fit_image_get_data(fit_header, node_offset, &internal_splash_data, + &internal_splash_size)) + memmove((void *)(uintptr_t)bmp_load_addr, internal_splash_data, + internal_splash_size); + else { printf("Failed to get splash image from FIT\n"); return -ENODATA; } diff --git a/common/update.c b/common/update.c index d149ca18e78..6801b49479d 100644 --- a/common/update.c +++ b/common/update.c @@ -200,7 +200,7 @@ static int update_fit_getparams(const void *fit, int noffset, ulong *addr, { const void *data;
- if (fit_image_get_emb_data(fit, noffset, &data, (size_t *)size)) + if (fit_image_get_data(fit, noffset, &data, (size_t *)size)) return 1;
if (fit_image_get_load(fit, noffset, (ulong *)fladdr))

This function uses separate arguments for data and size. Use the new abuf instead, so that they are paired and in one place. In some cases it also saves an argument, thus potentially reducing code size.
Move the prototype to the header file while here.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/arm/cpu/armv8/sec_firmware.c | 11 +++-- arch/arm/mach-k3/r5/sysfw-loader.c | 9 +++- arch/x86/lib/bootm.c | 7 ++- boot/image-board.c | 11 +++-- boot/image-fit.c | 71 +++++++++++------------------- cmd/ximg.c | 13 +++--- common/splash_source.c | 11 ++--- common/update.c | 7 +-- include/image.h | 19 +++++++- lib/abuf.c | 11 ++++- tools/fit_image.c | 8 ++-- 11 files changed, 94 insertions(+), 84 deletions(-)
diff --git a/arch/arm/cpu/armv8/sec_firmware.c b/arch/arm/cpu/armv8/sec_firmware.c index e3f8a6dcd60..555ab50625a 100644 --- a/arch/arm/cpu/armv8/sec_firmware.c +++ b/arch/arm/cpu/armv8/sec_firmware.c @@ -83,8 +83,6 @@ static int sec_firmware_check_copy_loadable(const void *sec_firmware_img, { phys_addr_t sec_firmware_loadable_addr = 0; int conf_node_off, ld_node_off, images; - const void *data; - size_t size; const char *name, *str, *type; ulong load; int len; @@ -114,6 +112,8 @@ static int sec_firmware_check_copy_loadable(const void *sec_firmware_img,
for (str = name; str && ((str - name) < len); str = strchr(str, '\0') + 1) { + struct abuf buf; + printf("%s: '%s'\n", type, str); ld_node_off = fdt_subnode_offset(sec_firmware_img, images, str); if (ld_node_off < 0) { @@ -128,8 +128,7 @@ static int sec_firmware_check_copy_loadable(const void *sec_firmware_img, return -EINVAL; }
- if (fit_image_get_data(sec_firmware_img, ld_node_off, - &data, &size)) { + if (fit_image_get_data(sec_firmware_img, ld_node_off, &buf)) { printf("SEC Loadable: Can't get subimage data/size"); return -ENOENT; } @@ -147,9 +146,9 @@ static int sec_firmware_check_copy_loadable(const void *sec_firmware_img, /* Copy loadable to secure memory and flush dcache */ debug("%s copied to address 0x%p\n", FIT_LOADABLE_PROP, (void *)sec_firmware_loadable_addr); - memcpy((void *)sec_firmware_loadable_addr, data, size); + memcpy((void *)sec_firmware_loadable_addr, buf.data, buf.size); flush_dcache_range(sec_firmware_loadable_addr, - sec_firmware_loadable_addr + size); + sec_firmware_loadable_addr + buf.size);
/* Populate loadable address only for Trusted OS */ if (!strcmp(str, "trustedOS@1")) { diff --git a/arch/arm/mach-k3/r5/sysfw-loader.c b/arch/arm/mach-k3/r5/sysfw-loader.c index f0ad7559b97..ca98d310450 100644 --- a/arch/arm/mach-k3/r5/sysfw-loader.c +++ b/arch/arm/mach-k3/r5/sysfw-loader.c @@ -117,7 +117,14 @@ static int fit_get_data_by_name(const void *fit, int images, const char *name, if (node_offset < 0) return -ENOENT;
- return fit_image_get_data(fit, node_offset, addr, size); + ret = fit_image_get_data(fit, node_offset, &buf); + if (ret) + return ret; + + *addr = buf.data; + *size = buf.size; + + return 0; }
static void k3_start_system_controller(int rproc_id, bool rproc_loaded, diff --git a/arch/x86/lib/bootm.c b/arch/x86/lib/bootm.c index 2a7933cdaf8..bbd8ee7870f 100644 --- a/arch/x86/lib/bootm.c +++ b/arch/x86/lib/bootm.c @@ -106,13 +106,16 @@ static int boot_prep_linux(struct bootm_headers *images) is_zimage = 1; #if defined(CONFIG_FIT) } else if (images->fit_uname_os && is_zimage) { + struct abuf buf; + ret = fit_image_get_data(images->fit_hdr_os, - images->fit_noffset_os, - (const void **)&data, &len); + images->fit_noffset_os, &buf); if (ret) { puts("Can't get image data/size!\n"); goto error; } + data = buf.data; + len = buf.size; is_zimage = 1; #endif } diff --git a/boot/image-board.c b/boot/image-board.c index 8e6b2974dcf..f8083fcb3f9 100644 --- a/boot/image-board.c +++ b/boot/image-board.c @@ -964,9 +964,7 @@ int image_locate_script(void *buf, int size, const char *fit_uname, const char *confname, char **datap, uint *lenp) { const struct legacy_img_hdr *hdr; - const void *fit_data; const void *fit_hdr; - size_t fit_len; int noffset; int verify; ulong len; @@ -1024,6 +1022,8 @@ int image_locate_script(void *buf, int size, const char *fit_uname, if (!IS_ENABLED(CONFIG_FIT)) { goto exit_image_format; } else { + struct abuf abuf; + fit_hdr = buf; if (fit_check_format(fit_hdr, IMAGE_SIZE_INVAL)) { puts("Bad FIT image format\n"); @@ -1087,14 +1087,13 @@ fallback: }
/* get script subimage data address and length */ - if (fit_image_get_data(fit_hdr, noffset, &fit_data, - &fit_len)) { + if (fit_image_get_data(fit_hdr, noffset, &abuf)) { puts("Could not find script subimage data\n"); return 1; }
- data = (u32 *)fit_data; - len = (ulong)fit_len; + data = abuf.data; + len = abuf.size; } break; default: diff --git a/boot/image-fit.c b/boot/image-fit.c index e9b4152eb84..8e69a3e1897 100644 --- a/boot/image-fit.c +++ b/boot/image-fit.c @@ -475,9 +475,8 @@ void fit_image_print(const void *fit, int image_noffset, const char *p) { char *desc; uint8_t type, arch, os, comp = IH_COMP_NONE; - size_t size; ulong load, entry; - const void *data; + struct abuf buf; int noffset; int ndepth; int ret; @@ -510,24 +509,21 @@ void fit_image_print(const void *fit, int image_noffset, const char *p) fit_image_get_comp(fit, image_noffset, &comp); printf("%s Compression: %s\n", p, genimg_get_comp_name(comp));
- ret = fit_image_get_data(fit, image_noffset, &data, &size); + ret = fit_image_get_data(fit, image_noffset, &buf);
if (!tools_build()) { printf("%s Data Start: ", p); - if (ret) { + if (ret) printf("unavailable\n"); - } else { - void *vdata = (void *)data; - - printf("0x%08lx\n", (ulong)map_to_sysmem(vdata)); - } + else + printf("0x%08lx\n", abuf_addr(&buf)); }
printf("%s Data Size: ", p); if (ret) printf("unavailable\n"); else - genimg_print_size(size); + genimg_print_size(buf.size);
/* Remaining, type dependent properties */ if ((type == IH_TYPE_KERNEL) || (type == IH_TYPE_STANDALONE) || @@ -1017,24 +1013,7 @@ int fit_image_get_data_size_unciphered(const void *fit, int noffset, return 0; }
-/** - * fit_image_get_data - get data and its size including - * both embedded and external data - * @fit: pointer to the FIT format image header - * @noffset: component image node offset - * @data: double pointer to void, will hold data property's data address - * @size: pointer to size_t, will hold data property's data size - * - * fit_image_get_data() finds data and its size including - * both embedded and external data. If the property is found - * its data start address and size are returned to the caller. - * - * returns: - * 0, on success - * otherwise, on failure - */ -int fit_image_get_data(const void *fit, int noffset, const void **data, - size_t *size) +int fit_image_get_data(const void *fit, int noffset, struct abuf *buf) { bool external_data = false; int offset; @@ -1056,16 +1035,10 @@ int fit_image_get_data(const void *fit, int noffset, const void **data, if (external_data) { debug("External Data\n"); ret = fit_image_get_data_size(fit, noffset, &len); - if (!ret) { - *data = fit + offset; - *size = len; - } + if (!ret) + abuf_init_const(buf, fit + offset, len); } else { - struct abuf buf; - - ret = fit_image_get_emb_data(fit, noffset, &buf); - *data = buf.data; - *size = buf.size; + ret = fit_image_get_emb_data(fit, noffset, buf); }
return ret; @@ -1410,9 +1383,8 @@ error: int fit_image_verify(const void *fit, int image_noffset) { const char *name = fit_get_name(fit, image_noffset, NULL); - const void *data; - size_t size; char *err_msg = ""; + struct abuf buf;
if (IS_ENABLED(CONFIG_FIT_SIGNATURE) && strchr(name, '@')) { /* @@ -1423,13 +1395,13 @@ int fit_image_verify(const void *fit, int image_noffset) goto err; } /* Get image data and data length */ - if (fit_image_get_data(fit, image_noffset, &data, &size)) { + if (fit_image_get_data(fit, image_noffset, &buf)) { err_msg = "Can't get image data/size"; goto err; }
return fit_image_verify_with_data(fit, image_noffset, gd_fdt_blob(), - data, size); + buf.data, buf.size);
err: printf("error!\n%s in '%s' image node\n", err_msg, @@ -1739,8 +1711,8 @@ int fit_conf_find_compat(const void *fit, const void *fdt) const char *kfdt_name; int kfdt_noffset, compat_noffset; const char *cur_fdt_compat; + struct abuf buf; int len; - size_t sz; int i;
if (ndepth > 1) @@ -1772,10 +1744,11 @@ int fit_conf_find_compat(const void *fit, const void *fdt) }
/* search in this config's kernel FDT */ - if (fit_image_get_data(fit, kfdt_noffset, &fdt, &sz)) { + if (fit_image_get_data(fit, kfdt_noffset, &buf)) { debug("Failed to get fdt "%s".\n", kfdt_name); continue; } + fdt = buf.data;
compat_noffset = 0; /* search kFDT under root node */ } @@ -1923,6 +1896,7 @@ int fit_conf_get_prop_node(const void *fit, int noffset, const char *prop_name, static int fit_get_data_tail(const void *fit, int noffset, const void **data, size_t *size) { + struct abuf buf; char *desc;
if (noffset < 0) @@ -1931,12 +1905,15 @@ static int fit_get_data_tail(const void *fit, int noffset, if (!fit_image_verify(fit, noffset)) return -EINVAL;
- if (fit_image_get_data(fit, noffset, data, size)) + if (fit_image_get_data(fit, noffset, &buf)) return -ENOENT;
if (!fit_get_desc(fit, noffset, &desc)) printf("%s\n", desc);
+ *data = buf.data; + *size = buf.size; + return 0; }
@@ -2047,6 +2024,7 @@ int fit_image_load(struct bootm_headers *images, ulong addr, const char *fit_uname; const char *fit_uname_config; const char *fit_base_uname_config; + struct abuf abuf; const void *fit; void *buf; void *loadbuf; @@ -2187,12 +2165,15 @@ int fit_image_load(struct bootm_headers *images, ulong addr, bootstage_mark(bootstage_id + BOOTSTAGE_SUB_CHECK_ALL_OK);
/* get image data address and length */ - if (fit_image_get_data(fit, noffset, (const void **)&buf, &size)) { + if (fit_image_get_data(fit, noffset, &abuf)) { printf("Could not find %s subimage data!\n", prop_name); bootstage_error(bootstage_id + BOOTSTAGE_SUB_GET_DATA); return -ENOENT; }
+ buf = abuf.data; + size = abuf.size; + /* Decrypt data before uncompress/move */ if (IS_ENABLED(CONFIG_FIT_CIPHER) && IMAGE_ENABLE_DECRYPT) { puts(" Decrypting Data ... "); diff --git a/cmd/ximg.c b/cmd/ximg.c index 29d7c3279b3..ad85806fdcb 100644 --- a/cmd/ximg.c +++ b/cmd/ximg.c @@ -44,8 +44,6 @@ do_imgextract(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) const char *uname = NULL; const void* fit_hdr; int noffset; - const void *fit_data; - size_t fit_len; #endif #ifdef CONFIG_GZIP uint unc_len = CONFIG_SYS_XIMG_LEN; @@ -122,7 +120,9 @@ do_imgextract(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) break; #endif #if defined(CONFIG_FIT) - case IMAGE_FORMAT_FIT: + case IMAGE_FORMAT_FIT: { + struct abuf buf; + if (uname == NULL) { puts("No FIT subimage unit name\n"); return 1; @@ -161,7 +161,7 @@ do_imgextract(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) }
/* get subimage/external data address and length */ - if (fit_image_get_data(fit_hdr, noffset, &fit_data, &fit_len)) { + if (fit_image_get_data(fit_hdr, noffset, &buf)) { puts("Could not find script subimage data\n"); return 1; } @@ -169,9 +169,10 @@ do_imgextract(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) if (fit_image_get_comp(fit_hdr, noffset, &comp)) comp = IH_COMP_NONE;
- data = (ulong)fit_data; - len = (ulong)fit_len; + data = abuf_addr(&buf); + len = buf.size; break; + } #endif default: puts("Invalid image type for imxtract\n"); diff --git a/common/splash_source.c b/common/splash_source.c index 9972a1b2a08..95a88731c31 100644 --- a/common/splash_source.c +++ b/common/splash_source.c @@ -347,8 +347,6 @@ static int splash_load_fit(struct splash_location *location, u32 bmp_load_addr) int res; int node_offset; const char *splash_file; - const void *internal_splash_data; - size_t internal_splash_size; int external_splash_addr; int external_splash_size; bool is_splash_external = false; @@ -356,6 +354,7 @@ static int splash_load_fit(struct splash_location *location, u32 bmp_load_addr) const u32 *fit_header; u32 fit_size; const size_t header_size = sizeof(struct legacy_img_hdr); + struct abuf buf;
/* Read in image header */ res = splash_storage_read_raw(location, bmp_load_addr, header_size); @@ -395,11 +394,9 @@ static int splash_load_fit(struct splash_location *location, u32 bmp_load_addr) }
/* Extract the splash data from FIT */ - if (!fit_image_get_data(fit_header, node_offset, &internal_splash_data, - &internal_splash_size)) - memmove((void *)(uintptr_t)bmp_load_addr, internal_splash_data, - internal_splash_size); - else { + if (!fit_image_get_emb_data(fit_header, node_offset, &buf)) { + memmove((void *)(uintptr_t)bmp_load_addr, buf.data, buf.size); + } else { printf("Failed to get splash image from FIT\n"); return -ENODATA; } diff --git a/common/update.c b/common/update.c index 6801b49479d..6d0b979cc97 100644 --- a/common/update.c +++ b/common/update.c @@ -6,6 +6,7 @@ * Bartlomiej Sieka tur@semihalf.com */
+#include <abuf.h> #include <cpu_func.h> #include <image.h> #include <linux/printk.h> @@ -198,15 +199,15 @@ static int update_flash(ulong addr_source, ulong addr_first, ulong size) static int update_fit_getparams(const void *fit, int noffset, ulong *addr, ulong *fladdr, ulong *size) { - const void *data; + struct abuf buf;
- if (fit_image_get_data(fit, noffset, &data, (size_t *)size)) + if (fit_image_get_data(fit, noffset, &buf)) return 1;
if (fit_image_get_load(fit, noffset, (ulong *)fladdr)) return 1;
- *addr = (ulong)data; + *addr = abuf_addr(&buf);
return 0; } diff --git a/include/image.h b/include/image.h index 29ac7a69ae9..19f5a7b2d83 100644 --- a/include/image.h +++ b/include/image.h @@ -1220,8 +1220,23 @@ int fit_image_get_data_position(const void *fit, int noffset, int fit_image_get_data_size(const void *fit, int noffset, int *data_size); int fit_image_get_data_size_unciphered(const void *fit, int noffset, size_t *data_size); -int fit_image_get_data(const void *fit, int noffset, const void **data, - size_t *size); + +/** + * fit_image_get_data() - Get a node's data and size + * + * @fit: pointer to the FIT format image header + * @noffset: component image node offset + * @buf: returns data (inited by this function) + * + * fit_image_get_data_and_size() finds data and its size including + * both embedded and external data. If the property is found + * its data start address and size are returned to the caller. + * + * returns: + * 0, on success + * otherwise, on failure + */ +int fit_image_get_data(const void *fit, int noffset, struct abuf *buf);
/** * fit_get_data_node() - Get verified image data for an image diff --git a/lib/abuf.c b/lib/abuf.c index 61adf7fc6b1..1999b2c1f5f 100644 --- a/lib/abuf.c +++ b/lib/abuf.c @@ -21,18 +21,25 @@ void abuf_set(struct abuf *abuf, void *data, size_t size) abuf->size = size; }
-#ifndef USE_HOSTCC void abuf_map_sysmem(struct abuf *abuf, ulong addr, size_t size) { +#ifdef USE_HOSTCC + abuf_set(abuf, (void *)addr, size); +#else abuf_set(abuf, map_sysmem(addr, size), size); +#endif }
ulong abuf_addr(const struct abuf *abuf) { +#ifdef USE_HOSTCC + return (ulong)abuf->data; +#else return map_to_sysmem(abuf->data); +#endif }
-#else +#ifdef USE_HOSTCC /* copied from lib/string.c for convenience */ static char *memdup(const void *src, size_t len) { diff --git a/tools/fit_image.c b/tools/fit_image.c index caed8d5f901..dfcfa66afa7 100644 --- a/tools/fit_image.c +++ b/tools/fit_image.c @@ -15,6 +15,7 @@
#include "imagetool.h" #include "fit_common.h" +#include <abuf.h> #include "mkimage.h" #include <image.h> #include <string.h> @@ -871,19 +872,18 @@ static int fit_image_extract( int image_noffset, const char *file_name) { - const void *file_data; - size_t file_size = 0; + struct abuf buf; int ret;
/* get the data address and size of component at offset "image_noffset" */ - ret = fit_image_get_data(fit, image_noffset, &file_data, &file_size); + ret = fit_image_get_data(fit, image_noffset, &buf); if (ret) { fprintf(stderr, "Could not get component information\n"); return ret; }
/* save the "file_data" into the file specified by "file_name" */ - return imagetool_save_subimage(file_name, (ulong) file_data, file_size); + return imagetool_save_subimage(file_name, abuf_addr(&buf), buf.size); }
/**

Fix a typo in the test comment.
Signed-off-by: Simon Glass sjg@chromium.org ---
test/py/tests/test_upl.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/test/py/tests/test_upl.py b/test/py/tests/test_upl.py index 3164bda6b71..90125c4dc1b 100644 --- a/test/py/tests/test_upl.py +++ b/test/py/tests/test_upl.py @@ -17,7 +17,7 @@ def test_upl_handoff(u_boot_console): proper and runs a test to check that the parameters are correct.
The entire FIT is loaded into memory in SPL (in upl_load_from_image()) so - that it can be inpected in upl_test_info_norun + that it can be inspected in upl_test_info_norun """ cons = u_boot_console ram = os.path.join(cons.config.build_dir, 'ram.bin')

QEMU always gets its devicetree from the OF_BOARD mechanism so we should not depend on !BLOBLIST here.
The logic of PRIOR_STAGE is quite a mess, unfortuantely. We should rely only standard passage to receive things from the prior stage. QEMU should implement standard passage to provide its devicetree to U-Boot However Linaro has blocked my patch to provide devicetree additions[1], so little breath should be held in respect of either change.
[1] https://lore.kernel.org/qemu-devel/20210926183410.256484-1-sjg@chromium.org/
Signed-off-by: Simon Glass sjg@chromium.org Fixes: 2b71470628c dts: OF_HAS_PRIOR_STAGE should depend on !BLOBLIST ---
dts/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/dts/Kconfig b/dts/Kconfig index 41a758e83a6..fc25a854708 100644 --- a/dts/Kconfig +++ b/dts/Kconfig @@ -191,7 +191,7 @@ config OF_BOARD
config OF_HAS_PRIOR_STAGE bool - depends on !BLOBLIST + depends on !BLOBLIST || ARCH_QEMU help Indicates that a prior stage of the firmware (before U-Boot proper) makes use of device tree and this board normally boots with that prior

QEMU can have its own internal ACPI and SMBIOS tables. At present U-Boot copies out the SMBIOS tables but points directly to the ACPI ones.
The ACPI tables are not aligned on a 4KB boundary, which means that UPL cannot use them directly, since it uses a reserved-memory node for the tables and that it assumed (by EDK2) to be 4KB-aligned.
On x86, QEMU completely takes over the generation of these tables, thus making it difficult to use any common code.
Adjust the logic to fit within the existing table-generation code. Use a bloblist always and ensure that the ACPI tables is placed in an aligned region. Set a size of 8K for QEMU. This does not actually put all the tables in one place, for QEMU, since it currently adds a pointer to the tables in QFW.
On ARM, enable bloblist so that SMBIOS tables can be added to the bloblist.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/x86/lib/tables.c | 2 +- configs/qemu-x86_64_defconfig | 1 - configs/qemu_arm64_defconfig | 2 ++ configs/qemu_arm_defconfig | 2 ++ drivers/misc/qfw_acpi.c | 37 ++++++++++++++++++++++++++-- drivers/misc/qfw_smbios.c | 45 ++++++++++++++++------------------- lib/Kconfig | 1 + lib/Makefile | 5 ++++ 8 files changed, 67 insertions(+), 28 deletions(-)
diff --git a/arch/x86/lib/tables.c b/arch/x86/lib/tables.c index 45a70e92763..5fc7dc75377 100644 --- a/arch/x86/lib/tables.c +++ b/arch/x86/lib/tables.c @@ -61,7 +61,7 @@ static struct table_info table_list[] = { #ifdef CONFIG_GENERATE_ACPI_TABLE { "acpi", write_acpi_tables, BLOBLISTT_ACPI_TABLES, 0x10000, 0x1000}, #endif -#if defined(CONFIG_GENERATE_SMBIOS_TABLE) && !defined(CONFIG_QFW_SMBIOS) +#ifdef CONFIG_GENERATE_SMBIOS_TABLE { "smbios", write_smbios_table, BLOBLISTT_SMBIOS_TABLES, 0x1000, 0x100}, #endif }; diff --git a/configs/qemu-x86_64_defconfig b/configs/qemu-x86_64_defconfig index f93721fceb8..3c0fc7a34fe 100644 --- a/configs/qemu-x86_64_defconfig +++ b/configs/qemu-x86_64_defconfig @@ -33,7 +33,6 @@ CONFIG_LOGF_FUNC=y CONFIG_SPL_LOG=y CONFIG_DISPLAY_BOARDINFO_LATE=y CONFIG_PCI_INIT_R=y -CONFIG_BLOBLIST=y CONFIG_BLOBLIST_FIXED=y CONFIG_BLOBLIST_ADDR=0x10000 CONFIG_SPL_NO_BSS_LIMIT=y diff --git a/configs/qemu_arm64_defconfig b/configs/qemu_arm64_defconfig index 8dffb91e93b..8a529acfba3 100644 --- a/configs/qemu_arm64_defconfig +++ b/configs/qemu_arm64_defconfig @@ -27,6 +27,8 @@ CONFIG_USE_PREBOOT=y # CONFIG_DISPLAY_CPUINFO is not set # CONFIG_DISPLAY_BOARDINFO is not set CONFIG_PCI_INIT_R=y +CONFIG_BLOBLIST=y +CONFIG_BLOBLIST_SIZE_RELOC=0x2000 CONFIG_CMD_SMBIOS=y CONFIG_CMD_BOOTZ=y CONFIG_CMD_BOOTEFI_SELFTEST=y diff --git a/configs/qemu_arm_defconfig b/configs/qemu_arm_defconfig index cc4f4540fd5..1dfa946f17d 100644 --- a/configs/qemu_arm_defconfig +++ b/configs/qemu_arm_defconfig @@ -28,6 +28,8 @@ CONFIG_USE_PREBOOT=y # CONFIG_DISPLAY_CPUINFO is not set # CONFIG_DISPLAY_BOARDINFO is not set CONFIG_PCI_INIT_R=y +CONFIG_BLOBLIST=y +CONFIG_BLOBLIST_SIZE_RELOC=0x2000 CONFIG_CMD_BOOTEFI_SELFTEST=y CONFIG_CMD_NVEDIT_EFI=y CONFIG_CMD_DFU=y diff --git a/drivers/misc/qfw_acpi.c b/drivers/misc/qfw_acpi.c index 7ffed1e8c02..0d0cf764689 100644 --- a/drivers/misc/qfw_acpi.c +++ b/drivers/misc/qfw_acpi.c @@ -7,6 +7,7 @@ #define LOG_CATEGORY UCLASS_QFW
#include <acpi/acpi_table.h> +#include <bloblist.h> #include <errno.h> #include <malloc.h> #include <mapmem.h> @@ -160,6 +161,15 @@ ulong write_acpi_tables(ulong addr) struct bios_linker_entry *entry; uint32_t size; struct udevice *dev; + struct acpi_ctx *ctx; + + ctx = malloc(sizeof(*ctx)); + if (!ctx) { + printf("error: out of memory for acpi ctx\n"); + return addr; + } + + acpi_setup_ctx(ctx, addr);
ret = qfw_get_dev(&dev); if (ret) { @@ -257,6 +267,29 @@ ulong acpi_get_rsdp_addr(void) return file->addr; }
+void acpi_write_rsdp(struct acpi_rsdp *rsdp, struct acpi_rsdt *rsdt, + struct acpi_xsdt *xsdt) +{ + memset(rsdp, 0, sizeof(struct acpi_rsdp)); + + memcpy(rsdp->signature, RSDP_SIG, 8); + memcpy(rsdp->oem_id, OEM_ID, 6); + + if (rsdt) + rsdp->rsdt_address = nomap_to_sysmem(rsdt); + + if (xsdt) + rsdp->xsdt_address = nomap_to_sysmem(xsdt); + + rsdp->length = sizeof(struct acpi_rsdp); + rsdp->revision = ACPI_RSDP_REV_ACPI_2_0; + + /* Calculate checksums */ + rsdp->checksum = table_compute_checksum(rsdp, 20); + rsdp->ext_checksum = table_compute_checksum(rsdp, + sizeof(struct acpi_rsdp)); +} + #ifndef CONFIG_X86 static int evt_write_acpi_tables(void) { @@ -264,9 +297,9 @@ static int evt_write_acpi_tables(void) void *ptr;
/* Reserve 64K for ACPI tables, aligned to a 4K boundary */ - ptr = memalign(SZ_4K, SZ_64K); + ptr = bloblist_add(BLOBLISTT_ACPI_TABLES, SZ_64K, 12); if (!ptr) - return -ENOMEM; + return -ENOBUFS; addr = map_to_sysmem(ptr);
/* Generate ACPI tables */ diff --git a/drivers/misc/qfw_smbios.c b/drivers/misc/qfw_smbios.c index c3e8c310d00..93c4a80286b 100644 --- a/drivers/misc/qfw_smbios.c +++ b/drivers/misc/qfw_smbios.c @@ -5,6 +5,7 @@
#define LOG_CATEGORY UCLASS_QFW
+#include <bloblist.h> #include <efi_loader.h> #include <errno.h> #include <log.h> @@ -15,6 +16,7 @@ #include <tables_csum.h> #include <linux/sizes.h> #include <asm/global_data.h> +#include <linux/err.h>
DECLARE_GLOBAL_DATA_PTR;
@@ -105,11 +107,10 @@ out: /** * qfw_write_smbios_tables() - copy SMBIOS tables from QEMU * - * @addr: target buffer - * @size: size of target buffer + * @addr: address of target buffer * Return: 0 for success, -ve on error */ -static int qfw_write_smbios_tables(u8 *addr, uint32_t size) +ulong write_smbios_table(ulong addr) { int ret; struct udevice *dev; @@ -143,16 +144,13 @@ static int qfw_write_smbios_tables(u8 *addr, uint32_t size)
table = qfw_load_smbios_table(dev, &table_size, "etc/smbios/smbios-tables"); - if (table_size + sizeof(struct smbios3_entry) > size) { - free(table); - return -ENOMEM; - } - memcpy(addr, table, table_size); + memcpy((void *)addr, table, table_size); free(table);
- return 0; + return addr + table_size; }
+#ifndef CONFIG_X86 /** * qfw_evt_write_smbios_tables() - event handler for copying QEMU SMBIOS tables * @@ -160,9 +158,9 @@ static int qfw_write_smbios_tables(u8 *addr, uint32_t size) */ static int qfw_evt_write_smbios_tables(void) { - phys_addr_t addr; + ulong addr, end; void *ptr; - int ret; + /* * TODO: * This size is currently hard coded in lib/efi_loader/efi_smbios.c. @@ -170,22 +168,21 @@ static int qfw_evt_write_smbios_tables(void) */ uint32_t size = SZ_4K;
- /* Reserve 64K for SMBIOS tables, aligned to a 4K boundary */ - ptr = memalign(SZ_4K, size); - if (!ptr) { - log_err("Out of memory\n"); - return -ENOMEM; - } + log_debug("qfw_evt_write_smbios_tables bloblist\n"); + /* Reserve 4K for SMBIOS tables, aligned to a 4K boundary */ + ptr = bloblist_add(BLOBLISTT_SMBIOS_TABLES, size, 12); + if (!ptr) + return log_msg_ret("bloblist", -ENOBUFS); + addr = map_to_sysmem(ptr);
/* Generate SMBIOS tables */ - ret = qfw_write_smbios_tables(ptr, size); - if (ret) { - if (CONFIG_IS_ENABLED(GENERATE_SMBIOS_TABLE)) { - log_info("Falling back to U-Boot generated SMBIOS tables\n"); - write_smbios_table(addr); - } + end = write_smbios_table(addr); + if (IS_ERR_VALUE(end)) { + log_warning("SMBIOS: Failed to write (err=%dE)\n", (int)end); } else { + if (end - addr > size) + return -ENOMEM; log_debug("SMBIOS tables copied from QEMU\n"); }
@@ -193,5 +190,5 @@ static int qfw_evt_write_smbios_tables(void)
return 0; } - EVENT_SPY_SIMPLE(EVT_LAST_STAGE_INIT, qfw_evt_write_smbios_tables); +#endif /* !X86 */ diff --git a/lib/Kconfig b/lib/Kconfig index 56ffdfa1839..3a1aaf08c70 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -1005,6 +1005,7 @@ menu "System tables" config BLOBLIST_TABLES bool "Put tables in a bloblist" depends on BLOBLIST + default y if X86 default y if (ARM && EFI_LOADER && GENERATE_ACPI_TABLE) default n help diff --git a/lib/Makefile b/lib/Makefile index dbcfa87ebd6..95aafe0c182 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -41,7 +41,12 @@ obj-$(CONFIG_ERRNO_STR) += errno_str.o obj-$(CONFIG_FIT) += fdtdec_common.o obj-$(CONFIG_TEST_FDTDEC) += fdtdec_test.o obj-$(CONFIG_GZIP_COMPRESSED) += gzip.o + +# With QEMU the SMBIOS tables come from there, not from U-Boot +ifndef CONFIG_QFW_SMBIOS obj-$(CONFIG_GENERATE_SMBIOS_TABLE) += smbios.o +endif + obj-$(CONFIG_SMBIOS_PARSER) += smbios-parser.o obj-$(CONFIG_IMAGE_SPARSE) += image-sparse.o obj-y += initcall.o

The space here is quite tight and there is plenty of room in the ROM. Move SPL earlier to allow for expansion.
Signed-off-by: Simon Glass sjg@chromium.org ---
configs/qemu-x86_64_defconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/configs/qemu-x86_64_defconfig b/configs/qemu-x86_64_defconfig index 3c0fc7a34fe..39375c76227 100644 --- a/configs/qemu-x86_64_defconfig +++ b/configs/qemu-x86_64_defconfig @@ -7,7 +7,7 @@ CONFIG_MAX_CPUS=2 CONFIG_SPL_DM_SPI=y CONFIG_DEFAULT_DEVICE_TREE="qemu-x86_i440fx" CONFIG_SPL_SYS_MALLOC_F_LEN=0x2000 -CONFIG_SPL_TEXT_BASE=0xfffd4000 +CONFIG_SPL_TEXT_BASE=0xfffd0000 CONFIG_DEBUG_UART_BASE=0x3f8 CONFIG_DEBUG_UART_CLOCK=1843200 CONFIG_X86_RUN_64BIT=y

Pull out the code which creates a new memory-node into its own function, since several functions have similar logic.
Signed-off-by: Simon Glass sjg@chromium.org ---
boot/upl_write.c | 66 ++++++++++++++++++++++++++++++++++-------------- 1 file changed, 47 insertions(+), 19 deletions(-)
diff --git a/boot/upl_write.c b/boot/upl_write.c index 7d637c15ba0..6e9f67f686f 100644 --- a/boot/upl_write.c +++ b/boot/upl_write.c @@ -287,6 +287,48 @@ static int buffer_addr_size(const struct upl *upl, char *buf, int size, return ptr - buf; }
+/** + * write_mem_node() - Write a memory node and reg property + * + * Creates a new node and then adds a 'reg' property within it, listing each of + * the memory regions in @mem + * + * @upl: UPL state + * @parent: Parent node for the new node + * @mem: List of memory regions to write (struct memregion) + * @leaf: Name of memory node (so name is <leaf>@<unit_address>) + * @nodep: Returns the created node + * Returns 0 if OK, -ve on error + */ +static int write_mem_node(const struct upl *upl, ofnode parent, + const struct alist *mem, const char *leaf, + ofnode *nodep) +{ + char buf[mem->count * sizeof(64) * 2]; + const struct memregion *first; + char name[26]; + ofnode node; + int ret, len; + + if (!mem->count) { + log_debug("Memory '%s' has no regions\n", leaf); + return log_msg_ret("reg", -EINVAL); + } + first = alist_get(mem, 0, struct memregion); + sprintf(name, "%s@0x%lx", leaf, first->base); + ret = ofnode_add_subnode(parent, name, &node); + if (ret) + return log_msg_ret("wmn", ret); + + len = buffer_addr_size(upl, buf, sizeof(buf), mem->count, mem); + ret = ofnode_write_prop(node, UPLP_REG, buf, len, true); + if (ret) + return log_msg_ret("wm1", ret); + *nodep = node; + + return 0; +} + /** * add_upl_memory() - Add /memory nodes to the tree * @@ -301,29 +343,15 @@ static int add_upl_memory(const struct upl *upl, ofnode root) for (i = 0; i < upl->mem.count; i++) { const struct upl_mem *mem = alist_get(&upl->mem, i, struct upl_mem); - char buf[mem->region.count * sizeof(64) * 2]; - const struct memregion *first; - char name[26]; - int ret, len; ofnode node; + int ret;
- if (!mem->region.count) { - log_debug("Memory %d has no regions\n", i); - return log_msg_ret("reg", -EINVAL); - } - first = alist_get(&mem->region, 0, struct memregion); - sprintf(name, UPLN_MEMORY "@0x%lx", first->base); - ret = ofnode_add_subnode(root, name, &node); + ret = write_mem_node(upl, root, &mem->region, UPLN_MEMORY, + &node); if (ret) - return log_msg_ret("mem", ret); + return log_msg_ret("ume", ret);
- len = buffer_addr_size(upl, buf, sizeof(buf), mem->region.count, - &mem->region); - if (len < 0) - return log_msg_ret("buf", len); - - ret = ofnode_write_prop(node, UPLP_REG, buf, len, true); - if (!ret && mem->hotpluggable) + if (mem->hotpluggable) ret = ofnode_write_bool(node, UPLP_HOTPLUGGABLE, mem->hotpluggable); if (ret)

Use this new helper function to simplify add_upl_memmap()
Signed-off-by: Simon Glass sjg@chromium.org ---
boot/upl_write.c | 24 +++++------------------- 1 file changed, 5 insertions(+), 19 deletions(-)
diff --git a/boot/upl_write.c b/boot/upl_write.c index 6e9f67f686f..3f38d533c4a 100644 --- a/boot/upl_write.c +++ b/boot/upl_write.c @@ -382,31 +382,17 @@ static int add_upl_memmap(const struct upl *upl, ofnode root) for (i = 0; i < upl->memmap.count; i++) { const struct upl_memmap *memmap = alist_get(&upl->memmap, i, struct upl_memmap); - char buf[memmap->region.count * sizeof(64) * 2]; - const struct memregion *first; - char name[26]; - int ret, len; ofnode node;
- if (!memmap->region.count) { - log_debug("Memory %d has no regions\n", i); - return log_msg_ret("reg", -EINVAL); - } - first = alist_get(&memmap->region, 0, struct memregion); - sprintf(name, "%s@0x%lx", memmap->name, first->base); - ret = ofnode_add_subnode(mem_node, name, &node); + ret = write_mem_node(upl, mem_node, &memmap->region, + memmap->name, &node); if (ret) - return log_msg_ret("memmap", ret); - - len = buffer_addr_size(upl, buf, sizeof(buf), - memmap->region.count, &memmap->region); - if (len < 0) - return log_msg_ret("buf", len); - ret = ofnode_write_prop(node, UPLP_REG, buf, len, true); - if (!ret && memmap->usage) + return log_msg_ret("umm", ret); + if (memmap->usage) { ret = ofnode_write_bitmask(node, UPLP_USAGE, usage_names, UPLUS_COUNT, memmap->usage); + } if (ret) return log_msg_ret("lst", ret); }

Use this new helper function to simplify add_upl_memmap()
Signed-off-by: Simon Glass sjg@chromium.org ---
boot/upl_write.c | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-)
diff --git a/boot/upl_write.c b/boot/upl_write.c index 3f38d533c4a..25ec6992573 100644 --- a/boot/upl_write.c +++ b/boot/upl_write.c @@ -425,26 +425,14 @@ static int add_upl_memres(const struct upl *upl, ofnode root, for (i = 0; i < upl->memres.count; i++) { const struct upl_memres *memres = alist_get(&upl->memres, i, struct upl_memres); - char buf[memres->region.count * sizeof(64) * 2]; - const struct memregion *first; - char name[26]; - int ret, len; ofnode node;
- if (!memres->region.count) { - log_debug("Memory %d has no regions\n", i); - return log_msg_ret("reg", -EINVAL); - } - first = alist_get(&memres->region, 0, struct memregion); - sprintf(name, "%s@0x%lx", memres->name, first->base); - ret = ofnode_add_subnode(mem_node, name, &node); + ret = write_mem_node(upl, mem_node, &memres->region, + memres->name, &node); if (ret) - return log_msg_ret("memres", ret); + return log_msg_ret("umr", ret);
- len = buffer_addr_size(upl, buf, sizeof(buf), - memres->region.count, &memres->region); - ret = ofnode_write_prop(node, UPLP_REG, buf, len, true); - if (!ret && memres->no_map) + if (memres->no_map) ret = ofnode_write_bool(node, UPLP_NO_MAP, memres->no_map); if (ret)

The existing code works only on sandbox, generating test data rather than a real payload. Add a check for this.
Eventually a real writer will be in place.
Signed-off-by: Simon Glass sjg@chromium.org ---
cmd/upl.c | 5 +++++ 1 file changed, 5 insertions(+)
diff --git a/cmd/upl.c b/cmd/upl.c index c9a823bbc06..d8d46cdf34f 100644 --- a/cmd/upl.c +++ b/cmd/upl.c @@ -56,6 +56,11 @@ static int do_upl_write(struct cmd_tbl *cmdtp, int flag, int argc, ulong addr; int ret;
+ if (!IS_ENABLED(CONFIG_UNIT_TEST)) { + printf("Not yet implemented\n"); + return CMD_RET_FAILURE; + } + upl_get_test_data(&uts, upl);
log_debug("Writing UPL\n");

We already have enum upl_access_type which is good enough, so drop the serial-specific enum.
Signed-off-by: Simon Glass sjg@chromium.org ---
include/upl.h | 7 +------ test/boot/upl.c | 2 +- 2 files changed, 2 insertions(+), 7 deletions(-)
diff --git a/include/upl.h b/include/upl.h index 4d0eca88047..9f2a6e7842d 100644 --- a/include/upl.h +++ b/include/upl.h @@ -169,11 +169,6 @@ struct upl_memres { bool no_map; };
-enum upl_serial_access_type { - UPLSAT_MMIO, - UPLSAT_IO, -}; - /* serial defaults */ enum { UPLD_REG_IO_SHIFT = 0, @@ -214,7 +209,7 @@ struct upl_serial { uint reg_offset; uint reg_io_width; ulong virtual_reg; - enum upl_serial_access_type access_type; + enum upl_access_type access_type; };
/** diff --git a/test/boot/upl.c b/test/boot/upl.c index 99f02b7951b..c2b571e06c4 100644 --- a/test/boot/upl.c +++ b/test/boot/upl.c @@ -142,7 +142,7 @@ int upl_get_test_data(struct unit_test_state *uts, struct upl *upl) upl->serial.reg_offset = 0x40; upl->serial.reg_io_width = 1; upl->serial.virtual_reg = 0x20000000; - upl->serial.access_type = UPLSAT_MMIO; + upl->serial.access_type = UPLAT_MMIO;
alist_init_struct(&upl->graphics.reg, struct memregion); ut_assertok(add_region(uts, &upl->graphics.reg, 0xd0000000, 0x10000000));

It is better and simpler to do this at the start, so that an uninited data structure doesn't cause problems. Update upl_init() to set up the remaining two alists and remove this from the reading/test code.
Signed-off-by: Simon Glass sjg@chromium.org ---
boot/upl_common.c | 2 ++ common/spl/spl_upl.c | 2 -- test/boot/upl.c | 2 -- 3 files changed, 2 insertions(+), 4 deletions(-)
diff --git a/boot/upl_common.c b/boot/upl_common.c index 3924423abd5..69a6673a9bf 100644 --- a/boot/upl_common.c +++ b/boot/upl_common.c @@ -57,4 +57,6 @@ void upl_init(struct upl *upl) alist_init_struct(&upl->mem, struct upl_mem); alist_init_struct(&upl->memmap, struct upl_memmap); alist_init_struct(&upl->memres, struct upl_memres); + alist_init_struct(&upl->serial.reg, struct memregion); + alist_init_struct(&upl->graphics.reg, struct memregion); } diff --git a/common/spl/spl_upl.c b/common/spl/spl_upl.c index 067d437150f..81a106570b8 100644 --- a/common/spl/spl_upl.c +++ b/common/spl/spl_upl.c @@ -75,7 +75,6 @@ static int write_serial(struct upl_serial *ser) ser->current_speed = gd->baudrate; region.base = info.addr; region.size = info.size; - alist_init_struct(&ser->reg, struct memregion); if (!alist_add(&ser->reg, region)) return -ENOMEM; ser->reg_io_shift = info.reg_shift; @@ -94,7 +93,6 @@ static int write_graphics(struct upl_graphics *gra) struct memregion region; struct udevice *dev;
- alist_init_struct(&gra->reg, struct memregion); uclass_find_first_device(UCLASS_VIDEO, &dev); if (!dev || !device_active(dev)) return log_msg_ret("vid", -ENOENT); diff --git a/test/boot/upl.c b/test/boot/upl.c index c2b571e06c4..89201e445ff 100644 --- a/test/boot/upl.c +++ b/test/boot/upl.c @@ -136,7 +136,6 @@ int upl_get_test_data(struct unit_test_state *uts, struct upl *upl) upl->serial.compatible = "ns16550a"; upl->serial.clock_frequency = 1843200; upl->serial.current_speed = 115200; - alist_init_struct(&upl->serial.reg, struct memregion); ut_assertok(add_region(uts, &upl->serial.reg, 0xf1de0000, 0x100)); upl->serial.reg_io_shift = 2; upl->serial.reg_offset = 0x40; @@ -144,7 +143,6 @@ int upl_get_test_data(struct unit_test_state *uts, struct upl *upl) upl->serial.virtual_reg = 0x20000000; upl->serial.access_type = UPLAT_MMIO;
- alist_init_struct(&upl->graphics.reg, struct memregion); ut_assertok(add_region(uts, &upl->graphics.reg, 0xd0000000, 0x10000000)); upl->graphics.width = 1280; upl->graphics.height = 1280;

This will be useful in U-Boot proper, so move the code from spl_upl to the generic spl_common file.
Tweak the compatible string for serial and make sure to use the UPL values for I/O / memory, even though they currently happen to be the same as is used by U-Boot.
Signed-off-by: Simon Glass sjg@chromium.org ---
boot/upl_common.c | 78 ++++++++++++++++++++++++++++++++++++++++++ common/spl/spl_upl.c | 80 ++------------------------------------------ include/upl.h | 18 ++++++++++ 3 files changed, 98 insertions(+), 78 deletions(-)
diff --git a/boot/upl_common.c b/boot/upl_common.c index 69a6673a9bf..a0ed5568854 100644 --- a/boot/upl_common.c +++ b/boot/upl_common.c @@ -8,8 +8,15 @@
#define LOG_CATEGORY UCLASS_BOOTSTD
+#include <dm.h> +#include <serial.h> #include <string.h> #include <upl.h> +#include <video.h> +#include <asm/global_data.h> +#include <dm/uclass-internal.h> + +DECLARE_GLOBAL_DATA_PTR;
/* Names of bootmodes */ const char *const bootmode_names[UPLBM_COUNT] = { @@ -50,6 +57,77 @@ const char *const graphics_formats[UPLUS_COUNT] = { [UPLGF_ABGR64] = "a16b16g16r16", };
+int upl_add_serial(struct upl_serial *ser) +{ + struct udevice *dev = gd->cur_serial_dev; + struct serial_device_info info; + struct memregion region; + int ret; + + if (!dev) + return log_msg_ret("ser", -ENOENT); + ret = serial_getinfo(dev, &info); + if (ret) + return log_msg_ret("inf", ret); + + ser->compatible = ofnode_read_string(dev_ofnode(dev), "compatible"); + ser->clock_frequency = info.clock; + ser->current_speed = info.baudrate; + region.base = info.addr; + region.size = info.size; + if (!alist_add(&ser->reg, region)) + return -ENOMEM; + ser->reg_io_shift = info.reg_shift; + ser->reg_offset = info.reg_offset; + ser->reg_io_width = info.reg_width; + ser->virtual_reg = 0; + ser->access_type = info.addr_space == SERIAL_ADDRESS_SPACE_IO ? + UPLAT_IO : UPLAT_MMIO; + + return 0; +} + +int upl_add_graphics(struct upl_graphics *gra) +{ + struct video_uc_plat *plat; + struct video_priv *priv; + struct memregion region; + struct udevice *dev; + + uclass_find_first_device(UCLASS_VIDEO, &dev); + if (!dev || !device_active(dev)) + return log_msg_ret("vid", -ENOENT); + + plat = dev_get_uclass_plat(dev); + region.base = plat->base; + region.size = plat->size; + if (!alist_add(&gra->reg, region)) + return log_msg_ret("reg", -ENOMEM); + + priv = dev_get_uclass_priv(dev); + gra->width = priv->xsize; + gra->height = priv->ysize; + gra->stride = priv->line_length; /* private field */ + switch (priv->format) { + case VIDEO_RGBA8888: + case VIDEO_X8R8G8B8: + gra->format = UPLGF_ARGB32; + break; + case VIDEO_X8B8G8R8: + gra->format = UPLGF_ABGR32; + break; + case VIDEO_X2R10G10B10: + log_debug("device '%s': VIDEO_X2R10G10B10 not supported\n", + dev->name); + return log_msg_ret("for", -EPROTO); + case VIDEO_UNKNOWN: + log_debug("device '%s': Unknown video format\n", dev->name); + return log_msg_ret("for", -EPROTO); + } + + return 0; +} + void upl_init(struct upl *upl) { memset(upl, '\0', sizeof(struct upl)); diff --git a/common/spl/spl_upl.c b/common/spl/spl_upl.c index 81a106570b8..5c68e4ab283 100644 --- a/common/spl/spl_upl.c +++ b/common/spl/spl_upl.c @@ -12,14 +12,8 @@ #include <bloblist.h> #include <dm.h> #include <image.h> -#include <mapmem.h> -#include <serial.h> #include <spl.h> #include <upl.h> -#include <video.h> -#include <asm/global_data.h> -#include <dm/read.h> -#include <dm/uclass-internal.h>
DECLARE_GLOBAL_DATA_PTR;
@@ -57,76 +51,6 @@ int _upl_add_image(int node, ulong load_addr, ulong size, const char *desc) return 0; }
-static int write_serial(struct upl_serial *ser) -{ - struct udevice *dev = gd->cur_serial_dev; - struct serial_device_info info; - struct memregion region; - int ret; - - if (!dev) - return log_msg_ret("ser", -ENOENT); - ret = serial_getinfo(dev, &info); - if (ret) - return log_msg_ret("inf", ret); - - ser->compatible = ofnode_read_string(dev_ofnode(dev), "compatible"); - ser->clock_frequency = info.clock; - ser->current_speed = gd->baudrate; - region.base = info.addr; - region.size = info.size; - if (!alist_add(&ser->reg, region)) - return -ENOMEM; - ser->reg_io_shift = info.reg_shift; - ser->reg_offset = info.reg_offset; - ser->reg_io_width = info.reg_width; - ser->virtual_reg = 0; - ser->access_type = info.addr_space; - - return 0; -} - -static int write_graphics(struct upl_graphics *gra) -{ - struct video_uc_plat *plat; - struct video_priv *priv; - struct memregion region; - struct udevice *dev; - - uclass_find_first_device(UCLASS_VIDEO, &dev); - if (!dev || !device_active(dev)) - return log_msg_ret("vid", -ENOENT); - - plat = dev_get_uclass_plat(dev); - region.base = plat->base; - region.size = plat->size; - if (!alist_add(&gra->reg, region)) - return log_msg_ret("reg", -ENOMEM); - - priv = dev_get_uclass_priv(dev); - gra->width = priv->xsize; - gra->height = priv->ysize; - gra->stride = priv->line_length; /* private field */ - switch (priv->format) { - case VIDEO_RGBA8888: - case VIDEO_X8R8G8B8: - gra->format = UPLGF_ARGB32; - break; - case VIDEO_X8B8G8R8: - gra->format = UPLGF_ABGR32; - break; - case VIDEO_X2R10G10B10: - log_debug("device '%s': VIDEO_X2R10G10B10 not supported\n", - dev->name); - return log_msg_ret("for", -EPROTO); - case VIDEO_UNKNOWN: - log_debug("device '%s': Unknown video format\n", dev->name); - return log_msg_ret("for", -EPROTO); - } - - return 0; -} - int spl_write_upl_handoff(struct spl_image_info *spl_image) { struct upl *upl = &s_upl; @@ -139,10 +63,10 @@ int spl_write_upl_handoff(struct spl_image_info *spl_image) upl->addr_cells = IS_ENABLED(CONFIG_PHYS_64BIT) ? 2 : 1; upl->size_cells = IS_ENABLED(CONFIG_PHYS_64BIT) ? 2 : 1; upl->bootmode = UPLBM_DEFAULT; - ret = write_serial(&upl->serial); + ret = upl_add_serial(&upl->serial); if (ret) return log_msg_ret("ser", ret); - ret = write_graphics(&upl->graphics); + ret = upl_add_graphics(&upl->graphics); if (ret && ret != -ENOENT) return log_msg_ret("gra", ret);
diff --git a/include/upl.h b/include/upl.h index 9f2a6e7842d..e415130d44f 100644 --- a/include/upl.h +++ b/include/upl.h @@ -371,6 +371,24 @@ static inline int upl_add_image(const void *fit, int node, ulong load_addr, return 0; }
+/** + * upl_add_serial() - Add serial information to the UPL struct + * + * Writes details about the current serial port to the UPL struct + * + * Return: 0 if OK, -ve on error + */ +int upl_add_serial(struct upl_serial *ser); + +/** + * upl_add_graphics() - Add video information to the UPL struct + * + * Writes details about the current video device to the UPL struct + * + * Return: 0 if OK, -ve on error + */ +int upl_add_graphics(struct upl_graphics *gra); + /** upl_init() - Set up a UPL struct */ void upl_init(struct upl *upl);

Add this information to the handoff structure so that it is available to U-Boot proper. Update bochs and the video handoff.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/pci/pci_rom.c | 3 +++ drivers/video/bochs.c | 1 + drivers/video/video-uclass.c | 1 + include/video.h | 2 ++ 4 files changed, 7 insertions(+)
diff --git a/drivers/pci/pci_rom.c b/drivers/pci/pci_rom.c index 2753df275ca..3697ad00be2 100644 --- a/drivers/pci/pci_rom.c +++ b/drivers/pci/pci_rom.c @@ -347,6 +347,7 @@ int vesa_setup_video_priv(struct vesa_mode_info *vesa, u64 fb, case 32: case 24: uc_priv->bpix = VIDEO_BPP32; + uc_priv->format = VIDEO_X8B8G8R8; break; case 16: uc_priv->bpix = VIDEO_BPP16; @@ -392,6 +393,7 @@ int vesa_setup_video(struct udevice *dev, int (*int15_handler)(void)) uc_priv->ysize = ho->ysize; uc_priv->line_length = ho->line_length; uc_priv->bpix = ho->bpix; + uc_priv->format = ho->format; } else { bootstage_start(BOOTSTAGE_ID_ACCUM_LCD, "vesa display"); ret = dm_pci_run_vga_bios(dev, int15_handler, @@ -438,6 +440,7 @@ int vesa_setup_video(struct udevice *dev, int (*int15_handler)(void)) ho->ysize = uc_priv->ysize; ho->line_length = uc_priv->line_length; ho->bpix = uc_priv->bpix; + ho->format = uc_priv->format; }
return 0; diff --git a/drivers/video/bochs.c b/drivers/video/bochs.c index 00e673a4db0..c34bc23f274 100644 --- a/drivers/video/bochs.c +++ b/drivers/video/bochs.c @@ -64,6 +64,7 @@ static int bochs_init_fb(struct udevice *dev) uc_priv->xsize = xsize; uc_priv->ysize = ysize; uc_priv->bpix = VIDEO_BPP32; + uc_priv->format = VIDEO_X8B8G8R8;
/* setup video mode */ bochs_write(mmio, INDEX_ENABLE, 0); diff --git a/drivers/video/video-uclass.c b/drivers/video/video-uclass.c index 407fb9fbe20..1e385f12f8e 100644 --- a/drivers/video/video-uclass.c +++ b/drivers/video/video-uclass.c @@ -616,6 +616,7 @@ static int video_post_probe(struct udevice *dev) ho->ysize = priv->ysize; ho->line_length = priv->line_length; ho->bpix = priv->bpix; + ho->format = priv->format; }
if (IS_ENABLED(CONFIG_VIDEO_COPY) && plat->copy_base) diff --git a/include/video.h b/include/video.h index 0d7b0d27e25..2fe2f73a865 100644 --- a/include/video.h +++ b/include/video.h @@ -161,6 +161,7 @@ struct video_ops { * set by the driver, but if not, the uclass will set it after * probing * @bpix: Encoded bits per pixel (enum video_log2_bpp) + * @format: Video format (enum video_format) */ struct video_handoff { u64 fb; @@ -169,6 +170,7 @@ struct video_handoff { u16 ysize; u32 line_length; u8 bpix; + u8 format; };
/** enum colour_idx - the 16 colors supported by consoles */

If video is enabled we expect it to work. Avoid silent failure by adding a panic if things go wrong.
Expand the SPL malloc-area for qemu-x86_64 to avoid a panic.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/x86/lib/spl.c | 9 +++++++-- configs/qemu-x86_64_defconfig | 2 +- 2 files changed, 8 insertions(+), 3 deletions(-)
diff --git a/arch/x86/lib/spl.c b/arch/x86/lib/spl.c index f761fbc8bc3..aad748532d0 100644 --- a/arch/x86/lib/spl.c +++ b/arch/x86/lib/spl.c @@ -300,9 +300,14 @@ void spl_board_init(void)
if (CONFIG_IS_ENABLED(VIDEO)) { struct udevice *dev; + int ret;
/* Set up PCI video in SPL if required */ - uclass_first_device_err(UCLASS_PCI, &dev); - uclass_first_device_err(UCLASS_VIDEO, &dev); + ret = uclass_first_device_err(UCLASS_PCI, &dev); + if (ret) + panic("Failed to set up PCI"); + ret = uclass_first_device_err(UCLASS_VIDEO, &dev); + if (ret) + panic("Failed to set up video"); } } diff --git a/configs/qemu-x86_64_defconfig b/configs/qemu-x86_64_defconfig index 39375c76227..2771a4b9e19 100644 --- a/configs/qemu-x86_64_defconfig +++ b/configs/qemu-x86_64_defconfig @@ -6,7 +6,7 @@ CONFIG_ENV_SIZE=0x40000 CONFIG_MAX_CPUS=2 CONFIG_SPL_DM_SPI=y CONFIG_DEFAULT_DEVICE_TREE="qemu-x86_i440fx" -CONFIG_SPL_SYS_MALLOC_F_LEN=0x2000 +CONFIG_SPL_SYS_MALLOC_F_LEN=0x3000 CONFIG_SPL_TEXT_BASE=0xfffd0000 CONFIG_DEBUG_UART_BASE=0x3f8 CONFIG_DEBUG_UART_CLOCK=1843200

Add a function to allow x86 boards to jump to a UPL images. Currently only 32-bit entry is supported.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/x86/lib/bootm.c | 11 +++++++++++ 1 file changed, 11 insertions(+)
diff --git a/arch/x86/lib/bootm.c b/arch/x86/lib/bootm.c index bbd8ee7870f..e7a98bf1590 100644 --- a/arch/x86/lib/bootm.c +++ b/arch/x86/lib/bootm.c @@ -283,3 +283,14 @@ int do_bootm_linux(int flag, struct bootm_info *bmi)
return boot_jump_linux(images); } + +int arch_upl_jump(ulong entry, const struct abuf *buf) +{ + typedef EFIAPI void (*h_func)(void *hoff); + h_func func; + + func = (h_func)(ulong)entry; + func(buf->data); + + return -EFAULT; +}

Add the GD_FLG_UPL so that a UPL-handoff is created.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/x86/lib/spl.c | 3 +++ 1 file changed, 3 insertions(+)
diff --git a/arch/x86/lib/spl.c b/arch/x86/lib/spl.c index aad748532d0..7a033505101 100644 --- a/arch/x86/lib/spl.c +++ b/arch/x86/lib/spl.c @@ -298,6 +298,9 @@ void spl_board_init(void) if (IS_ENABLED(CONFIG_QEMU)) qemu_chipset_init();
+ if (CONFIG_IS_ENABLED(UPL_OUT)) + gd->flags |= GD_FLG_UPL; + if (CONFIG_IS_ENABLED(VIDEO)) { struct udevice *dev; int ret;

This isn't strictly needed, but with UPL we use the reserved-memory nodes to indicate where the SMBIOS table is. Tianocore requires 4KB alignment on these regions, so it is easier to adjust the alignment to match.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/x86/lib/tables.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/arch/x86/lib/tables.c b/arch/x86/lib/tables.c index 5fc7dc75377..3978945a5ad 100644 --- a/arch/x86/lib/tables.c +++ b/arch/x86/lib/tables.c @@ -16,6 +16,7 @@ #include <asm/tables.h> #include <asm/coreboot_tables.h> #include <linux/log2.h> +#include <linux/sizes.h>
DECLARE_GLOBAL_DATA_PTR;
@@ -62,7 +63,11 @@ static struct table_info table_list[] = { { "acpi", write_acpi_tables, BLOBLISTT_ACPI_TABLES, 0x10000, 0x1000}, #endif #ifdef CONFIG_GENERATE_SMBIOS_TABLE - { "smbios", write_smbios_table, BLOBLISTT_SMBIOS_TABLES, 0x1000, 0x100}, + /* + * align this to a 4KB boundary, since UPL adds a reserved-memory node + * for it + */ + { "smbios", write_smbios_table, BLOBLISTT_SMBIOS_TABLES, SZ_4K, 0x1000}, #endif };

On 01.01.25 23:09, Simon Glass wrote:
This isn't strictly needed, but with UPL we use the reserved-memory nodes to indicate where the SMBIOS table is. Tianocore requires 4KB
Nits:
%s/4KB/4 KiB/
Cf. https://physics.nist.gov/cuu/Units/binary.html
alignment on these regions, so it is easier to adjust the alignment to match.
Signed-off-by: Simon Glass sjg@chromium.org
arch/x86/lib/tables.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/arch/x86/lib/tables.c b/arch/x86/lib/tables.c index 5fc7dc75377..3978945a5ad 100644 --- a/arch/x86/lib/tables.c +++ b/arch/x86/lib/tables.c @@ -16,6 +16,7 @@ #include <asm/tables.h> #include <asm/coreboot_tables.h> #include <linux/log2.h> +#include <linux/sizes.h>
DECLARE_GLOBAL_DATA_PTR;
@@ -62,7 +63,11 @@ static struct table_info table_list[] = { { "acpi", write_acpi_tables, BLOBLISTT_ACPI_TABLES, 0x10000, 0x1000}, #endif #ifdef CONFIG_GENERATE_SMBIOS_TABLE
- { "smbios", write_smbios_table, BLOBLISTT_SMBIOS_TABLES, 0x1000, 0x100},
- /*
* align this to a 4KB boundary, since UPL adds a reserved-memory node
* for it
*/
- { "smbios", write_smbios_table, BLOBLISTT_SMBIOS_TABLES, SZ_4K, 0x1000},
Please, avoid using once SZ_4K and once 0x1000 when expressing the same number.
If you want to go with SZ_4K, please, also change the ACPI table entry to use SZ_16K and SZ_4K to be consistent.
Best regards
Heinrich
#endif };

This requires a new oftree to be created, which is only supported if this option is enabled. Add a 'select' to ensure this.
Signed-off-by: Simon Glass sjg@chromium.org ---
boot/Kconfig | 1 + 1 file changed, 1 insertion(+)
diff --git a/boot/Kconfig b/boot/Kconfig index 705947cfa95..f9263513268 100644 --- a/boot/Kconfig +++ b/boot/Kconfig @@ -786,6 +786,7 @@ config UPL_READ
config UPL_WRITE bool "upl - Support writing a Universal Payload handoff" + select OFNODE_MULTI_TREE help Provides support for encoding a UPL-format payload from a C structure so it can be passed to another program. This is just the writing

This argument is not used so drop it.
Signed-off-by: Simon Glass sjg@chromium.org ---
common/spl/spl.c | 2 +- common/spl/spl_upl.c | 2 +- include/spl.h | 3 +-- 3 files changed, 3 insertions(+), 4 deletions(-)
diff --git a/common/spl/spl.c b/common/spl/spl.c index 1ceb63daf31..46360ec4408 100644 --- a/common/spl/spl.c +++ b/common/spl/spl.c @@ -809,7 +809,7 @@ void board_init_r(gd_t *dummy1, ulong dummy2) "SPL hand-off write failed (err=%d)\n", ret); } if (CONFIG_IS_ENABLED(UPL_OUT) && (gd->flags & GD_FLG_UPL)) { - ret = spl_write_upl_handoff(&spl_image); + ret = spl_write_upl_handoff(); if (ret) { printf(PHASE_PROMPT "UPL hand-off write failed (err=%d)\n", ret); diff --git a/common/spl/spl_upl.c b/common/spl/spl_upl.c index 5c68e4ab283..32c8ea62ef3 100644 --- a/common/spl/spl_upl.c +++ b/common/spl/spl_upl.c @@ -51,7 +51,7 @@ int _upl_add_image(int node, ulong load_addr, ulong size, const char *desc) return 0; }
-int spl_write_upl_handoff(struct spl_image_info *spl_image) +int spl_write_upl_handoff(void) { struct upl *upl = &s_upl; struct abuf buf; diff --git a/include/spl.h b/include/spl.h index 269e36bb441..137deb18d5e 100644 --- a/include/spl.h +++ b/include/spl.h @@ -1101,10 +1101,9 @@ static inline bool spl_decompression_enabled(void) /** * spl_write_upl_handoff() - Write a Universal Payload hand-off structure * - * @spl_image: Information about the image being booted * Return: 0 if OK, -ve on error */ -int spl_write_upl_handoff(struct spl_image_info *spl_image); +int spl_write_upl_handoff(void);
/** * spl_upl_init() - Get UPL ready for information to be added

Enable creation of a UPL handdoff in U-Boot proper, so that the next-stage firmware can be called.
Signed-off-by: Simon Glass sjg@chromium.org ---
configs/qemu-x86_64_defconfig | 3 +++ configs/qemu-x86_defconfig | 2 ++ 2 files changed, 5 insertions(+)
diff --git a/configs/qemu-x86_64_defconfig b/configs/qemu-x86_64_defconfig index 2771a4b9e19..003af54498b 100644 --- a/configs/qemu-x86_64_defconfig +++ b/configs/qemu-x86_64_defconfig @@ -22,6 +22,9 @@ CONFIG_SYS_MONITOR_BASE=0x01110000 CONFIG_FIT=y CONFIG_SPL_LOAD_FIT=y CONFIG_BOOTSTD_FULL=y +CONFIG_UPL=y +CONFIG_UPL_IN=y +# CONFIG_SPL_UPL_OUT is not set CONFIG_BOOTSTAGE=y CONFIG_BOOTSTAGE_REPORT=y CONFIG_SHOW_BOOT_PROGRESS=y diff --git a/configs/qemu-x86_defconfig b/configs/qemu-x86_defconfig index 947d15cd727..5183117854c 100644 --- a/configs/qemu-x86_defconfig +++ b/configs/qemu-x86_defconfig @@ -13,6 +13,8 @@ CONFIG_GENERATE_PIRQ_TABLE=y CONFIG_GENERATE_MP_TABLE=y CONFIG_FIT=y CONFIG_BOOTSTD_FULL=y +CONFIG_UPL=y +CONFIG_UPL_IN=y CONFIG_BOOTSTAGE=y CONFIG_BOOTSTAGE_REPORT=y CONFIG_SHOW_BOOT_PROGRESS=y

Reword the function comment for clarity and correct the test for no records.
Signed-off-by: Simon Glass sjg@chromium.org ---
boot/upl_write.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/boot/upl_write.c b/boot/upl_write.c index 25ec6992573..b2e9ae85712 100644 --- a/boot/upl_write.c +++ b/boot/upl_write.c @@ -401,7 +401,7 @@ static int add_upl_memmap(const struct upl *upl, ofnode root) }
/** - * add_upl_memres() - Add /memory-reserved nodes to the tree + * add_upl_memres() - Add /reserved-memory nodes to the tree * * @upl: UPL state * @root: Parent node to contain the new node @@ -413,7 +413,7 @@ static int add_upl_memres(const struct upl *upl, ofnode root, ofnode mem_node; int i, ret;
- if (!upl->memmap.count) + if (!upl->memres.count) return 0; ret = ofnode_add_subnode(root, UPLN_MEMORY_RESERVED, &mem_node); if (ret) {

This node should have tags indicating the size of the addresses it uses.
The existing add_root_props() function only serves to add these tags to a node. Rename it and allow passing the target-node to the function.
Use this to add nodes to the root and reserved-memory nodes.
Signed-off-by: Simon Glass sjg@chromium.org ---
boot/upl_write.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-)
diff --git a/boot/upl_write.c b/boot/upl_write.c index b2e9ae85712..60548937090 100644 --- a/boot/upl_write.c +++ b/boot/upl_write.c @@ -144,18 +144,18 @@ static int ofnode_write_value(ofnode node, const char *prop, }
/** - * add_root_props() - Add root properties to the tree + * add_addr_size_cells() - Add #address/#size-cells properties to the tree * * @node: Node to add to * Return 0 if OK, -ve on error */ -static int add_root_props(const struct upl *upl, ofnode node) +static int add_addr_size_cells(ofnode node, int addr_cells, int size_cells) { int ret;
- ret = ofnode_write_u32(node, UPLP_ADDRESS_CELLS, upl->addr_cells); + ret = ofnode_write_u32(node, UPLP_ADDRESS_CELLS, addr_cells); if (!ret) - ret = ofnode_write_u32(node, UPLP_SIZE_CELLS, upl->size_cells); + ret = ofnode_write_u32(node, UPLP_SIZE_CELLS, size_cells); if (ret) return log_msg_ret("cel", ret);
@@ -421,6 +421,9 @@ static int add_upl_memres(const struct upl *upl, ofnode root, return 0; return log_msg_ret("img", ret); } + ret = add_addr_size_cells(mem_node, upl->addr_cells, upl->size_cells); + if (ret) + return log_msg_ret("im2", ret);
for (i = 0; i < upl->memres.count; i++) { const struct upl_memres *memres = alist_get(&upl->memres, i, @@ -562,7 +565,7 @@ int upl_write_handoff(const struct upl *upl, ofnode root, bool skip_existing) ofnode options; int ret;
- ret = add_root_props(upl, root); + ret = add_addr_size_cells(root, upl->addr_cells, upl->size_cells); if (ret) return log_msg_ret("ad1", ret); ret = ofnode_add_subnode(root, UPLN_OPTIONS, &options);

The framebuffer address and size will be needed for the reserved-memory section, so return them to the caller.
Signed-off-by: Simon Glass sjg@chromium.org ---
boot/upl_common.c | 4 +++- common/spl/spl_upl.c | 3 ++- include/upl.h | 7 ++++++- 3 files changed, 11 insertions(+), 3 deletions(-)
diff --git a/boot/upl_common.c b/boot/upl_common.c index a0ed5568854..01301049341 100644 --- a/boot/upl_common.c +++ b/boot/upl_common.c @@ -87,7 +87,7 @@ int upl_add_serial(struct upl_serial *ser) return 0; }
-int upl_add_graphics(struct upl_graphics *gra) +int upl_add_graphics(struct upl_graphics *gra, ulong *basep, ulong *sizep) { struct video_uc_plat *plat; struct video_priv *priv; @@ -101,6 +101,8 @@ int upl_add_graphics(struct upl_graphics *gra) plat = dev_get_uclass_plat(dev); region.base = plat->base; region.size = plat->size; + *basep = plat->base; + *sizep = plat->size; if (!alist_add(&gra->reg, region)) return log_msg_ret("reg", -ENOMEM);
diff --git a/common/spl/spl_upl.c b/common/spl/spl_upl.c index 32c8ea62ef3..a78ae75e56c 100644 --- a/common/spl/spl_upl.c +++ b/common/spl/spl_upl.c @@ -54,6 +54,7 @@ int _upl_add_image(int node, ulong load_addr, ulong size, const char *desc) int spl_write_upl_handoff(void) { struct upl *upl = &s_upl; + ulong addr, size; struct abuf buf; ofnode root; void *ptr; @@ -66,7 +67,7 @@ int spl_write_upl_handoff(void) ret = upl_add_serial(&upl->serial); if (ret) return log_msg_ret("ser", ret); - ret = upl_add_graphics(&upl->graphics); + ret = upl_add_graphics(&upl->graphics, &addr, &size); if (ret && ret != -ENOENT) return log_msg_ret("gra", ret);
diff --git a/include/upl.h b/include/upl.h index e415130d44f..edd333f648a 100644 --- a/include/upl.h +++ b/include/upl.h @@ -226,6 +226,8 @@ enum upl_graphics_format { };
/** + * struct upl_graphics - Information about graphics display + * * @reg: List of base address and size of registers (struct memregion) * @width: Width of display in pixels * @height: Height of display in pixels @@ -385,9 +387,12 @@ int upl_add_serial(struct upl_serial *ser); * * Writes details about the current video device to the UPL struct * + * @gra: Struct to fill in + * @basep: Returns base address of framebuffer + * @sizep: Returns size of framebuffer * Return: 0 if OK, -ve on error */ -int upl_add_graphics(struct upl_graphics *gra); +int upl_add_graphics(struct upl_graphics *gra, ulong *basep, ulong *sizep);
/** upl_init() - Set up a UPL struct */ void upl_init(struct upl *upl);

Create a convenience function which can write a UPL handoff into an abuf and return it.
Signed-off-by: Simon Glass sjg@chromium.org ---
boot/upl_common.c | 48 ++++++++++++++++++++++++++++++++++++++++++++ boot/upl_write.c | 28 ++++++++++++++++++++++++++ common/spl/spl_upl.c | 26 ++++-------------------- include/upl.h | 23 +++++++++++++++++++++ 4 files changed, 103 insertions(+), 22 deletions(-)
diff --git a/boot/upl_common.c b/boot/upl_common.c index 01301049341..b0246f72597 100644 --- a/boot/upl_common.c +++ b/boot/upl_common.c @@ -8,6 +8,7 @@
#define LOG_CATEGORY UCLASS_BOOTSTD
+#include <cpu.h> #include <dm.h> #include <serial.h> #include <string.h> @@ -130,6 +131,53 @@ int upl_add_graphics(struct upl_graphics *gra, ulong *basep, ulong *sizep) return 0; }
+int upl_create(struct upl *upl) +{ + ulong base, size; + int ret; + + /* hard-code this for now to keep Tianocore happy */ + upl->addr_cells = 2; + upl->size_cells = 1; + + upl->bootmode = 0; + log_debug("conf_offset %d\n", upl->conf_offset); + if (IS_ENABLED(CONFIG_X86)) + upl->addr_width = cpu_phys_address_size(); + + /* no reserved memory */ + + ret = upl_add_serial(&upl->serial); + if (ret && ret != -ENOENT) + return log_msg_ret("ser", ret); + ret = upl_add_graphics(&upl->graphics, &base, &size); + if (ret && ret != -ENOENT) + return log_msg_ret("gra", ret); + + return 0; +} + +int upl_write_to_buf(struct upl *upl, ofnode root, struct abuf *buf) +{ + int ret; + + ret = upl_create(upl); + if (ret) + return log_msg_ret("uwr", ret); + + log_debug("writing to root node %d\n", ofnode_to_offset(root)); + ret = upl_write_handoff(upl, root, true); + if (ret) + return log_msg_ret("wr", ret); + + ret = oftree_to_fdt(oftree_default(), buf); + if (ret) + return log_msg_ret("fdt", ret); + log_debug("FDT size %zx\n", abuf_size(buf)); + + return 0; +} + void upl_init(struct upl *upl) { memset(upl, '\0', sizeof(struct upl)); diff --git a/boot/upl_write.c b/boot/upl_write.c index 60548937090..c53fa5396e8 100644 --- a/boot/upl_write.c +++ b/boot/upl_write.c @@ -625,3 +625,31 @@ int upl_create_handoff_tree(const struct upl *upl, oftree *treep)
return 0; } + +int upl_create_handoff(struct upl *upl, ulong addr, struct abuf *buf) +{ + oftree tree; + int ret; + + ret = upl_create(upl); + if (ret) { + log_debug("Failed to create handoff (err=%dE)\n", ret); + return log_msg_ret("cho", ret); + } + log_debug("2a images %d\n", upl->image.count); + + ret = oftree_new(&tree); + if (ret) + return log_msg_ret("new", ret); + + ret = upl_write_handoff(upl, oftree_root(tree), true); + if (ret) + return log_msg_ret("wr", ret); + + ret = oftree_to_fdt(tree, buf); + if (ret) + return log_msg_ret("fdt", ret); + oftree_dispose(tree); + + return 0; +} diff --git a/common/spl/spl_upl.c b/common/spl/spl_upl.c index a78ae75e56c..2bc0e265661 100644 --- a/common/spl/spl_upl.c +++ b/common/spl/spl_upl.c @@ -15,8 +15,6 @@ #include <spl.h> #include <upl.h>
-DECLARE_GLOBAL_DATA_PTR; - struct upl s_upl;
void upl_set_fit_addr(ulong fit) @@ -53,38 +51,22 @@ int _upl_add_image(int node, ulong load_addr, ulong size, const char *desc)
int spl_write_upl_handoff(void) { - struct upl *upl = &s_upl; - ulong addr, size; + struct upl s_upl, *upl = &s_upl; struct abuf buf; - ofnode root; void *ptr; int ret;
log_debug("UPL: Writing handoff - image_count=%d\n", upl->image.count); - upl->addr_cells = IS_ENABLED(CONFIG_PHYS_64BIT) ? 2 : 1; - upl->size_cells = IS_ENABLED(CONFIG_PHYS_64BIT) ? 2 : 1; - upl->bootmode = UPLBM_DEFAULT; - ret = upl_add_serial(&upl->serial); - if (ret) - return log_msg_ret("ser", ret); - ret = upl_add_graphics(&upl->graphics, &addr, &size); - if (ret && ret != -ENOENT) - return log_msg_ret("gra", ret); - - root = ofnode_root(); - ret = upl_write_handoff(upl, root, true); - if (ret) - return log_msg_ret("wr", ret);
- ret = oftree_to_fdt(oftree_default(), &buf); + ret = upl_write_to_buf(upl, ofnode_root(), &buf); if (ret) - return log_msg_ret("fdt", ret); - log_debug("FDT size %zx\n", abuf_size(&buf)); + return log_msg_ret("wuh", ret);
ptr = bloblist_add(BLOBLISTT_CONTROL_FDT, abuf_size(&buf), 0); if (!ptr) return log_msg_ret("blo", -ENOENT); memcpy(ptr, abuf_data(&buf), abuf_size(&buf)); + abuf_uninit(&buf);
return 0; } diff --git a/include/upl.h b/include/upl.h index edd333f648a..ce357d16ebe 100644 --- a/include/upl.h +++ b/include/upl.h @@ -394,6 +394,29 @@ int upl_add_serial(struct upl_serial *ser); */ int upl_add_graphics(struct upl_graphics *gra, ulong *basep, ulong *sizep);
+/** + * upl_create() - Create a basic UPL handoff structure + * + * Sets up common fields which don't depend on having a FIT available + * + * @upl: UPL structure to create + * Return: 0 if OK, -ve on error + */ +int upl_create(struct upl *upl); + +#ifndef USE_HOSTCC +/** + * upl_write_to_buf() - Write a UPL struct to a tree then flatten it into a buf + * + * @upl: UPL struct to fill up + * @root: Root node to write UPL information to (this is updated before the + * finally buffer is written) + * @buf: Buffer to contain the final flattened tree + * Return: 0 if OK, -ve on error + */ +int upl_write_to_buf(struct upl *upl, ofnode root, struct abuf *buf); +#endif + /** upl_init() - Set up a UPL struct */ void upl_init(struct upl *upl);

With 32-bit machines sometimes a 64-bit address needs to be provided. For example, ISA I/O access is indicated by setting bit 32 of the base address.
Update the existing type to use 64 bits and drop the 0x prefix on unit addresses.
Fix a 'nennap' typo while here.
Signed-off-by: Simon Glass sjg@chromium.org ---
boot/upl_write.c | 6 +++--- include/upl.h | 7 ++++--- 2 files changed, 7 insertions(+), 6 deletions(-)
diff --git a/boot/upl_write.c b/boot/upl_write.c index c53fa5396e8..c2bb3187803 100644 --- a/boot/upl_write.c +++ b/boot/upl_write.c @@ -315,7 +315,7 @@ static int write_mem_node(const struct upl *upl, ofnode parent, return log_msg_ret("reg", -EINVAL); } first = alist_get(mem, 0, struct memregion); - sprintf(name, "%s@0x%lx", leaf, first->base); + sprintf(name, "%s@%llx", leaf, first->base); ret = ofnode_add_subnode(parent, name, &node); if (ret) return log_msg_ret("wmn", ret); @@ -466,7 +466,7 @@ static int add_upl_serial(const struct upl *upl, ofnode root, if (!ser->reg.count) return log_msg_ret("ser", -EINVAL); first = alist_get(&ser->reg, 0, struct memregion); - sprintf(name, UPLN_SERIAL "@0x%lx", first->base); + sprintf(name, UPLN_SERIAL "@%llx", first->base); ret = ofnode_add_subnode(root, name, &node); if (ret) return log_msg_ret("img", ret); @@ -526,7 +526,7 @@ static int add_upl_graphics(const struct upl *upl, ofnode root) if (!gra->reg.count) return log_msg_ret("gra", -ENOENT); first = alist_get(&gra->reg, 0, struct memregion); - sprintf(name, UPLN_GRAPHICS "@0x%lx", first->base); + sprintf(name, UPLN_GRAPHICS "@%llx", first->base); ret = ofnode_add_subnode(root, name, &node); if (ret) return log_msg_ret("gra", ret); diff --git a/include/upl.h b/include/upl.h index ce357d16ebe..aef23ad8e8e 100644 --- a/include/upl.h +++ b/include/upl.h @@ -14,6 +14,7 @@ #include <alist.h> #include <image.h> #include <dm/ofnode_decl.h> +#include <asm/types.h>
struct unit_test_state;
@@ -111,7 +112,7 @@ struct upl_image { * @size: Size in bytes */ struct memregion { - ulong base; + u64 base; ulong size; };
@@ -254,8 +255,8 @@ struct upl_graphics { * @acpi_nvs_size: Size of the ACPI non-volatile-storage area in bytes * @image: Information about each image (struct upl_image) * @mem: Information about physical-memory regions (struct upl_mem) - * @nennap: Information about logical-memory regions (struct upl_memmap) - * @nennap: Information about reserved-memory regions (struct upl_memres) + * @menmap: Information about logical-memory regions (struct upl_memmap) + * @memres: Information about reserved-memory regions (struct upl_memres) */ struct upl { int addr_cells;

The convention is to set bit 32 to indicate an I/O access. Do this when using an ISA serial port.
Signed-off-by: Simon Glass sjg@chromium.org ---
boot/upl_common.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-)
diff --git a/boot/upl_common.c b/boot/upl_common.c index b0246f72597..a5a1da9cb57 100644 --- a/boot/upl_common.c +++ b/boot/upl_common.c @@ -62,7 +62,7 @@ int upl_add_serial(struct upl_serial *ser) { struct udevice *dev = gd->cur_serial_dev; struct serial_device_info info; - struct memregion region; + u64 addr; int ret;
if (!dev) @@ -74,10 +74,13 @@ int upl_add_serial(struct upl_serial *ser) ser->compatible = ofnode_read_string(dev_ofnode(dev), "compatible"); ser->clock_frequency = info.clock; ser->current_speed = info.baudrate; - region.base = info.addr; - region.size = info.size; - if (!alist_add(&ser->reg, region)) - return -ENOMEM; + + /* Set bit 32 of the address if using I/O */ + addr = info.addr; + if (info.addr_space == SERIAL_ADDRESS_SPACE_IO) + addr |= BIT_ULL(32); + ret = upl_add_region(&ser->reg, addr, info.size); + ser->reg_io_shift = info.reg_shift; ser->reg_offset = info.reg_offset; ser->reg_io_width = info.reg_width;

Indicate the address and size of RAM in the UPL handoff.
Signed-off-by: Simon Glass sjg@chromium.org ---
boot/upl_common.c | 22 +++++++++++++++++++++- include/upl.h | 12 ++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-)
diff --git a/boot/upl_common.c b/boot/upl_common.c index a5a1da9cb57..e60f22f47e0 100644 --- a/boot/upl_common.c +++ b/boot/upl_common.c @@ -136,6 +136,7 @@ int upl_add_graphics(struct upl_graphics *gra, ulong *basep, ulong *sizep)
int upl_create(struct upl *upl) { + struct upl_mem mem; ulong base, size; int ret;
@@ -148,7 +149,14 @@ int upl_create(struct upl *upl) if (IS_ENABLED(CONFIG_X86)) upl->addr_width = cpu_phys_address_size();
- /* no reserved memory */ + memset(&mem, '\0', sizeof(mem)); + alist_init_struct(&mem.region, struct memregion); + + ret = upl_add_region(&mem.region, gd->ram_base, gd->ram_size); + if (ret) + return log_msg_ret("uar", ret); + if (!alist_add(&upl->mem, mem)) + return log_msg_ret("arg", -ENOMEM);
ret = upl_add_serial(&upl->serial); if (ret && ret != -ENOENT) @@ -181,6 +189,18 @@ int upl_write_to_buf(struct upl *upl, ofnode root, struct abuf *buf) return 0; }
+int upl_add_region(struct alist *lst, u64 base, ulong size) +{ + struct memregion region; + + region.base = base; + region.size = size; + if (!alist_add(lst, region)) + return log_msg_ret("uar", -ENOMEM); + + return 0; +} + void upl_init(struct upl *upl) { memset(upl, '\0', sizeof(struct upl)); diff --git a/include/upl.h b/include/upl.h index aef23ad8e8e..5ddcd990de4 100644 --- a/include/upl.h +++ b/include/upl.h @@ -416,6 +416,18 @@ int upl_create(struct upl *upl); * Return: 0 if OK, -ve on error */ int upl_write_to_buf(struct upl *upl, ofnode root, struct abuf *buf); + +/** + * upl_add_region() - Add a region to a memory-region list + * + * Adds a new entry to the end of a list + * + * @lst: List to add to (struct memregion) + * @base: Base address of new region + * @size: Size of new region + * Return: 0 if OK, -ve on error + */ +int upl_add_region(struct alist *lst, u64 base, ulong size); #endif
/** upl_init() - Set up a UPL struct */

The latest UPL spec uses a compatible string for this node rather than relying just on the node's name to indicate its purpose. Add one.
Signed-off-by: Simon Glass sjg@chromium.org ---
boot/upl_write.c | 4 +++- include/upl.h | 1 + 2 files changed, 4 insertions(+), 1 deletion(-)
diff --git a/boot/upl_write.c b/boot/upl_write.c index c2bb3187803..c29848a9ce3 100644 --- a/boot/upl_write.c +++ b/boot/upl_write.c @@ -178,7 +178,9 @@ static int add_upl_params(const struct upl *upl, ofnode options) if (ret) return log_msg_ret("img", ret);
- ret = write_addr(upl, node, UPLP_SMBIOS, upl->smbios); + ret = ofnode_write_string(node, "compatible", UPLP_UPL_PARAMS_COMPAT); + if (!ret) + ret = write_addr(upl, node, UPLP_SMBIOS, upl->smbios); if (!ret) ret = write_addr(upl, node, UPLP_ACPI, upl->acpi); if (!ret && upl->bootmode) diff --git a/include/upl.h b/include/upl.h index 5ddcd990de4..a4ed24edbb8 100644 --- a/include/upl.h +++ b/include/upl.h @@ -23,6 +23,7 @@ struct unit_test_state;
#define UPLN_OPTIONS "options" #define UPLN_UPL_PARAMS "upl-params" +#define UPLP_UPL_PARAMS_COMPAT "upl" #define UPLP_SMBIOS "smbios" #define UPLP_ACPI "acpi" #define UPLP_BOOTMODE "bootmode"

Move this function higher in the file so that it can later be used by add_upl_params()
Name the functions encode_reg() to better fit with the naming of the equivalent upl_read functions.
Signed-off-by: Simon Glass sjg@chromium.org ---
boot/upl_write.c | 90 ++++++++++++++++++++++++------------------------ 1 file changed, 45 insertions(+), 45 deletions(-)
diff --git a/boot/upl_write.c b/boot/upl_write.c index c29848a9ce3..eed84832a42 100644 --- a/boot/upl_write.c +++ b/boot/upl_write.c @@ -143,6 +143,48 @@ static int ofnode_write_value(ofnode node, const char *prop, return 0; }
+/** + * encode_reg() - Generate a set of addr/size pairs + * + * Each base/size value from each region is written to the buffer in a suitable + * format to be written to the devicetree + * + * @upl: UPL state + * @buf: Buffer to write to + * @size: Buffer size + * @num_regions: Number of regions to process + * @region: List of regions to process (struct memregion) + * Returns: Number of bytes written, or -ENOSPC if the buffer is too small + */ +static int encode_reg(const struct upl *upl, char *buf, int size, + uint num_regions, const struct alist *region) +{ + char *ptr, *end = buf + size; + int i; + + ptr = buf; + for (i = 0; i < num_regions; i++) { + const struct memregion *reg = alist_get(region, i, + struct memregion); + + if (upl->addr_cells == 1) + *(u32 *)ptr = cpu_to_fdt32(reg->base); + else + *(u64 *)ptr = cpu_to_fdt64(reg->base); + ptr += upl->addr_cells * sizeof(u32); + + if (upl->size_cells == 1) + *(u32 *)ptr = cpu_to_fdt32(reg->size); + else + *(u64 *)ptr = cpu_to_fdt64(reg->size); + ptr += upl->size_cells * sizeof(u32); + if (ptr > end) + return log_msg_ret("uer", -ENOSPC); + } + + return ptr - buf; +} + /** * add_addr_size_cells() - Add #address/#size-cells properties to the tree * @@ -247,48 +289,6 @@ static int add_upl_image(const struct upl *upl, ofnode options) return 0; }
-/** - * buffer_addr_size() - Generate a set of addr/size pairs - * - * Each base/size value from each region is written to the buffer in a suitable - * format to be written to the devicetree - * - * @upl: UPL state - * @buf: Buffer to write to - * @size: Buffer size - * @num_regions: Number of regions to process - * @region: List of regions to process (struct memregion) - * Returns: Number of bytes written, or -ENOSPC if the buffer is too small - */ -static int buffer_addr_size(const struct upl *upl, char *buf, int size, - uint num_regions, const struct alist *region) -{ - char *ptr, *end = buf + size; - int i; - - ptr = buf; - for (i = 0; i < num_regions; i++) { - const struct memregion *reg = alist_get(region, i, - struct memregion); - - if (upl->addr_cells == 1) - *(u32 *)ptr = cpu_to_fdt32(reg->base); - else - *(u64 *)ptr = cpu_to_fdt64(reg->base); - ptr += upl->addr_cells * sizeof(u32); - - if (upl->size_cells == 1) - *(u32 *)ptr = cpu_to_fdt32(reg->size); - else - *(u64 *)ptr = cpu_to_fdt64(reg->size); - ptr += upl->size_cells * sizeof(u32); - if (ptr > end) - return -ENOSPC; - } - - return ptr - buf; -} - /** * write_mem_node() - Write a memory node and reg property * @@ -322,7 +322,7 @@ static int write_mem_node(const struct upl *upl, ofnode parent, if (ret) return log_msg_ret("wmn", ret);
- len = buffer_addr_size(upl, buf, sizeof(buf), mem->count, mem); + len = encode_reg(upl, buf, sizeof(buf), mem->count, mem); ret = ofnode_write_prop(node, UPLP_REG, buf, len, true); if (ret) return log_msg_ret("wm1", ret); @@ -483,7 +483,7 @@ static int add_upl_serial(const struct upl *upl, ofnode root, char buf[16]; int len;
- len = buffer_addr_size(upl, buf, sizeof(buf), 1, &ser->reg); + len = encode_reg(upl, buf, sizeof(buf), 1, &ser->reg); if (len < 0) return log_msg_ret("buf", len);
@@ -538,7 +538,7 @@ static int add_upl_graphics(const struct upl *upl, ofnode root) char buf[16]; int len;
- len = buffer_addr_size(upl, buf, sizeof(buf), 1, &gra->reg); + len = encode_reg(upl, buf, sizeof(buf), 1, &gra->reg); if (len < 0) return log_msg_ret("buf", len);

This function performs the same operation on each list element. Move this processing into a separate function so that it can be called without an alist
Signed-off-by: Simon Glass sjg@chromium.org ---
boot/upl_write.c | 54 ++++++++++++++++++++++++++++++++++++------------ 1 file changed, 41 insertions(+), 13 deletions(-)
diff --git a/boot/upl_write.c b/boot/upl_write.c index eed84832a42..a1ecb809cbc 100644 --- a/boot/upl_write.c +++ b/boot/upl_write.c @@ -143,6 +143,42 @@ static int ofnode_write_value(ofnode node, const char *prop, return 0; }
+/** + * encode_addr_size() - Write an address/size pair + * + * Writes an address and size into a buffer suitable for placing in a devicetree + * 'reg' property. This uses upl->addr/size_cells to determine the number of + * cells for each value + * + * @upl: UPL state + * @buf: Buffer to write to + * @size: Buffer size in bytes + * @reg: Region to process + * Returns: Number of bytes written, or -ENOSPC if the buffer is too small + */ +static int encode_addr_size(const struct upl *upl, char *buf, uint size, + const struct memregion *reg) +{ + char *ptr = buf; + + if (sizeof(fdt32_t) * (upl->addr_cells + upl->size_cells) > size) + return log_msg_ret("eas", -ENOSPC); + + if (upl->addr_cells == 1) + *(u32 *)ptr = cpu_to_fdt32(reg->base); + else + *(u64 *)ptr = cpu_to_fdt64(reg->base); + ptr += upl->addr_cells * sizeof(u32); + + if (upl->size_cells == 1) + *(u32 *)ptr = cpu_to_fdt32(reg->size); + else + *(u64 *)ptr = cpu_to_fdt64(reg->size); + ptr += upl->size_cells * sizeof(u32); + + return ptr - buf; +} + /** * encode_reg() - Generate a set of addr/size pairs * @@ -166,20 +202,12 @@ static int encode_reg(const struct upl *upl, char *buf, int size, for (i = 0; i < num_regions; i++) { const struct memregion *reg = alist_get(region, i, struct memregion); + int ret;
- if (upl->addr_cells == 1) - *(u32 *)ptr = cpu_to_fdt32(reg->base); - else - *(u64 *)ptr = cpu_to_fdt64(reg->base); - ptr += upl->addr_cells * sizeof(u32); - - if (upl->size_cells == 1) - *(u32 *)ptr = cpu_to_fdt32(reg->size); - else - *(u64 *)ptr = cpu_to_fdt64(reg->size); - ptr += upl->size_cells * sizeof(u32); - if (ptr > end) - return log_msg_ret("uer", -ENOSPC); + ret = encode_addr_size(upl, ptr, end - ptr, reg); + if (ret < 0) + return log_msg_ret("uer", ret); + ptr += ret; }
return ptr - buf;

Move this function higher in the file so that it can later be used by decode_upl_params()
Name the functions decode_reg() since it operates on an entire 'reg' property.
Signed-off-by: Simon Glass sjg@chromium.org ---
boot/upl_read.c | 96 ++++++++++++++++++++++++------------------------- 1 file changed, 48 insertions(+), 48 deletions(-)
diff --git a/boot/upl_read.c b/boot/upl_read.c index be3e1d116e1..bf5aa8f785c 100644 --- a/boot/upl_read.c +++ b/boot/upl_read.c @@ -172,6 +172,49 @@ static int read_uint(ofnode node, const char *prop, uint *valp) return 0; }
+/** + * decode_reg() - Decide a set of addr/size pairs + * + * Each base/size value from the devicetree is written to the region list + * + * @upl: UPL state + * @buf: Bytes to decode + * @size: Number of bytes to decode + * @regions: List of regions to process (struct memregion) + * Returns: number of regions found, if OK, else -ve on error + */ +static int decode_reg(const struct upl *upl, const char *buf, int size, + struct alist *regions) +{ + const char *ptr, *end = buf + size; + int i; + + alist_init_struct(regions, struct memregion); + ptr = buf; + for (i = 0; ptr < end; i++) { + struct memregion reg; + + if (upl->addr_cells == 1) + reg.base = fdt32_to_cpu(*(u32 *)ptr); + else + reg.base = fdt64_to_cpu(*(u64 *)ptr); + ptr += upl->addr_cells * sizeof(u32); + + if (upl->size_cells == 1) + reg.size = fdt32_to_cpu(*(u32 *)ptr); + else + reg.size = fdt64_to_cpu(*(u64 *)ptr); + ptr += upl->size_cells * sizeof(u32); + if (ptr > end) + return -ENOSPC; + + if (!alist_add(regions, reg)) + return log_msg_ret("reg", -ENOMEM); + } + + return i; +} + /** * decode_root_props() - Decode root properties from the tree * @@ -269,49 +312,6 @@ static int decode_upl_images(struct upl *upl, ofnode options) return 0; }
-/** - * decode_addr_size() - Decide a set of addr/size pairs - * - * Each base/size value from the devicetree is written to the region list - * - * @upl: UPL state - * @buf: Bytes to decode - * @size: Number of bytes to decode - * @regions: List of regions to process (struct memregion) - * Returns: number of regions found, if OK, else -ve on error - */ -static int decode_addr_size(const struct upl *upl, const char *buf, int size, - struct alist *regions) -{ - const char *ptr, *end = buf + size; - int i; - - alist_init_struct(regions, struct memregion); - ptr = buf; - for (i = 0; ptr < end; i++) { - struct memregion reg; - - if (upl->addr_cells == 1) - reg.base = fdt32_to_cpu(*(u32 *)ptr); - else - reg.base = fdt64_to_cpu(*(u64 *)ptr); - ptr += upl->addr_cells * sizeof(u32); - - if (upl->size_cells == 1) - reg.size = fdt32_to_cpu(*(u32 *)ptr); - else - reg.size = fdt64_to_cpu(*(u64 *)ptr); - ptr += upl->size_cells * sizeof(u32); - if (ptr > end) - return -ENOSPC; - - if (!alist_add(regions, reg)) - return log_msg_ret("reg", -ENOMEM); - } - - return i; -} - /** * node_matches_at() - Check if a node name matches "base@..." * @@ -345,7 +345,7 @@ static int decode_upl_memory_node(struct upl *upl, ofnode node) ofnode_get_name(node), UPLP_REG); return log_msg_ret("reg", -EINVAL); } - len = decode_addr_size(upl, buf, size, &mem.region); + len = decode_reg(upl, buf, size, &mem.region); if (len < 0) return log_msg_ret("buf", len); mem.hotpluggable = ofnode_read_bool(node, UPLP_HOTPLUGGABLE); @@ -381,7 +381,7 @@ static int decode_upl_memmap(struct upl *upl, ofnode root) continue; }
- len = decode_addr_size(upl, buf, size, &memmap.region); + len = decode_reg(upl, buf, size, &memmap.region); if (len < 0) return log_msg_ret("buf", len); ret = ofnode_read_bitmask(node, UPLP_USAGE, usage_names, @@ -422,7 +422,7 @@ static int decode_upl_memres(struct upl *upl, ofnode root) continue; }
- len = decode_addr_size(upl, buf, size, &memres.region); + len = decode_reg(upl, buf, size, &memres.region); if (len < 0) return log_msg_ret("buf", len); memres.no_map = ofnode_read_bool(node, UPLP_NO_MAP); @@ -467,7 +467,7 @@ static int decode_upl_serial(struct upl *upl, ofnode node) return log_msg_ret("reg", -EINVAL); }
- len = decode_addr_size(upl, buf, sizeof(buf), &ser->reg); + len = decode_reg(upl, buf, sizeof(buf), &ser->reg); if (len < 0) return log_msg_ret("buf", len);
@@ -520,7 +520,7 @@ static int decode_upl_graphics(struct upl *upl, ofnode node) return log_msg_ret("reg", -EINVAL); }
- len = decode_addr_size(upl, buf, size, &gra->reg); + len = decode_reg(upl, buf, size, &gra->reg); if (len < 0) return log_msg_ret("buf", len);

This function performs the same operation on each reg element. Move this processing into a separate function so that it can be called without an alist
Signed-off-by: Simon Glass sjg@chromium.org ---
boot/upl_read.c | 55 +++++++++++++++++++++++++++++++++++++------------ 1 file changed, 42 insertions(+), 13 deletions(-)
diff --git a/boot/upl_read.c b/boot/upl_read.c index bf5aa8f785c..fe48ae31ffb 100644 --- a/boot/upl_read.c +++ b/boot/upl_read.c @@ -172,6 +172,42 @@ static int read_uint(ofnode node, const char *prop, uint *valp) return 0; }
+/** + * decode_addr_size() - Read an address/size pair + * + * Reads an address and size from a buffer containing a devicetree 'reg' + * property. This uses upl->addr/size_cells to determine the number of cells for + * each value + * + * @upl: UPL state + * @buf: Buffer to read from + * @size: Buffer size in bytes + * @reg: Region to process + * Returns: Number of bytes written, or -ENOSPC if the buffer is too small + */ +static int decode_addr_size(const struct upl *upl, const char *buf, uint size, + struct memregion *reg) +{ + const char *ptr = buf; + + if (sizeof(fdt32_t) * (upl->addr_cells + upl->size_cells) > size) + return log_msg_ret("was", -ENOSPC); + + if (upl->addr_cells == 1) + reg->base = fdt32_to_cpu(*(u32 *)ptr); + else + reg->base = fdt64_to_cpu(*(u64 *)ptr); + ptr += upl->addr_cells * sizeof(u32); + + if (upl->size_cells == 1) + reg->size = fdt32_to_cpu(*(u32 *)ptr); + else + reg->size = fdt64_to_cpu(*(u64 *)ptr); + ptr += upl->size_cells * sizeof(u32); + + return ptr - buf; +} + /** * decode_reg() - Decide a set of addr/size pairs * @@ -193,23 +229,16 @@ static int decode_reg(const struct upl *upl, const char *buf, int size, ptr = buf; for (i = 0; ptr < end; i++) { struct memregion reg; + int ret;
- if (upl->addr_cells == 1) - reg.base = fdt32_to_cpu(*(u32 *)ptr); - else - reg.base = fdt64_to_cpu(*(u64 *)ptr); - ptr += upl->addr_cells * sizeof(u32); + ret = decode_addr_size(upl, ptr, end - ptr, ®); + if (ret < 0) + return log_msg_ret("udr", ret);
- if (upl->size_cells == 1) - reg.size = fdt32_to_cpu(*(u32 *)ptr); - else - reg.size = fdt64_to_cpu(*(u64 *)ptr); - ptr += upl->size_cells * sizeof(u32); - if (ptr > end) - return -ENOSPC; + ptr += ret;
if (!alist_add(regions, reg)) - return log_msg_ret("reg", -ENOMEM); + return log_msg_ret("udm", -ENOMEM); }
return i;

The spec originally had both singular and plural versions of this node, but has settled on plural. Update U-Boot to match.
Signed-off-by: Simon Glass sjg@chromium.org ---
boot/upl_read.c | 4 ++-- boot/upl_write.c | 8 ++++---- include/upl.h | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/boot/upl_read.c b/boot/upl_read.c index fe48ae31ffb..1b6290ffb1c 100644 --- a/boot/upl_read.c +++ b/boot/upl_read.c @@ -302,7 +302,7 @@ static int decode_upl_params(struct upl *upl, ofnode options) }
/** - * decode_upl_images() - Decode /options/upl-image nodes + * decode_upl_images() - Decode /options/upl-images nodes * * @node: /options node in which to look for the node * Return 0 if OK, -ve on error @@ -312,7 +312,7 @@ static int decode_upl_images(struct upl *upl, ofnode options) ofnode node, images; int ret;
- images = ofnode_find_subnode(options, UPLN_UPL_IMAGE); + images = ofnode_find_subnode(options, UPLN_UPL_IMAGES); if (!ofnode_valid(images)) return log_msg_ret("img", -EINVAL); log_debug("decoding '%s'\n", ofnode_get_name(images)); diff --git a/boot/upl_write.c b/boot/upl_write.c index a1ecb809cbc..9702ef91930 100644 --- a/boot/upl_write.c +++ b/boot/upl_write.c @@ -268,18 +268,18 @@ static int add_upl_params(const struct upl *upl, ofnode options) }
/** - * add_upl_image() - Add /options/upl-image nodes and properties to the tree + * add_upl_images() - Add /options/upl-images nodes and properties to the tree * * @upl: UPL state * @node: /options node to add to * Return 0 if OK, -ve on error */ -static int add_upl_image(const struct upl *upl, ofnode options) +static int add_upl_images(const struct upl *upl, ofnode options) { ofnode node; int ret, i;
- ret = ofnode_add_subnode(options, UPLN_UPL_IMAGE, &node); + ret = ofnode_add_subnode(options, UPLN_UPL_IMAGES, &node); if (ret) return log_msg_ret("img", ret);
@@ -606,7 +606,7 @@ int upl_write_handoff(const struct upl *upl, ofnode root, bool skip_existing) if (ret) return log_msg_ret("ad1", ret);
- ret = add_upl_image(upl, options); + ret = add_upl_images(upl, options); if (ret) return log_msg_ret("ad2", ret);
diff --git a/include/upl.h b/include/upl.h index a4ed24edbb8..dd43e8e8529 100644 --- a/include/upl.h +++ b/include/upl.h @@ -30,8 +30,8 @@ struct unit_test_state; #define UPLP_ADDR_WIDTH "addr-width" #define UPLP_ACPI_NVS_SIZE "acpi-nvs-size"
-#define UPLPATH_UPL_IMAGE "/options/upl-image" -#define UPLN_UPL_IMAGE "upl-image" +#define UPLPATH_UPL_IMAGES "/options/upl-images" +#define UPLN_UPL_IMAGES "upl-images" #define UPLN_IMAGE "image" #define UPLP_FIT "fit" #define UPLP_CONF_OFFSET "conf-offset"

This function is somewhat ambiguous, so expand the comments and add a test for the undefined behaviour.
Signed-off-by: Simon Glass sjg@chromium.org ---
include/dm/ofnode.h | 7 +++---- test/dm/core.c | 2 ++ 2 files changed, 5 insertions(+), 4 deletions(-)
diff --git a/include/dm/ofnode.h b/include/dm/ofnode.h index 024ae4cd289..6d6a6fef8ef 100644 --- a/include/dm/ofnode.h +++ b/include/dm/ofnode.h @@ -386,11 +386,10 @@ static inline oftree oftree_from_np(struct device_node *root) void oftree_dispose(oftree tree);
/** - * ofnode_name_eq() - Check if the node name is equivalent to a given name - * ignoring the unit address + * ofnode_name_eq() - Check a node name ignoring its unit address * - * @node: valid node reference that has to be compared - * @name: name that has to be compared with the node name + * @node: valid node to compared, which may have a unit address + * @name: name (without unit address) to compare with the node name * Return: true if matches, false if it doesn't match */ bool ofnode_name_eq(ofnode node, const char *name); diff --git a/test/dm/core.c b/test/dm/core.c index c59ffc6f611..d40916ef588 100644 --- a/test/dm/core.c +++ b/test/dm/core.c @@ -186,6 +186,8 @@ static int dm_test_compare_node_name(struct unit_test_state *uts) ut_assert(ofnode_valid(node)); ut_assert(ofnode_name_eq(node, "mmio-bus"));
+ ut_assert(!ofnode_name_eq(node, "mmio-bus@0")); + return 0; } DM_TEST(dm_test_compare_node_name, UTF_SCAN_PDATA);

When a unit-address is provided, use it to match against the node name.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/core/ofnode.c | 18 ++++++++++++++---- include/dm/ofnode.h | 4 +++- test/dm/core.c | 5 ++++- 3 files changed, 21 insertions(+), 6 deletions(-)
diff --git a/drivers/core/ofnode.c b/drivers/core/ofnode.c index 5b8be218d3b..e6f390c710b 100644 --- a/drivers/core/ofnode.c +++ b/drivers/core/ofnode.c @@ -298,15 +298,25 @@ static ofnode ofnode_from_tree_offset(oftree tree, int offset)
bool ofnode_name_eq(ofnode node, const char *name) { - const char *node_name; - size_t len; + const char *node_name, *p; + int len;
assert(ofnode_valid(node));
node_name = ofnode_get_name(node); - len = strchrnul(node_name, '@') - node_name;
- return (strlen(name) == len) && !strncmp(node_name, name, len); + /* check the whole name */ + if (!strcmp(node_name, name)) + return true; + + /* if @name has no unit address, try the node name without it */ + len = strlen(name); + p = strchr(node_name, '@'); + if (p && !strchr(name, '@') && len == p - node_name && + !strncmp(node_name, name, len)) + return true; + + return false; }
int ofnode_read_u8(ofnode node, const char *propname, u8 *outp) diff --git a/include/dm/ofnode.h b/include/dm/ofnode.h index 6d6a6fef8ef..9d73a321cbc 100644 --- a/include/dm/ofnode.h +++ b/include/dm/ofnode.h @@ -389,7 +389,9 @@ void oftree_dispose(oftree tree); * ofnode_name_eq() - Check a node name ignoring its unit address * * @node: valid node to compared, which may have a unit address - * @name: name (without unit address) to compare with the node name + * @name: name to compare with the node name. If this contains a unit + * address, it is matched, otherwise the unit address is ignored + * when searching for matches * Return: true if matches, false if it doesn't match */ bool ofnode_name_eq(ofnode node, const char *name); diff --git a/test/dm/core.c b/test/dm/core.c index d40916ef588..ba78ac8ba6a 100644 --- a/test/dm/core.c +++ b/test/dm/core.c @@ -186,7 +186,10 @@ static int dm_test_compare_node_name(struct unit_test_state *uts) ut_assert(ofnode_valid(node)); ut_assert(ofnode_name_eq(node, "mmio-bus"));
- ut_assert(!ofnode_name_eq(node, "mmio-bus@0")); + ut_assert(ofnode_name_eq(node, "mmio-bus@0")); + ut_assert(!ofnode_name_eq(node, "mmio-bus@1")); + ut_assert(!ofnode_name_eq(node, "mmio-bu")); + ut_assert(!ofnode_name_eq(node, "mmio-buss@0"));
return 0; }

This function currently processes things two different ways, so the treatment of unit addresses differs depending on whether OF_LIVE is enabled or not.
Rewrite it to use the ofnode API and add a test to check that unit addresses can be matched correctly.
Unfortunately this increases code size by about 104 bytes on Thumb2, mostly due to the extra logic in ofnode_name_eq(). We could fix that by having two separate ofnode_name_eq() functions, only one of which allows an @ sign in its parameter.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/core/ofnode.c | 24 +++++++++--------------- include/dm/ofnode.h | 4 +++- test/dm/ofnode.c | 19 +++++++++++++++++++ 3 files changed, 31 insertions(+), 16 deletions(-)
diff --git a/drivers/core/ofnode.c b/drivers/core/ofnode.c index e6f390c710b..62e7a041fdf 100644 --- a/drivers/core/ofnode.c +++ b/drivers/core/ofnode.c @@ -580,28 +580,22 @@ int ofnode_read_size(ofnode node, const char *propname)
ofnode ofnode_find_subnode(ofnode node, const char *subnode_name) { - ofnode subnode; + ofnode subnode, found = ofnode_null();
assert(ofnode_valid(node)); log_debug("%s: %s: ", __func__, subnode_name);
- if (ofnode_is_np(node)) { - struct device_node *np = ofnode_to_np(node); - - for (np = np->child; np; np = np->sibling) { - if (!strcmp(subnode_name, np->name)) - break; + ofnode_for_each_subnode(subnode, node) { + if (ofnode_name_eq(subnode, subnode_name)) { + found = subnode; + break; } - subnode = np_to_ofnode(np); - } else { - int ooffset = fdt_subnode_offset(ofnode_to_fdt(node), - ofnode_to_offset(node), subnode_name); - subnode = noffset_to_ofnode(node, ooffset); } - log_debug("%s\n", ofnode_valid(subnode) ? - ofnode_get_name(subnode) : "<none>");
- return subnode; + log_debug("%s\n", ofnode_valid(found) ? + ofnode_get_name(found) : "<none>"); + + return found; }
int ofnode_read_u32_array(ofnode node, const char *propname, diff --git a/include/dm/ofnode.h b/include/dm/ofnode.h index 9d73a321cbc..5e043616803 100644 --- a/include/dm/ofnode.h +++ b/include/dm/ofnode.h @@ -589,7 +589,9 @@ bool ofnode_read_bool(ofnode node, const char *propname); * ofnode_find_subnode() - find a named subnode of a parent node * * @node: valid reference to parent node - * @subnode_name: name of subnode to find + * @subnode_name: name of subnode to find, including any unit address. If the + * unit address is omitted, any subnode which matches the name (excluding + * any unit address) is returned * Return: reference to subnode (which can be invalid if there is no such * subnode) */ diff --git a/test/dm/ofnode.c b/test/dm/ofnode.c index ce996567c3c..47c890e0f92 100644 --- a/test/dm/ofnode.c +++ b/test/dm/ofnode.c @@ -1201,6 +1201,25 @@ static int dm_test_ofnode_find_subnode(struct unit_test_state *uts) } DM_TEST(dm_test_ofnode_find_subnode, UTF_SCAN_FDT);
+/* check ofnode_find_subnode() with unit addresses */ +static int dm_test_ofnode_find_subnode_unit(struct unit_test_state *uts) +{ + ofnode node, subnode; + + node = ofnode_path("/some-bus"); + ut_assert(ofnode_valid(node)); + subnode = ofnode_find_subnode(node, "c-test@5"); + ut_assert(ofnode_valid(subnode)); + ut_asserteq_str("c-test@5", ofnode_get_name(subnode)); + + subnode = ofnode_find_subnode(node, "c-test"); + ut_assert(ofnode_valid(subnode)); + ut_asserteq_str("c-test@5", ofnode_get_name(subnode)); + + return 0; +} +DM_TEST(dm_test_ofnode_find_subnode_unit, UTF_SCAN_FDT); + /* test ofnode_find_subnode() on the 'other' tree */ static int dm_test_ofnode_find_subnode_ot(struct unit_test_state *uts) {

Add a few lines to print out the entire handoff FDT when LOG_DEBUG is enabled, to aid debugging.
Signed-off-by: Simon Glass sjg@chromium.org ---
test/boot/upl.c | 6 ++++++ 1 file changed, 6 insertions(+)
diff --git a/test/boot/upl.c b/test/boot/upl.c index 89201e445ff..e1454ba3469 100644 --- a/test/boot/upl.c +++ b/test/boot/upl.c @@ -6,6 +6,8 @@ * Written by Simon Glass sjg@chromium.org */
+#define LOG_CATEGORY UCLASS_BOOTSTD + #include <abuf.h> #include <mapmem.h> #include <upl.h> @@ -341,6 +343,10 @@ static int upl_test_base(struct unit_test_state *uts) ut_assertok(upl_create_handoff_tree(&upl, &tree)); ut_assertok(oftree_to_fdt(tree, &buf));
+ if (_LOG_DEBUG) { + set_working_fdt_addr(abuf_addr(&buf)); + ut_assertok(run_command("fdt print", 0)); + } /* * strings in check_tree and therefore check are only valid so long as * buf stays around. As soon as we call abuf_uninit they go away

The spec has changed to use a unit address and reg property for this value. Update the implementation to match. It is now possible to obtain the size of the FIT as well as its address.
Add #address/size-cells properties as well.
Signed-off-by: Simon Glass sjg@chromium.org ---
boot/upl_read.c | 12 +++++++++--- boot/upl_write.c | 25 +++++++++++++++++++++---- cmd/upl.c | 2 +- common/spl/spl_upl.c | 4 ++-- include/upl.h | 4 ++-- test/boot/upl.c | 10 ++++++---- 6 files changed, 41 insertions(+), 16 deletions(-)
diff --git a/boot/upl_read.c b/boot/upl_read.c index 1b6290ffb1c..8fcc5a77c15 100644 --- a/boot/upl_read.c +++ b/boot/upl_read.c @@ -310,6 +310,8 @@ static int decode_upl_params(struct upl *upl, ofnode options) static int decode_upl_images(struct upl *upl, ofnode options) { ofnode node, images; + const char *buf; + int size; int ret;
images = ofnode_find_subnode(options, UPLN_UPL_IMAGES); @@ -317,9 +319,13 @@ static int decode_upl_images(struct upl *upl, ofnode options) return log_msg_ret("img", -EINVAL); log_debug("decoding '%s'\n", ofnode_get_name(images));
- ret = read_addr(upl, images, UPLP_FIT, &upl->fit); - if (!ret) - ret = read_uint(images, UPLP_CONF_OFFSET, &upl->conf_offset); + buf = ofnode_read_prop(images, UPLP_REG, &size); + if (buf) { + ret = decode_addr_size(upl, buf, size, &upl->fit); + if (ret < 0) + return log_msg_ret("uft", ret); + } + ret = read_uint(images, UPLP_CONF_OFFSET, &upl->conf_offset); if (ret) return log_msg_ret("cnf", ret);
diff --git a/boot/upl_write.c b/boot/upl_write.c index 9702ef91930..32c68308149 100644 --- a/boot/upl_write.c +++ b/boot/upl_write.c @@ -244,6 +244,9 @@ static int add_upl_params(const struct upl *upl, ofnode options) ofnode node; int ret;
+ ret = add_addr_size_cells(options, upl->addr_cells, upl->size_cells); + if (ret) + return log_msg_ret("upa", ret); ret = ofnode_add_subnode(options, UPLN_UPL_PARAMS, &node); if (ret) return log_msg_ret("img", ret); @@ -276,21 +279,35 @@ static int add_upl_params(const struct upl *upl, ofnode options) */ static int add_upl_images(const struct upl *upl, ofnode options) { + char name[40]; ofnode node; int ret, i;
- ret = ofnode_add_subnode(options, UPLN_UPL_IMAGES, &node); + snprintf(name, sizeof(name), UPLN_UPL_IMAGES "@%llx", upl->fit.base); + ret = ofnode_add_subnode(options, name, &node); if (ret) return log_msg_ret("img", ret);
- if (upl->fit) - ret = ofnode_write_u32(node, UPLP_FIT, upl->fit); - if (!ret && upl->conf_offset) + if (upl->fit.base) { + char buf[4 * sizeof(u64)]; + + ret = encode_addr_size(upl, buf, sizeof(buf), &upl->fit); + if (ret < 0) + return log_msg_ret("uft", ret); + ret = ofnode_write_prop(node, UPLP_REG, buf, ret, true); + if (ret) + return log_msg_ret("ufw", ret); + } + if (upl->conf_offset) ret = ofnode_write_u32(node, UPLP_CONF_OFFSET, upl->conf_offset); if (ret) return log_msg_ret("cnf", ret);
+ ret = add_addr_size_cells(node, upl->addr_cells, upl->size_cells); + if (ret) + return log_msg_ret("upi", ret); + for (i = 0; i < upl->image.count; i++) { const struct upl_image *img = alist_get(&upl->image, i, struct upl_image); diff --git a/cmd/upl.c b/cmd/upl.c index d8d46cdf34f..676e8f1f9e2 100644 --- a/cmd/upl.c +++ b/cmd/upl.c @@ -31,7 +31,7 @@ static int do_upl_info(struct cmd_tbl *cmdtp, int flag, int argc, if (argc > 1 && !strcmp("-v", argv[1])) { int i;
- printf("fit %lx\n", upl->fit); + printf("fit %llx size %lx\n", upl->fit.base, upl->fit.size); printf("conf_offset %x\n", upl->conf_offset); for (i = 0; i < upl->image.count; i++) { const struct upl_image *img = diff --git a/common/spl/spl_upl.c b/common/spl/spl_upl.c index 2bc0e265661..5777148bbe4 100644 --- a/common/spl/spl_upl.c +++ b/common/spl/spl_upl.c @@ -21,14 +21,14 @@ void upl_set_fit_addr(ulong fit) { struct upl *upl = &s_upl;
- upl->fit = fit; + upl->fit.base = fit; }
void upl_set_fit_info(ulong fit, int conf_offset, ulong entry_addr) { struct upl *upl = &s_upl;
- upl->fit = fit; + upl->fit.base = fit; upl->conf_offset = conf_offset; log_debug("upl: add fit %lx conf %x\n", fit, conf_offset); } diff --git a/include/upl.h b/include/upl.h index dd43e8e8529..cff3401a932 100644 --- a/include/upl.h +++ b/include/upl.h @@ -250,7 +250,7 @@ struct upl_graphics { * @addr_cells: Number of address cells used in the handoff * @size_cells: Number of size cells used in the handoff * @bootmode: Boot-mode mask (enum upl_boot_mode) - * @fit: Address of FIT image that was loaded + * @fit: Address and size of FIT image that was loaded * @conf_offset: Offset in FIT of the configuration that was selected * @addr_width: Adress-bus width of machine, e.g. 46 for 46 bits * @acpi_nvs_size: Size of the ACPI non-volatile-storage area in bytes @@ -266,7 +266,7 @@ struct upl { ulong smbios; ulong acpi; uint bootmode; - ulong fit; + struct memregion fit; uint conf_offset; uint addr_width; uint acpi_nvs_size; diff --git a/test/boot/upl.c b/test/boot/upl.c index e1454ba3469..8e1a016943a 100644 --- a/test/boot/upl.c +++ b/test/boot/upl.c @@ -46,7 +46,8 @@ int upl_get_test_data(struct unit_test_state *uts, struct upl *upl) upl->smbios = 0x123; upl->acpi = 0x456; upl->bootmode = BIT(UPLBM_DEFAULT) | BIT(UPLBM_S3); - upl->fit = 0x789; + upl->fit.base = 0x789; + upl->fit.size = 0xabc; upl->conf_offset = 0x234; upl->addr_width = 46; upl->acpi_nvs_size = 0x100; @@ -294,7 +295,8 @@ static int compare_upl(struct unit_test_state *uts, struct upl *base, ut_asserteq(base->smbios, cmp->smbios); ut_asserteq(base->acpi, cmp->acpi); ut_asserteq(base->bootmode, cmp->bootmode); - ut_asserteq(base->fit, cmp->fit); + ut_asserteq(base->fit.base, cmp->fit.base); + ut_asserteq(base->fit.size, cmp->fit.size); ut_asserteq(base->conf_offset, cmp->conf_offset); ut_asserteq(base->addr_width, cmp->addr_width); ut_asserteq(base->acpi_nvs_size, cmp->acpi_nvs_size); @@ -411,14 +413,14 @@ static int upl_test_info_norun(struct unit_test_state *uts)
ut_assertok(run_command("upl info -v", 0)); ut_assert_nextline("UPL state: active"); - ut_assert_nextline("fit %lx", upl->fit); + ut_assert_nextline("fit %llx (size %lx)", upl->fit.base, upl->fit.size); ut_assert_nextline("conf_offset %x", upl->conf_offset); ut_assert_nextlinen("image 0"); ut_assert_nextlinen("image 1"); ut_assert_console_end();
/* check the offsets */ - fit = map_sysmem(upl->fit, 0); + fit = map_sysmem(upl->fit.base, 0); ut_asserteq_str("conf-1", fdt_get_name(fit, upl->conf_offset, NULL));
ut_asserteq(2, upl->image.count);

The current implementation of images does not cover all the requirements of the current, updated UPL spec. Add support for an entry address, the offset of the image within the FIT as well as the load address and size, which are subsumed into the new 'reg' property.
Support writing this information out to the UPL handoff.
Update SPL to handle the struct change as well.
Signed-off-by: Simon Glass sjg@chromium.org ---
boot/upl_read.c | 51 +++++++++++-------------------------------- boot/upl_write.c | 52 ++++++++++++++++---------------------------- cmd/upl.c | 4 ++-- common/spl/spl_upl.c | 5 +++-- include/upl.h | 34 ++++++++++++++--------------- test/boot/upl.c | 36 +++++++++++++++--------------- 6 files changed, 73 insertions(+), 109 deletions(-)
diff --git a/boot/upl_read.c b/boot/upl_read.c index 8fcc5a77c15..99f7a83ff0a 100644 --- a/boot/upl_read.c +++ b/boot/upl_read.c @@ -46,39 +46,6 @@ static int read_addr(const struct upl *upl, ofnode node, const char *prop, return ret; }
-/** - * read_size() - Read a size - * - * Reads a size in the correct format, either 32- or 64-bit - * - * @upl: UPL state - * @node: Node to read from - * @prop: Property name to read - * @addr: Place to put the size - * Return: 0 if OK, -ve on error - */ -static int read_size(const struct upl *upl, ofnode node, const char *prop, - ulong *sizep) -{ - int ret; - - if (upl->size_cells == 1) { - u32 val; - - ret = ofnode_read_u32(node, prop, &val); - if (!ret) - *sizep = val; - } else { - u64 val; - - ret = ofnode_read_u64(node, prop, &val); - if (!ret) - *sizep = val; - } - - return ret; -} - /** * ofnode_read_bitmask() - Read a bit mask from a string list * @@ -332,11 +299,19 @@ static int decode_upl_images(struct upl *upl, ofnode options) ofnode_for_each_subnode(node, images) { struct upl_image img;
- ret = read_addr(upl, node, UPLP_LOAD, &img.load); - if (!ret) - ret = read_size(upl, node, UPLP_SIZE, &img.size); - if (!ret) - ret = read_uint(node, UPLP_OFFSET, &img.offset); + memset(&img, '\0', sizeof(img)); + buf = ofnode_read_prop(node, UPLP_REG, &size); + if (!buf) + return log_msg_ret("dui", ret); + ret = decode_addr_size(upl, buf, size, &img.reg); + log_debug("node %s: ret=%d, base=%llx\n", ofnode_get_name(node), + ret, img.reg.base); + if (ret < 0) + return log_msg_ret("duI", ret); + + read_addr(upl, node, UPLP_ENTRY, &img.entry); + + ret = read_uint(node, UPLP_OFFSET, &img.offset); img.description = ofnode_read_string(node, UPLP_DESCRIPTION); if (!img.description) return log_msg_ret("sim", ret); diff --git a/boot/upl_write.c b/boot/upl_write.c index 32c68308149..4b4232af6e5 100644 --- a/boot/upl_write.c +++ b/boot/upl_write.c @@ -37,30 +37,6 @@ static int write_addr(const struct upl *upl, ofnode node, const char *prop, return ret; }
-/** - * write_size() - Write a size - * - * Writes a size in the correct format, either 32- or 64-bit - * - * @upl: UPL state - * @node: Node to write to - * @prop: Property name to write - * @size: Size to write - * Return: 0 if OK, -ve on error - */ -static int write_size(const struct upl *upl, ofnode node, const char *prop, - ulong size) -{ - int ret; - - if (upl->size_cells == 1) - ret = ofnode_write_u32(node, prop, size); - else - ret = ofnode_write_u64(node, prop, size); - - return ret; -} - /** * ofnode_write_bitmask() - Write a bit mask as a string list * @@ -309,24 +285,34 @@ static int add_upl_images(const struct upl *upl, ofnode options) return log_msg_ret("upi", ret);
for (i = 0; i < upl->image.count; i++) { - const struct upl_image *img = alist_get(&upl->image, i, - struct upl_image); + const struct upl_image *img; + char buf[sizeof(u64) * 4]; ofnode subnode; - char name[10]; + char name[30]; + int len;
- snprintf(name, sizeof(name), UPLN_IMAGE "-%d", i + 1); + img = alist_get(&upl->image, i, struct upl_image); + snprintf(name, sizeof(name), UPLN_IMAGE "@%llx", img->reg.base); ret = ofnode_add_subnode(node, name, &subnode); if (ret) return log_msg_ret("sub", ret);
- ret = write_addr(upl, subnode, UPLP_LOAD, img->load); - if (!ret) - ret = write_size(upl, subnode, UPLP_SIZE, img->size); + len = encode_addr_size(upl, buf, sizeof(buf), &img->reg); + if (len < 0) + return log_msg_ret("rbf", len); + ret = ofnode_write_prop(subnode, UPLP_REG, buf, len, true); + + if (!ret && img->entry) { + ret = write_addr(upl, subnode, UPLP_ENTRY, img->entry); + if (ret < 0) + return log_msg_ret("uwr", ret); + } if (!ret && img->offset) ret = ofnode_write_u32(subnode, UPLP_OFFSET, img->offset); - ret = ofnode_write_string(subnode, UPLP_DESCRIPTION, - img->description); + if (!ret) + ret = ofnode_write_string(subnode, UPLP_DESCRIPTION, + img->description); if (ret) return log_msg_ret("sim", ret); } diff --git a/cmd/upl.c b/cmd/upl.c index 676e8f1f9e2..461f8f4f0aa 100644 --- a/cmd/upl.c +++ b/cmd/upl.c @@ -37,8 +37,8 @@ static int do_upl_info(struct cmd_tbl *cmdtp, int flag, int argc, const struct upl_image *img = alist_get(&upl->image, i, struct upl_image);
- printf("image %d: load %lx size %lx offset %x: %s\n", i, - img->load, img->size, img->offset, + printf("image %d: load %llx size %lx entry %lx offset %x: %s\n", + i, img->reg.base, img->reg.size, img->entry, img->offset, img->description); } } diff --git a/common/spl/spl_upl.c b/common/spl/spl_upl.c index 5777148bbe4..71b699aed23 100644 --- a/common/spl/spl_upl.c +++ b/common/spl/spl_upl.c @@ -38,8 +38,9 @@ int _upl_add_image(int node, ulong load_addr, ulong size, const char *desc) struct upl *upl = &s_upl; struct upl_image img;
- img.load = load_addr; - img.size = size; + memset(&img, '\0', sizeof(img)); + img.reg.base = load_addr; + img.reg.size = size; img.offset = node; img.description = desc; if (!alist_add(&upl->image, img)) diff --git a/include/upl.h b/include/upl.h index cff3401a932..19fa78b108e 100644 --- a/include/upl.h +++ b/include/upl.h @@ -35,8 +35,7 @@ struct unit_test_state; #define UPLN_IMAGE "image" #define UPLP_FIT "fit" #define UPLP_CONF_OFFSET "conf-offset" -#define UPLP_LOAD "load" -#define UPLP_SIZE "size" +#define UPLP_ENTRY "entry" #define UPLP_OFFSET "offset" #define UPLP_DESCRIPTION "description"
@@ -91,21 +90,6 @@ enum upl_boot_mode { UPLBM_COUNT, };
-/** - * struct upl_image - UPL image informaiton - * - * @load: Address image was loaded to - * @size: Size of image in bytes - * @offset: Offset of the image in the FIT (0=none) - * @desc: Description of the iamge (taken from the FIT) - */ -struct upl_image { - ulong load; - ulong size; - uint offset; - const char *description; -}; - /** * struct memregion - Information about a region of memory * @@ -117,6 +101,22 @@ struct memregion { ulong size; };
+/** + * struct upl_image - UPL image informaiton + * + * @reg: address and size of image in memory (within FIT) + * @offset: Offset of the image in the FIT (0=none) + * @load: Address image should be loaded to + * @entry: Entry address to jump to (must be within the image), or 0 if none + * @desc: Description of the iamge (taken from the FIT) + */ +struct upl_image { + struct memregion reg; + uint offset; + ulong entry; + const char *description; +}; + /** * struct upl_mem - Information about physical-memory layout * diff --git a/test/boot/upl.c b/test/boot/upl.c index 8e1a016943a..264aab3038c 100644 --- a/test/boot/upl.c +++ b/test/boot/upl.c @@ -53,16 +53,18 @@ int upl_get_test_data(struct unit_test_state *uts, struct upl *upl) upl->acpi_nvs_size = 0x100;
/* image[0] */ - img.load = 0x1; - img.size = 0x2; + img.reg.base = 0x1; + img.reg.size = 0x2; img.offset = 0x3; + img.entry = 0x4; img.description = "U-Boot"; ut_assertnonnull(alist_add(&upl->image, img));
/* image[1] */ - img.load = 0x4; - img.size = 0x5; - img.offset = 0x6; + img.reg.base = 0x5; + img.reg.size = 0x6; + img.offset = 0x7; + img.entry = 0x8; img.description = "ATF"; ut_assertnonnull(alist_add(&upl->image, img));
@@ -155,24 +157,24 @@ int upl_get_test_data(struct unit_test_state *uts, struct upl *upl) return 0; }
-static int compare_upl_image(struct unit_test_state *uts, - const struct upl_image *base, - const struct upl_image *cmp) +static int compare_upl_memregion(struct unit_test_state *uts, + const struct memregion *base, + const struct memregion *cmp) { - ut_asserteq(base->load, cmp->load); + ut_asserteq(base->base, cmp->base); ut_asserteq(base->size, cmp->size); - ut_asserteq(base->offset, cmp->offset); - ut_asserteq_str(base->description, cmp->description);
return 0; }
-static int compare_upl_memregion(struct unit_test_state *uts, - const struct memregion *base, - const struct memregion *cmp) +static int compare_upl_image(struct unit_test_state *uts, + const struct upl_image *base, + const struct upl_image *cmp) { - ut_asserteq(base->base, cmp->base); - ut_asserteq(base->size, cmp->size); + ut_assertok(compare_upl_memregion(uts, &base->reg, &cmp->reg)); + ut_asserteq(base->offset, cmp->offset); + ut_asserteq(base->entry, cmp->entry); + ut_asserteq_str(base->description, cmp->description);
return 0; } @@ -427,7 +429,7 @@ static int upl_test_info_norun(struct unit_test_state *uts)
img = alist_get(&upl->image, 1, struct upl_image); ut_asserteq_str("firmware-1", fdt_get_name(fit, img->offset, NULL)); - ut_asserteq(CONFIG_TEXT_BASE, img->load); + ut_asserteq(CONFIG_TEXT_BASE, img->reg.base);
return 0; }

This is more convenient than a for() loop, so update upl_write to use this new feature.
Signed-off-by: Simon Glass sjg@chromium.org ---
boot/upl_write.c | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-)
diff --git a/boot/upl_write.c b/boot/upl_write.c index 4b4232af6e5..ec1f5daac92 100644 --- a/boot/upl_write.c +++ b/boot/upl_write.c @@ -255,9 +255,10 @@ static int add_upl_params(const struct upl *upl, ofnode options) */ static int add_upl_images(const struct upl *upl, ofnode options) { + const struct upl_image *img; char name[40]; ofnode node; - int ret, i; + int ret;
snprintf(name, sizeof(name), UPLN_UPL_IMAGES "@%llx", upl->fit.base); ret = ofnode_add_subnode(options, name, &node); @@ -284,14 +285,12 @@ static int add_upl_images(const struct upl *upl, ofnode options) if (ret) return log_msg_ret("upi", ret);
- for (i = 0; i < upl->image.count; i++) { - const struct upl_image *img; + alist_for_each(img, &upl->image) { char buf[sizeof(u64) * 4]; ofnode subnode; char name[30]; int len;
- img = alist_get(&upl->image, i, struct upl_image); snprintf(name, sizeof(name), UPLN_IMAGE "@%llx", img->reg.base); ret = ofnode_add_subnode(node, name, &subnode); if (ret) @@ -371,11 +370,9 @@ static int write_mem_node(const struct upl *upl, ofnode parent, */ static int add_upl_memory(const struct upl *upl, ofnode root) { - int i; + const struct upl_mem *mem;
- for (i = 0; i < upl->mem.count; i++) { - const struct upl_mem *mem = alist_get(&upl->mem, i, - struct upl_mem); + alist_for_each(mem, &upl->mem) { ofnode node; int ret;
@@ -403,8 +400,9 @@ static int add_upl_memory(const struct upl *upl, ofnode root) */ static int add_upl_memmap(const struct upl *upl, ofnode root) { + const struct upl_memmap *memmap; ofnode mem_node; - int i, ret; + int ret;
if (!upl->memmap.count) return 0; @@ -412,9 +410,7 @@ static int add_upl_memmap(const struct upl *upl, ofnode root) if (ret) return log_msg_ret("img", ret);
- for (i = 0; i < upl->memmap.count; i++) { - const struct upl_memmap *memmap = alist_get(&upl->memmap, i, - struct upl_memmap); + alist_for_each(memmap, &upl->memmap) { ofnode node;
ret = write_mem_node(upl, mem_node, &memmap->region, @@ -443,8 +439,9 @@ static int add_upl_memmap(const struct upl *upl, ofnode root) static int add_upl_memres(const struct upl *upl, ofnode root, bool skip_existing) { + const struct upl_memres *memres; ofnode mem_node; - int i, ret; + int ret;
if (!upl->memres.count) return 0; @@ -458,9 +455,7 @@ static int add_upl_memres(const struct upl *upl, ofnode root, if (ret) return log_msg_ret("im2", ret);
- for (i = 0; i < upl->memres.count; i++) { - const struct upl_memres *memres = alist_get(&upl->memres, i, - struct upl_memres); + alist_for_each(memres, &upl->memres) { ofnode node;
ret = write_mem_node(upl, mem_node, &memres->region,

The write_mem_node() function uses sizeof(64) when sizeof(u64) is intended. This can cause an error due to the buffer-space being exhausted.
Correct this.
Signed-off-by: Simon Glass sjg@chromium.org ---
boot/upl_write.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/boot/upl_write.c b/boot/upl_write.c index ec1f5daac92..773c03ad1c6 100644 --- a/boot/upl_write.c +++ b/boot/upl_write.c @@ -336,7 +336,7 @@ static int write_mem_node(const struct upl *upl, ofnode parent, const struct alist *mem, const char *leaf, ofnode *nodep) { - char buf[mem->count * sizeof(64) * 2]; + char buf[mem->count * sizeof(u64) * 2]; const struct memregion *first; char name[26]; ofnode node;

This was removed from the spec in favour of reserved-memory nodes. Drop the field and its uses.
Future work will address the new implementation of ACPI NVS.
Signed-off-by: Simon Glass sjg@chromium.org ---
boot/upl_read.c | 3 --- boot/upl_write.c | 3 --- include/upl.h | 3 --- test/boot/upl.c | 2 -- 4 files changed, 11 deletions(-)
diff --git a/boot/upl_read.c b/boot/upl_read.c index 99f7a83ff0a..4f07204546e 100644 --- a/boot/upl_read.c +++ b/boot/upl_read.c @@ -261,9 +261,6 @@ static int decode_upl_params(struct upl *upl, ofnode options) ret = read_uint(node, UPLP_ADDR_WIDTH, &upl->addr_width); if (ret) return log_msg_ret("add", ret); - ret = read_uint(node, UPLP_ACPI_NVS_SIZE, &upl->acpi_nvs_size); - if (ret) - return log_msg_ret("nvs", ret);
return 0; } diff --git a/boot/upl_write.c b/boot/upl_write.c index 773c03ad1c6..79613a0f463 100644 --- a/boot/upl_write.c +++ b/boot/upl_write.c @@ -237,9 +237,6 @@ static int add_upl_params(const struct upl *upl, ofnode options) UPLBM_COUNT, upl->bootmode); if (!ret) ret = ofnode_write_u32(node, UPLP_ADDR_WIDTH, upl->addr_width); - if (!ret) - ret = ofnode_write_u32(node, UPLP_ACPI_NVS_SIZE, - upl->acpi_nvs_size); if (ret) return log_msg_ret("cnf", ret);
diff --git a/include/upl.h b/include/upl.h index 19fa78b108e..0d76595cc48 100644 --- a/include/upl.h +++ b/include/upl.h @@ -28,7 +28,6 @@ struct unit_test_state; #define UPLP_ACPI "acpi" #define UPLP_BOOTMODE "bootmode" #define UPLP_ADDR_WIDTH "addr-width" -#define UPLP_ACPI_NVS_SIZE "acpi-nvs-size"
#define UPLPATH_UPL_IMAGES "/options/upl-images" #define UPLN_UPL_IMAGES "upl-images" @@ -253,7 +252,6 @@ struct upl_graphics { * @fit: Address and size of FIT image that was loaded * @conf_offset: Offset in FIT of the configuration that was selected * @addr_width: Adress-bus width of machine, e.g. 46 for 46 bits - * @acpi_nvs_size: Size of the ACPI non-volatile-storage area in bytes * @image: Information about each image (struct upl_image) * @mem: Information about physical-memory regions (struct upl_mem) * @menmap: Information about logical-memory regions (struct upl_memmap) @@ -269,7 +267,6 @@ struct upl { struct memregion fit; uint conf_offset; uint addr_width; - uint acpi_nvs_size;
struct alist image; struct alist mem; diff --git a/test/boot/upl.c b/test/boot/upl.c index 264aab3038c..7171f16e42e 100644 --- a/test/boot/upl.c +++ b/test/boot/upl.c @@ -50,7 +50,6 @@ int upl_get_test_data(struct unit_test_state *uts, struct upl *upl) upl->fit.size = 0xabc; upl->conf_offset = 0x234; upl->addr_width = 46; - upl->acpi_nvs_size = 0x100;
/* image[0] */ img.reg.base = 0x1; @@ -301,7 +300,6 @@ static int compare_upl(struct unit_test_state *uts, struct upl *base, ut_asserteq(base->fit.size, cmp->fit.size); ut_asserteq(base->conf_offset, cmp->conf_offset); ut_asserteq(base->addr_width, cmp->addr_width); - ut_asserteq(base->acpi_nvs_size, cmp->acpi_nvs_size);
ut_asserteq(base->image.count, cmp->image.count); for (i = 0; i < base->image.count; i++)

Adjust some of these to make them more likely to be unique. Fix up the comment for buffer_addr_size() while we are here.
Fix an incorrect error-return in upl_write_handoff() while we are here.
Signed-off-by: Simon Glass sjg@chromium.org ---
boot/upl_write.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/boot/upl_write.c b/boot/upl_write.c index 79613a0f463..eecb56214df 100644 --- a/boot/upl_write.c +++ b/boot/upl_write.c @@ -244,7 +244,7 @@ static int add_upl_params(const struct upl *upl, ofnode options) }
/** - * add_upl_images() - Add /options/upl-images nodes and properties to the tree + * add_upl_images() - Add /options/upl-images/upl-image nodes / props to tree * * @upl: UPL state * @node: /options node to add to @@ -508,7 +508,7 @@ static int add_upl_serial(const struct upl *upl, ofnode root,
len = encode_reg(upl, buf, sizeof(buf), 1, &ser->reg); if (len < 0) - return log_msg_ret("buf", len); + return log_msg_ret("aus", len);
ret = ofnode_write_prop(node, UPLP_REG, buf, len, true); } @@ -549,7 +549,7 @@ static int add_upl_graphics(const struct upl *upl, ofnode root) int ret;
if (!gra->reg.count) - return log_msg_ret("gra", -ENOENT); + return log_msg_ret("ugr", -ENOENT); first = alist_get(&gra->reg, 0, struct memregion); sprintf(name, UPLN_GRAPHICS "@%llx", first->base); ret = ofnode_add_subnode(root, name, &node); @@ -563,7 +563,7 @@ static int add_upl_graphics(const struct upl *upl, ofnode root)
len = encode_reg(upl, buf, sizeof(buf), 1, &gra->reg); if (len < 0) - return log_msg_ret("buf", len); + return log_msg_ret("aug", len);
ret = ofnode_write_prop(node, UPLP_REG, buf, len, true); } @@ -595,7 +595,7 @@ int upl_write_handoff(const struct upl *upl, ofnode root, bool skip_existing) return log_msg_ret("ad1", ret); ret = ofnode_add_subnode(root, UPLN_OPTIONS, &options); if (ret && ret != -EEXIST) - return log_msg_ret("opt", -EINVAL); + return log_msg_ret("opt", ret);
ret = add_upl_params(upl, options); if (ret) @@ -623,7 +623,7 @@ int upl_write_handoff(const struct upl *upl, ofnode root, bool skip_existing)
ret = add_upl_graphics(upl, root); if (ret && ret != -ENOENT) - return log_msg_ret("ad6", ret); + return log_msg_ret("ad7", ret);
return 0; } @@ -636,7 +636,7 @@ int upl_create_handoff_tree(const struct upl *upl, oftree *treep)
ret = oftree_new(&tree); if (ret) - return log_msg_ret("new", ret); + return log_msg_ret("cht", -EINVAL);
root = oftree_root(tree); if (!ofnode_valid(root))

So far we have not needed PCI information, but EDK2 does complain when it is missing. Add the required structures, as a starting point.
Signed-off-by: Simon Glass sjg@chromium.org ---
include/upl.h | 40 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-)
diff --git a/include/upl.h b/include/upl.h index 0d76595cc48..62341f2f719 100644 --- a/include/upl.h +++ b/include/upl.h @@ -243,6 +243,43 @@ struct upl_graphics { enum upl_graphics_format format; };
+/** + * struct pci_range - Information about a PCI 'ranges' entry + * + * The ranges property contains: + * + * child_flags (1 cell) + * child_base (1 or 2 cells) + * parent_base (1 or 2 cells) + * child_len (1 or 2 cells) + * + * @child_base: Child base address + * @child_flags: Child flags and space code (first cell of devicetree) + * @parent_base: Parent base address + * @child_size: Child-space size + * @first_bus: Bus number of the first child bus + * @last_bus: Bus number of the last child bus + */ +struct pci_range { + u64 parent_base; + u64 child_base; + ulong child_flags; + ulong child_len; + uint first_bus; + uint last_bus; +}; + +/** + * struct upl_pci - Information about PCI root bridge + * + * @reg: PCI ECAM region + * @range: List of ranges (struct pci_range) + */ +struct upl_pci { + struct memregion reg; + struct alist range; +}; + /* * Information about the UPL state * @@ -263,7 +300,7 @@ struct upl {
ulong smbios; ulong acpi; - uint bootmode; + enum upl_boot_mode bootmode; struct memregion fit; uint conf_offset; uint addr_width; @@ -274,6 +311,7 @@ struct upl { struct alist memres; struct upl_serial serial; struct upl_graphics graphics; + struct upl_pci pci; };
/**

When the serial port uses I/O ports, it is expected to be on an ISA bus. Handle this by creating a suitable node and putting the serial port in that node.
Add a reference to the serial port in the /chosen node.
Signed-off-by: Simon Glass sjg@chromium.org ---
boot/upl_write.c | 46 ++++++++++++++++++++++++++++++++++++++++------ include/upl.h | 3 +++ test/boot/upl.c | 1 + 3 files changed, 44 insertions(+), 6 deletions(-)
diff --git a/boot/upl_write.c b/boot/upl_write.c index eecb56214df..c43a588dc40 100644 --- a/boot/upl_write.c +++ b/boot/upl_write.c @@ -482,19 +482,48 @@ static int add_upl_serial(const struct upl *upl, ofnode root, { const struct upl_serial *ser = &upl->serial; const struct memregion *first; - char name[26]; - ofnode node; + char name[26], alias[36]; + ofnode node, parent; int ret;
- if (!ser->compatible || skip_existing) + if (!ser->compatible) return 0; if (!ser->reg.count) return log_msg_ret("ser", -EINVAL); + + ret = ofnode_add_subnode(root, UPLN_CHOSEN, &node); + if (ret) + return log_msg_ret("uch", ret); + + parent = root; + if (ser->access_type == UPLAT_IO) { + ret = ofnode_write_string(node, UPLP_STDOUT_PATH, "/isa/serial"); + if (ret) + return log_msg_ret("uc0", ret); + + ret = ofnode_add_subnode(root, "isa", &node); + if (ret) + return log_msg_ret("uc1", ret); + if (ofnode_write_string(node, UPLP_UPL_PARAMS_COMPAT, "isa") || + add_addr_size_cells(node, 2, 1)) + return log_msg_ret("uc2", -EINVAL); + parent = node; + strcpy(alias, "/isa"); + } + first = alist_get(&ser->reg, 0, struct memregion); sprintf(name, UPLN_SERIAL "@%llx", first->base); - ret = ofnode_add_subnode(root, name, &node); - if (ret) - return log_msg_ret("img", ret); + ret = ofnode_add_subnode(parent, name, &node); + if (ret) { + if (ret == -EEXIST) { + if (skip_existing) + return 0; + } else { + return log_msg_ret("img", ret); + } + } + + // ret = ofnode_write_string(node, UPLP_COMPATIBLE, "ns8250"); ret = ofnode_write_string(node, UPLP_COMPATIBLE, ser->compatible); if (!ret) ret = ofnode_write_u32(node, UPLP_CLOCK_FREQUENCY, @@ -527,6 +556,11 @@ static int add_upl_serial(const struct upl *upl, ofnode root, ARRAY_SIZE(access_types), ser->access_type); } + if (!ret) { + strlcat(alias, "/", sizeof(alias)); + strlcat(alias, name, sizeof(alias)); + ret = ofnode_write_string(node, UPLP_STDOUT_PATH, alias); + } if (ret) return log_msg_ret("ser", ret);
diff --git a/include/upl.h b/include/upl.h index 62341f2f719..d5b2cad7196 100644 --- a/include/upl.h +++ b/include/upl.h @@ -21,6 +21,9 @@ struct unit_test_state; #define UPLP_ADDRESS_CELLS "#address-cells" #define UPLP_SIZE_CELLS "#size-cells"
+#define UPLN_CHOSEN "chosen" +#define UPLP_STDOUT_PATH "stdout-path" + #define UPLN_OPTIONS "options" #define UPLN_UPL_PARAMS "upl-params" #define UPLP_UPL_PARAMS_COMPAT "upl" diff --git a/test/boot/upl.c b/test/boot/upl.c index 7171f16e42e..91b7baa75e2 100644 --- a/test/boot/upl.c +++ b/test/boot/upl.c @@ -6,6 +6,7 @@ * Written by Simon Glass sjg@chromium.org */
+#define LOG_DEBUG #define LOG_CATEGORY UCLASS_BOOTSTD
#include <abuf.h>

The word 'we' is missing. Add it.
Signed-off-by: Simon Glass sjg@chromium.org ---
include/upl.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/include/upl.h b/include/upl.h index d5b2cad7196..b9bcdf60089 100644 --- a/include/upl.h +++ b/include/upl.h @@ -324,7 +324,7 @@ struct upl { * @root: root node to write it to * @skip_existing: Avoid recreating any nodes which already exist in the * devicetree. For example, if there is a serial node, just leave it alone, - * since don't need to create a new one + * since we don't need to create a new one * Return: 0 on success, -ve on error */ int upl_write_handoff(const struct upl *upl, ofnode root, bool skip_existing);

Add a new 'upl exec' command which loads a payload, sets up the handoff information and jumps to it.
This collects image information as the FIT's images are loaded.
With this, the size of the FIT is not known so is reported through UPL as zero. Future work will address this.
Signed-off-by: Simon Glass sjg@chromium.org ---
boot/Kconfig | 8 +++ boot/Makefile | 1 + boot/upl_exec.c | 130 +++++++++++++++++++++++++++++++++++++++++++++++ boot/upl_write.c | 2 +- cmd/upl.c | 25 ++++++++- include/upl.h | 29 ++++++++++- 6 files changed, 191 insertions(+), 4 deletions(-) create mode 100644 boot/upl_exec.c
diff --git a/boot/Kconfig b/boot/Kconfig index f9263513268..983bd9cdbf6 100644 --- a/boot/Kconfig +++ b/boot/Kconfig @@ -765,6 +765,7 @@ config BOOTMETH_SCRIPT config UPL bool "upl - Universal Payload Specification" imply CMD_UPL + imply UPL_EXEC imply UPL_READ imply UPL_WRITE imply SPL_UPL if SPL @@ -794,6 +795,13 @@ config UPL_WRITE for how to tell U-Boot SPL to actually write it before jumping to the next phase.
+config UPL_EXEC + bool "upl - Support for executing a UPL image" + help + Provides support for executing a loaded UPL image, passing it a + suitable handoff block. This can be used to pass control to a UPL from + another firmware project. + config UPL_IN bool "upl - Read the UPL handoff on startup" select UPL_READ diff --git a/boot/Makefile b/boot/Makefile index 9446c6b82a9..bc4ff91a934 100644 --- a/boot/Makefile +++ b/boot/Makefile @@ -42,6 +42,7 @@ obj-$(CONFIG_$(PHASE_)OF_LIBFDT) += fdt_support.o obj-$(CONFIG_$(PHASE_)FDT_SIMPLEFB) += fdt_simplefb.o
obj-$(CONFIG_$(PHASE_)UPL) += upl_common.o +obj-$(CONFIG_$(PHASE_)UPL_EXEC) += upl_exec.o obj-$(CONFIG_$(PHASE_)UPL_READ) += upl_read.o obj-$(CONFIG_$(PHASE_)UPL_WRITE) += upl_write.o
diff --git a/boot/upl_exec.c b/boot/upl_exec.c new file mode 100644 index 00000000000..8eb72a4cb16 --- /dev/null +++ b/boot/upl_exec.c @@ -0,0 +1,130 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * UPL handoff parsing + * + * Copyright 2024 Google LLC + * Written by Simon Glass sjg@chromium.org + */ + +#define LOG_CATEGORY UCLASS_BOOTSTD + +#include <bootstage.h> +#include <cpu.h> +#include <display_options.h> +#include <dm.h> +#include <image.h> +#include <log.h> +#include <mapmem.h> +#include <serial.h> +#include <upl.h> +#include <video.h> +#include <asm/global_data.h> +#include <dm/root.h> + +DECLARE_GLOBAL_DATA_PTR; + +struct upl *cur_upl; + +static void upl_prepare(const struct upl_image *img, const struct abuf *buf) +{ + printf("\nUPL: handoff at %lx size %zx\n", abuf_addr(buf), buf->size); + printf("Starting at %lx ...\n\n", img->entry); + + bootstage_mark_name(BOOTSTAGE_ID_BOOTM_HANDOFF, "upl_prepare"); + if (IS_ENABLED(CONFIG_BOOTSTAGE_REPORT)) + bootstage_report(); + + /* + * Call remove function of all devices with a removal flag set. + * This may be useful for last-stage operations, like cancelling + * of DMA operation or releasing device internal buffers. + */ + dm_remove_devices_active(); +} + +int _upl_add_image(int node, ulong load_addr, ulong size, const char *desc) +{ + struct upl_image img; + + if (!cur_upl) + return 0; + + memset(&img, '\0', sizeof(img)); + img.reg.base = load_addr; + img.reg.size = size; + img.offset = node; + img.description = desc; + if (!alist_add(&cur_upl->image, img)) + return -ENOMEM; + log_debug("upl: add image %s at %lx size %lx\n", desc, load_addr, size); + + return 0; +} + +int upl_exec(ulong addr) +{ + struct bootm_headers images; + struct upl s_upl, *upl = &s_upl; + struct upl_image *img; + ulong img_data, img_len; + const char *uname; + struct abuf buf; + int ret; + + upl_init(upl); + + cur_upl = upl; + uname = NULL; + memset(&images, '\0', sizeof(images)); + images.fit_uname_cfg = "conf-1"; + + /* a side-effect of this function is to call _upl_add_image() above */ + ret = fit_image_load(&images, addr, &uname, &images.fit_uname_cfg, + IH_ARCH_DEFAULT, IH_TYPE_FIRMWARE, + BOOTSTAGE_ID_FIT_KERNEL_START, + FIT_LOAD_OPTIONAL_NON_ZERO, &img_data, &img_len); + if (ret < 0) { + cur_upl = NULL; + return log_msg_retz("ufi", ret); + } + + /* add the FIT */ + upl->fit.base = addr; + upl->fit.size = 0; /* TODO(sjg@chromium.org): Add size */ + + images.fit_hdr_os = map_sysmem(addr, 0); + img = alist_getw(&upl->image, 0, struct upl_image); + if (!img) + return log_msg_ret("uim", ret); + + if (fit_image_get_entry(images.fit_hdr_os, ret, &img->entry)) + return log_msg_ret("uae", -ENOENT); + log_debug("entry %lx\n", img->entry); + + /* this calls _upl_add_image() with each loaded image */ + ret = boot_get_loadable(&images); + cur_upl = NULL; + if (ret) + return log_msg_ret("ulo", ret); + + /* we now have a full handoff state, including the images */ + ret = upl_create_handoff(upl, &buf); + if (ret) + return log_msg_ret("uec", ret); + + if (_DEBUG) { + set_working_fdt_addr(abuf_addr(&buf)); + run_command("fdt print", 0); + } + + upl_prepare(img, &buf); + + if (IS_ENABLED(CONFIG_X86)) { + ret = arch_upl_jump(img->entry, &buf); + } else { + printf("UPL is not supported on this architecture\n"); + ret = -ENOSYS; + } + + return ret; +} diff --git a/boot/upl_write.c b/boot/upl_write.c index c43a588dc40..ce9f733b450 100644 --- a/boot/upl_write.c +++ b/boot/upl_write.c @@ -685,7 +685,7 @@ int upl_create_handoff_tree(const struct upl *upl, oftree *treep) return 0; }
-int upl_create_handoff(struct upl *upl, ulong addr, struct abuf *buf) +int upl_create_handoff(struct upl *upl, struct abuf *buf) { oftree tree; int ret; diff --git a/cmd/upl.c b/cmd/upl.c index 461f8f4f0aa..e64ac7bbd20 100644 --- a/cmd/upl.c +++ b/cmd/upl.c @@ -112,12 +112,33 @@ static int do_upl_read(struct cmd_tbl *cmdtp, int flag, int argc, return 0; }
+static int do_upl_exec(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + ulong addr; + int ret; + + if (argc < 2) + return CMD_RET_USAGE; + + addr = hextoul(argv[1], NULL); + ret = upl_exec(addr); + if (ret) { + printf("Failed (err=%dE)\n", ret); + return CMD_RET_FAILURE; + } + + return 0; +} + U_BOOT_LONGHELP(upl, "info [-v] - Check UPL status\n" "upl read <addr> - Read handoff information\n" - "upl write - Write handoff information"); + "upl write - Write handoff information\n" + "upl exec - Execute a loaded UPL");
U_BOOT_CMD_WITH_SUBCMDS(upl, "Universal Payload support", upl_help_text, U_BOOT_SUBCMD_MKENT(info, 2, 1, do_upl_info), U_BOOT_SUBCMD_MKENT(read, 2, 1, do_upl_read), - U_BOOT_SUBCMD_MKENT(write, 1, 1, do_upl_write)); + U_BOOT_SUBCMD_MKENT(write, 1, 1, do_upl_write), + U_BOOT_SUBCMD_MKENT(exec, 2, 1, do_upl_exec)); diff --git a/include/upl.h b/include/upl.h index b9bcdf60089..f210a39df0c 100644 --- a/include/upl.h +++ b/include/upl.h @@ -347,6 +347,14 @@ int upl_create_handoff_tree(const struct upl *upl, oftree *treep); */ int upl_read_handoff(struct upl *upl, oftree tree);
+/** + * upl_exec() - Execulated a loaded UPL image + * + * @addr: Address of image + * Return: 0 on success, or -ve error + */ +int upl_exec(ulong addr); + /** * upl_get_test_data() - Fill a UPL with some test data * @@ -404,7 +412,7 @@ int _upl_add_image(int node, ulong load_addr, ulong size, const char *desc); static inline int upl_add_image(const void *fit, int node, ulong load_addr, ulong size) { - if (CONFIG_IS_ENABLED(UPL) && IS_ENABLED(CONFIG_XPL_BUILD)) { + if (CONFIG_IS_ENABLED(UPL)) { const char *desc = fdt_getprop(fit, node, FIT_DESC_PROP, NULL);
return _upl_add_image(node, load_addr, size, desc); @@ -469,6 +477,25 @@ int upl_write_to_buf(struct upl *upl, ofnode root, struct abuf *buf); int upl_add_region(struct alist *lst, u64 base, ulong size); #endif
+/** + * upl_create_handoff() - Create a UPL handoff + * + * @upl: Returns the handoff structure that was created + * @buf: Returns buffer containing the final handoff info + * Return: 0 if OK, -ve on error + */ +int upl_create_handoff(struct upl *upl, struct abuf *buf); + +/** + * arch_upl_jump() - Jump to the UPL payload + * + * Jump to + * + * @entry: Address to jump to + * @buf: Buffer containing UPL-handoff information + */ +int arch_upl_jump(ulong entry, const struct abuf *buf); + /** upl_init() - Set up a UPL struct */ void upl_init(struct upl *upl);

Some UPL images such as EDK2 may change into 64-bit mode after starting. Avoid a crash by always using the 64-bit machine QEMU. This seems to have no ill effects for 32-bit code.
Signed-off-by: Simon Glass sjg@chromium.org ---
scripts/build-qemu.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/scripts/build-qemu.sh b/scripts/build-qemu.sh index f9ee0072573..10ea99982d2 100755 --- a/scripts/build-qemu.sh +++ b/scripts/build-qemu.sh @@ -176,7 +176,8 @@ arm) x86) BOARD="qemu-x86" BIOS="u-boot.rom" - qemu=qemu-system-i386 + # Use 64-bit version to allow UPL to change to 64-bit mode later + qemu=qemu-system-x86_64 suffix="i386" if [[ "${bitness}" == "64" ]]; then BOARD="qemu-x86_64"

Add a -u option to specify a UPL to load. This is made available in a separate virtio device. Allow this to work even if the -B flag is provided, to allow iterating on the payload, without changing U-Boot
Signed-off-by: Simon Glass sjg@chromium.org ---
scripts/build-qemu.sh | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-)
diff --git a/scripts/build-qemu.sh b/scripts/build-qemu.sh index 10ea99982d2..b92623c9bc5 100755 --- a/scripts/build-qemu.sh +++ b/scripts/build-qemu.sh @@ -30,6 +30,7 @@ usage() { echo " -R <os> - Select OS release (e.g. 24.04)" echo " -s - Use serial only (no display)" echo " -S <seq> - Select SCT sequence-file" + echo " -u <file> - Run Universal Payload (UPL) file" echo " -w - Use word version (32-bit)" ) >&2 exit 1 } @@ -69,11 +70,14 @@ serial= # Use kvm kvm=
+# Use UPL +upl= + # Set ubdir to the build directory where you build U-Boot out-of-tree # We avoid in-tree build because it gets confusing trying different builds ubdir=${ubdir-/tmp/b}
-while getopts "a:Beko:rR:sS:w" opt; do +while getopts "a:Beko:rR:sS:u:w" opt; do case "${opt}" in a) arch=$OPTARG @@ -113,6 +117,9 @@ while getopts "a:Beko:rR:sS:w" opt; do S) seq=$OPTARG ;; + u) + upl=$OPTARG + ;; w) bitness=32 ;; @@ -140,11 +147,24 @@ update_sct_seq() { sudo losetup -d ${LOOP} }
+# Add a Universal Payload into the image +add_upl() { + if [[ -z "${upl}" ]]; then + return + fi + qemu-img create upl.img 8M + mkfs.fat upl.img + mcopy -vs -i upl.img "${upl}" ::/upl.fit +} + # Run QEMU with U-Boot run_qemu() { if [[ -n "${os_image}" ]]; then extra+=" -drive if=virtio,file=${os_image},format=raw,id=hd0" fi + if [[ -n "${upl}" ]]; then + extra+=" -drive if=virtio,file=upl.img,format=raw,id=hd0" + fi if [[ -n "${serial}" ]]; then extra+=" -display none -serial mon:stdio" else @@ -204,8 +224,9 @@ DIR=${ubdir}/${BOARD}
if [[ -n "${build}" ]]; then build_u_boot - update_sct_seq fi +update_sct_seq +add_upl
if [[ -n "${run}" ]]; then run_qemu

Mark these as reserved memory-regions so that the payload can find the tables. Remove the upl-params properties which are no-longer in the spec. Add a compatible string instead.
Signed-off-by: Simon Glass sjg@chromium.org ---
boot/upl_common.c | 40 +++++++++++++++++++++++++++++++++++++++- boot/upl_read.c | 25 ++++++++++++++++++------- boot/upl_write.c | 38 +++++++++++++++++++++++++++++++------- include/alist.h | 2 +- include/upl.h | 21 +++++++++++++++++++-- lib/alist.c | 2 +- test/boot/upl.c | 13 +++++++++---- 7 files changed, 118 insertions(+), 23 deletions(-)
diff --git a/boot/upl_common.c b/boot/upl_common.c index e60f22f47e0..e07a07cc945 100644 --- a/boot/upl_common.c +++ b/boot/upl_common.c @@ -8,6 +8,7 @@
#define LOG_CATEGORY UCLASS_BOOTSTD
+#include <bloblist.h> #include <cpu.h> #include <dm.h> #include <serial.h> @@ -138,7 +139,8 @@ int upl_create(struct upl *upl) { struct upl_mem mem; ulong base, size; - int ret; + int ret, bsize; + void *ptr;
/* hard-code this for now to keep Tianocore happy */ upl->addr_cells = 2; @@ -158,12 +160,28 @@ int upl_create(struct upl *upl) if (!alist_add(&upl->mem, mem)) return log_msg_ret("arg", -ENOMEM);
+ ptr = bloblist_get_blob(BLOBLISTT_SMBIOS_TABLES, &bsize); + if (ptr) { + upl->smbios.base = map_to_sysmem(ptr); + upl->smbios.size = bsize; + } + ptr = bloblist_get_blob(BLOBLISTT_ACPI_TABLES, &bsize); + if (ptr) { + upl->acpi.base = map_to_sysmem(ptr); + upl->acpi.size = bsize; + } + ret = upl_add_serial(&upl->serial); if (ret && ret != -ENOENT) return log_msg_ret("ser", ret); ret = upl_add_graphics(&upl->graphics, &base, &size); if (ret && ret != -ENOENT) return log_msg_ret("gra", ret); + if (!ret) { + ret = upl_add_memres(upl, UPLN_MEMORY, base, size, true); + if (ret) + return log_msg_ret("grr", ret); + }
return 0; } @@ -201,6 +219,26 @@ int upl_add_region(struct alist *lst, u64 base, ulong size) return 0; }
+int upl_add_memres(struct upl *upl, const char *name, u64 base, ulong size, + bool no_map) +{ + struct upl_memres memres; + int ret; + + log_debug("base = %llx size = %lx\n", base, size); + memset(&memres, '\0', sizeof(memres)); + alist_init_struct(&memres.region, struct memregion); + memres.name = name; + memres.no_map = no_map; + ret = upl_add_region(&memres.region, base, size); + if (ret) + return log_msg_ret("uav", ret); + if (!alist_add(&upl->memres, memres)) + return log_msg_ret("uaM", -ENOMEM); + + return 0; +} + void upl_init(struct upl *upl) { memset(upl, '\0', sizeof(struct upl)); diff --git a/boot/upl_read.c b/boot/upl_read.c index 4f07204546e..05db559efdb 100644 --- a/boot/upl_read.c +++ b/boot/upl_read.c @@ -248,12 +248,6 @@ static int decode_upl_params(struct upl *upl, ofnode options) return log_msg_ret("par", -EINVAL); log_debug("decoding '%s'\n", ofnode_get_name(node));
- ret = read_addr(upl, node, UPLP_SMBIOS, &upl->smbios); - if (ret) - return log_msg_ret("smb", ret); - ret = read_addr(upl, node, UPLP_ACPI, &upl->acpi); - if (ret) - return log_msg_ret("acp", ret); ret = ofnode_read_bitmask(node, UPLP_BOOTMODE, bootmode_names, UPLBM_COUNT, &upl->bootmode); if (ret) @@ -416,7 +410,7 @@ static int decode_upl_memres(struct upl *upl, ofnode root)
ofnode_for_each_subnode(node, root) { struct upl_memres memres; - const char *buf; + const char *buf, *compat; int size, len;
log_debug("decoding '%s'\n", ofnode_get_name(node)); @@ -434,6 +428,23 @@ static int decode_upl_memres(struct upl *upl, ofnode root) return log_msg_ret("buf", len); memres.no_map = ofnode_read_bool(node, UPLP_NO_MAP);
+ compat = ofnode_read_string(node, UPLP_COMPATIBLE); + if (compat && memres.region.count == 1) { + const struct memregion *rgn; + + rgn = alist_get(&memres.region, 0, struct memregion); + if (!strcmp(compat, UPLP_SMBIOS)) + upl->smbios = *rgn; + else if (!strcmp(compat, UPLP_ACPI)) + upl->acpi = *rgn; + else + log_warning("Ignoring compat '%s'\n", compat); + + /* don't add this node to the memres list */ + alist_uninit(&memres.region); + continue; + } + if (!alist_add(&upl->memres, memres)) return log_msg_ret("mre", -ENOMEM); } diff --git a/boot/upl_write.c b/boot/upl_write.c index ce9f733b450..5db5d02e6e8 100644 --- a/boot/upl_write.c +++ b/boot/upl_write.c @@ -228,10 +228,6 @@ static int add_upl_params(const struct upl *upl, ofnode options) return log_msg_ret("img", ret);
ret = ofnode_write_string(node, "compatible", UPLP_UPL_PARAMS_COMPAT); - if (!ret) - ret = write_addr(upl, node, UPLP_SMBIOS, upl->smbios); - if (!ret) - ret = write_addr(upl, node, UPLP_ACPI, upl->acpi); if (!ret && upl->bootmode) ret = ofnode_write_bitmask(node, UPLP_BOOTMODE, bootmode_names, UPLBM_COUNT, upl->bootmode); @@ -350,6 +346,8 @@ static int write_mem_node(const struct upl *upl, ofnode parent, return log_msg_ret("wmn", ret);
len = encode_reg(upl, buf, sizeof(buf), mem->count, mem); + if (len < 0) + return log_msg_ret("uer", ret); ret = ofnode_write_prop(node, UPLP_REG, buf, len, true); if (ret) return log_msg_ret("wm1", ret); @@ -437,7 +435,8 @@ static int add_upl_memres(const struct upl *upl, ofnode root, bool skip_existing) { const struct upl_memres *memres; - ofnode mem_node; + struct alist region; + ofnode mem_node, node; int ret;
if (!upl->memres.count) @@ -453,8 +452,6 @@ static int add_upl_memres(const struct upl *upl, ofnode root, return log_msg_ret("im2", ret);
alist_for_each(memres, &upl->memres) { - ofnode node; - ret = write_mem_node(upl, mem_node, &memres->region, memres->name, &node); if (ret) @@ -467,6 +464,33 @@ static int add_upl_memres(const struct upl *upl, ofnode root, return log_msg_ret("lst", ret); }
+ if (upl->smbios.base) { + alist_init_struct(®ion, struct memregion); + if (!alist_add(®ion, upl->smbios)) + return log_msg_ret("ups", ret); + ret = write_mem_node(upl, mem_node, ®ion, UPLN_MEMORY, + &node); + alist_uninit(®ion); + if (ret) + return log_msg_ret("mrs", ret); + ret = ofnode_write_string(node, UPLP_COMPATIBLE, UPLP_SMBIOS); + if (ret) + return log_msg_ret("mrS", ret); + } + if (upl->acpi.base) { + alist_init_struct(®ion, struct memregion); + if (!alist_add(®ion, upl->acpi)) + return log_msg_ret("upa", ret); + ret = write_mem_node(upl, mem_node, ®ion, UPLN_MEMORY, + &node); + alist_uninit(®ion); + if (ret) + return log_msg_ret("mra", ret); + ret = ofnode_write_string(node, UPLP_COMPATIBLE, UPLP_ACPI); + if (ret) + return log_msg_ret("mrA", ret); + } + return 0; }
diff --git a/include/alist.h b/include/alist.h index b00d9ea97d6..8aac5cd46ec 100644 --- a/include/alist.h +++ b/include/alist.h @@ -184,7 +184,7 @@ void *alist_add_placeholder(struct alist *lst); * @obj: Pointer to object to copy in * Returns: pointer to where the object was copied, or NULL if out of memory */ -void *alist_add_ptr(struct alist *lst, void *obj); +void *alist_add_ptr(struct alist *lst, const void *obj);
/** * alist_expand_by() - Expand a list by the given amount diff --git a/include/upl.h b/include/upl.h index f210a39df0c..eb7ef463b9e 100644 --- a/include/upl.h +++ b/include/upl.h @@ -288,6 +288,8 @@ struct upl_pci { * * @addr_cells: Number of address cells used in the handoff * @size_cells: Number of size cells used in the handoff + * @smbios: SMBIOS region, base is 0 if none + * @acpi: ACPI region, base is 0 if none * @bootmode: Boot-mode mask (enum upl_boot_mode) * @fit: Address and size of FIT image that was loaded * @conf_offset: Offset in FIT of the configuration that was selected @@ -301,8 +303,8 @@ struct upl { int addr_cells; int size_cells;
- ulong smbios; - ulong acpi; + struct memregion smbios; + struct memregion acpi; enum upl_boot_mode bootmode; struct memregion fit; uint conf_offset; @@ -475,6 +477,21 @@ int upl_write_to_buf(struct upl *upl, ofnode root, struct abuf *buf); * Return: 0 if OK, -ve on error */ int upl_add_region(struct alist *lst, u64 base, ulong size); + +/** + * upl_add_memres() - Add a new reserved-memory region + * + * Adds a new entry to the end of the memres list + * + * @upl: UPL to add to + * @name: Node name to use for new region) + * @base: Base address of new region + * @size: Size of new region + * @no_map: true if the no-map property should be enabled + * Return: 0 if OK, -ve on error + */ +int upl_add_memres(struct upl *upl, const char *name, u64 base, ulong size, + bool no_map); #endif
/** diff --git a/lib/alist.c b/lib/alist.c index 4ce651f5c45..05399c78a92 100644 --- a/lib/alist.c +++ b/lib/alist.c @@ -167,7 +167,7 @@ void *alist_add_placeholder(struct alist *lst) return alist_ensure_ptr(lst, lst->count); }
-void *alist_add_ptr(struct alist *lst, void *obj) +void *alist_add_ptr(struct alist *lst, const void *obj) { void *ptr;
diff --git a/test/boot/upl.c b/test/boot/upl.c index 91b7baa75e2..ae7abed72f1 100644 --- a/test/boot/upl.c +++ b/test/boot/upl.c @@ -26,6 +26,7 @@ static int add_region(struct unit_test_state *uts, struct alist *lst, { struct memregion region;
+ memset(®ion, '\0', sizeof(region)); region.base = base; region.size = size; ut_assertnonnull(alist_add(lst, region)); @@ -44,8 +45,10 @@ int upl_get_test_data(struct unit_test_state *uts, struct upl *upl)
upl->addr_cells = 1; upl->size_cells = 1; - upl->smbios = 0x123; - upl->acpi = 0x456; + upl->smbios.base = 0x123; + upl->smbios.size = 0x321; + upl->acpi.base = 0x456; + upl->acpi.size = 0x654; upl->bootmode = BIT(UPLBM_DEFAULT) | BIT(UPLBM_S3); upl->fit.base = 0x789; upl->fit.size = 0xabc; @@ -294,8 +297,10 @@ static int compare_upl(struct unit_test_state *uts, struct upl *base, ut_asserteq(base->addr_cells, cmp->addr_cells); ut_asserteq(base->size_cells, cmp->size_cells);
- ut_asserteq(base->smbios, cmp->smbios); - ut_asserteq(base->acpi, cmp->acpi); + ut_asserteq(base->smbios.base, cmp->smbios.base); + ut_asserteq(base->smbios.size, cmp->smbios.size); + ut_asserteq(base->acpi.base, cmp->acpi.base); + ut_asserteq(base->acpi.size, cmp->acpi.size); ut_asserteq(base->bootmode, cmp->bootmode); ut_asserteq(base->fit.base, cmp->fit.base); ut_asserteq(base->fit.size, cmp->fit.size);

Tianocore expects this property to specify the entry address. Add it until it can be updated to follow the spec in this area, i.e. use an 'entry' property in the relevant upl-image node.
Signed-off-by: Simon Glass sjg@chromium.org ---
boot/upl_write.c | 6 ++++++ 1 file changed, 6 insertions(+)
diff --git a/boot/upl_write.c b/boot/upl_write.c index 5db5d02e6e8..a9d25f607fe 100644 --- a/boot/upl_write.c +++ b/boot/upl_write.c @@ -307,6 +307,12 @@ static int add_upl_images(const struct upl *upl, ofnode options) img->description); if (ret) return log_msg_ret("sim", ret); + + /* temporary hack for Tinaocore, until March 2025 */ + ret = write_addr(upl, node, "addr", upl->fit.base); + if (ret < 0) + return log_msg_ret("uma", ret); + }
return 0;

On Thu, Jan 02, 2025 at 11:08:46AM +1300, Simon Glass wrote:
The current UPL spec[1] has been tidied up and improved over the last year, since U-Boot's original UPL support was written.
This series addresses various issues, with a goal of having U-Boot boot EDK2.
There is still more work to do, but this series gets to the point (on QEMU) where the ACPI tables are required. Further work will be needed to relocate the tables out of the QEMU firmware-filesystem.
[1] git@github.com:UniversalPayload/spec.git commit 3f1450d
Since this is on top of your fork, and not mainline, and you aren't even noting that in your cover letter it's probably not worth the time of everyone you sent this to, to look at.

Hi Tom,
On Fri, 3 Jan 2025 at 03:44, Tom Rini trini@konsulko.com wrote:
On Thu, Jan 02, 2025 at 11:08:46AM +1300, Simon Glass wrote:
The current UPL spec[1] has been tidied up and improved over the last year, since U-Boot's original UPL support was written.
This series addresses various issues, with a goal of having U-Boot boot EDK2.
There is still more work to do, but this series gets to the point (on QEMU) where the ACPI tables are required. Further work will be needed to relocate the tables out of the QEMU firmware-filesystem.
[1] git@github.com:UniversalPayload/spec.git commit 3f1450d
Since this is on top of your fork, and not mainline, and you aren't even noting that in your cover letter it's probably not worth the time of everyone you sent this to, to look at.
It applies to -next except for the QEMU script which you rejected. I can't do anything about that. So I think you may have the wrong end of the stick here.
The only thing I can think of is that the UPL series depends on Raymond's bloblist patch [1]. But I was assuming that would be applied at some point and I didn't want to resend someone else's patch. I don't have it in the sjg tree either yet, as I was hoping he would write a test. In fact I would very-much like people to write tests (and docs if needed) without needing to be asked.
Regards, Simon
[1] https://lore.kernel.org/u-boot/CAFLszTjSGqmk8yYYbXFEaFZWFhF8uhj_rNxZz7ship1-...

On Fri, Jan 03, 2025 at 12:45:36PM +1300, Simon Glass wrote:
Hi Tom,
On Fri, 3 Jan 2025 at 03:44, Tom Rini trini@konsulko.com wrote:
On Thu, Jan 02, 2025 at 11:08:46AM +1300, Simon Glass wrote:
The current UPL spec[1] has been tidied up and improved over the last year, since U-Boot's original UPL support was written.
This series addresses various issues, with a goal of having U-Boot boot EDK2.
There is still more work to do, but this series gets to the point (on QEMU) where the ACPI tables are required. Further work will be needed to relocate the tables out of the QEMU firmware-filesystem.
[1] git@github.com:UniversalPayload/spec.git commit 3f1450d
Since this is on top of your fork, and not mainline, and you aren't even noting that in your cover letter it's probably not worth the time of everyone you sent this to, to look at.
It applies to -next except for the QEMU script which you rejected. I can't do anything about that. So I think you may have the wrong end of the stick here.
The only thing I can think of is that the UPL series depends on Raymond's bloblist patch [1]. But I was assuming that would be applied at some point and I didn't want to resend someone else's patch. I don't have it in the sjg tree either yet, as I was hoping he would write a test. In fact I would very-much like people to write tests (and docs if needed) without needing to be asked.
Regards, Simon
[1] https://lore.kernel.org/u-boot/CAFLszTjSGqmk8yYYbXFEaFZWFhF8uhj_rNxZz7ship1-...
A 60 part series that includes changes to something that was rejected, and depends on a series from someone else that was changes requested, and is again, 60+ patches, is not at all helpful. Please stop doing this.

Hi Tom,
On Sat, 4 Jan 2025 at 03:26, Tom Rini trini@konsulko.com wrote:
On Fri, Jan 03, 2025 at 12:45:36PM +1300, Simon Glass wrote:
Hi Tom,
On Fri, 3 Jan 2025 at 03:44, Tom Rini trini@konsulko.com wrote:
On Thu, Jan 02, 2025 at 11:08:46AM +1300, Simon Glass wrote:
The current UPL spec[1] has been tidied up and improved over the last year, since U-Boot's original UPL support was written.
This series addresses various issues, with a goal of having U-Boot boot EDK2.
There is still more work to do, but this series gets to the point (on QEMU) where the ACPI tables are required. Further work will be needed to relocate the tables out of the QEMU firmware-filesystem.
[1] git@github.com:UniversalPayload/spec.git commit 3f1450d
Since this is on top of your fork, and not mainline, and you aren't even noting that in your cover letter it's probably not worth the time of everyone you sent this to, to look at.
It applies to -next except for the QEMU script which you rejected. I can't do anything about that. So I think you may have the wrong end of the stick here.
The only thing I can think of is that the UPL series depends on Raymond's bloblist patch [1]. But I was assuming that would be applied at some point and I didn't want to resend someone else's patch. I don't have it in the sjg tree either yet, as I was hoping he would write a test. In fact I would very-much like people to write tests (and docs if needed) without needing to be asked.
Regards, Simon
[1] https://lore.kernel.org/u-boot/CAFLszTjSGqmk8yYYbXFEaFZWFhF8uhj_rNxZz7ship1-...
A 60 part series that includes changes to something that was rejected, and depends on a series from someone else that was changes requested, and is again, 60+ patches, is not at all helpful. Please stop doing this.
As I see it, my only alternatives were to:
a) resend Raymond's patch unchanged (with a note that it is merely for convenience), or b) not send it, knowing that his patch will likely be applied before this series
I chose b. The single, dependent patch is really not an issue, IMO.
I often send large series, e.g. [2]. Sometimes, as with UPL, there is just an enormous amount of work to get through. I really don't like combining patches just to reduce the patch count. But I can split of the pre-req patches (about 30) so I'll do that for v2. Honestly, I was just desperate to get some of the work sent out so it didn't die on the vine.
BTW, please reconsider your objections to the qemu script. I think it might make sense to convert it to Python at some point, but the complexity of building images and running QEMU for different use cases is such that a script makes a lot of sense.
Regards, Simon
[2] https://patchwork.ozlabs.org/project/uboot/list/?series=364775&state=*
participants (3)
-
Heinrich Schuchardt
-
Simon Glass
-
Tom Rini