Commit 8218f7b5fc33628e84581a46446e6f9a2b66e844

Authored by Heinrich Schuchardt
Committed by Alexander Graf
1 parent cc20ed03f9

efi_selftest: test start image

This pair of tests checks the StartImage boot service.

Each test loads an EFI application into memory and starts it.
One returns by calling the Exit boot service. The other returns directly.

The tests are not built on x86_64 because the relocation code for the efi
binary cannot be created.

Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
Signed-off-by: Alexander Graf <agraf@suse.de>

Showing 7 changed files with 406 additions and 0 deletions Side-by-side Diff

arch/arm/lib/Makefile
... ... @@ -112,5 +112,6 @@
112 112 CFLAGS_REMOVE_$(EFI_RELOC) := $(CFLAGS_NON_EFI)
113 113  
114 114 extra-$(CONFIG_CMD_BOOTEFI_HELLO_COMPILE) += $(EFI_CRT0) $(EFI_RELOC)
  115 +extra-$(CONFIG_CMD_BOOTEFI_SELFTEST) += $(EFI_CRT0) $(EFI_RELOC)
115 116 extra-$(CONFIG_EFI) += $(EFI_CRT0) $(EFI_RELOC)
lib/efi_selftest/.gitignore
  1 +efi_miniapp_file_image.h
  2 +*.efi
lib/efi_selftest/Makefile
... ... @@ -7,6 +7,9 @@
7 7 # This file only gets included with CONFIG_EFI_LOADER set, so all
8 8 # object inclusion implicitly depends on it
9 9  
  10 +CFLAGS_efi_selftest_miniapp.o := $(CFLAGS_EFI) -Os -ffreestanding
  11 +CFLAGS_REMOVE_efi_selftest_miniapp.o := $(CFLAGS_NON_EFI) -Os
  12 +
10 13 obj-$(CONFIG_CMD_BOOTEFI_SELFTEST) += \
11 14 efi_selftest.o \
12 15 efi_selftest_controllers.o \
... ... @@ -21,4 +24,37 @@
21 24 efi_selftest_tpl.o \
22 25 efi_selftest_util.o \
23 26 efi_selftest_watchdog.o
  27 +
  28 +
  29 +# TODO: As of v2018.01 the relocation code for the EFI application cannot
  30 +# be built on x86_64.
  31 +ifeq ($(CONFIG_X86_64),)
  32 +
  33 +ifneq ($(CONFIG_CMD_BOOTEFI_SELFTEST),)
  34 +
  35 +obj-y += \
  36 +efi_selftest_startimage_exit.o \
  37 +efi_selftest_startimage_return.o
  38 +
  39 +targets += \
  40 +efi_miniapp_file_image_exit.h \
  41 +efi_miniapp_file_image_return.h \
  42 +efi_selftest_miniapp_exit.efi \
  43 +efi_selftest_miniapp_return.efi
  44 +
  45 +$(obj)/efi_miniapp_file_image_exit.h: $(obj)/efi_selftest_miniapp_exit.efi
  46 + $(obj)/../../tools/file2include $(obj)/efi_selftest_miniapp_exit.efi > \
  47 + $(obj)/efi_miniapp_file_image_exit.h
  48 +
  49 +$(obj)/efi_miniapp_file_image_return.h: $(obj)/efi_selftest_miniapp_return.efi
  50 + $(obj)/../../tools/file2include $(obj)/efi_selftest_miniapp_return.efi > \
  51 + $(obj)/efi_miniapp_file_image_return.h
  52 +
  53 +$(obj)/efi_selftest_startimage_exit.o: $(obj)/efi_miniapp_file_image_exit.h
  54 +
  55 +$(obj)/efi_selftest_startimage_return.o: $(obj)/efi_miniapp_file_image_return.h
  56 +
  57 +endif
  58 +
  59 +endif
lib/efi_selftest/efi_selftest_miniapp_exit.c
  1 +/*
  2 + * efi_selftest_miniapp_exit
  3 + *
  4 + * Copyright (c) 2018 Heinrich Schuchardt
  5 + *
  6 + * SPDX-License-Identifier: GPL-2.0+
  7 + *
  8 + * This EFI application is run by the StartImage selftest.
  9 + * It uses the Exit boot service to return.
  10 + */
  11 +
  12 +#include <common.h>
  13 +#include <efi_api.h>
  14 +
  15 +/*
  16 + * Entry point of the EFI application.
  17 + *
  18 + * @handle handle of the loaded image
  19 + * @systable system table
  20 + * @return status code
  21 + */
  22 +efi_status_t EFIAPI efi_main(efi_handle_t handle,
  23 + struct efi_system_table *systable)
  24 +{
  25 + struct efi_simple_text_output_protocol *con_out = systable->con_out;
  26 +
  27 + con_out->output_string(con_out, L"EFI application calling Exit");
  28 +
  29 + /* The return value is checked by the calling test */
  30 + systable->boottime->exit(handle, EFI_UNSUPPORTED, 0, NULL);
  31 +
  32 + /*
  33 + * This statement should not be reached.
  34 + * To enable testing use a different return value.
  35 + */
  36 + return EFI_SUCCESS;
  37 +}
lib/efi_selftest/efi_selftest_miniapp_return.c
  1 +/*
  2 + * efi_selftest_miniapp_return
  3 + *
  4 + * Copyright (c) 2018 Heinrich Schuchardt
  5 + *
  6 + * SPDX-License-Identifier: GPL-2.0+
  7 + *
  8 + * This EFI application is run by the StartImage selftest.
  9 + * It returns directly without calling the Exit boot service.
  10 + */
  11 +
  12 +#include <common.h>
  13 +#include <efi_api.h>
  14 +
  15 +/*
  16 + * Entry point of the EFI application.
  17 + *
  18 + * @handle handle of the loaded image
  19 + * @systable system table
  20 + * @return status code
  21 + */
  22 +efi_status_t EFIAPI efi_main(efi_handle_t handle,
  23 + struct efi_system_table *systable)
  24 +{
  25 + struct efi_simple_text_output_protocol *con_out = systable->con_out;
  26 +
  27 + con_out->output_string(con_out,
  28 + L"EFI application returning w/o calling Exit");
  29 +
  30 + /* The return value is checked by the calling test */
  31 + return EFI_INCOMPATIBLE_VERSION;
  32 +}
lib/efi_selftest/efi_selftest_startimage_exit.c
  1 +/*
  2 + * efi_selftest_start_image
  3 + *
  4 + * Copyright (c) 2018 Heinrich Schuchardt <xypron.glpk@gmx.de>
  5 + *
  6 + * SPDX-License-Identifier: GPL-2.0+
  7 + *
  8 + * This test checks the StartImage boot service.
  9 + * The efi_selftest_miniapp_exit.efi application is loaded into memory
  10 + * and started.
  11 + */
  12 +
  13 +#include <efi_selftest.h>
  14 +/* Include containing the miniapp.efi application */
  15 +#include "efi_miniapp_file_image_exit.h"
  16 +
  17 +/* Block size of compressed disk image */
  18 +#define COMPRESSED_DISK_IMAGE_BLOCK_SIZE 8
  19 +
  20 +/* Binary logarithm of the block size */
  21 +#define LB_BLOCK_SIZE 9
  22 +
  23 +static efi_handle_t image_handle;
  24 +static struct efi_boot_services *boottime;
  25 +
  26 +/* One 8 byte block of the compressed disk image */
  27 +struct line {
  28 + size_t addr;
  29 + char *line;
  30 +};
  31 +
  32 +/* Compressed file image */
  33 +struct compressed_file_image {
  34 + size_t length;
  35 + struct line lines[];
  36 +};
  37 +
  38 +static struct compressed_file_image img = EFI_ST_DISK_IMG;
  39 +
  40 +/* Decompressed file image */
  41 +static u8 *image;
  42 +
  43 +/*
  44 + * Decompress the disk image.
  45 + *
  46 + * @image decompressed disk image
  47 + * @return status code
  48 + */
  49 +static efi_status_t decompress(u8 **image)
  50 +{
  51 + u8 *buf;
  52 + size_t i;
  53 + size_t addr;
  54 + size_t len;
  55 + efi_status_t ret;
  56 +
  57 + ret = boottime->allocate_pool(EFI_LOADER_DATA, img.length,
  58 + (void **)&buf);
  59 + if (ret != EFI_SUCCESS) {
  60 + efi_st_error("Out of memory\n");
  61 + return ret;
  62 + }
  63 + boottime->set_mem(buf, img.length, 0);
  64 +
  65 + for (i = 0; ; ++i) {
  66 + if (!img.lines[i].line)
  67 + break;
  68 + addr = img.lines[i].addr;
  69 + len = COMPRESSED_DISK_IMAGE_BLOCK_SIZE;
  70 + if (addr + len > img.length)
  71 + len = img.length - addr;
  72 + boottime->copy_mem(buf + addr, img.lines[i].line, len);
  73 + }
  74 + *image = buf;
  75 + return ret;
  76 +}
  77 +
  78 +/*
  79 + * Setup unit test.
  80 + *
  81 + * @handle: handle of the loaded image
  82 + * @systable: system table
  83 + * @return: EFI_ST_SUCCESS for success
  84 + */
  85 +static int setup(const efi_handle_t handle,
  86 + const struct efi_system_table *systable)
  87 +{
  88 + image_handle = handle;
  89 + boottime = systable->boottime;
  90 +
  91 + /* Load the application image into memory */
  92 + decompress(&image);
  93 +
  94 + return EFI_ST_SUCCESS;
  95 +}
  96 +
  97 +/*
  98 + * Tear down unit test.
  99 + *
  100 + * @return: EFI_ST_SUCCESS for success
  101 + */
  102 +static int teardown(void)
  103 +{
  104 + efi_status_t r = EFI_ST_SUCCESS;
  105 +
  106 + if (image) {
  107 + r = efi_free_pool(image);
  108 + if (r != EFI_SUCCESS) {
  109 + efi_st_error("Failed to free image\n");
  110 + return EFI_ST_FAILURE;
  111 + }
  112 + }
  113 + return r;
  114 +}
  115 +
  116 +/*
  117 + * Execute unit test.
  118 + *
  119 + * Load and start the application image.
  120 + *
  121 + * @return: EFI_ST_SUCCESS for success
  122 + */
  123 +static int execute(void)
  124 +{
  125 + efi_status_t ret;
  126 + efi_handle_t handle;
  127 +
  128 + ret = boottime->load_image(false, image_handle, NULL, image,
  129 + img.length, &handle);
  130 + if (ret != EFI_SUCCESS) {
  131 + efi_st_error("Failed to load image\n");
  132 + return EFI_ST_FAILURE;
  133 + }
  134 + ret = boottime->start_image(handle, NULL, NULL);
  135 + if (ret != EFI_UNSUPPORTED) {
  136 + efi_st_error("Wrong return value from application\n");
  137 + return EFI_ST_FAILURE;
  138 + }
  139 +
  140 + return EFI_ST_SUCCESS;
  141 +}
  142 +
  143 +EFI_UNIT_TEST(startimage_exit) = {
  144 + .name = "start image exit",
  145 + .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT,
  146 + .setup = setup,
  147 + .execute = execute,
  148 + .teardown = teardown,
  149 +};
lib/efi_selftest/efi_selftest_startimage_return.c
  1 +/*
  2 + * efi_selftest_start_image
  3 + *
  4 + * Copyright (c) 2018 Heinrich Schuchardt <xypron.glpk@gmx.de>
  5 + *
  6 + * SPDX-License-Identifier: GPL-2.0+
  7 + *
  8 + * This test checks the StartImage boot service.
  9 + * The efi_selftest_miniapp_return.efi application is loaded into memory
  10 + * and started.
  11 + */
  12 +
  13 +#include <efi_selftest.h>
  14 +/* Include containing the miniapp.efi application */
  15 +#include "efi_miniapp_file_image_return.h"
  16 +
  17 +/* Block size of compressed disk image */
  18 +#define COMPRESSED_DISK_IMAGE_BLOCK_SIZE 8
  19 +
  20 +/* Binary logarithm of the block size */
  21 +#define LB_BLOCK_SIZE 9
  22 +
  23 +static efi_handle_t image_handle;
  24 +static struct efi_boot_services *boottime;
  25 +
  26 +/* One 8 byte block of the compressed disk image */
  27 +struct line {
  28 + size_t addr;
  29 + char *line;
  30 +};
  31 +
  32 +/* Compressed file image */
  33 +struct compressed_file_image {
  34 + size_t length;
  35 + struct line lines[];
  36 +};
  37 +
  38 +static struct compressed_file_image img = EFI_ST_DISK_IMG;
  39 +
  40 +/* Decompressed file image */
  41 +static u8 *image;
  42 +
  43 +/*
  44 + * Decompress the disk image.
  45 + *
  46 + * @image decompressed disk image
  47 + * @return status code
  48 + */
  49 +static efi_status_t decompress(u8 **image)
  50 +{
  51 + u8 *buf;
  52 + size_t i;
  53 + size_t addr;
  54 + size_t len;
  55 + efi_status_t ret;
  56 +
  57 + ret = boottime->allocate_pool(EFI_LOADER_DATA, img.length,
  58 + (void **)&buf);
  59 + if (ret != EFI_SUCCESS) {
  60 + efi_st_error("Out of memory\n");
  61 + return ret;
  62 + }
  63 + boottime->set_mem(buf, img.length, 0);
  64 +
  65 + for (i = 0; ; ++i) {
  66 + if (!img.lines[i].line)
  67 + break;
  68 + addr = img.lines[i].addr;
  69 + len = COMPRESSED_DISK_IMAGE_BLOCK_SIZE;
  70 + if (addr + len > img.length)
  71 + len = img.length - addr;
  72 + boottime->copy_mem(buf + addr, img.lines[i].line, len);
  73 + }
  74 + *image = buf;
  75 + return ret;
  76 +}
  77 +
  78 +/*
  79 + * Setup unit test.
  80 + *
  81 + * @handle: handle of the loaded image
  82 + * @systable: system table
  83 + * @return: EFI_ST_SUCCESS for success
  84 + */
  85 +static int setup(const efi_handle_t handle,
  86 + const struct efi_system_table *systable)
  87 +{
  88 + image_handle = handle;
  89 + boottime = systable->boottime;
  90 +
  91 + /* Load the application image into memory */
  92 + decompress(&image);
  93 +
  94 + return EFI_ST_SUCCESS;
  95 +}
  96 +
  97 +/*
  98 + * Tear down unit test.
  99 + *
  100 + * @return: EFI_ST_SUCCESS for success
  101 + */
  102 +static int teardown(void)
  103 +{
  104 + efi_status_t r = EFI_ST_SUCCESS;
  105 +
  106 + if (image) {
  107 + r = efi_free_pool(image);
  108 + if (r != EFI_SUCCESS) {
  109 + efi_st_error("Failed to free image\n");
  110 + return EFI_ST_FAILURE;
  111 + }
  112 + }
  113 + return r;
  114 +}
  115 +
  116 +/*
  117 + * Execute unit test.
  118 + *
  119 + * Load and start the application image.
  120 + *
  121 + * @return: EFI_ST_SUCCESS for success
  122 + */
  123 +static int execute(void)
  124 +{
  125 + efi_status_t ret;
  126 + efi_handle_t handle;
  127 +
  128 + ret = boottime->load_image(false, image_handle, NULL, image,
  129 + img.length, &handle);
  130 + if (ret != EFI_SUCCESS) {
  131 + efi_st_error("Failed to load image\n");
  132 + return EFI_ST_FAILURE;
  133 + }
  134 + ret = boottime->start_image(handle, NULL, NULL);
  135 + if (ret != EFI_INCOMPATIBLE_VERSION) {
  136 + efi_st_error("Wrong return value from application\n");
  137 + return EFI_ST_FAILURE;
  138 + }
  139 +
  140 + return EFI_ST_SUCCESS;
  141 +}
  142 +
  143 +EFI_UNIT_TEST(startimage) = {
  144 + .name = "start image return",
  145 + .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT,
  146 + .setup = setup,
  147 + .execute = execute,
  148 + .teardown = teardown,
  149 +};