1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3 * efi_selftest_manageprotocols
4 *
5 * Copyright (c) 2017 Heinrich Schuchardt <xypron.glpk@gmx.de>
6 *
7 * This unit test checks the following protocol services:
8 * InstallProtocolInterface, UninstallProtocolInterface,
9 * InstallMultipleProtocolsInterfaces, UninstallMultipleProtocolsInterfaces,
10 * HandleProtocol, ProtocolsPerHandle,
11 * LocateHandle, LocateHandleBuffer.
12 */
13
14 #include <efi_selftest.h>
15
16 /*
17 * The test currently does not actually call the interface function.
18 * So this is just a dummy structure.
19 */
20 struct interface {
21 void (EFIAPI * inc)(void);
22 };
23
24 static struct efi_boot_services *boottime;
25 static efi_guid_t guid1 =
26 EFI_GUID(0x2e7ca819, 0x21d3, 0x0a3a,
27 0xf7, 0x91, 0x82, 0x1f, 0x7a, 0x83, 0x67, 0xaf);
28 static efi_guid_t guid2 =
29 EFI_GUID(0xf909f2bb, 0x90a8, 0x0d77,
30 0x94, 0x0c, 0x3e, 0xa8, 0xea, 0x38, 0xd6, 0x6f);
31 static efi_guid_t guid3 =
32 EFI_GUID(0x06d641a3, 0xf4e7, 0xe0c9,
33 0xe7, 0x8d, 0x41, 0x2d, 0x72, 0xa6, 0xb1, 0x24);
34 static efi_handle_t handle1;
35 static efi_handle_t handle2;
36 static struct interface interface1;
37 static struct interface interface2;
38 static struct interface interface3;
39 static struct interface interface4;
40
41 /*
42 * Find a handle in an array.
43 *
44 * @handle: handle to find
45 * @count: number of entries in the array
46 * @buffer: array to search
47 */
find_in_buffer(efi_handle_t handle,size_t count,efi_handle_t * buffer)48 efi_status_t find_in_buffer(efi_handle_t handle, size_t count,
49 efi_handle_t *buffer)
50 {
51 size_t i;
52
53 for (i = 0; i < count; ++i) {
54 if (buffer[i] == handle)
55 return EFI_SUCCESS;
56 }
57 return EFI_NOT_FOUND;
58 }
59
60 /*
61 * Setup unit test.
62 *
63 * Create two handles and install two out of three protocol interfaces on each
64 * of them:
65 *
66 * handle1
67 * guid1 interface1
68 * guid3 interface3
69 * handle2
70 * guid1 interface4
71 * guid2 interface2
72 *
73 * @handle: handle of the loaded image
74 * @systable: system table
75 */
setup(const efi_handle_t img_handle,const struct efi_system_table * systable)76 static int setup(const efi_handle_t img_handle,
77 const struct efi_system_table *systable)
78 {
79 efi_status_t ret;
80 efi_handle_t handle;
81
82 handle1 = NULL;
83 handle2 = NULL;
84 boottime = systable->boottime;
85
86 ret = boottime->install_protocol_interface(&handle1, &guid3,
87 EFI_NATIVE_INTERFACE,
88 &interface3);
89 if (ret != EFI_SUCCESS) {
90 efi_st_error("InstallProtocolInterface failed\n");
91 return EFI_ST_FAILURE;
92 }
93 if (!handle1) {
94 efi_st_error("InstallProtocolInterface failed to create handle\n");
95 return EFI_ST_FAILURE;
96 }
97 handle = handle1;
98 ret = boottime->install_protocol_interface(&handle1, &guid1,
99 EFI_NATIVE_INTERFACE,
100 &interface1);
101 if (ret != EFI_SUCCESS) {
102 efi_st_error("InstallProtocolInterface failed\n");
103 return EFI_ST_FAILURE;
104 }
105 if (handle != handle1) {
106 efi_st_error("InstallProtocolInterface failed to use handle\n");
107 return EFI_ST_FAILURE;
108 }
109 ret = boottime->install_multiple_protocol_interfaces(&handle2,
110 &guid1, &interface4, &guid2, &interface2, NULL);
111 if (ret != EFI_SUCCESS) {
112 efi_st_error("InstallMultipleProtocolInterfaces failed\n");
113 return EFI_ST_FAILURE;
114 }
115 if (!handle2 || handle1 == handle2) {
116 efi_st_error("InstallMultipleProtocolInterfaces failed to create handle\n");
117 return EFI_ST_FAILURE;
118 }
119
120 return EFI_ST_SUCCESS;
121 }
122
123 /*
124 * Tear down unit test.
125 *
126 */
teardown(void)127 static int teardown(void)
128 {
129 return EFI_ST_SUCCESS;
130 }
131
132 /*
133 * Execute unit test.
134 *
135 */
execute(void)136 static int execute(void)
137 {
138 struct interface *interface;
139 efi_status_t ret;
140 efi_handle_t *buffer;
141 size_t buffer_size;
142 efi_uintn_t count = 0;
143 efi_guid_t **prot_buffer;
144 efi_uintn_t prot_count;
145
146 /*
147 * Test HandleProtocol
148 */
149 ret = boottime->handle_protocol(handle1, &guid3, (void **)&interface);
150 if (ret != EFI_SUCCESS) {
151 efi_st_error("HandleProtocol failed to retrieve interface\n");
152 return EFI_ST_FAILURE;
153 }
154 if (interface != &interface3) {
155 efi_st_error("HandleProtocol returned wrong interface\n");
156 return EFI_ST_FAILURE;
157 }
158 ret = boottime->handle_protocol(handle1, &guid2, (void **)&interface);
159 if (ret == EFI_SUCCESS) {
160 efi_st_error("HandleProtocol returned not installed interface\n");
161 return EFI_ST_FAILURE;
162 }
163
164 /*
165 * Test LocateHandleBuffer with AllHandles
166 */
167 ret = boottime->locate_handle_buffer(ALL_HANDLES, NULL, NULL,
168 &count, &buffer);
169 if (ret != EFI_SUCCESS) {
170 efi_st_error("LocateHandleBuffer with AllHandles failed\n");
171 return EFI_ST_FAILURE;
172 }
173 buffer_size = count;
174 ret = find_in_buffer(handle1, count, buffer);
175 if (ret != EFI_SUCCESS) {
176 efi_st_error("LocateHandleBuffer failed to locate new handle\n");
177 return EFI_ST_FAILURE;
178 }
179 ret = find_in_buffer(handle2, count, buffer);
180 if (ret != EFI_SUCCESS) {
181 efi_st_error("LocateHandleBuffer failed to locate new handle\n");
182 return EFI_ST_FAILURE;
183 }
184 /* Release buffer */
185 ret = boottime->free_pool(buffer);
186 if (ret != EFI_SUCCESS) {
187 efi_st_error("FreePool failed\n");
188 return EFI_ST_FAILURE;
189 }
190
191 /*
192 * Test error handling in UninstallMultipleProtocols
193 *
194 * These are the installed protocol interfaces on handle 2:
195 *
196 * guid1 interface4
197 * guid2 interface2
198 *
199 * Try to uninstall more protocols than there are installed. This
200 * should return an error EFI_INVALID_PARAMETER. All deleted protocols
201 * should be reinstalled.
202 */
203 ret = boottime->uninstall_multiple_protocol_interfaces(
204 handle2,
205 &guid1, &interface4,
206 &guid2, &interface2,
207 &guid3, &interface3,
208 NULL);
209 if (ret != EFI_INVALID_PARAMETER) {
210 printf("%lx", ret);
211 efi_st_error("UninstallMultipleProtocolInterfaces did not catch error\n");
212 return EFI_ST_FAILURE;
213 }
214
215 /*
216 * Test LocateHandleBuffer with ByProtocol
217 *
218 * These are the handles with a guid1 protocol interface installed:
219 *
220 * handle1, handle2
221 */
222 count = buffer_size;
223 ret = boottime->locate_handle_buffer(BY_PROTOCOL, &guid1, NULL,
224 &count, &buffer);
225 if (ret != EFI_SUCCESS) {
226 efi_st_error("LocateHandleBuffer failed to locate new handles\n");
227 return EFI_ST_FAILURE;
228 }
229 if (count != 2) {
230 efi_st_error("UninstallMultipleProtocolInterfaces deleted handle\n");
231 return EFI_ST_FAILURE;
232 }
233 ret = find_in_buffer(handle1, count, buffer);
234 if (ret != EFI_SUCCESS) {
235 efi_st_error("LocateHandleBuffer failed to locate new handle\n");
236 return EFI_ST_FAILURE;
237 }
238 ret = find_in_buffer(handle2, count, buffer);
239 if (ret != EFI_SUCCESS) {
240 efi_st_error("LocateHandleBuffer failed to locate new handle\n");
241 return EFI_ST_FAILURE;
242 }
243 /* Clear the buffer, we are reusing it it the next step. */
244 boottime->set_mem(buffer, sizeof(efi_handle_t) * buffer_size, 0);
245
246 /*
247 * Test LocateHandle with ByProtocol
248 */
249 count = buffer_size * sizeof(efi_handle_t);
250 ret = boottime->locate_handle(BY_PROTOCOL, &guid1, NULL,
251 &count, buffer);
252 if (ret != EFI_SUCCESS) {
253 efi_st_error("LocateHandle with ByProtocol failed\n");
254 return EFI_ST_FAILURE;
255 }
256 if (count / sizeof(efi_handle_t) != 2) {
257 efi_st_error("LocateHandle failed to locate new handles\n");
258 return EFI_ST_FAILURE;
259 }
260 buffer_size = count;
261 ret = find_in_buffer(handle1, count, buffer);
262 if (ret != EFI_SUCCESS) {
263 efi_st_error("LocateHandle failed to locate new handles\n");
264 return EFI_ST_FAILURE;
265 }
266 ret = find_in_buffer(handle2, count, buffer);
267 if (ret != EFI_SUCCESS) {
268 efi_st_error("LocateHandle failed to locate new handles\n");
269 return EFI_ST_FAILURE;
270 }
271 /* Release buffer */
272 ret = boottime->free_pool(buffer);
273 if (ret != EFI_SUCCESS) {
274 efi_st_error("FreePool failed\n");
275 return EFI_ST_FAILURE;
276 }
277
278 /*
279 * Test LocateProtocol
280 */
281 ret = boottime->locate_protocol(&guid1, NULL, (void **)&interface);
282 if (ret != EFI_SUCCESS) {
283 efi_st_error("LocateProtocol failed\n");
284 return EFI_ST_FAILURE;
285 }
286 if (interface != &interface1 && interface != &interface4) {
287 efi_st_error("LocateProtocol failed to locate protocol\n");
288 return EFI_ST_FAILURE;
289 }
290
291 /*
292 * Test UninstallMultipleProtocols
293 */
294 ret = boottime->uninstall_multiple_protocol_interfaces(
295 handle2,
296 &guid1, &interface4,
297 &guid2, &interface2,
298 NULL);
299 if (ret != EFI_SUCCESS) {
300 efi_st_error("UninstallMultipleProtocolInterfaces failed\n");
301 return EFI_ST_FAILURE;
302 }
303 /*
304 * Check that the protocols are really uninstalled.
305 */
306 count = buffer_size;
307 ret = boottime->locate_handle_buffer(BY_PROTOCOL, &guid1, NULL,
308 &count, &buffer);
309 if (ret != EFI_SUCCESS) {
310 efi_st_error("LocateHandleBuffer failed\n");
311 return EFI_ST_FAILURE;
312 }
313 if (count != 1) {
314 efi_st_error("UninstallMultipleProtocolInterfaces failed to uninstall protocols\n");
315 return EFI_ST_FAILURE;
316 }
317 ret = find_in_buffer(handle1, count, buffer);
318 if (ret != EFI_SUCCESS) {
319 efi_st_error("Failed to locate new handle\n");
320 return EFI_ST_FAILURE;
321 }
322 boottime->set_mem(buffer, sizeof(efi_handle_t) * buffer_size, 0);
323
324 /*
325 * Test ProtocolsPerHandle
326 */
327 ret = boottime->protocols_per_handle(handle1,
328 &prot_buffer, &prot_count);
329 if (ret != EFI_SUCCESS) {
330 efi_st_error("Failed to get protocols per handle\n");
331 return EFI_ST_FAILURE;
332 }
333 if (prot_count != 2) {
334 efi_st_error("Failed to get protocols per handle\n");
335 return EFI_ST_FAILURE;
336 }
337 if (memcmp(prot_buffer[0], &guid1, 16) &&
338 memcmp(prot_buffer[1], &guid1, 16)) {
339 efi_st_error("Failed to get protocols per handle\n");
340 return EFI_ST_FAILURE;
341 }
342 if (memcmp(prot_buffer[0], &guid3, 16) &&
343 memcmp(prot_buffer[1], &guid3, 16)) {
344 efi_st_error("Failed to get protocols per handle\n");
345 return EFI_ST_FAILURE;
346 }
347 /* Release buffer */
348 ret = boottime->free_pool(prot_buffer);
349 if (ret != EFI_SUCCESS) {
350 efi_st_error("FreePool failed\n");
351 return EFI_ST_FAILURE;
352 }
353
354 /*
355 * Uninstall remaining protocols
356 */
357 ret = boottime->uninstall_protocol_interface(handle1, &guid1,
358 &interface1);
359 if (ret != EFI_SUCCESS) {
360 efi_st_error("UninstallProtocolInterface failed\n");
361 return EFI_ST_FAILURE;
362 }
363 ret = boottime->handle_protocol(handle1, &guid1, (void **)&interface);
364 if (ret == EFI_SUCCESS) {
365 efi_st_error("UninstallProtocolInterface failed\n");
366 return EFI_ST_FAILURE;
367 }
368 ret = boottime->uninstall_protocol_interface(handle1, &guid3,
369 &interface3);
370 if (ret != EFI_SUCCESS) {
371 efi_st_error("UninstallProtocolInterface failed\n");
372 return EFI_ST_FAILURE;
373 }
374
375 return EFI_ST_SUCCESS;
376 }
377
378 EFI_UNIT_TEST(protserv) = {
379 .name = "manage protocols",
380 .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT,
381 .setup = setup,
382 .execute = execute,
383 .teardown = teardown,
384 };
385