[PATCH v9 00/11] efi: Add a test for EFI bootmeth

The test coverage for the EFI bootmeth is incomplete since it does not actually boot the application.
This series creates a simple test for this purpose. It includes a few patches to make this work:
- Revert of an unreviewed patch to change the sandbox efi filename - Hang in sandbox virtio due to EFI probing all block devices
Other necessary fixes have already been applied.
Changes in v9: - Update license - Fix 'sevices' typo - Move the function into efi_helper.c - Split out into a separate change - Split out into its own patch - Separate into separate patches - Add new patch to drop sandbox PXE architecture - Mark the image as complete after writing it - Fix 'sevices' typo
Changes in v8: - Add new patch to control on-host behaviour - Add new patch to move default filename to a function - Add new patch to report host default-filename in native mode - Add new patch to report host default-filename in native mode
Changes in v7: - Update commit message - Drop patches already applied - Drop patch 'Disable ANSI output for tests' - Rebase on -master
Changes in v6: - Drop the patch to disable sandbox virtio blk with EFI - Add new patch to disable the sandbox virtio blk device - Deal with sandbox CONFIG_LOGF_FUNC - Rebase on -next - Drop patches previously applied - Drop mention of helloworld since it is no-longer used by this test
Changes in v4: - Add efi_loader tag to some patches - Split out non-EFI patches into a different series
Changes in v2: - Add many new patches to resolve all the outstanding test issues
Simon Glass (11): test: boot: Update bootflow_iter() for console checking efi_loader: Add a test app sandbox: Add a -N flag to control on-host behaviour efi: Move default filename to a function efi_loader: Move get_efi_pxe_arch() to efi_helper efi_loader: Allow reporting the host defaults sandbox: Report host default-filename in native mode efi_loader: Drop sandbox PXE architecture sandbox: virtio: Disable the sandbox virtio blk device test: efi: boot: Set up an image suitable for EFI testing test: efi: boot: Add a test for the efi bootmeth
arch/Kconfig | 3 +- arch/sandbox/cpu/start.c | 10 ++++ arch/sandbox/dts/test.dts | 2 +- arch/sandbox/include/asm/state.h | 1 + boot/bootmeth_efi.c | 29 ++---------- cmd/efidebug.c | 25 ++++++++++ include/efi.h | 34 +++++++++++++ include/efi_default_filename.h | 56 ---------------------- lib/efi_loader/Kconfig | 10 ++++ lib/efi_loader/Makefile | 1 + lib/efi_loader/efi_bootmgr.c | 10 ++-- lib/efi_loader/efi_helper.c | 71 ++++++++++++++++++++++++++++ lib/efi_loader/testapp.c | 68 ++++++++++++++++++++++++++ test/boot/bootdev.c | 18 ++++++- test/boot/bootflow.c | 71 ++++++++++++++++++++++++++-- test/py/tests/bootstd/flash1.img.xz | Bin 0 -> 4980 bytes test/py/tests/test_ut.py | 53 ++++++++++++++++++--- 17 files changed, 364 insertions(+), 98 deletions(-) delete mode 100644 include/efi_default_filename.h create mode 100644 lib/efi_loader/testapp.c create mode 100644 test/py/tests/bootstd/flash1.img.xz

This test checks console output so should have the UTF_CONSOLE flag. Add it.
Signed-off-by: Simon Glass sjg@chromium.org ---
(no changes since v1)
test/boot/bootflow.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/test/boot/bootflow.c b/test/boot/bootflow.c index 0d4e966892e..841729bd1ac 100644 --- a/test/boot/bootflow.c +++ b/test/boot/bootflow.c @@ -370,7 +370,7 @@ static int bootflow_iter(struct unit_test_state *uts)
return 0; } -BOOTSTD_TEST(bootflow_iter, UTF_DM | UTF_SCAN_FDT); +BOOTSTD_TEST(bootflow_iter, UTF_DM | UTF_SCAN_FDT | UTF_CONSOLE);
#if defined(CONFIG_SANDBOX) && defined(CONFIG_BOOTMETH_GLOBAL) /* Check using the system bootdev */

Add a simple app to use for testing. This is intended to do whatever it needs to for testing purposes. For now it just prints a message and exits boot services.
There was a considerable amount of discussion about whether it is OK to call exit-boot-services and then return to U-Boot. This is not normally done in a real application, since exit-boot-services is used to completely disconnect from U-Boot. However, since this is a test, we need to check the results of running the app, so returning is necessary. It works correctly and it provides a nice model of how to test the EFI code in a simple way.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v9: - Update license - Fix 'sevices' typo
Changes in v7: - Update commit message
lib/efi_loader/Kconfig | 10 ++++++ lib/efi_loader/Makefile | 1 + lib/efi_loader/testapp.c | 68 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 79 insertions(+) create mode 100644 lib/efi_loader/testapp.c
diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig index 37572c82f54..44319729bda 100644 --- a/lib/efi_loader/Kconfig +++ b/lib/efi_loader/Kconfig @@ -584,6 +584,16 @@ config BOOTEFI_HELLO_COMPILE No additional space will be required in the resulting U-Boot binary when this option is enabled.
+config BOOTEFI_TESTAPP_COMPILE + bool "Compile an EFI test app for testing" + default y + help + This compiles an app designed for testing. It is packed into an image + by the test.py testing frame in the setup_efi_image() function. + + No additional space will be required in the resulting U-Boot binary + when this option is enabled. + endif
source "lib/efi/Kconfig" diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile index 8ec240cb864..7c8b2dd1ad6 100644 --- a/lib/efi_loader/Makefile +++ b/lib/efi_loader/Makefile @@ -20,6 +20,7 @@ apps-$(CONFIG_EFI_LOAD_FILE2_INITRD) += initrddump ifeq ($(CONFIG_GENERATE_ACPI_TABLE),) apps-y += dtbdump endif +apps-$(CONFIG_BOOTEFI_TESTAPP_COMPILE) += testapp
obj-$(CONFIG_CMD_BOOTEFI_HELLO) += helloworld_efi.o obj-$(CONFIG_EFI_BOOTMGR) += efi_bootmgr.o diff --git a/lib/efi_loader/testapp.c b/lib/efi_loader/testapp.c new file mode 100644 index 00000000000..a28fc17ce5b --- /dev/null +++ b/lib/efi_loader/testapp.c @@ -0,0 +1,68 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Hello world EFI application + * + * Copyright 2024 Google LLC + * Written by Simon Glass sjg@chromium.org + * + * This test program is used to test the invocation of an EFI application. + * It writes a few messages to the console and then exits boot services + */ + +#include <efi_api.h> + +static const efi_guid_t loaded_image_guid = EFI_LOADED_IMAGE_PROTOCOL_GUID; + +static struct efi_system_table *systable; +static struct efi_boot_services *boottime; +static struct efi_simple_text_output_protocol *con_out; + +/** + * efi_main() - entry point of the EFI application. + * + * @handle: handle of the loaded image + * @systab: system table + * Return: status code + */ +efi_status_t EFIAPI efi_main(efi_handle_t handle, + struct efi_system_table *systab) +{ + struct efi_loaded_image *loaded_image; + efi_status_t ret; + efi_uintn_t map_size; + efi_uintn_t map_key; + efi_uintn_t desc_size; + u32 desc_version; + + systable = systab; + boottime = systable->boottime; + con_out = systable->con_out; + + /* Get the loaded image protocol */ + ret = boottime->open_protocol(handle, &loaded_image_guid, + (void **)&loaded_image, NULL, NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (ret != EFI_SUCCESS) { + con_out->output_string + (con_out, u"Cannot open loaded image protocol\r\n"); + goto out; + } + + /* UEFI requires CR LF */ + con_out->output_string(con_out, u"U-Boot test app for EFI_LOADER\r\n"); + +out: + map_size = 0; + ret = boottime->get_memory_map(&map_size, NULL, &map_key, &desc_size, + &desc_version); + con_out->output_string(con_out, u"Exiting boot services\n"); + + /* exit boot services so that this part of U-Boot can be tested */ + boottime->exit_boot_services(handle, map_key); + + /* now exit for real */ + ret = boottime->exit(handle, ret, 0, NULL); + + /* We should never arrive here */ + return ret; +}

On Tue, Oct 29, 2024 at 08:22:10PM +0100, Simon Glass wrote:
Add a simple app to use for testing. This is intended to do whatever it needs to for testing purposes. For now it just prints a message and exits boot services.
There was a considerable amount of discussion about whether it is OK to call exit-boot-services and then return to U-Boot. This is not normally done in a real application, since exit-boot-services is used to completely disconnect from U-Boot. However, since this is a test, we need to check the results of running the app, so returning is necessary. It works correctly and it provides a nice model of how to test the EFI code in a simple way.
Signed-off-by: Simon Glass sjg@chromium.org
This approach has been specifically rejected with an explained rationale: It breaks how UEFI applications work and you cannot run further UEFI tests in sandbox without resetting.
Since as you note, you can't reset in a C-based test, rework this to be a python test where we can safely reset the system and verify that. I believe Heinrich even noted that a test which checks ExitBootServices() working as expected would be helpful as we only have a watchdog test currently.

Hi Tom,
On Tue, 29 Oct 2024 at 21:13, Tom Rini trini@konsulko.com wrote:
On Tue, Oct 29, 2024 at 08:22:10PM +0100, Simon Glass wrote:
Add a simple app to use for testing. This is intended to do whatever it needs to for testing purposes. For now it just prints a message and exits boot services.
There was a considerable amount of discussion about whether it is OK to call exit-boot-services and then return to U-Boot. This is not normally done in a real application, since exit-boot-services is used to completely disconnect from U-Boot. However, since this is a test, we need to check the results of running the app, so returning is necessary. It works correctly and it provides a nice model of how to test the EFI code in a simple way.
Signed-off-by: Simon Glass sjg@chromium.org
This approach has been specifically rejected with an explained rationale: It breaks how UEFI applications work and you cannot run further UEFI tests in sandbox without resetting.
Since as you note, you can't reset in a C-based test, rework this to be a python test where we can safely reset the system and verify that. I believe Heinrich even noted that a test which checks ExitBootServices() working as expected would be helpful as we only have a watchdog test currently.
Unfortunately I believe this is the wrong direction, as we are unable to check the state of anything once a reset has happened. Thus I cannot build on this test, e.g. to see what happened to the devices and whether they are still bound. It becomes just a 'black box' test. None of the other bootflow tests work this way, BTW.
Regards, Simon

On Wed, Oct 30, 2024 at 08:44:04AM +0100, Simon Glass wrote:
Hi Tom,
On Tue, 29 Oct 2024 at 21:13, Tom Rini trini@konsulko.com wrote:
On Tue, Oct 29, 2024 at 08:22:10PM +0100, Simon Glass wrote:
Add a simple app to use for testing. This is intended to do whatever it needs to for testing purposes. For now it just prints a message and exits boot services.
There was a considerable amount of discussion about whether it is OK to call exit-boot-services and then return to U-Boot. This is not normally done in a real application, since exit-boot-services is used to completely disconnect from U-Boot. However, since this is a test, we need to check the results of running the app, so returning is necessary. It works correctly and it provides a nice model of how to test the EFI code in a simple way.
Signed-off-by: Simon Glass sjg@chromium.org
This approach has been specifically rejected with an explained rationale: It breaks how UEFI applications work and you cannot run further UEFI tests in sandbox without resetting.
Since as you note, you can't reset in a C-based test, rework this to be a python test where we can safely reset the system and verify that. I believe Heinrich even noted that a test which checks ExitBootServices() working as expected would be helpful as we only have a watchdog test currently.
Unfortunately I believe this is the wrong direction, as we are unable to check the state of anything once a reset has happened. Thus I cannot build on this test, e.g. to see what happened to the devices and whether they are still bound. It becomes just a 'black box' test. None of the other bootflow tests work this way, BTW.
That's unfortunate in a number of ways then really. It's good when we can test the state machine is still where we expect it. It's better when we can test that the functionality works for real. It would probably be generically useful to have some verification functions that can dump the state of DM before we finish ourselves up and hand things over to the OS. We could even make use of this in test/py/tests/test_net_boot.py when we're booting Linux to make sure it's working as expected.

On 10/29/24 20:22, Simon Glass wrote:
Add a simple app to use for testing. This is intended to do whatever it needs to for testing purposes. For now it just prints a message and exits boot services.
There was a considerable amount of discussion about whether it is OK to call exit-boot-services and then return to U-Boot. This is not normally done in a real application, since exit-boot-services is used to completely disconnect from U-Boot. However, since this is a test, we need to check the results of running the app, so returning is necessary. It works correctly and it provides a nice model of how to test the EFI code in a simple way.
Signed-off-by: Simon Glass sjg@chromium.org
Changes in v9:
- Update license
- Fix 'sevices' typo
Changes in v7:
Update commit message
lib/efi_loader/Kconfig | 10 ++++++ lib/efi_loader/Makefile | 1 + lib/efi_loader/testapp.c | 68 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 79 insertions(+) create mode 100644 lib/efi_loader/testapp.c
diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig index 37572c82f54..44319729bda 100644 --- a/lib/efi_loader/Kconfig +++ b/lib/efi_loader/Kconfig @@ -584,6 +584,16 @@ config BOOTEFI_HELLO_COMPILE No additional space will be required in the resulting U-Boot binary when this option is enabled.
+config BOOTEFI_TESTAPP_COMPILE
bool "Compile an EFI test app for testing"
default y
help
This compiles an app designed for testing. It is packed into an image
by the test.py testing frame in the setup_efi_image() function.
No additional space will be required in the resulting U-Boot binary
when this option is enabled.
endif
source "lib/efi/Kconfig"
diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile index 8ec240cb864..7c8b2dd1ad6 100644 --- a/lib/efi_loader/Makefile +++ b/lib/efi_loader/Makefile @@ -20,6 +20,7 @@ apps-$(CONFIG_EFI_LOAD_FILE2_INITRD) += initrddump ifeq ($(CONFIG_GENERATE_ACPI_TABLE),) apps-y += dtbdump endif +apps-$(CONFIG_BOOTEFI_TESTAPP_COMPILE) += testapp
obj-$(CONFIG_CMD_BOOTEFI_HELLO) += helloworld_efi.o obj-$(CONFIG_EFI_BOOTMGR) += efi_bootmgr.o diff --git a/lib/efi_loader/testapp.c b/lib/efi_loader/testapp.c new file mode 100644 index 00000000000..a28fc17ce5b --- /dev/null +++ b/lib/efi_loader/testapp.c @@ -0,0 +1,68 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/*
- Hello world EFI application
- Copyright 2024 Google LLC
- Written by Simon Glass sjg@chromium.org
- This test program is used to test the invocation of an EFI application.
- It writes a few messages to the console and then exits boot services
- */
+#include <efi_api.h>
+static const efi_guid_t loaded_image_guid = EFI_LOADED_IMAGE_PROTOCOL_GUID;
+static struct efi_system_table *systable; +static struct efi_boot_services *boottime; +static struct efi_simple_text_output_protocol *con_out;
+/**
- efi_main() - entry point of the EFI application.
- @handle: handle of the loaded image
- @systab: system table
- Return: status code
- */
+efi_status_t EFIAPI efi_main(efi_handle_t handle,
struct efi_system_table *systab)
+{
- struct efi_loaded_image *loaded_image;
- efi_status_t ret;
- efi_uintn_t map_size;
- efi_uintn_t map_key;
- efi_uintn_t desc_size;
- u32 desc_version;
- systable = systab;
- boottime = systable->boottime;
- con_out = systable->con_out;
- /* Get the loaded image protocol */
- ret = boottime->open_protocol(handle, &loaded_image_guid,
(void **)&loaded_image, NULL, NULL,
EFI_OPEN_PROTOCOL_GET_PROTOCOL);
- if (ret != EFI_SUCCESS) {
con_out->output_string
(con_out, u"Cannot open loaded image protocol\r\n");
goto out;
- }
- /* UEFI requires CR LF */
- con_out->output_string(con_out, u"U-Boot test app for EFI_LOADER\r\n");
+out:
- map_size = 0;
- ret = boottime->get_memory_map(&map_size, NULL, &map_key, &desc_size,
&desc_version);
- con_out->output_string(con_out, u"Exiting boot services\n");
- /* exit boot services so that this part of U-Boot can be tested */
- boottime->exit_boot_services(handle, map_key);
Hello Simon,
I am not NAKing this patch. But maybe you could rethink if this call tells us anything new about the correct function of ExitBootServices().
We already have a test of ExitBootServices() in lib/efi_selftest/ and maybe we should extend that test to check more.
By removing ExitBootServices() we could keep U-Boot in a well defined state which will allow us to run any number of bootmeth tests in sequence and keep the EFI sub-system in a consistent state.
Best regards
Heinrich
- /* now exit for real */
- ret = boottime->exit(handle, ret, 0, NULL);
- /* We should never arrive here */
- return ret;
+}

Hi Heinrich
On Wed, 30 Oct 2024 at 18:55, Heinrich Schuchardt xypron.glpk@gmx.de wrote:
On 10/29/24 20:22, Simon Glass wrote:
Add a simple app to use for testing. This is intended to do whatever it needs to for testing purposes. For now it just prints a message and exits boot services.
There was a considerable amount of discussion about whether it is OK to call exit-boot-services and then return to U-Boot. This is not normally done in a real application, since exit-boot-services is used to completely disconnect from U-Boot. However, since this is a test, we need to check the results of running the app, so returning is necessary. It works correctly and it provides a nice model of how to test the EFI code in a simple way.
Signed-off-by: Simon Glass sjg@chromium.org
Changes in v9:
- Update license
- Fix 'sevices' typo
Changes in v7:
Update commit message
lib/efi_loader/Kconfig | 10 ++++++ lib/efi_loader/Makefile | 1 + lib/efi_loader/testapp.c | 68 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 79 insertions(+) create mode 100644 lib/efi_loader/testapp.c
diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig index 37572c82f54..44319729bda 100644 --- a/lib/efi_loader/Kconfig +++ b/lib/efi_loader/Kconfig @@ -584,6 +584,16 @@ config BOOTEFI_HELLO_COMPILE No additional space will be required in the resulting U-Boot binary when this option is enabled.
+config BOOTEFI_TESTAPP_COMPILE
bool "Compile an EFI test app for testing"
default y
help
This compiles an app designed for testing. It is packed into an image
by the test.py testing frame in the setup_efi_image() function.
No additional space will be required in the resulting U-Boot binary
when this option is enabled.
endif
source "lib/efi/Kconfig"
diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile index 8ec240cb864..7c8b2dd1ad6 100644 --- a/lib/efi_loader/Makefile +++ b/lib/efi_loader/Makefile @@ -20,6 +20,7 @@ apps-$(CONFIG_EFI_LOAD_FILE2_INITRD) += initrddump ifeq ($(CONFIG_GENERATE_ACPI_TABLE),) apps-y += dtbdump endif +apps-$(CONFIG_BOOTEFI_TESTAPP_COMPILE) += testapp
obj-$(CONFIG_CMD_BOOTEFI_HELLO) += helloworld_efi.o obj-$(CONFIG_EFI_BOOTMGR) += efi_bootmgr.o diff --git a/lib/efi_loader/testapp.c b/lib/efi_loader/testapp.c new file mode 100644 index 00000000000..a28fc17ce5b --- /dev/null +++ b/lib/efi_loader/testapp.c @@ -0,0 +1,68 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/*
- Hello world EFI application
- Copyright 2024 Google LLC
- Written by Simon Glass sjg@chromium.org
- This test program is used to test the invocation of an EFI application.
- It writes a few messages to the console and then exits boot services
- */
+#include <efi_api.h>
+static const efi_guid_t loaded_image_guid = EFI_LOADED_IMAGE_PROTOCOL_GUID;
+static struct efi_system_table *systable; +static struct efi_boot_services *boottime; +static struct efi_simple_text_output_protocol *con_out;
+/**
- efi_main() - entry point of the EFI application.
- @handle: handle of the loaded image
- @systab: system table
- Return: status code
- */
+efi_status_t EFIAPI efi_main(efi_handle_t handle,
struct efi_system_table *systab)
+{
struct efi_loaded_image *loaded_image;
efi_status_t ret;
efi_uintn_t map_size;
efi_uintn_t map_key;
efi_uintn_t desc_size;
u32 desc_version;
systable = systab;
boottime = systable->boottime;
con_out = systable->con_out;
/* Get the loaded image protocol */
ret = boottime->open_protocol(handle, &loaded_image_guid,
(void **)&loaded_image, NULL, NULL,
EFI_OPEN_PROTOCOL_GET_PROTOCOL);
if (ret != EFI_SUCCESS) {
con_out->output_string
(con_out, u"Cannot open loaded image protocol\r\n");
goto out;
}
/* UEFI requires CR LF */
con_out->output_string(con_out, u"U-Boot test app for EFI_LOADER\r\n");
+out:
map_size = 0;
ret = boottime->get_memory_map(&map_size, NULL, &map_key, &desc_size,
&desc_version);
con_out->output_string(con_out, u"Exiting boot services\n");
/* exit boot services so that this part of U-Boot can be tested */
boottime->exit_boot_services(handle, map_key);
Hello Simon,
I am not NAKing this patch. But maybe you could rethink if this call tells us anything new about the correct function of ExitBootServices().
We already have a test of ExitBootServices() in lib/efi_selftest/ and maybe we should extend that test to check more.
By removing ExitBootServices() we could keep U-Boot in a well defined state which will allow us to run any number of bootmeth tests in sequence and keep the EFI sub-system in a consistent state.
FWIW I proposed exactly the same in [0].
[0] https://lore.kernel.org/u-boot/CAC_iWjJYqrh6MS50d6MxdStJFGg2pWnf1PHwQ9muYDPm...
Thanks /Ilias
Best regards
Heinrich
/* now exit for real */
ret = boottime->exit(handle, ret, 0, NULL);
/* We should never arrive here */
return ret;
+}

Hi,
On Wed, 30 Oct 2024 at 18:55, Ilias Apalodimas ilias.apalodimas@linaro.org wrote:
Hi Heinrich
On Wed, 30 Oct 2024 at 18:55, Heinrich Schuchardt xypron.glpk@gmx.de wrote:
On 10/29/24 20:22, Simon Glass wrote:
Add a simple app to use for testing. This is intended to do whatever it needs to for testing purposes. For now it just prints a message and exits boot services.
There was a considerable amount of discussion about whether it is OK to call exit-boot-services and then return to U-Boot. This is not normally done in a real application, since exit-boot-services is used to completely disconnect from U-Boot. However, since this is a test, we need to check the results of running the app, so returning is necessary. It works correctly and it provides a nice model of how to test the EFI code in a simple way.
Signed-off-by: Simon Glass sjg@chromium.org
Changes in v9:
- Update license
- Fix 'sevices' typo
Changes in v7:
Update commit message
lib/efi_loader/Kconfig | 10 ++++++ lib/efi_loader/Makefile | 1 + lib/efi_loader/testapp.c | 68 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 79 insertions(+) create mode 100644 lib/efi_loader/testapp.c
diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig index 37572c82f54..44319729bda 100644 --- a/lib/efi_loader/Kconfig +++ b/lib/efi_loader/Kconfig @@ -584,6 +584,16 @@ config BOOTEFI_HELLO_COMPILE No additional space will be required in the resulting U-Boot binary when this option is enabled.
+config BOOTEFI_TESTAPP_COMPILE
bool "Compile an EFI test app for testing"
default y
help
This compiles an app designed for testing. It is packed into an image
by the test.py testing frame in the setup_efi_image() function.
No additional space will be required in the resulting U-Boot binary
when this option is enabled.
endif
source "lib/efi/Kconfig"
diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile index 8ec240cb864..7c8b2dd1ad6 100644 --- a/lib/efi_loader/Makefile +++ b/lib/efi_loader/Makefile @@ -20,6 +20,7 @@ apps-$(CONFIG_EFI_LOAD_FILE2_INITRD) += initrddump ifeq ($(CONFIG_GENERATE_ACPI_TABLE),) apps-y += dtbdump endif +apps-$(CONFIG_BOOTEFI_TESTAPP_COMPILE) += testapp
obj-$(CONFIG_CMD_BOOTEFI_HELLO) += helloworld_efi.o obj-$(CONFIG_EFI_BOOTMGR) += efi_bootmgr.o diff --git a/lib/efi_loader/testapp.c b/lib/efi_loader/testapp.c new file mode 100644 index 00000000000..a28fc17ce5b --- /dev/null +++ b/lib/efi_loader/testapp.c @@ -0,0 +1,68 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/*
- Hello world EFI application
- Copyright 2024 Google LLC
- Written by Simon Glass sjg@chromium.org
- This test program is used to test the invocation of an EFI application.
- It writes a few messages to the console and then exits boot services
- */
+#include <efi_api.h>
+static const efi_guid_t loaded_image_guid = EFI_LOADED_IMAGE_PROTOCOL_GUID;
+static struct efi_system_table *systable; +static struct efi_boot_services *boottime; +static struct efi_simple_text_output_protocol *con_out;
+/**
- efi_main() - entry point of the EFI application.
- @handle: handle of the loaded image
- @systab: system table
- Return: status code
- */
+efi_status_t EFIAPI efi_main(efi_handle_t handle,
struct efi_system_table *systab)
+{
struct efi_loaded_image *loaded_image;
efi_status_t ret;
efi_uintn_t map_size;
efi_uintn_t map_key;
efi_uintn_t desc_size;
u32 desc_version;
systable = systab;
boottime = systable->boottime;
con_out = systable->con_out;
/* Get the loaded image protocol */
ret = boottime->open_protocol(handle, &loaded_image_guid,
(void **)&loaded_image, NULL, NULL,
EFI_OPEN_PROTOCOL_GET_PROTOCOL);
if (ret != EFI_SUCCESS) {
con_out->output_string
(con_out, u"Cannot open loaded image protocol\r\n");
goto out;
}
/* UEFI requires CR LF */
con_out->output_string(con_out, u"U-Boot test app for EFI_LOADER\r\n");
+out:
map_size = 0;
ret = boottime->get_memory_map(&map_size, NULL, &map_key, &desc_size,
&desc_version);
con_out->output_string(con_out, u"Exiting boot services\n");
/* exit boot services so that this part of U-Boot can be tested */
boottime->exit_boot_services(handle, map_key);
Hello Simon,
I am not NAKing this patch. But maybe you could rethink if this call tells us anything new about the correct function of ExitBootServices().
We already have a test of ExitBootServices() in lib/efi_selftest/ and maybe we should extend that test to check more.
By removing ExitBootServices() we could keep U-Boot in a well defined state which will allow us to run any number of bootmeth tests in sequence and keep the EFI sub-system in a consistent state.
In the interests of trying to make some progress, I will drop that line and worry about it later, when we can come up with follow-on tests. It is exactly the 'exit-boot-services' call which was stopping Ubuntu from booting. But since I don't have any test pieces to check what happens in that situation, we can leave it for now.
FWIW I proposed exactly the same in [0].
[0] https://lore.kernel.org/u-boot/CAC_iWjJYqrh6MS50d6MxdStJFGg2pWnf1PHwQ9muYDPm...
Thanks /Ilias
Best regards
Heinrich
/* now exit for real */
ret = boottime->exit(handle, ret, 0, NULL);
/* We should never arrive here */
return ret;
+}
Regards, Simon

Sandbox is its own architecture, but sometimes we want to mimic the host architecture, e.g. when running an EFI app not built by U-Boot.
Add a -N/--native flag which tells sandbox to reflect the architecture of the host.
Signed-off-by: Simon Glass sjg@chromium.org ---
(no changes since v8)
Changes in v8: - Add new patch to control on-host behaviour
arch/sandbox/cpu/start.c | 10 ++++++++++ arch/sandbox/include/asm/state.h | 1 + 2 files changed, 11 insertions(+)
diff --git a/arch/sandbox/cpu/start.c b/arch/sandbox/cpu/start.c index 81752edc9f8..2940768cd1c 100644 --- a/arch/sandbox/cpu/start.c +++ b/arch/sandbox/cpu/start.c @@ -449,6 +449,16 @@ static void setup_ram_buf(struct sandbox_state *state) gd->ram_size = state->ram_size; }
+static int sandbox_cmdline_cb_native(struct sandbox_state *state, + const char *arg) +{ + state->native = true; + + return 0; +} +SANDBOX_CMDLINE_OPT_SHORT(native, 'N', 0, + "Use native mode (host-based EFI boot filename)"); + void state_show(struct sandbox_state *state) { char **p; diff --git a/arch/sandbox/include/asm/state.h b/arch/sandbox/include/asm/state.h index e7dc01759e8..dc21a623106 100644 --- a/arch/sandbox/include/asm/state.h +++ b/arch/sandbox/include/asm/state.h @@ -101,6 +101,7 @@ struct sandbox_state { bool disable_eth; /* Disable Ethernet devices */ bool disable_sf_bootdevs; /* Don't bind SPI flash bootdevs */ bool upl; /* Enable Universal Payload (UPL) */ + bool native; /* Adjust to reflect host arch */
/* Pointer to information for each SPI bus/cs */ struct sandbox_spi_info spi[CONFIG_SANDBOX_SPI_MAX_BUS]

On Tue, Oct 29, 2024 at 08:22:11PM +0100, Simon Glass wrote:
Sandbox is its own architecture, but sometimes we want to mimic the host architecture, e.g. when running an EFI app not built by U-Boot.
Add a -N/--native flag which tells sandbox to reflect the architecture of the host.
Signed-off-by: Simon Glass sjg@chromium.org
(no changes since v8)
I believe Heinrich asked that you invert the logic here and add a flag for when you need the unexpected behavior.

Hi Tom,
On Tue, 29 Oct 2024 at 21:14, Tom Rini trini@konsulko.com wrote:
On Tue, Oct 29, 2024 at 08:22:11PM +0100, Simon Glass wrote:
Sandbox is its own architecture, but sometimes we want to mimic the host architecture, e.g. when running an EFI app not built by U-Boot.
Add a -N/--native flag which tells sandbox to reflect the architecture of the host.
Signed-off-by: Simon Glass sjg@chromium.org
(no changes since v8)
I believe Heinrich asked that you invert the logic here and add a flag for when you need the unexpected behavior.
Yes, but that is not correct, unfortunately. The expected behaviour is for CI to use the same filename for its efi apps, no matter what host architecture it is happens to be running on.
The use case that Heinrich mentions seems to be broken on x86_64 now, as I mentioned on the other thread, perhaps due to a recently introduced bug in UEFI or QEMU. Just to be clear, this is not a problem with sandbox. I suspect Heinrich will figure that out at some point and then I will be able to try it too. I would also like to run it on sandbox.
I hope to get an ARM machine running CI eventually, but I need to get my lab running first.
Regards, Simon

On Thu, Oct 31, 2024 at 06:52:33PM +0100, Simon Glass wrote:
Hi Tom,
On Tue, 29 Oct 2024 at 21:14, Tom Rini trini@konsulko.com wrote:
On Tue, Oct 29, 2024 at 08:22:11PM +0100, Simon Glass wrote:
Sandbox is its own architecture, but sometimes we want to mimic the host architecture, e.g. when running an EFI app not built by U-Boot.
Add a -N/--native flag which tells sandbox to reflect the architecture of the host.
Signed-off-by: Simon Glass sjg@chromium.org
(no changes since v8)
I believe Heinrich asked that you invert the logic here and add a flag for when you need the unexpected behavior.
Yes, but that is not correct, unfortunately. The expected behaviour is for CI to use the same filename for its efi apps, no matter what host architecture it is happens to be running on.
The use case that Heinrich mentions seems to be broken on x86_64 now, as I mentioned on the other thread, perhaps due to a recently introduced bug in UEFI or QEMU. Just to be clear, this is not a problem with sandbox. I suspect Heinrich will figure that out at some point and then I will be able to try it too. I would also like to run it on sandbox.
I hope to get an ARM machine running CI eventually, but I need to get my lab running first.
I talked with Heinrich about this in private and while neither of us understand why you want this behavior, we'll stop objecting to it.

Hi Tom,
On Thu, 31 Oct 2024 at 19:14, Tom Rini trini@konsulko.com wrote:
On Thu, Oct 31, 2024 at 06:52:33PM +0100, Simon Glass wrote:
Hi Tom,
On Tue, 29 Oct 2024 at 21:14, Tom Rini trini@konsulko.com wrote:
On Tue, Oct 29, 2024 at 08:22:11PM +0100, Simon Glass wrote:
Sandbox is its own architecture, but sometimes we want to mimic the host architecture, e.g. when running an EFI app not built by U-Boot.
Add a -N/--native flag which tells sandbox to reflect the architecture of the host.
Signed-off-by: Simon Glass sjg@chromium.org
(no changes since v8)
I believe Heinrich asked that you invert the logic here and add a flag for when you need the unexpected behavior.
Yes, but that is not correct, unfortunately. The expected behaviour is for CI to use the same filename for its efi apps, no matter what host architecture it is happens to be running on.
The use case that Heinrich mentions seems to be broken on x86_64 now, as I mentioned on the other thread, perhaps due to a recently introduced bug in UEFI or QEMU. Just to be clear, this is not a problem with sandbox. I suspect Heinrich will figure that out at some point and then I will be able to try it too. I would also like to run it on sandbox.
I hope to get an ARM machine running CI eventually, but I need to get my lab running first.
I talked with Heinrich about this in private and while neither of us understand why you want this behavior, we'll stop objecting to it.
OK, good.
Heinrich mentioned that the RISC-V server did not work, for some reason. But eventually we might have one of those.
I know from my fiddling with 32-bit rpi that even *running* sandbox on ARM will be a challenge, let alone passing tests, but we'll see.
We should encourage ARM/Linux to set up an ARM runner at some point.
Regards, Simon

Use a function to obtain the device EFI filename, so that we can control how sandbox behaves.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v9: - Move the function into efi_helper.c
Changes in v8: - Add new patch to move default filename to a function
boot/bootmeth_efi.c | 4 +-- include/efi.h | 9 ++++++ include/efi_default_filename.h | 56 ---------------------------------- lib/efi_loader/efi_bootmgr.c | 10 ++++-- lib/efi_loader/efi_helper.c | 45 +++++++++++++++++++++++++++ test/boot/bootflow.c | 7 +++-- 6 files changed, 67 insertions(+), 64 deletions(-) delete mode 100644 include/efi_default_filename.h
diff --git a/boot/bootmeth_efi.c b/boot/bootmeth_efi.c index 2ad6d3b4ace..371b36d550b 100644 --- a/boot/bootmeth_efi.c +++ b/boot/bootmeth_efi.c @@ -13,7 +13,7 @@ #include <bootmeth.h> #include <command.h> #include <dm.h> -#include <efi_default_filename.h> +#include <efi.h> #include <efi_loader.h> #include <fs.h> #include <malloc.h> @@ -168,7 +168,7 @@ static int distro_efi_try_bootflow_files(struct udevice *dev, }
strcpy(fname, EFI_DIRNAME); - strcat(fname, BOOTEFI_NAME); + strcat(fname, efi_get_basename());
if (bflow->blk) desc = dev_get_uclass_plat(bflow->blk); diff --git a/include/efi.h b/include/efi.h index f7419b80d4d..fef88e9c5d6 100644 --- a/include/efi.h +++ b/include/efi.h @@ -670,4 +670,13 @@ int efi_get_mmap(struct efi_mem_desc **descp, int *sizep, uint *keyp, */ void efi_show_tables(struct efi_system_table *systab);
+/** + * efi_get_basename() - Get the default filename to use when loading + * + * E.g. this function returns BOOTAA64.EFI for an aarch target + * + * Return: Default EFI filename + */ +const char *efi_get_basename(void); + #endif /* _LINUX_EFI_H */ diff --git a/include/efi_default_filename.h b/include/efi_default_filename.h deleted file mode 100644 index 77932984b55..00000000000 --- a/include/efi_default_filename.h +++ /dev/null @@ -1,56 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * When a boot option does not provide a file path the EFI file to be - * booted is \EFI\BOOT$(BOOTEFI_NAME).EFI. The architecture specific - * file name is defined in this include. - * - * Copyright (c) 2022, Heinrich Schuchardt xypron.glpk@gmx.de - * Copyright (c) 2022, Linaro Limited - */ - -#ifndef _EFI_DEFAULT_FILENAME_H -#define _EFI_DEFAULT_FILENAME_H - -#include <host_arch.h> - -#undef BOOTEFI_NAME - -#ifdef CONFIG_SANDBOX - -#if HOST_ARCH == HOST_ARCH_X86_64 -#define BOOTEFI_NAME "BOOTX64.EFI" -#elif HOST_ARCH == HOST_ARCH_X86 -#define BOOTEFI_NAME "BOOTIA32.EFI" -#elif HOST_ARCH == HOST_ARCH_AARCH64 -#define BOOTEFI_NAME "BOOTAA64.EFI" -#elif HOST_ARCH == HOST_ARCH_ARM -#define BOOTEFI_NAME "BOOTARM.EFI" -#elif HOST_ARCH == HOST_ARCH_RISCV32 -#define BOOTEFI_NAME "BOOTRISCV32.EFI" -#elif HOST_ARCH == HOST_ARCH_RISCV64 -#define BOOTEFI_NAME "BOOTRISCV64.EFI" -#else -#error Unsupported UEFI architecture -#endif - -#else - -#if defined(CONFIG_ARM64) -#define BOOTEFI_NAME "BOOTAA64.EFI" -#elif defined(CONFIG_ARM) -#define BOOTEFI_NAME "BOOTARM.EFI" -#elif defined(CONFIG_X86_64) -#define BOOTEFI_NAME "BOOTX64.EFI" -#elif defined(CONFIG_X86) -#define BOOTEFI_NAME "BOOTIA32.EFI" -#elif defined(CONFIG_ARCH_RV32I) -#define BOOTEFI_NAME "BOOTRISCV32.EFI" -#elif defined(CONFIG_ARCH_RV64I) -#define BOOTEFI_NAME "BOOTRISCV64.EFI" -#else -#error Unsupported UEFI architecture -#endif - -#endif - -#endif diff --git a/lib/efi_loader/efi_bootmgr.c b/lib/efi_loader/efi_bootmgr.c index 431a38704e9..2ea20909491 100644 --- a/lib/efi_loader/efi_bootmgr.c +++ b/lib/efi_loader/efi_bootmgr.c @@ -11,10 +11,10 @@ #include <blkmap.h> #include <charset.h> #include <dm.h> +#include <efi.h> #include <log.h> #include <malloc.h> #include <net.h> -#include <efi_default_filename.h> #include <efi_loader.h> #include <efi_variable.h> #include <asm/unaligned.h> @@ -82,8 +82,12 @@ struct efi_device_path *expand_media_path(struct efi_device_path *device_path) &efi_simple_file_system_protocol_guid, &rem); if (handle) { if (rem->type == DEVICE_PATH_TYPE_END) { - full_path = efi_dp_from_file(device_path, - "/EFI/BOOT/" BOOTEFI_NAME); + char fname[30]; + + snprintf(fname, sizeof(fname), "/EFI/BOOT/%s", + efi_get_basename()); + full_path = efi_dp_from_file(device_path, fname); + } else { full_path = efi_dp_dup(device_path); } diff --git a/lib/efi_loader/efi_helper.c b/lib/efi_loader/efi_helper.c index 00167bd2a10..51e0c4852c5 100644 --- a/lib/efi_loader/efi_helper.c +++ b/lib/efi_loader/efi_helper.c @@ -12,18 +12,63 @@ #include <mapmem.h> #include <dm.h> #include <fs.h> +#include <efi.h> #include <efi_api.h> #include <efi_load_initrd.h> #include <efi_loader.h> #include <efi_variable.h> +#include <host_arch.h> #include <linux/libfdt.h> #include <linux/list.h>
+#ifdef CONFIG_SANDBOX + +#if HOST_ARCH == HOST_ARCH_X86_64 +#define BOOTEFI_NAME "BOOTX64.EFI" +#elif HOST_ARCH == HOST_ARCH_X86 +#define BOOTEFI_NAME "BOOTIA32.EFI" +#elif HOST_ARCH == HOST_ARCH_AARCH64 +#define BOOTEFI_NAME "BOOTAA64.EFI" +#elif HOST_ARCH == HOST_ARCH_ARM +#define BOOTEFI_NAME "BOOTARM.EFI" +#elif HOST_ARCH == HOST_ARCH_RISCV32 +#define BOOTEFI_NAME "BOOTRISCV32.EFI" +#elif HOST_ARCH == HOST_ARCH_RISCV64 +#define BOOTEFI_NAME "BOOTRISCV64.EFI" +#else +#error Unsupported UEFI architecture +#endif + +#else + +#if defined(CONFIG_ARM64) +#define BOOTEFI_NAME "BOOTAA64.EFI" +#elif defined(CONFIG_ARM) +#define BOOTEFI_NAME "BOOTARM.EFI" +#elif defined(CONFIG_X86_64) +#define BOOTEFI_NAME "BOOTX64.EFI" +#elif defined(CONFIG_X86) +#define BOOTEFI_NAME "BOOTIA32.EFI" +#elif defined(CONFIG_ARCH_RV32I) +#define BOOTEFI_NAME "BOOTRISCV32.EFI" +#elif defined(CONFIG_ARCH_RV64I) +#define BOOTEFI_NAME "BOOTRISCV64.EFI" +#else +#error Unsupported UEFI architecture +#endif + +#endif + #if defined(CONFIG_CMD_EFIDEBUG) || defined(CONFIG_EFI_LOAD_FILE2_INITRD) /* GUID used by Linux to identify the LoadFile2 protocol with the initrd */ const efi_guid_t efi_lf2_initrd_guid = EFI_INITRD_MEDIA_GUID; #endif
+const char *efi_get_basename(void) +{ + return BOOTEFI_NAME; +} + /** * efi_create_current_boot_var() - Return Boot#### name were #### is replaced by * the value of BootCurrent diff --git a/test/boot/bootflow.c b/test/boot/bootflow.c index 841729bd1ac..7cfb217088e 100644 --- a/test/boot/bootflow.c +++ b/test/boot/bootflow.c @@ -12,7 +12,7 @@ #include <bootstd.h> #include <cli.h> #include <dm.h> -#include <efi_default_filename.h> +#include <efi.h> #include <expo.h> #ifdef CONFIG_SANDBOX #include <asm/test.h> @@ -184,8 +184,9 @@ static int bootflow_cmd_scan_e(struct unit_test_state *uts) ut_assert_nextline(" 3 efi media mmc 0 mmc1.bootdev.whole "); ut_assert_nextline(" ** No partition found, err=-2: No such file or directory"); ut_assert_nextline(" 4 extlinux ready mmc 1 mmc1.bootdev.part_1 /extlinux/extlinux.conf"); - ut_assert_nextline(" 5 efi fs mmc 1 mmc1.bootdev.part_1 /EFI/BOOT/" - BOOTEFI_NAME); + ut_assert_nextline( + " 5 efi fs mmc 1 mmc1.bootdev.part_1 /EFI/BOOT/%s", + efi_get_basename());
ut_assert_skip_to_line("Scanning bootdev 'mmc0.bootdev':"); ut_assert_skip_to_line(

Move this function from the EFI bootmeth to the common efi_helper file. No functional change is intended.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v9: - Split out into a separate change
boot/bootmeth_efi.c | 25 ++----------------------- include/efi.h | 10 ++++++++++ lib/efi_loader/efi_helper.c | 23 +++++++++++++++++++++++ 3 files changed, 35 insertions(+), 23 deletions(-)
diff --git a/boot/bootmeth_efi.c b/boot/bootmeth_efi.c index 371b36d550b..f836aa655f5 100644 --- a/boot/bootmeth_efi.c +++ b/boot/bootmeth_efi.c @@ -25,32 +25,11 @@
#define EFI_DIRNAME "/EFI/BOOT/"
-static int get_efi_pxe_arch(void) -{ - /* http://www.iana.org/assignments/dhcpv6-parameters/dhcpv6-parameters.xml */ - if (IS_ENABLED(CONFIG_ARM64)) - return 0xb; - else if (IS_ENABLED(CONFIG_ARM)) - return 0xa; - else if (IS_ENABLED(CONFIG_X86_64)) - return 0x6; - else if (IS_ENABLED(CONFIG_X86)) - return 0x7; - else if (IS_ENABLED(CONFIG_ARCH_RV32I)) - return 0x19; - else if (IS_ENABLED(CONFIG_ARCH_RV64I)) - return 0x1b; - else if (IS_ENABLED(CONFIG_SANDBOX)) - return 0; /* not used */ - - return -EINVAL; -} - static int get_efi_pxe_vci(char *str, int max_len) { int ret;
- ret = get_efi_pxe_arch(); + ret = efi_get_pxe_arch(); if (ret < 0) return ret;
@@ -239,7 +218,7 @@ static int distro_efi_read_bootflow_net(struct bootflow *bflow) ret = get_efi_pxe_vci(str, sizeof(str)); if (ret) return log_msg_ret("vci", ret); - ret = get_efi_pxe_arch(); + ret = efi_get_pxe_arch(); if (ret < 0) return log_msg_ret("arc", ret); arch = ret; diff --git a/include/efi.h b/include/efi.h index fef88e9c5d6..633f5b4acb5 100644 --- a/include/efi.h +++ b/include/efi.h @@ -679,4 +679,14 @@ void efi_show_tables(struct efi_system_table *systab); */ const char *efi_get_basename(void);
+/** + * efi_get_pxe_arch() - Get the architecture value for PXE + * + * See: + * http://www.iana.org/assignments/dhcpv6-parameters/dhcpv6-parameters.xml + * + * Return: Architecture value + */ +int efi_get_pxe_arch(void); + #endif /* _LINUX_EFI_H */ diff --git a/lib/efi_loader/efi_helper.c b/lib/efi_loader/efi_helper.c index 51e0c4852c5..b8ece1c2e0c 100644 --- a/lib/efi_loader/efi_helper.c +++ b/lib/efi_loader/efi_helper.c @@ -21,6 +21,8 @@ #include <linux/libfdt.h> #include <linux/list.h>
+#undef BOOTEFI_NAME + #ifdef CONFIG_SANDBOX
#if HOST_ARCH == HOST_ARCH_X86_64 @@ -69,6 +71,27 @@ const char *efi_get_basename(void) return BOOTEFI_NAME; }
+int efi_get_pxe_arch(void) +{ + /* http://www.iana.org/assignments/dhcpv6-parameters/dhcpv6-parameters.xml */ + if (IS_ENABLED(CONFIG_ARM64)) + return 0xb; + else if (IS_ENABLED(CONFIG_ARM)) + return 0xa; + else if (IS_ENABLED(CONFIG_X86_64)) + return 0x6; + else if (IS_ENABLED(CONFIG_X86)) + return 0x7; + else if (IS_ENABLED(CONFIG_ARCH_RV32I)) + return 0x19; + else if (IS_ENABLED(CONFIG_ARCH_RV64I)) + return 0x1b; + else if (IS_ENABLED(CONFIG_SANDBOX)) + return 0; /* not used */ + + return -EINVAL; +} + /** * efi_create_current_boot_var() - Return Boot#### name were #### is replaced by * the value of BootCurrent

Add an 'efidebug filename' command to report the default filename and PXE architecture.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v9: - Split out into its own patch
Changes in v8: - Add new patch to report host default-filename in native mode
cmd/efidebug.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+)
diff --git a/cmd/efidebug.c b/cmd/efidebug.c index bba984b2b75..ff6d118876d 100644 --- a/cmd/efidebug.c +++ b/cmd/efidebug.c @@ -536,6 +536,27 @@ static int do_efi_show_log(struct cmd_tbl *cmdtp, int flag, return CMD_RET_FAILURE; }
+ return 0; +} + +/** + * do_efi_show_defaults() - show UEFI default filename and PXE architecture + * + * @cmdtp: Command table + * @flag: Command flag + * @argc: Number of arguments + * @argv: Argument array + * Return: CMD_RET_SUCCESS on success, CMD_RET_RET_FAILURE on failure + * + * Implement efidebug "defaults" sub-command. + * Shows the default EFI filename and PXE architecture + */ +static int do_efi_show_defaults(struct cmd_tbl *cmdtp, int flag, + int argc, char *const argv[]) +{ + printf("Default boot path: EFI\BOOT\%s\n", efi_get_basename()); + printf("PXE arch: 0x%02x\n", efi_get_pxe_arch()); + return CMD_RET_SUCCESS; }
@@ -1589,6 +1610,8 @@ static struct cmd_tbl cmd_efidebug_sub[] = { "", ""), U_BOOT_CMD_MKENT(dh, CONFIG_SYS_MAXARGS, 1, do_efi_show_handles, "", ""), + U_BOOT_CMD_MKENT(defaults, CONFIG_SYS_MAXARGS, 1, do_efi_show_defaults, + "", ""), U_BOOT_CMD_MKENT(images, CONFIG_SYS_MAXARGS, 1, do_efi_show_images, "", ""), U_BOOT_CMD_MKENT(log, CONFIG_SYS_MAXARGS, 1, do_efi_show_log, "", ""), @@ -1688,6 +1711,8 @@ U_BOOT_LONGHELP(efidebug, " - show UEFI drivers\n" "efidebug dh\n" " - show UEFI handles\n" + "efidebug defaults\n" + " - show default EFI filename and PXE architecture\n" "efidebug images\n" " - show loaded images\n" "efidebug log\n"

When the --native flag is given, pretend to be running the host architecture rather than sandbox.
Allow the same control for PXE too.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v9: - Separate into separate patches
Changes in v8: - Add new patch to report host default-filename in native mode
include/efi.h | 15 +++++++++++++++ lib/efi_loader/efi_helper.c | 35 ++++++++++++++++++++--------------- 2 files changed, 35 insertions(+), 15 deletions(-)
diff --git a/include/efi.h b/include/efi.h index 633f5b4acb5..817bc56c835 100644 --- a/include/efi.h +++ b/include/efi.h @@ -679,6 +679,21 @@ void efi_show_tables(struct efi_system_table *systab); */ const char *efi_get_basename(void);
+#ifdef CONFIG_SANDBOX +#include <asm/state.h> +#endif + +static inline bool efi_use_host_arch(void) +{ +#ifdef CONFIG_SANDBOX + struct sandbox_state *state = state_get_current(); + + return state->native; +#else + return false; +#endif +} + /** * efi_get_pxe_arch() - Get the architecture value for PXE * diff --git a/lib/efi_loader/efi_helper.c b/lib/efi_loader/efi_helper.c index b8ece1c2e0c..ab5678eb66c 100644 --- a/lib/efi_loader/efi_helper.c +++ b/lib/efi_loader/efi_helper.c @@ -23,27 +23,31 @@
#undef BOOTEFI_NAME
-#ifdef CONFIG_SANDBOX - #if HOST_ARCH == HOST_ARCH_X86_64 -#define BOOTEFI_NAME "BOOTX64.EFI" +#define HOST_BOOTEFI_NAME "BOOTX64.EFI" +#define HOST_PXE_ARCH 0x6 #elif HOST_ARCH == HOST_ARCH_X86 -#define BOOTEFI_NAME "BOOTIA32.EFI" +#define HOST_BOOTEFI_NAME "BOOTIA32.EFI" +#define HOST_PXE_ARCH 0x7 #elif HOST_ARCH == HOST_ARCH_AARCH64 -#define BOOTEFI_NAME "BOOTAA64.EFI" +#define HOST_BOOTEFI_NAME "BOOTAA64.EFI" +#define HOST_PXE_ARCH 0xb #elif HOST_ARCH == HOST_ARCH_ARM -#define BOOTEFI_NAME "BOOTARM.EFI" +#define HOST_BOOTEFI_NAME "BOOTARM.EFI" +#define HOST_PXE_ARCH 0xa #elif HOST_ARCH == HOST_ARCH_RISCV32 -#define BOOTEFI_NAME "BOOTRISCV32.EFI" +#define HOST_BOOTEFI_NAME "BOOTRISCV32.EFI" +#define HOST_PXE_ARCH 0x19 #elif HOST_ARCH == HOST_ARCH_RISCV64 -#define BOOTEFI_NAME "BOOTRISCV64.EFI" +#define HOST_BOOTEFI_NAME "BOOTRISCV64.EFI" +#define HOST_PXE_ARCH 0x1b #else -#error Unsupported UEFI architecture +#error Unsupported Host architecture #endif
-#else - -#if defined(CONFIG_ARM64) +#if defined(CONFIG_SANDBOX) +#define BOOTEFI_NAME "BOOTSBOX.EFI" +#elif defined(CONFIG_ARM64) #define BOOTEFI_NAME "BOOTAA64.EFI" #elif defined(CONFIG_ARM) #define BOOTEFI_NAME "BOOTARM.EFI" @@ -59,8 +63,6 @@ #error Unsupported UEFI architecture #endif
-#endif - #if defined(CONFIG_CMD_EFIDEBUG) || defined(CONFIG_EFI_LOAD_FILE2_INITRD) /* GUID used by Linux to identify the LoadFile2 protocol with the initrd */ const efi_guid_t efi_lf2_initrd_guid = EFI_INITRD_MEDIA_GUID; @@ -68,11 +70,14 @@ const efi_guid_t efi_lf2_initrd_guid = EFI_INITRD_MEDIA_GUID;
const char *efi_get_basename(void) { - return BOOTEFI_NAME; + return efi_use_host_arch() ? HOST_BOOTEFI_NAME : BOOTEFI_NAME; }
int efi_get_pxe_arch(void) { + if (efi_use_host_arch()) + return HOST_PXE_ARCH; + /* http://www.iana.org/assignments/dhcpv6-parameters/dhcpv6-parameters.xml */ if (IS_ENABLED(CONFIG_ARM64)) return 0xb;

Rather than returning 0, just return an error, since sandbox is not used with PXE at present.
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v9: - Add new patch to drop sandbox PXE architecture
lib/efi_loader/efi_helper.c | 2 -- 1 file changed, 2 deletions(-)
diff --git a/lib/efi_loader/efi_helper.c b/lib/efi_loader/efi_helper.c index ab5678eb66c..bf96f61d3d0 100644 --- a/lib/efi_loader/efi_helper.c +++ b/lib/efi_loader/efi_helper.c @@ -91,8 +91,6 @@ int efi_get_pxe_arch(void) return 0x19; else if (IS_ENABLED(CONFIG_ARCH_RV64I)) return 0x1b; - else if (IS_ENABLED(CONFIG_SANDBOX)) - return 0; /* not used */
return -EINVAL; }

On Tue, Oct 29, 2024 at 08:22:16PM +0100, Simon Glass wrote:
Rather than returning 0, just return an error, since sandbox is not used with PXE at present.
Signed-off-by: Simon Glass sjg@chromium.org
Reviewed-by: Tom Rini trini@konsulko.com

This is not implemented so cannot actually be used to read blocks. Disable it until it is implemented, to avoid causing a hang with EFI, which probes every available BLK device.
Signed-off-by: Simon Glass sjg@chromium.org Reviewed-by: Tom Rini trini@konsulko.com Issue: https://source.denx.de/u-boot/u-boot/-/issues/37 ---
(no changes since v6)
Changes in v6: - Drop the patch to disable sandbox virtio blk with EFI - Add new patch to disable the sandbox virtio blk device
arch/Kconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/arch/Kconfig b/arch/Kconfig index 8f1f4667012..c39efb4d0a2 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -212,7 +212,8 @@ config SANDBOX imply VIRTIO_MMIO imply VIRTIO_PCI imply VIRTIO_SANDBOX - imply VIRTIO_BLK + # Re-enable this when fully implemented + # imply VIRTIO_BLK imply VIRTIO_NET imply DM_SOUND imply PCI_SANDBOX_EP

Create a new disk for use with tests, which contains the new 'testapp' EFI app specifically intended for testing the EFI loader.
Attach it to the USB device, since most testing is currently done with mmc.
Initially this image will be used to test the EFI bootmeth.
Fix a stale comment in prep_mmc_bootdev() while we are here.
For now this uses sudo and a compressed fallback file, like all the other bootstd tests. Once this series is in, the patch which moves this to use user-space tools will be cleaned up and re-submitted.
Signed-off-by: Simon Glass sjg@chromium.org
--- Here is the patch to avoid sudo and CI fallback:
[1] https://patchwork.ozlabs.org/project/uboot/patch/ 20240802093322.15240-1-richard@nod.at/
Changes in v9: - Mark the image as complete after writing it
arch/sandbox/dts/test.dts | 2 +- test/boot/bootdev.c | 18 +++++++++- test/boot/bootflow.c | 2 +- test/py/tests/bootstd/flash1.img.xz | Bin 0 -> 4980 bytes test/py/tests/test_ut.py | 53 ++++++++++++++++++++++++---- 5 files changed, 66 insertions(+), 9 deletions(-) create mode 100644 test/py/tests/bootstd/flash1.img.xz
diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts index 3017b33d67b..dee280184b1 100644 --- a/arch/sandbox/dts/test.dts +++ b/arch/sandbox/dts/test.dts @@ -1515,7 +1515,7 @@ flash-stick@1 { reg = <1>; compatible = "sandbox,usb-flash"; - sandbox,filepath = "testflash1.bin"; + sandbox,filepath = "flash1.img"; };
flash-stick@2 { diff --git a/test/boot/bootdev.c b/test/boot/bootdev.c index 369105ca4cf..c892854b227 100644 --- a/test/boot/bootdev.c +++ b/test/boot/bootdev.c @@ -221,6 +221,10 @@ static int bootdev_test_order(struct unit_test_state *uts) /* Use the environment variable to override it */ ut_assertok(env_set("boot_targets", "mmc1 mmc2 usb")); ut_assertok(bootflow_scan_first(NULL, NULL, &iter, 0, &bflow)); + + /* get the usb device which has a backing file (flash1.img) */ + ut_asserteq(0, bootflow_scan_next(&iter, &bflow)); + ut_asserteq(-ENODEV, bootflow_scan_next(&iter, &bflow)); ut_asserteq(5, iter.num_devs); ut_asserteq_str("mmc1.bootdev", iter.dev_used[0]->name); @@ -260,7 +264,11 @@ static int bootdev_test_order(struct unit_test_state *uts) ut_assertok(bootflow_scan_first(NULL, NULL, &iter, 0, &bflow)); ut_asserteq(2, iter.num_devs);
- /* Now scan past mmc1 and make sure that the 3 USB devices show up */ + /* + * Now scan past mmc1 and make sure that the 3 USB devices show up. The + * first one has a backing file so returns success + */ + ut_asserteq(0, bootflow_scan_next(&iter, &bflow)); ut_asserteq(-ENODEV, bootflow_scan_next(&iter, &bflow)); ut_asserteq(6, iter.num_devs); ut_asserteq_str("mmc2.bootdev", iter.dev_used[0]->name); @@ -322,6 +330,10 @@ static int bootdev_test_prio(struct unit_test_state *uts)
/* 3 MMC and 3 USB bootdevs: MMC should come before USB */ ut_assertok(bootflow_scan_first(NULL, NULL, &iter, 0, &bflow)); + + /* get the usb device which has a backing file (flash1.img) */ + ut_asserteq(0, bootflow_scan_next(&iter, &bflow)); + ut_asserteq(-ENODEV, bootflow_scan_next(&iter, &bflow)); ut_asserteq(6, iter.num_devs); ut_asserteq_str("mmc2.bootdev", iter.dev_used[0]->name); @@ -339,6 +351,10 @@ static int bootdev_test_prio(struct unit_test_state *uts) bootflow_iter_uninit(&iter); ut_assertok(bootflow_scan_first(NULL, NULL, &iter, BOOTFLOWIF_HUNT, &bflow)); + + /* get the usb device which has a backing file (flash1.img) */ + ut_asserteq(0, bootflow_scan_next(&iter, &bflow)); + ut_asserteq(-ENODEV, bootflow_scan_next(&iter, &bflow)); ut_asserteq(7, iter.num_devs); ut_asserteq_str("usb_mass_storage.lun0.bootdev", diff --git a/test/boot/bootflow.c b/test/boot/bootflow.c index 7cfb217088e..d7e94c8cc59 100644 --- a/test/boot/bootflow.c +++ b/test/boot/bootflow.c @@ -534,7 +534,7 @@ static int prep_mmc_bootdev(struct unit_test_state *uts, const char *mmc_dev,
order[2] = mmc_dev;
- /* Enable the mmc4 node since we need a second bootflow */ + /* Enable the requested mmc node since we need a second bootflow */ root = oftree_root(oftree_default()); node = ofnode_find_subnode(root, mmc_dev); ut_assert(ofnode_valid(node)); diff --git a/test/py/tests/bootstd/flash1.img.xz b/test/py/tests/bootstd/flash1.img.xz new file mode 100644 index 0000000000000000000000000000000000000000..0efd9cbe146db6e8f422d9d66f11a772a493ce29 GIT binary patch literal 4980 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 ByL$it
literal 0 HcmV?d00001
diff --git a/test/py/tests/test_ut.py b/test/py/tests/test_ut.py index 39aa1035e34..9b54f941014 100644 --- a/test/py/tests/test_ut.py +++ b/test/py/tests/test_ut.py @@ -28,21 +28,22 @@ def mkdir_cond(dirname): if not os.path.exists(dirname): os.mkdir(dirname)
-def setup_image(cons, mmc_dev, part_type, second_part=False): +def setup_image(cons, devnum, part_type, second_part=False, basename='mmc'): """Create a 20MB disk image with a single partition
Args: cons (ConsoleBase): Console to use - mmc_dev (int): MMC device number to use, e.g. 1 + devnum (int): Device number to use, e.g. 1 part_type (int): Partition type, e.g. 0xc for FAT32 second_part (bool): True to contain a small second partition + basename (str): Base name to use in the filename, e.g. 'mmc'
Returns: tuple: str: Filename of MMC image str: Directory name of 'mnt' directory """ - fname = os.path.join(cons.config.source_dir, f'mmc{mmc_dev}.img') + fname = os.path.join(cons.config.source_dir, f'{basename}{devnum}.img') mnt = os.path.join(cons.config.persistent_data_dir, 'mnt') mkdir_cond(mnt)
@@ -78,16 +79,17 @@ def mount_image(cons, fname, mnt, fstype): u_boot_utils.run_and_log(cons, f'sudo chown {getpass.getuser()} {mnt}') return loop
-def copy_prepared_image(cons, mmc_dev, fname): +def copy_prepared_image(cons, devnum, fname, basename='mmc'): """Use a prepared image since we cannot create one
Args: cons (ConsoleBase): Console touse - mmc_dev (int): MMC device number + devnum (int): device number fname (str): Filename of MMC image + basename (str): Base name to use in the filename, e.g. 'mmc' """ infname = os.path.join(cons.config.source_dir, - f'test/py/tests/bootstd/mmc{mmc_dev}.img.xz') + f'test/py/tests/bootstd/{basename}{devnum}.img.xz') u_boot_utils.run_and_log(cons, ['sh', '-c', f'xz -dc {infname} >{fname}'])
def setup_bootmenu_image(cons): @@ -549,6 +551,44 @@ def test_ut_dm_init(u_boot_console): with open(fn, 'wb') as fh: fh.write(data)
+ +def setup_efi_image(cons): + """Create a 20MB disk image with an EFI app on it""" + devnum = 1 + basename = 'flash' + fname, mnt = setup_image(cons, devnum, 0xc, second_part=True, + basename=basename) + + loop = None + mounted = False + complete = False + try: + loop = mount_image(cons, fname, mnt, 'ext4') + mounted = True + efi_dir = os.path.join(mnt, 'EFI') + mkdir_cond(efi_dir) + bootdir = os.path.join(efi_dir, 'BOOT') + mkdir_cond(bootdir) + efi_src = os.path.join(cons.config.build_dir, + f'lib/efi_loader/testapp.efi') + efi_dst = os.path.join(bootdir, 'BOOTSBOX.EFI') + with open(efi_src, 'rb') as inf: + with open(efi_dst, 'wb') as outf: + outf.write(inf.read()) + complete = True + except ValueError as exc: + print(f'Falled to create image, failing back to prepared copy: {exc}') + + finally: + if mounted: + u_boot_utils.run_and_log(cons, 'sudo umount --lazy %s' % mnt) + if loop: + u_boot_utils.run_and_log(cons, 'sudo losetup -d %s' % loop) + + if not complete: + copy_prepared_image(cons, devnum, fname, basename) + + @pytest.mark.buildconfigspec('cmd_bootflow') @pytest.mark.buildconfigspec('sandbox') def test_ut_dm_init_bootstd(u_boot_console): @@ -559,6 +599,7 @@ def test_ut_dm_init_bootstd(u_boot_console): setup_cedit_file(u_boot_console) setup_cros_image(u_boot_console) setup_android_image(u_boot_console) + setup_efi_image(u_boot_console)
# Restart so that the new mmc1.img is picked up u_boot_console.restart_uboot()

Add a simple test of booting with the EFI bootmeth, which runs the app and checks that it can call 'exit boot-services' (to check that all the device-removal code doesn't break anything) and then exit back to U-Boot.
This uses a disk image containing the testapp, ready for execution by sandbox when needed.
Signed-off-by: Simon Glass sjg@chromium.org
--- Note that this uses the same mechanism as for the other images which are created. Once this series lands I will update[1] and revisit.
[1] https://patchwork.ozlabs.org/project/uboot/patch/ 20240802093322.15240-1-richard@nod.at/
Changes in v9: - Fix 'sevices' typo
Changes in v7: - Drop patches already applied - Drop patch 'Disable ANSI output for tests' - Rebase on -master
Changes in v6: - Deal with sandbox CONFIG_LOGF_FUNC - Rebase on -next - Drop patches previously applied - Drop mention of helloworld since it is no-longer used by this test
Changes in v4: - Add efi_loader tag to some patches - Split out non-EFI patches into a different series
Changes in v2: - Add many new patches to resolve all the outstanding test issues
test/boot/bootflow.c | 60 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+)
diff --git a/test/boot/bootflow.c b/test/boot/bootflow.c index d7e94c8cc59..8d4cbbb0702 100644 --- a/test/boot/bootflow.c +++ b/test/boot/bootflow.c @@ -13,6 +13,7 @@ #include <cli.h> #include <dm.h> #include <efi.h> +#include <efi_loader.h> #include <expo.h> #ifdef CONFIG_SANDBOX #include <asm/test.h> @@ -31,6 +32,9 @@ extern U_BOOT_DRIVER(bootmeth_android); extern U_BOOT_DRIVER(bootmeth_cros); extern U_BOOT_DRIVER(bootmeth_2script);
+/* Use this as the vendor for EFI to tell the app to exit boot services */ +static u16 __efi_runtime_data test_vendor[] = u"U-Boot testing"; + static int inject_response(struct unit_test_state *uts) { /* @@ -1217,3 +1221,59 @@ static int bootflow_android(struct unit_test_state *uts) return 0; } BOOTSTD_TEST(bootflow_android, UTF_CONSOLE); + +/* Test EFI bootmeth */ +static int bootflow_efi(struct unit_test_state *uts) +{ + /* disable ethernet since the hunter will run dhcp */ + test_set_eth_enable(false); + + /* make USB scan without delays */ + test_set_skip_delays(true); + + bootstd_reset_usb(); + + ut_assertok(bootstd_test_drop_bootdev_order(uts)); + ut_assertok(run_command("bootflow scan", 0)); + ut_assert_skip_to_line( + "Bus usb@1: scanning bus usb@1 for devices... 5 USB Device(s) found"); + + ut_assertok(run_command("bootflow list", 0)); + + ut_assert_nextlinen("Showing all"); + ut_assert_nextlinen("Seq"); + ut_assert_nextlinen("---"); + ut_assert_nextlinen(" 0 extlinux"); + ut_assert_nextlinen( + " 1 efi ready usb_mass_ 1 usb_mass_storage.lun0.boo /EFI/BOOT/BOOTSBOX.EFI"); + ut_assert_nextlinen("---"); + ut_assert_skip_to_line("(2 bootflows, 2 valid)"); + ut_assert_console_end(); + + ut_assertok(run_command("bootflow select 1", 0)); + ut_assert_console_end(); + + systab.fw_vendor = test_vendor; + + ut_asserteq(1, run_command("bootflow boot", 0)); + ut_assert_nextline( + "** Booting bootflow 'usb_mass_storage.lun0.bootdev.part_1' with efi"); + if (IS_ENABLED(CONFIG_LOGF_FUNC)) + ut_assert_skip_to_line(" efi_run_image() Booting /\EFI\BOOT\BOOTSBOX.EFI"); + else + ut_assert_skip_to_line("Booting /\EFI\BOOT\BOOTSBOX.EFI"); + + /* TODO: Why the \r ? */ + ut_assert_nextline("U-Boot test app for EFI_LOADER\r"); + ut_assert_nextline("Exiting boot services"); + if (IS_ENABLED(CONFIG_LOGF_FUNC)) + ut_assert_nextline(" do_bootefi_exec() ## Application failed, r = 5"); + else + ut_assert_nextline("## Application failed, r = 5"); + ut_assert_nextline("Boot failed (err=-22)"); + + ut_assert_console_end(); + + return 0; +} +BOOTSTD_TEST(bootflow_efi, UTF_CONSOLE);
participants (4)
-
Heinrich Schuchardt
-
Ilias Apalodimas
-
Simon Glass
-
Tom Rini