diff options
Diffstat (limited to 'lib/efi_selftest')
-rw-r--r-- | lib/efi_selftest/.gitignore | 2 | ||||
-rw-r--r-- | lib/efi_selftest/Makefile | 36 | ||||
-rw-r--r-- | lib/efi_selftest/efi_selftest_miniapp_exit.c | 37 | ||||
-rw-r--r-- | lib/efi_selftest/efi_selftest_miniapp_return.c | 32 | ||||
-rw-r--r-- | lib/efi_selftest/efi_selftest_startimage_exit.c | 149 | ||||
-rw-r--r-- | lib/efi_selftest/efi_selftest_startimage_return.c | 149 |
6 files changed, 405 insertions, 0 deletions
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 e549553c82..70ad0b71ce 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 \ @@ -21,3 +24,36 @@ efi_selftest_textoutput.o \ efi_selftest_tpl.o \ efi_selftest_util.o \ efi_selftest_watchdog.o + + +# TODO: As of v2018.01 the relocation code for the EFI application cannot +# be built on x86_64. +ifeq ($(CONFIG_X86_64),) + +ifneq ($(CONFIG_CMD_BOOTEFI_SELFTEST),) + +obj-y += \ +efi_selftest_startimage_exit.o \ +efi_selftest_startimage_return.o + +targets += \ +efi_miniapp_file_image_exit.h \ +efi_miniapp_file_image_return.h \ +efi_selftest_miniapp_exit.efi \ +efi_selftest_miniapp_return.efi + +$(obj)/efi_miniapp_file_image_exit.h: $(obj)/efi_selftest_miniapp_exit.efi + $(obj)/../../tools/file2include $(obj)/efi_selftest_miniapp_exit.efi > \ + $(obj)/efi_miniapp_file_image_exit.h + +$(obj)/efi_miniapp_file_image_return.h: $(obj)/efi_selftest_miniapp_return.efi + $(obj)/../../tools/file2include $(obj)/efi_selftest_miniapp_return.efi > \ + $(obj)/efi_miniapp_file_image_return.h + +$(obj)/efi_selftest_startimage_exit.o: $(obj)/efi_miniapp_file_image_exit.h + +$(obj)/efi_selftest_startimage_return.o: $(obj)/efi_miniapp_file_image_return.h + +endif + +endif diff --git a/lib/efi_selftest/efi_selftest_miniapp_exit.c b/lib/efi_selftest/efi_selftest_miniapp_exit.c new file mode 100644 index 0000000000..590c948a1c --- /dev/null +++ b/lib/efi_selftest/efi_selftest_miniapp_exit.c @@ -0,0 +1,37 @@ +/* + * efi_selftest_miniapp_exit + * + * Copyright (c) 2018 Heinrich Schuchardt + * + * SPDX-License-Identifier: GPL-2.0+ + * + * This EFI application is run by the StartImage selftest. + * It uses the Exit boot service to return. + */ + +#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->output_string(con_out, L"EFI application calling Exit"); + + /* The return value is checked by the calling test */ + systable->boottime->exit(handle, EFI_UNSUPPORTED, 0, NULL); + + /* + * This statement should not be reached. + * To enable testing use a different return value. + */ + return EFI_SUCCESS; +} diff --git a/lib/efi_selftest/efi_selftest_miniapp_return.c b/lib/efi_selftest/efi_selftest_miniapp_return.c new file mode 100644 index 0000000000..e5d3979b03 --- /dev/null +++ b/lib/efi_selftest/efi_selftest_miniapp_return.c @@ -0,0 +1,32 @@ +/* + * efi_selftest_miniapp_return + * + * Copyright (c) 2018 Heinrich Schuchardt + * + * SPDX-License-Identifier: GPL-2.0+ + * + * This EFI application is run by the StartImage selftest. + * It returns directly without calling the Exit boot service. + */ + +#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->output_string(con_out, + L"EFI application returning w/o calling Exit"); + + /* The return value is checked by the calling test */ + return EFI_INCOMPATIBLE_VERSION; +} diff --git a/lib/efi_selftest/efi_selftest_startimage_exit.c b/lib/efi_selftest/efi_selftest_startimage_exit.c new file mode 100644 index 0000000000..0809690e97 --- /dev/null +++ b/lib/efi_selftest/efi_selftest_startimage_exit.c @@ -0,0 +1,149 @@ +/* + * efi_selftest_start_image + * + * Copyright (c) 2018 Heinrich Schuchardt <xypron.glpk@gmx.de> + * + * SPDX-License-Identifier: GPL-2.0+ + * + * This test checks the StartImage boot service. + * The efi_selftest_miniapp_exit.efi application is loaded into memory + * and started. + */ + +#include <efi_selftest.h> +/* Include containing the miniapp.efi application */ +#include "efi_miniapp_file_image_exit.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); + if (ret != EFI_UNSUPPORTED) { + efi_st_error("Wrong return value from application\n"); + return EFI_ST_FAILURE; + } + + return EFI_ST_SUCCESS; +} + +EFI_UNIT_TEST(startimage_exit) = { + .name = "start image exit", + .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT, + .setup = setup, + .execute = execute, + .teardown = teardown, +}; diff --git a/lib/efi_selftest/efi_selftest_startimage_return.c b/lib/efi_selftest/efi_selftest_startimage_return.c new file mode 100644 index 0000000000..2209911457 --- /dev/null +++ b/lib/efi_selftest/efi_selftest_startimage_return.c @@ -0,0 +1,149 @@ +/* + * efi_selftest_start_image + * + * Copyright (c) 2018 Heinrich Schuchardt <xypron.glpk@gmx.de> + * + * SPDX-License-Identifier: GPL-2.0+ + * + * This test checks the StartImage boot service. + * The efi_selftest_miniapp_return.efi application is loaded into memory + * and started. + */ + +#include <efi_selftest.h> +/* Include containing the miniapp.efi application */ +#include "efi_miniapp_file_image_return.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); + if (ret != EFI_INCOMPATIBLE_VERSION) { + efi_st_error("Wrong return value from application\n"); + return EFI_ST_FAILURE; + } + + return EFI_ST_SUCCESS; +} + +EFI_UNIT_TEST(startimage) = { + .name = "start image return", + .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT, + .setup = setup, + .execute = execute, + .teardown = teardown, +}; |