[U-Boot] [PATCH 0/2] efi_loader: correctly call images

This patch series fixes various problems with the StartImage boot time service. It further provides a unit test.
Heinrich Schuchardt (2): efi_loader: correctly call images efi_selftest: test start image
lib/efi_loader/efi_boottime.c | 21 ++-- lib/efi_selftest/.gitignore | 2 + lib/efi_selftest/Makefile | 14 +++ lib/efi_selftest/efi_selftest_miniapp.c | 34 +++++++ lib/efi_selftest/efi_selftest_start_image.c | 144 ++++++++++++++++++++++++++++ 5 files changed, 208 insertions(+), 7 deletions(-) create mode 100644 lib/efi_selftest/.gitignore create mode 100644 lib/efi_selftest/efi_selftest_miniapp.c create mode 100644 lib/efi_selftest/efi_selftest_start_image.c

Avoid a failed assertion when an EFI app calls an EFI app.
Avoid that the indent level increases when calling 'bootefi hello' repeatedly.
Avoid negative indent level when an EFI app calls an EFI app that calls an EFI app (e.g. iPXE loads grub which starts the kernel).
Return the status code of a loaded image that returns without calling the Exit boot service.
Signed-off-by: Heinrich Schuchardt xypron.glpk@gmx.de --- lib/efi_loader/efi_boottime.c | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-)
diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 4b3b63e39a..e13a2ac22e 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -1537,6 +1537,7 @@ static efi_status_t EFIAPI efi_start_image(efi_handle_t image_handle, asmlinkage ulong (*entry)(efi_handle_t image_handle, struct efi_system_table *st); struct efi_loaded_image *info = image_handle; + efi_status_t ret;
EFI_ENTRY("%p, %p, %p", image_handle, exit_data_size, exit_data); entry = info->reserved; @@ -1546,17 +1547,23 @@ static efi_status_t EFIAPI efi_start_image(efi_handle_t image_handle, /* call the image! */ if (setjmp(&info->exit_jmp)) { /* We returned from the child image */ +#ifdef CONFIG_ARM + /* efi_exit() called efi_restore_gd() */ + gd = app_gd; +#endif + /* Execute the return part of EFI_CALL */ + assert(__efi_entry_check()); + debug("%sEFI: %lu returned by started image\n", + __efi_nesting_dec(), + (unsigned long)((uintptr_t)info->exit_status & + ~EFI_ERROR_MASK)); return EFI_EXIT(info->exit_status); }
- __efi_nesting_dec(); - __efi_exit_check(); - entry(image_handle, &systab); - __efi_entry_check(); - __efi_nesting_inc(); + ret = EFI_CALL(entry(image_handle, &systab));
/* Should usually never get here */ - return EFI_EXIT(EFI_SUCCESS); + return EFI_EXIT(ret); }
/* @@ -1593,7 +1600,7 @@ static efi_status_t EFIAPI efi_exit(efi_handle_t image_handle, exit_data_size, exit_data);
/* Make sure entry/exit counts for EFI world cross-overs match */ - __efi_exit_check(); + EFI_EXIT(exit_status);
/* * But longjmp out with the U-Boot gd, not the application's, as

This test checks the StartImage boottime service. An EFI application is loaded into memory and started.
Signed-off-by: Heinrich Schuchardt xypron.glpk@gmx.de --- lib/efi_selftest/.gitignore | 2 + lib/efi_selftest/Makefile | 14 +++ lib/efi_selftest/efi_selftest_miniapp.c | 34 +++++++ lib/efi_selftest/efi_selftest_start_image.c | 144 ++++++++++++++++++++++++++++ 4 files changed, 194 insertions(+) create mode 100644 lib/efi_selftest/.gitignore create mode 100644 lib/efi_selftest/efi_selftest_miniapp.c create mode 100644 lib/efi_selftest/efi_selftest_start_image.c
diff --git a/lib/efi_selftest/.gitignore b/lib/efi_selftest/.gitignore new file mode 100644 index 0000000000..c527e464e5 --- /dev/null +++ b/lib/efi_selftest/.gitignore @@ -0,0 +1,2 @@ +efi_miniapp_file_image.h +*.efi diff --git a/lib/efi_selftest/Makefile b/lib/efi_selftest/Makefile index 20f614d6ba..c353a01860 100644 --- a/lib/efi_selftest/Makefile +++ b/lib/efi_selftest/Makefile @@ -7,6 +7,9 @@ # This file only gets included with CONFIG_EFI_LOADER set, so all # object inclusion implicitly depends on it
+CFLAGS_efi_selftest_miniapp.o := $(CFLAGS_EFI) -Os -ffreestanding +CFLAGS_REMOVE_efi_selftest_miniapp.o := $(CFLAGS_NON_EFI) -Os + obj-$(CONFIG_CMD_BOOTEFI_SELFTEST) += \ efi_selftest.o \ efi_selftest_controllers.o \ @@ -17,6 +20,7 @@ efi_selftest_exitbootservices.o \ efi_selftest_gop.o \ efi_selftest_manageprotocols.o \ efi_selftest_snp.o \ +efi_selftest_start_image.o \ efi_selftest_textoutput.o \ efi_selftest_tpl.o \ efi_selftest_util.o \ @@ -25,3 +29,13 @@ efi_selftest_watchdog.o ifeq ($(CONFIG_BLK)$(CONFIG_PARTITIONS),yy) obj-$(CONFIG_CMD_BOOTEFI_SELFTEST) += efi_selftest_block_device.o endif + +targets += \ +efi_miniapp_file_image.h \ +efi_selftest_miniapp.efi + +$(obj)/efi_miniapp_file_image.h: $(obj)/efi_selftest_miniapp.efi + $(obj)/../../tools/file2include $(obj)/efi_selftest_miniapp.efi > \ + $(obj)/efi_miniapp_file_image.h + +$(obj)/efi_selftest_start_image.o: $(obj)/efi_miniapp_file_image.h diff --git a/lib/efi_selftest/efi_selftest_miniapp.c b/lib/efi_selftest/efi_selftest_miniapp.c new file mode 100644 index 0000000000..bcdb37e86b --- /dev/null +++ b/lib/efi_selftest/efi_selftest_miniapp.c @@ -0,0 +1,34 @@ +/* + * efi_selftest_miniapp + * + * Copyright (c) 2018 Heinrich Schuchardt + * + * SPDX-License-Identifier: GPL-2.0+ + * + * This EFI application is run by the StartImage selftest. + */ + +#include <common.h> +#include <efi_api.h> + +/* + * Entry point of the EFI application. + * + * @handle handle of the loaded image + * @systable system table + * @return status code + */ +efi_status_t EFIAPI efi_main(efi_handle_t handle, + struct efi_system_table *systable) +{ + struct efi_simple_text_output_protocol *con_out = systable->con_out; + + con_out->set_attribute(con_out, EFI_BACKGROUND_BROWN | EFI_WHITE); + con_out->output_string(con_out, L"Entering EFI application"); + con_out->set_attribute(con_out, EFI_LIGHTGRAY); + con_out->output_string(con_out, L"\n"); + + systable->boottime->exit(handle, EFI_SUCCESS, 0, NULL); + + return EFI_SUCCESS; +} diff --git a/lib/efi_selftest/efi_selftest_start_image.c b/lib/efi_selftest/efi_selftest_start_image.c new file mode 100644 index 0000000000..012f64e369 --- /dev/null +++ b/lib/efi_selftest/efi_selftest_start_image.c @@ -0,0 +1,144 @@ +/* + * efi_selftest_start_image + * + * Copyright (c) 2018 Heinrich Schuchardt xypron.glpk@gmx.de + * + * SPDX-License-Identifier: GPL-2.0+ + * + * This test checks the StartImage boottime service. + * The efi_selftest_miniapp.efi application is loaded into memory and started. + */ + +#include <efi_selftest.h> +/* Include containing the miniapp.efi application */ +#include "efi_miniapp_file_image.h" + +/* Block size of compressed disk image */ +#define COMPRESSED_DISK_IMAGE_BLOCK_SIZE 8 + +/* Binary logarithm of the block size */ +#define LB_BLOCK_SIZE 9 + +static efi_handle_t image_handle; +static struct efi_boot_services *boottime; + +/* One 8 byte block of the compressed disk image */ +struct line { + size_t addr; + char *line; +}; + +/* Compressed file image */ +struct compressed_file_image { + size_t length; + struct line lines[]; +}; + +static struct compressed_file_image img = EFI_ST_DISK_IMG; + +/* Decompressed file image */ +static u8 *image; + +/* + * Decompress the disk image. + * + * @image decompressed disk image + * @return status code + */ +static efi_status_t decompress(u8 **image) +{ + u8 *buf; + size_t i; + size_t addr; + size_t len; + efi_status_t ret; + + ret = boottime->allocate_pool(EFI_LOADER_DATA, img.length, + (void **)&buf); + if (ret != EFI_SUCCESS) { + efi_st_error("Out of memory\n"); + return ret; + } + boottime->set_mem(buf, img.length, 0); + + for (i = 0; ; ++i) { + if (!img.lines[i].line) + break; + addr = img.lines[i].addr; + len = COMPRESSED_DISK_IMAGE_BLOCK_SIZE; + if (addr + len > img.length) + len = img.length - addr; + boottime->copy_mem(buf + addr, img.lines[i].line, len); + } + *image = buf; + return ret; +} + +/* + * Setup unit test. + * + * @handle: handle of the loaded image + * @systable: system table + * @return: EFI_ST_SUCCESS for success + */ +static int setup(const efi_handle_t handle, + const struct efi_system_table *systable) +{ + image_handle = handle; + boottime = systable->boottime; + + /* Load the application image into memory */ + decompress(&image); + + return EFI_ST_SUCCESS; +} + +/* + * Tear down unit test. + * + * @return: EFI_ST_SUCCESS for success + */ +static int teardown(void) +{ + efi_status_t r = EFI_ST_SUCCESS; + + if (image) { + r = efi_free_pool(image); + if (r != EFI_SUCCESS) { + efi_st_error("Failed to free image\n"); + return EFI_ST_FAILURE; + } + } + return r; +} + +/* + * Execute unit test. + * + * Load and start the application image. + * + * @return: EFI_ST_SUCCESS for success + */ +static int execute(void) +{ + efi_status_t ret; + efi_handle_t handle; + + ret = boottime->load_image(false, image_handle, NULL, image, + img.length, &handle); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to load image\n"); + return EFI_ST_FAILURE; + } + ret = boottime->start_image(handle, NULL, NULL); + + return EFI_ST_SUCCESS; +} + +EFI_UNIT_TEST(startimage) = { + .name = "start image", + .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT, + .setup = setup, + .execute = execute, + .teardown = teardown, +};
participants (1)
-
Heinrich Schuchardt