From 4834bf1bc80a52421d4eff48dd5b7f89faf2d098 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Tue, 13 Jun 2023 21:02:01 +0200 Subject: [PATCH 1/9] doc: man-page for imxtract Provide a man-page for the imxtract command. Signed-off-by: Heinrich Schuchardt --- doc/usage/cmd/imxtract.rst | 81 ++++++++++++++++++++++++++++++++++++++ doc/usage/index.rst | 1 + 2 files changed, 82 insertions(+) create mode 100644 doc/usage/cmd/imxtract.rst diff --git a/doc/usage/cmd/imxtract.rst b/doc/usage/cmd/imxtract.rst new file mode 100644 index 00000000000..eb64b1cefab --- /dev/null +++ b/doc/usage/cmd/imxtract.rst @@ -0,0 +1,81 @@ +.. SPDX-License-Identifier: GPL-2.0+: + +imxtract command +================ + +Synopsis +-------- + +:: + + imxtract addr part [dest] + imxtract addr uname [dest] + +Description +----------- + +The imxtract command is used to extract a part of a multi-image file. + +Two different file formats are supported: + +* FIT images +* legacy U-Boot images + +addr + Address of the multi-image file from which a part shall be extracted + +part + Index (hexadecimal) of the part of a legacy U-Boot image to be extracted + +uname + Name of the part of a FIT image to be extracted + +dest + Destination address (defaults to 0x0) + +The value of environment variable *verify* controls if the hashes and +signatures of FIT images or the check sums of legacy U-Boot images are checked. +To enable checking set *verify* to one of the values *1*, *yes*, *true*. +(Actually only the first letter is checked disregarding the case.) + +To list the parts of an image the *iminfo* command can be used. + +Examples +-------- + +With verify=no incorrect hashes, signatures, or check sums don't stop the +extraction. But correct hashes are still indicated in the output +(here: md5, sha1). + +.. code-block:: console + + => setenv verify no + => imxtract $loadaddr kernel-1 $kernel_addr_r + ## Copying 'kernel-1' subimage from FIT image at 40200000 ... + md5+ sha1+ Loading part 0 ... OK + => + +With verify=yes incorrect hashes, signatures, or check sums stop the extraction. + +.. code-block:: console + + => setenv verify yes + => imxtract $loadaddr kernel-1 $kernel_addr_r + ## Copying 'kernel-1' subimage from FIT image at 40200000 ... + md5 error! + Bad hash value for 'hash-1' hash node in 'kernel-1' image node + Bad Data Hash + => + +Configuration +------------- + +The imxtract command is only available if CONFIG_CMD_XIMG=y. Support for FIT +images requires CONFIG_FIT=y. Support for legacy U-Boot images requires +CONFIG_LEGACY_IMAGE_FORMAT=y. + +Return value +------------ + +On success the return value $? of the command is 0 (true). On failure the +return value is 1 (false). diff --git a/doc/usage/index.rst b/doc/usage/index.rst index 84ef8a9a427..54ef89edb21 100644 --- a/doc/usage/index.rst +++ b/doc/usage/index.rst @@ -62,6 +62,7 @@ Shell commands cmd/fwu_mdata cmd/gpio cmd/host + cmd/imxtract cmd/load cmd/loadb cmd/loadm From 268d25f3109f77ef0c61a05078b4762f804e0ba2 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Mon, 12 Jun 2023 14:12:13 +0800 Subject: [PATCH 2/9] doc: event: Correct EVT_DM_POST_INIT_F description EVT_DM_POST_INIT_F only works in U-Boot proper, not SPL. Signed-off-by: Bin Meng Reviewed-by: Simon Glass Polish the wording a bit Reviewed-by: Heinrich Schuchardt --- doc/develop/event.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/develop/event.rst b/doc/develop/event.rst index 1c1c9ef7f1b..cb09e9c85a9 100644 --- a/doc/develop/event.rst +++ b/doc/develop/event.rst @@ -28,8 +28,8 @@ To declare a spy, use something like this:: } EVENT_SPY(EVT_DM_POST_INIT_F, snow_setup_cpus); -Your function is called when EVT_DM_POST_INIT_F is emitted, i.e. after driver -model is inited (in SPL, or in U-Boot proper before and after relocation). +This function is called when EVT_DM_POST_INIT_F is emitted, i.e. after the +driver model is initialized (in U-Boot proper before and after relocation). Debugging From 12858ab216a2f3faf7e37fb5c292b64afff673cf Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Fri, 2 Jun 2023 22:18:23 +0200 Subject: [PATCH 3/9] Makefile: clean lib/efi_loader/helloworld_efi.S lib/efi_loader/helloworld_efi.S is a generated file and shall be removed by 'make clean'. Signed-off-by: Heinrich Schuchardt --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 8b030f31be9..444baaefd0e 100644 --- a/Makefile +++ b/Makefile @@ -2160,7 +2160,7 @@ CLEAN_FILES += include/bmp_logo.h include/bmp_logo_data.h \ mkimage-out.spl.mkimage mkimage.spl.mkimage imx-boot.map \ itb.fit.fit itb.fit.itb itb.map spl.map mkimage-out.rom.mkimage \ mkimage.rom.mkimage rom.map simple-bin.map simple-bin-spi.map \ - idbloader-spi.img + idbloader-spi.img lib/efi_loader/helloworld_efi.S # Directories & files removed with 'make mrproper' MRPROPER_DIRS += include/config include/generated spl tpl \ From a61e6ad76914a30a562ac01339c5d21f3283def8 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sat, 10 Jun 2023 21:25:18 +0200 Subject: [PATCH 4/9] efi_selftest: ReinstallProtocolInterface test Test ReinstallProtocolInterface() more rigorously. Replacing the sole installed protocol interface must not result in deleting the handle and creating a new one. Check which interface is actually installed before and after ReinstallProtocolInterface(). Signed-off-by: Heinrich Schuchardt --- .../efi_selftest_register_notify.c | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/lib/efi_selftest/efi_selftest_register_notify.c b/lib/efi_selftest/efi_selftest_register_notify.c index ad4bcce1a10..adf5dd00a1e 100644 --- a/lib/efi_selftest/efi_selftest_register_notify.c +++ b/lib/efi_selftest/efi_selftest_register_notify.c @@ -124,6 +124,7 @@ static int execute(void) { efi_status_t ret; efi_handle_t handle1 = NULL, handle2 = NULL; + struct interface *interface; struct interface interface1, interface2; ret = boottime->install_protocol_interface(&handle1, &guid1, @@ -145,6 +146,18 @@ static int execute(void) efi_st_error("LocateHandle failed\n"); return EFI_ST_FAILURE; } + interface = NULL; + ret = boottime->open_protocol(handle1, &guid1, (void**)&interface, + NULL, NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (ret != EFI_SUCCESS) { + efi_st_error("Cannot find installed protocol on handle\n"); + return EFI_ST_FAILURE; + } + if (interface != &interface1) { + efi_st_error("Wrong interface after install\n"); + return EFI_ST_FAILURE; + } ret = boottime->free_pool(context.handles); if (ret != EFI_SUCCESS) { efi_st_error("FreePool failed\n"); @@ -186,6 +199,18 @@ static int execute(void) efi_st_error("FreePool failed\n"); return EFI_ST_FAILURE; } + interface = NULL; + ret = boottime->open_protocol(handle1, &guid1, (void**)&interface, + NULL, NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (ret != EFI_SUCCESS) { + efi_st_error("Cannot find reinstalled protocol on handle\n"); + return EFI_ST_FAILURE; + } + if (interface != &interface2) { + efi_st_error("Wrong interface after reinstall\n"); + return EFI_ST_FAILURE; + } context.notify_count = 0; ret = boottime->install_protocol_interface(&handle2, &guid1, EFI_NATIVE_INTERFACE, From 4533b3d0a346ab974b59badc61c904f3adb55a84 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Tue, 13 Jun 2023 08:18:27 +0200 Subject: [PATCH 5/9] bootm: don't call booti_setup for EFI images On the arm64 architecture booti_setup() is called for EFI FIT images. This function call fails because EFI images typically do not have a kernel signature. Check that the operating system property "os" of the image is "linux" before invoking booti_setup(). Fixes: 487b5fa6deb1 ("bootm: Handle kernel_noload on arm64") Signed-off-by: Heinrich Schuchardt Reviewed-by: Simon Glass --- boot/bootm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/boot/bootm.c b/boot/bootm.c index 4144ff3b031..75f0b4a9af8 100644 --- a/boot/bootm.c +++ b/boot/bootm.c @@ -240,7 +240,8 @@ static int bootm_find_os(struct cmd_tbl *cmdtp, int flag, int argc, if (images.os.type == IH_TYPE_KERNEL_NOLOAD) { if (IS_ENABLED(CONFIG_CMD_BOOTI) && - images.os.arch == IH_ARCH_ARM64) { + images.os.arch == IH_ARCH_ARM64 && + images.os.os == IH_OS_LINUX) { ulong image_addr; ulong image_size; From 0773e4d9d90ad7c955088b122e7319a1071813fd Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Thu, 15 Jun 2023 13:40:05 +0200 Subject: [PATCH 6/9] test: correct architecture in EFI FIT test On arm64 the its we use to generate the test FIT image has arch = "arm"; We should use "arm64" here which is mapped to IH_ARCH_ARM64 via uimage_arch[]. Fixes: 8391f955494e ("test/py: Create a test for launching UEFI binaries from FIT images") Signed-off-by: Heinrich Schuchardt --- test/py/tests/test_efi_fit.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/py/tests/test_efi_fit.py b/test/py/tests/test_efi_fit.py index 7b7c98fb04c..0ad483500f8 100644 --- a/test/py/tests/test_efi_fit.py +++ b/test/py/tests/test_efi_fit.py @@ -431,6 +431,11 @@ def test_efi_fit_launch(u_boot_console): cons = u_boot_console # Array slice removes leading/trailing quotes. sys_arch = cons.config.buildconfig.get('config_sys_arch', '"sandbox"')[1:-1] + if sys_arch == 'arm': + arm64 = cons.config.buildconfig.get('config_arm64') + if arm64: + sys_arch = 'arm64' + is_sandbox = sys_arch == 'sandbox' if is_sandbox: From 3ae95fe21cbd1e367e6169968ed2497a2ea8561a Mon Sep 17 00:00:00 2001 From: Ilias Apalodimas Date: Wed, 14 Jun 2023 09:55:48 +0300 Subject: [PATCH 7/9] efi_selftests: fix controllers repeated selftesting Running the controller selftest more than one times fails with => setenv efi_selftest 'controllers' && bootefi selftest Testing EFI API implementation Selected test: 'controllers' Setting up 'controllers' Setting up 'controllers' succeeded Executing 'controllers' Executing 'controllers' succeeded Summary: 0 failures => bootefi selftest Testing EFI API implementation Selected test: 'controllers' Setting up 'controllers' lib/efi_selftest/efi_selftest_controllers.c(280): ERROR: InstallProtocolInterface failed lib/efi_selftest/efi_selftest.c(89): ERROR: Setting up 'controllers' failed Summary: 1 failures There are multiple reason for this. We don't uninstall the binding interface from the controller handle and we don't reset the handle pointers either. So let's uninstall all the protocols properly and reset the handles to NULL on setup(). While at it add a forgotten check when uninstalling protocols from the handle_controller and make sure the number of child controllers is 0 Signed-off-by: Ilias Apalodimas Reviewed-by: Heinrich Schuchardt Signed-off-by: Heinrich Schuchardt --- lib/efi_selftest/efi_selftest_controllers.c | 26 ++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/lib/efi_selftest/efi_selftest_controllers.c b/lib/efi_selftest/efi_selftest_controllers.c index d2bbd1c4f65..63e674bedc0 100644 --- a/lib/efi_selftest/efi_selftest_controllers.c +++ b/lib/efi_selftest/efi_selftest_controllers.c @@ -271,6 +271,8 @@ static int setup(const efi_handle_t img_handle, efi_status_t ret; boottime = systable->boottime; + handle_controller = NULL; + handle_driver = NULL; /* Create controller handle */ ret = boottime->install_protocol_interface( @@ -402,14 +404,36 @@ static int execute(void) /* Check number of child controllers */ ret = count_child_controllers(handle_controller, &guid_controller, &count); - if (ret == EFI_SUCCESS) + if (ret == EFI_SUCCESS || count) { efi_st_error("Uninstall failed\n"); + return EFI_ST_FAILURE; + } + + return EFI_ST_SUCCESS; } + /* + * Tear down unit test. + * + */ +static int teardown(void) +{ + efi_status_t ret; + /* Uninstall binding protocol */ + ret = boottime->uninstall_protocol_interface(handle_driver, + &guid_driver_binding_protocol, + &binding_interface); + if (ret != EFI_SUCCESS) + efi_st_error("Failed to uninstall protocols\n"); + + return ret; +} + EFI_UNIT_TEST(controllers) = { .name = "controllers", .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT, .setup = setup, .execute = execute, + .teardown = teardown, }; From 3cc2b9f5b982ff3a192202b6d422eeb1893fa667 Mon Sep 17 00:00:00 2001 From: Ilias Apalodimas Date: Mon, 12 Jun 2023 18:35:58 +0300 Subject: [PATCH 8/9] efi_loader: simplify efi_disk_remove Instead of discovering the ID of the device and call two different functions for a block device or a partition, we can rewrite efi_disk_remove() and handle the minor differences between the two variants internally. As a results we can simplify efi_disk_remove() a lot and get rid of the extra efi_disk_delete_raw/blk calls. Signed-off-by: Ilias Apalodimas If a handle is not found, return 0 to let the device be removed. Reviewed-by: Heinrich Schuchardt --- lib/efi_loader/efi_disk.c | 109 ++++++++++++-------------------------- 1 file changed, 35 insertions(+), 74 deletions(-) diff --git a/lib/efi_loader/efi_disk.c b/lib/efi_loader/efi_disk.c index d2256713a8e..28c8cdf7100 100644 --- a/lib/efi_loader/efi_disk.c +++ b/lib/efi_loader/efi_disk.c @@ -690,89 +690,50 @@ int efi_disk_probe(void *ctx, struct event *event) return 0; } -/* - * Delete an efi_disk object for a whole raw disk +/** + * efi_disk_remove - delete an efi_disk object for a block device or partition * - * @dev uclass device (UCLASS_BLK) + * @ctx: event context: driver binding protocol + * @event: EV_PM_PRE_REMOVE event * - * Delete an efi_disk object which is associated with @dev. - * The type of @dev must be UCLASS_BLK. + * Delete an efi_disk object which is associated with the UCLASS_BLK or + * UCLASS_PARTITION device for which the EV_PM_PRE_REMOVE event is raised. * - * @return 0 on success, -1 otherwise - */ -static int efi_disk_delete_raw(struct udevice *dev) -{ - efi_handle_t handle; - struct blk_desc *desc; - struct efi_disk_obj *diskobj; - - if (dev_tag_get_ptr(dev, DM_TAG_EFI, (void **)&handle)) - return -1; - - desc = dev_get_uclass_plat(dev); - if (desc->uclass_id != UCLASS_EFI_LOADER) { - diskobj = container_of(handle, struct efi_disk_obj, header); - efi_free_pool(diskobj->dp); - } - - efi_delete_handle(handle); - dev_tag_del(dev, DM_TAG_EFI); - - return 0; -} - -/* - * Delete an efi_disk object for a disk partition - * - * @dev uclass device (UCLASS_PARTITION) - * - * Delete an efi_disk object which is associated with @dev. - * The type of @dev must be UCLASS_PARTITION. - * - * @return 0 on success, -1 otherwise - */ -static int efi_disk_delete_part(struct udevice *dev) -{ - efi_handle_t handle; - struct efi_disk_obj *diskobj; - - if (dev_tag_get_ptr(dev, DM_TAG_EFI, (void **)&handle)) - return -1; - - diskobj = container_of(handle, struct efi_disk_obj, header); - - efi_free_pool(diskobj->dp); - efi_delete_handle(handle); - dev_tag_del(dev, DM_TAG_EFI); - - return 0; -} - -/* - * Delete an efi_disk object for a block device - * - * @dev uclass device (UCLASS_BLK or UCLASS_PARTITION) - * - * Delete an efi_disk object which is associated with @dev. - * The type of @dev must be either UCLASS_BLK or UCLASS_PARTITION. - * This function is expected to be called at EV_PM_PRE_REMOVE. - * - * @return 0 on success, -1 otherwise + * Return: 0 on success, -1 otherwise */ int efi_disk_remove(void *ctx, struct event *event) { enum uclass_id id; - struct udevice *dev; + struct udevice *dev = event->data.dm.dev; + efi_handle_t handle; + struct blk_desc *desc; + struct efi_disk_obj *diskobj = NULL; - dev = event->data.dm.dev; - id = device_get_uclass_id(dev); - - if (id == UCLASS_BLK) - return efi_disk_delete_raw(dev); - else if (id == UCLASS_PARTITION) - return efi_disk_delete_part(dev); - else + if (dev_tag_get_ptr(dev, DM_TAG_EFI, (void **)&handle)) return 0; + + id = device_get_uclass_id(dev); + switch (id) { + case UCLASS_BLK: + desc = dev_get_uclass_plat(dev); + if (desc && desc->uclass_id != UCLASS_EFI_LOADER) + diskobj = container_of(handle, struct efi_disk_obj, + header); + break; + case UCLASS_PARTITION: + diskobj = container_of(handle, struct efi_disk_obj, header); + break; + default: + return 0; + } + + if (diskobj) + efi_free_pool(diskobj->dp); + + efi_delete_handle(handle); + dev_tag_del(dev, DM_TAG_EFI); + + return 0; } /** From 5669591dd8d2b21bc79237b161107300eb7f2b12 Mon Sep 17 00:00:00 2001 From: Ilias Apalodimas Date: Tue, 13 Jun 2023 16:23:06 +0300 Subject: [PATCH 9/9] efi_selftests: fix protocol repeated selftesting Running the protocols selftest more than one times fails with => setenv efi_selftest 'manage protocols' && bootefi selftest Testing EFI API implementation Selected test: 'manage protocols' Setting up 'manage protocols' Setting up 'manage protocols' succeeded Executing 'manage protocols' Executing 'manage protocols' succeeded Tearing down 'manage protocols' Tearing down 'manage protocols' succeeded Summary: 0 failures => bootefi selftest Testing EFI API implementation Selected test: 'manage protocols' Setting up 'manage protocols' lib/efi_selftest/efi_selftest_manageprotocols.c(88): ERROR: InstallProtocolInterface failed lib/efi_selftest/efi_selftest.c(89): ERROR: Setting up 'manage protocols' failed Tearing down 'manage protocols' Tearing down 'manage protocols' succeeded Summary: 1 failures The reason is that we don't set the handles to NULL after deleting and freeing them. As a result the subsequent protocol installation will try to use an existing handle which we just removed that from our object list. Signed-off-by: Ilias Apalodimas --- lib/efi_selftest/efi_selftest_manageprotocols.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/efi_selftest/efi_selftest_manageprotocols.c b/lib/efi_selftest/efi_selftest_manageprotocols.c index 8edb1e4d467..097b2ae3545 100644 --- a/lib/efi_selftest/efi_selftest_manageprotocols.c +++ b/lib/efi_selftest/efi_selftest_manageprotocols.c @@ -79,6 +79,8 @@ static int setup(const efi_handle_t img_handle, efi_status_t ret; efi_handle_t handle; + handle1 = NULL; + handle2 = NULL; boottime = systable->boottime; ret = boottime->install_protocol_interface(&handle1, &guid3,