1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * efi_selftest_config_tables
4  *
5  * Copyright (c) 2018 Heinrich Schuchardt <xypron.glpk@gmx.de>
6  *
7  * This test checks the following service:
8  * InstallConfigurationTable.
9  */
10 
11 #include <efi_selftest.h>
12 #include <u-boot/crc.h>
13 
14 static const struct efi_system_table *sys_table;
15 static struct efi_boot_services *boottime;
16 
17 static efi_guid_t table_guid =
18 	EFI_GUID(0xff1c3f9e, 0x795b, 0x1529, 0xf1, 0x55,
19 		 0x17, 0x2e, 0x51, 0x6b, 0x49, 0x75);
20 
21 /*
22  * Notification function, increments the notification count if parameter
23  * context is provided.
24  *
25  * @event	notified event
26  * @context	pointer to the notification count
27  */
notify(struct efi_event * event,void * context)28 static void EFIAPI notify(struct efi_event *event, void *context)
29 {
30 	unsigned int *count = context;
31 
32 	if (count)
33 		++*count;
34 }
35 
36 /*
37  * Check CRC32 of a table.
38  */
check_table(const void * table)39 static int check_table(const void *table)
40 {
41 	efi_status_t ret;
42 	u32 crc32, res;
43 	/* Casting from constant to not constant */
44 	struct efi_table_hdr *hdr = (struct efi_table_hdr *)table;
45 
46 	crc32 = hdr->crc32;
47 	/*
48 	 * Setting the CRC32 of the 'const' table to zero is easier than
49 	 * copying
50 	 */
51 	hdr->crc32 = 0;
52 	ret = boottime->calculate_crc32(table, hdr->headersize, &res);
53 	/* Reset table CRC32 so it stays constant */
54 	hdr->crc32 = crc32;
55 	if (ret != EFI_ST_SUCCESS) {
56 		efi_st_error("CalculateCrc32 failed\n");
57 		return EFI_ST_FAILURE;
58 	}
59 	if (res != crc32) {
60 		efi_st_error("Incorrect CRC32\n");
61 		return EFI_ST_FAILURE;
62 	}
63 	return EFI_ST_SUCCESS;
64 }
65 
66 /*
67  * Setup unit test.
68  *
69  * @handle:	handle of the loaded image
70  * @systable:	system table
71  * @return:	EFI_ST_SUCCESS for success
72  */
setup(const efi_handle_t handle,const struct efi_system_table * systable)73 static int setup(const efi_handle_t handle,
74 		 const struct efi_system_table *systable)
75 {
76 	sys_table = systable;
77 	boottime = systable->boottime;
78 
79 	return EFI_ST_SUCCESS;
80 }
81 
82 /*
83  * Execute unit test.
84  *
85  * A table is installed, updated, removed. The table entry and the
86  * triggering of events is checked.
87  *
88  * @return:	EFI_ST_SUCCESS for success
89  */
execute(void)90 static int execute(void)
91 {
92 	efi_status_t ret;
93 	unsigned int counter = 0;
94 	struct efi_event *event;
95 	void *table;
96 	const unsigned int tables[2];
97 	efi_uintn_t i;
98 	efi_uintn_t tabcnt;
99 	efi_uintn_t table_count = sys_table->nr_tables;
100 
101 	ret = boottime->create_event_ex(0, TPL_NOTIFY,
102 					notify, (void *)&counter,
103 					&table_guid, &event);
104 	if (ret != EFI_SUCCESS) {
105 		efi_st_error("Failed to create event\n");
106 		return EFI_ST_FAILURE;
107 	}
108 
109 	/* Try to delete non-existent table */
110 	ret = boottime->install_configuration_table(&table_guid, NULL);
111 	if (ret != EFI_NOT_FOUND) {
112 		efi_st_error("Failed to detect missing table\n");
113 		return EFI_ST_FAILURE;
114 	}
115 	if (counter) {
116 		efi_st_error("Notification function was called.\n");
117 		return EFI_ST_FAILURE;
118 	}
119 	/* Check if the event was signaled  */
120 	ret = boottime->check_event(event);
121 	if (ret == EFI_SUCCESS) {
122 		efi_st_error("Event was signaled on EFI_NOT_FOUND\n");
123 		return EFI_ST_FAILURE;
124 	}
125 	if (counter != 1) {
126 		efi_st_error("Notification function was not called.\n");
127 		return EFI_ST_FAILURE;
128 	}
129 	if (table_count != sys_table->nr_tables) {
130 		efi_st_error("Incorrect table count %u, expected %u\n",
131 			     (unsigned int)sys_table->nr_tables,
132 			     (unsigned int)table_count);
133 		return EFI_ST_FAILURE;
134 	}
135 
136 	/* Install table */
137 	ret = boottime->install_configuration_table(&table_guid,
138 						    (void *)&tables[0]);
139 	if (ret != EFI_SUCCESS) {
140 		efi_st_error("Failed to install table\n");
141 		return EFI_ST_FAILURE;
142 	}
143 	/* Check signaled state */
144 	ret = boottime->check_event(event);
145 	if (ret != EFI_SUCCESS) {
146 		efi_st_error("Event was not signaled on insert\n");
147 		return EFI_ST_FAILURE;
148 	}
149 	if (++table_count != sys_table->nr_tables) {
150 		efi_st_error("Incorrect table count %u, expected %u\n",
151 			     (unsigned int)sys_table->nr_tables,
152 			     (unsigned int)table_count);
153 		return EFI_ST_FAILURE;
154 	}
155 	table = NULL;
156 	for (i = 0; i < sys_table->nr_tables; ++i) {
157 		if (!memcmp(&sys_table->tables[i].guid, &table_guid,
158 			    sizeof(efi_guid_t)))
159 			table = sys_table->tables[i].table;
160 	}
161 	if (!table) {
162 		efi_st_error("Installed table not found\n");
163 		return EFI_ST_FAILURE;
164 	}
165 	if (table != &tables[0]) {
166 		efi_st_error("Incorrect table address\n");
167 		return EFI_ST_FAILURE;
168 	}
169 	if (check_table(sys_table) != EFI_ST_SUCCESS) {
170 		efi_st_error("Checking system table\n");
171 		return EFI_ST_FAILURE;
172 	}
173 
174 	/* Update table */
175 	ret = boottime->install_configuration_table(&table_guid,
176 						    (void *)&tables[1]);
177 	if (ret != EFI_SUCCESS) {
178 		efi_st_error("Failed to update table\n");
179 		return EFI_ST_FAILURE;
180 	}
181 	/* Check signaled state */
182 	ret = boottime->check_event(event);
183 	if (ret != EFI_SUCCESS) {
184 		efi_st_error("Event was not signaled on update\n");
185 		return EFI_ST_FAILURE;
186 	}
187 	if (table_count != sys_table->nr_tables) {
188 		efi_st_error("Incorrect table count %u, expected %u\n",
189 			     (unsigned int)sys_table->nr_tables,
190 			     (unsigned int)table_count);
191 		return EFI_ST_FAILURE;
192 	}
193 	table = NULL;
194 	tabcnt = 0;
195 	for (i = 0; i < sys_table->nr_tables; ++i) {
196 		if (!memcmp(&sys_table->tables[i].guid, &table_guid,
197 			    sizeof(efi_guid_t))) {
198 			table = sys_table->tables[i].table;
199 			++tabcnt;
200 		}
201 	}
202 	if (!table) {
203 		efi_st_error("Installed table not found\n");
204 		return EFI_ST_FAILURE;
205 	}
206 	if (tabcnt > 1) {
207 		efi_st_error("Duplicate table GUID\n");
208 		return EFI_ST_FAILURE;
209 	}
210 	if (table != &tables[1]) {
211 		efi_st_error("Incorrect table address\n");
212 		return EFI_ST_FAILURE;
213 	}
214 	if (check_table(sys_table) != EFI_ST_SUCCESS) {
215 		efi_st_error("Checking system table\n");
216 		return EFI_ST_FAILURE;
217 	}
218 
219 	/* Delete table */
220 	ret = boottime->install_configuration_table(&table_guid, NULL);
221 	if (ret != EFI_SUCCESS) {
222 		efi_st_error("Failed to delete table\n");
223 		return EFI_ST_FAILURE;
224 	}
225 	/* Check signaled state */
226 	ret = boottime->check_event(event);
227 	if (ret != EFI_SUCCESS) {
228 		efi_st_error("Event was not signaled on delete\n");
229 		return EFI_ST_FAILURE;
230 	}
231 	if (--table_count != sys_table->nr_tables) {
232 		efi_st_error("Incorrect table count %u, expected %u\n",
233 			     (unsigned int)sys_table->nr_tables,
234 			     (unsigned int)table_count);
235 		return EFI_ST_FAILURE;
236 	}
237 	table = NULL;
238 	for (i = 0; i < sys_table->nr_tables; ++i) {
239 		if (!memcmp(&sys_table->tables[i].guid, &table_guid,
240 			    sizeof(efi_guid_t))) {
241 			table = sys_table->tables[i].table;
242 		}
243 	}
244 	if (table) {
245 		efi_st_error("Wrong table deleted\n");
246 		return EFI_ST_FAILURE;
247 	}
248 
249 	ret = boottime->close_event(event);
250 	if (ret != EFI_SUCCESS) {
251 		efi_st_error("Failed to close event\n");
252 		return EFI_ST_FAILURE;
253 	}
254 	if (check_table(sys_table) != EFI_ST_SUCCESS) {
255 		efi_st_error("Checking system table\n");
256 		return EFI_ST_FAILURE;
257 	}
258 
259 	return EFI_ST_SUCCESS;
260 }
261 
262 EFI_UNIT_TEST(configtables) = {
263 	.name = "configuration tables",
264 	.phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT,
265 	.setup = setup,
266 	.execute = execute,
267 };
268