Home | History | Annotate | Download | only in efi_selftest
      1 // SPDX-License-Identifier: GPL-2.0+
      2 /*
      3  * efi_selftest_start_image
      4  *
      5  * Copyright (c) 2018 Heinrich Schuchardt <xypron.glpk (at) gmx.de>
      6  *
      7  * This test checks the StartImage boot service.
      8  * The efi_selftest_miniapp_return.efi application is loaded into memory
      9  * and started.
     10  */
     11 
     12 #include <efi_selftest.h>
     13 /* Include containing the miniapp.efi application */
     14 #include "efi_miniapp_file_image_return.h"
     15 
     16 /* Block size of compressed disk image */
     17 #define COMPRESSED_DISK_IMAGE_BLOCK_SIZE 8
     18 
     19 /* Binary logarithm of the block size */
     20 #define LB_BLOCK_SIZE 9
     21 
     22 static efi_handle_t image_handle;
     23 static struct efi_boot_services *boottime;
     24 
     25 /* One 8 byte block of the compressed disk image */
     26 struct line {
     27 	size_t addr;
     28 	char *line;
     29 };
     30 
     31 /* Compressed file image */
     32 struct compressed_file_image {
     33 	size_t length;
     34 	struct line lines[];
     35 };
     36 
     37 static struct compressed_file_image img = EFI_ST_DISK_IMG;
     38 
     39 /* Decompressed file image */
     40 static u8 *image;
     41 
     42 /*
     43  * Decompress the disk image.
     44  *
     45  * @image	decompressed disk image
     46  * @return	status code
     47  */
     48 static efi_status_t decompress(u8 **image)
     49 {
     50 	u8 *buf;
     51 	size_t i;
     52 	size_t addr;
     53 	size_t len;
     54 	efi_status_t ret;
     55 
     56 	ret = boottime->allocate_pool(EFI_LOADER_DATA, img.length,
     57 				      (void **)&buf);
     58 	if (ret != EFI_SUCCESS) {
     59 		efi_st_error("Out of memory\n");
     60 		return ret;
     61 	}
     62 	boottime->set_mem(buf, img.length, 0);
     63 
     64 	for (i = 0; ; ++i) {
     65 		if (!img.lines[i].line)
     66 			break;
     67 		addr = img.lines[i].addr;
     68 		len = COMPRESSED_DISK_IMAGE_BLOCK_SIZE;
     69 		if (addr + len > img.length)
     70 			len = img.length - addr;
     71 		boottime->copy_mem(buf + addr, img.lines[i].line, len);
     72 	}
     73 	*image = buf;
     74 	return ret;
     75 }
     76 
     77 /*
     78  * Setup unit test.
     79  *
     80  * @handle:	handle of the loaded image
     81  * @systable:	system table
     82  * @return:	EFI_ST_SUCCESS for success
     83  */
     84 static int setup(const efi_handle_t handle,
     85 		 const struct efi_system_table *systable)
     86 {
     87 	image_handle = handle;
     88 	boottime = systable->boottime;
     89 
     90 	/* Load the application image into memory */
     91 	decompress(&image);
     92 
     93 	return EFI_ST_SUCCESS;
     94 }
     95 
     96 /*
     97  * Tear down unit test.
     98  *
     99  * @return:	EFI_ST_SUCCESS for success
    100  */
    101 static int teardown(void)
    102 {
    103 	efi_status_t r = EFI_ST_SUCCESS;
    104 
    105 	if (image) {
    106 		r = efi_free_pool(image);
    107 		if (r != EFI_SUCCESS) {
    108 			efi_st_error("Failed to free image\n");
    109 			return EFI_ST_FAILURE;
    110 		}
    111 	}
    112 	return r;
    113 }
    114 
    115 /*
    116  * Execute unit test.
    117  *
    118  * Load and start the application image.
    119  *
    120  * @return:	EFI_ST_SUCCESS for success
    121  */
    122 static int execute(void)
    123 {
    124 	efi_status_t ret;
    125 	efi_handle_t handle;
    126 
    127 	ret = boottime->load_image(false, image_handle, NULL, image,
    128 				   img.length, &handle);
    129 	if (ret != EFI_SUCCESS) {
    130 		efi_st_error("Failed to load image\n");
    131 		return EFI_ST_FAILURE;
    132 	}
    133 	ret = boottime->start_image(handle, NULL, NULL);
    134 	if (ret != EFI_INCOMPATIBLE_VERSION) {
    135 		efi_st_error("Wrong return value from application\n");
    136 		return EFI_ST_FAILURE;
    137 	}
    138 
    139 	return EFI_ST_SUCCESS;
    140 }
    141 
    142 EFI_UNIT_TEST(startimage) = {
    143 	.name = "start image return",
    144 	.phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT,
    145 	.setup = setup,
    146 	.execute = execute,
    147 	.teardown = teardown,
    148 };
    149