summaryrefslogtreecommitdiffstats
path: root/lib/efi_selftest/efi_selftest_startimage_exit.c
blob: 11207b8162f76ce2a8cd59e0d58378d224a80765 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
// SPDX-License-Identifier: GPL-2.0+
/*
 * efi_selftest_start_image
 *
 * Copyright (c) 2018 Heinrich Schuchardt <xypron.glpk@gmx.de>
 *
 * 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 = boottime->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;
	efi_uintn_t exit_data_size = 0;
	u16 *exit_data = NULL;
	u16 expected_text[] = EFI_ST_SUCCESS_STR;

	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, &exit_data_size, &exit_data);
	if (ret != EFI_UNSUPPORTED) {
		efi_st_error("Wrong return value from application\n");
		return EFI_ST_FAILURE;
	}
	if (!exit_data || exit_data_size != sizeof(expected_text) ||
	    memcmp(exit_data, expected_text, sizeof(expected_text))) {
		efi_st_error("Incorrect exit data\n");
		return EFI_ST_FAILURE;
	}
	ret = boottime->free_pool(exit_data);
	if (ret != EFI_SUCCESS) {
		efi_st_error("Failed to free exit data\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,
};