[PATCH v2 36/39] efi: Add a test app

Simon Glass sjg at chromium.org
Sun Aug 11 16:50:17 CEST 2024


Hi Heinrich,

On Thu, 8 Aug 2024 at 15:17, Heinrich Schuchardt <xypron.glpk at gmx.de> wrote:
>
> On 07.08.24 16:36, Simon Glass wrote:
> > Hi Heinrich,
> >
> > On Tue, 6 Aug 2024 at 19:47, Heinrich Schuchardt <xypron.glpk at gmx.de> wrote:
> >>
> >> On 06.08.24 14:58, 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.
> >>>
> >>> Signed-off-by: Simon Glass <sjg at chromium.org>
> >>> ---
> >>>
> >>> (no changes since v1)
> >>>
> >>>    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 ab2c1c44364..4de05c6f2d6 100644
> >>> --- a/lib/efi_loader/Kconfig
> >>> +++ b/lib/efi_loader/Kconfig
> >>> @@ -528,4 +528,14 @@ 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
> >>> diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile
> >>> index 00d18966f9e..87131ab911d 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..feb444c92e9
> >>> --- /dev/null
> >>> +++ b/lib/efi_loader/testapp.c
> >>> @@ -0,0 +1,68 @@
> >>> +// SPDX-License-Identifier: GPL-2.0+
> >>> +/*
> >>> + * Hello world EFI application
> >>> + *
> >>> + * Copyright 2024 Google LLC
> >>> + * Written by Simon Glass <sjg at 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 sevices\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);
> >>
> >> Please, have a look at chapter 7.4.6,
> >> "EFI_BOOT_SERVICES.ExitBootServices" of the UEFI specification.
> >>
> >> After ExitBootServices() you cannot return anywhere. Boot services are
> >> not available anymore. You can only invoke the UEFI runtime services
> >> which include ResetSystem().
> >
> > Yes, understood, but this is a test, so returning is needed so that
> > the test can check the output is correct.
> >
>
> ExitBootServices() calls dm_remove_devices_flags(DM_REMOVE_ACTIVE_ALL).
> You cannot print anything afterwards as all devices are gone.

That only removes activate devices, i.e. those which use DMA, etc. So
for example the serial port will still be present.

>
> But you can check if a reboot occurs. This is enough to verify that a
> ResetSystem() call placed after ExitBootServices() was executed.
>
> We already have
>
> * lib/efi_selftest/efi_selftest_exitbootservices.c
> * lib/efi_selftest/efi_selftest_variables_runtime.c
> * lib/efi_selftest/efi_selftest_set_virtual_address_map.c
>
> which test different aspects of ExitBootServices() on the sandbox.
>
> There is no need to duplicate these.

Ilias asked that I not put my stuff into HelloWorld, which is why I
added a new app. I can then use it how I please!

Actually none of the examples you list does what my new test does,
which is to boot an app from a bootflow. This was the subject of a
nasty bug, so I do what to add a test for it.

I don't want to reboot, since then it cannot be a unit test. I may
have mentioned this before...but the EFI approach to testing is quite
poor in this respect. We need to test specific regions of the code and
avoid these large, slow and complicated tests.

Regards,
Simon


More information about the U-Boot mailing list