]>
Commit | Line | Data |
---|---|---|
83d290c5 | 1 | // SPDX-License-Identifier: GPL-2.0+ |
927ca890 HS |
2 | /* |
3 | * efi_selftest_manageprotocols | |
4 | * | |
5 | * Copyright (c) 2017 Heinrich Schuchardt <[email protected]> | |
6 | * | |
927ca890 HS |
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 | */ | |
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 | */ | |
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 | boottime = systable->boottime; | |
83 | ||
84 | ret = boottime->install_protocol_interface(&handle1, &guid3, | |
85 | EFI_NATIVE_INTERFACE, | |
86 | &interface3); | |
87 | if (ret != EFI_SUCCESS) { | |
88 | efi_st_error("InstallProtocolInterface failed\n"); | |
89 | return EFI_ST_FAILURE; | |
90 | } | |
91 | if (!handle1) { | |
92 | efi_st_error("InstallProtocolInterface failed to create handle\n"); | |
93 | return EFI_ST_FAILURE; | |
94 | } | |
95 | handle = handle1; | |
96 | ret = boottime->install_protocol_interface(&handle1, &guid1, | |
97 | EFI_NATIVE_INTERFACE, | |
98 | &interface1); | |
99 | if (ret != EFI_SUCCESS) { | |
100 | efi_st_error("InstallProtocolInterface failed\n"); | |
101 | return EFI_ST_FAILURE; | |
102 | } | |
103 | if (handle != handle1) { | |
104 | efi_st_error("InstallProtocolInterface failed to use handle\n"); | |
105 | return EFI_ST_FAILURE; | |
106 | } | |
107 | ret = boottime->install_multiple_protocol_interfaces(&handle2, | |
108 | &guid1, &interface4, &guid2, &interface2, NULL); | |
109 | if (ret != EFI_SUCCESS) { | |
110 | efi_st_error("InstallMultipleProtocolInterfaces failed\n"); | |
111 | return EFI_ST_FAILURE; | |
112 | } | |
113 | if (!handle2 || handle1 == handle2) { | |
114 | efi_st_error("InstallMultipleProtocolInterfaces failed to create handle\n"); | |
115 | return EFI_ST_FAILURE; | |
116 | } | |
117 | ||
118 | return EFI_ST_SUCCESS; | |
119 | } | |
120 | ||
121 | /* | |
122 | * Tear down unit test. | |
123 | * | |
124 | */ | |
125 | static int teardown(void) | |
126 | { | |
127 | return EFI_ST_SUCCESS; | |
128 | } | |
129 | ||
130 | /* | |
131 | * Execute unit test. | |
132 | * | |
133 | */ | |
134 | static int execute(void) | |
135 | { | |
136 | struct interface *interface; | |
137 | efi_status_t ret; | |
138 | efi_handle_t *buffer; | |
139 | size_t buffer_size; | |
f5a2a938 | 140 | efi_uintn_t count = 0; |
927ca890 | 141 | efi_guid_t **prot_buffer; |
f5a2a938 | 142 | efi_uintn_t prot_count; |
927ca890 HS |
143 | |
144 | /* | |
145 | * Test HandleProtocol | |
146 | */ | |
147 | ret = boottime->handle_protocol(handle1, &guid3, (void **)&interface); | |
148 | if (ret != EFI_SUCCESS) { | |
149 | efi_st_error("HandleProtocol failed to retrieve interface\n"); | |
150 | return EFI_ST_FAILURE; | |
151 | } | |
152 | if (interface != &interface3) { | |
153 | efi_st_error("HandleProtocol returned wrong interface\n"); | |
154 | return EFI_ST_FAILURE; | |
155 | } | |
156 | ret = boottime->handle_protocol(handle1, &guid2, (void **)&interface); | |
157 | if (ret == EFI_SUCCESS) { | |
158 | efi_st_error("HandleProtocol returned not installed interface\n"); | |
159 | return EFI_ST_FAILURE; | |
160 | } | |
161 | ||
162 | /* | |
163 | * Test LocateHandleBuffer with AllHandles | |
164 | */ | |
165 | ret = boottime->locate_handle_buffer(ALL_HANDLES, NULL, NULL, | |
166 | &count, &buffer); | |
167 | if (ret != EFI_SUCCESS) { | |
168 | efi_st_error("LocateHandleBuffer with AllHandles failed\n"); | |
169 | return EFI_ST_FAILURE; | |
170 | } | |
171 | buffer_size = count; | |
172 | ret = find_in_buffer(handle1, count, buffer); | |
173 | if (ret != EFI_SUCCESS) { | |
174 | efi_st_error("LocateHandleBuffer failed to locate new handle\n"); | |
175 | return EFI_ST_FAILURE; | |
176 | } | |
177 | ret = find_in_buffer(handle2, count, buffer); | |
178 | if (ret != EFI_SUCCESS) { | |
179 | efi_st_error("LocateHandleBuffer failed to locate new handle\n"); | |
180 | return EFI_ST_FAILURE; | |
181 | } | |
e470efd2 HS |
182 | /* Release buffer */ |
183 | ret = boottime->free_pool(buffer); | |
184 | if (ret != EFI_SUCCESS) { | |
185 | efi_st_error("FreePool failed\n"); | |
186 | return EFI_ST_FAILURE; | |
187 | } | |
927ca890 HS |
188 | |
189 | /* | |
190 | * Test error handling in UninstallMultipleProtocols | |
191 | * | |
e2373021 HS |
192 | * These are the installed protocol interfaces on handle 2: |
193 | * | |
194 | * guid1 interface4 | |
195 | * guid2 interface2 | |
196 | * | |
197 | * Try to uninstall more protocols than there are installed. This | |
198 | * should return an error EFI_INVALID_PARAMETER. All deleted protocols | |
199 | * should be reinstalled. | |
927ca890 HS |
200 | */ |
201 | ret = boottime->uninstall_multiple_protocol_interfaces( | |
202 | handle2, | |
203 | &guid1, &interface4, | |
204 | &guid2, &interface2, | |
205 | &guid3, &interface3, | |
206 | NULL); | |
e2373021 HS |
207 | if (ret != EFI_INVALID_PARAMETER) { |
208 | printf("%lx", ret); | |
77425e73 | 209 | efi_st_error("UninstallMultipleProtocolInterfaces did not catch error\n"); |
927ca890 HS |
210 | return EFI_ST_FAILURE; |
211 | } | |
212 | ||
213 | /* | |
214 | * Test LocateHandleBuffer with ByProtocol | |
e2373021 HS |
215 | * |
216 | * These are the handles with a guid1 protocol interface installed: | |
217 | * | |
218 | * handle1, handle2 | |
927ca890 HS |
219 | */ |
220 | count = buffer_size; | |
221 | ret = boottime->locate_handle_buffer(BY_PROTOCOL, &guid1, NULL, | |
222 | &count, &buffer); | |
223 | if (ret != EFI_SUCCESS) { | |
224 | efi_st_error("LocateHandleBuffer failed to locate new handles\n"); | |
225 | return EFI_ST_FAILURE; | |
226 | } | |
227 | if (count != 2) { | |
e2373021 | 228 | efi_st_error("UninstallMultipleProtocolInterfaces deleted handle\n"); |
927ca890 HS |
229 | return EFI_ST_FAILURE; |
230 | } | |
231 | ret = find_in_buffer(handle1, count, buffer); | |
232 | if (ret != EFI_SUCCESS) { | |
233 | efi_st_error("LocateHandleBuffer failed to locate new handle\n"); | |
234 | return EFI_ST_FAILURE; | |
235 | } | |
236 | ret = find_in_buffer(handle2, count, buffer); | |
237 | if (ret != EFI_SUCCESS) { | |
238 | efi_st_error("LocateHandleBuffer failed to locate new handle\n"); | |
239 | return EFI_ST_FAILURE; | |
240 | } | |
e470efd2 | 241 | /* Clear the buffer, we are reusing it it the next step. */ |
927ca890 HS |
242 | boottime->set_mem(buffer, sizeof(efi_handle_t) * buffer_size, 0); |
243 | ||
244 | /* | |
245 | * Test LocateHandle with ByProtocol | |
246 | */ | |
247 | count = buffer_size * sizeof(efi_handle_t); | |
248 | ret = boottime->locate_handle(BY_PROTOCOL, &guid1, NULL, | |
249 | &count, buffer); | |
250 | if (ret != EFI_SUCCESS) { | |
251 | efi_st_error("LocateHandle with ByProtocol failed\n"); | |
252 | return EFI_ST_FAILURE; | |
253 | } | |
254 | if (count / sizeof(efi_handle_t) != 2) { | |
255 | efi_st_error("LocateHandle failed to locate new handles\n"); | |
256 | return EFI_ST_FAILURE; | |
257 | } | |
258 | buffer_size = count; | |
259 | ret = find_in_buffer(handle1, count, buffer); | |
260 | if (ret != EFI_SUCCESS) { | |
261 | efi_st_error("LocateHandle failed to locate new handles\n"); | |
262 | return EFI_ST_FAILURE; | |
263 | } | |
264 | ret = find_in_buffer(handle2, count, buffer); | |
265 | if (ret != EFI_SUCCESS) { | |
266 | efi_st_error("LocateHandle failed to locate new handles\n"); | |
267 | return EFI_ST_FAILURE; | |
268 | } | |
e470efd2 HS |
269 | /* Release buffer */ |
270 | ret = boottime->free_pool(buffer); | |
271 | if (ret != EFI_SUCCESS) { | |
272 | efi_st_error("FreePool failed\n"); | |
273 | return EFI_ST_FAILURE; | |
274 | } | |
927ca890 HS |
275 | |
276 | /* | |
277 | * Test LocateProtocol | |
278 | */ | |
279 | ret = boottime->locate_protocol(&guid1, NULL, (void **)&interface); | |
280 | if (ret != EFI_SUCCESS) { | |
281 | efi_st_error("LocateProtocol failed\n"); | |
282 | return EFI_ST_FAILURE; | |
283 | } | |
284 | if (interface != &interface1 && interface != &interface4) { | |
285 | efi_st_error("LocateProtocol failed to locate protocol\n"); | |
286 | return EFI_ST_FAILURE; | |
287 | } | |
288 | ||
289 | /* | |
290 | * Test UninstallMultipleProtocols | |
291 | */ | |
292 | ret = boottime->uninstall_multiple_protocol_interfaces( | |
293 | handle2, | |
294 | &guid1, &interface4, | |
295 | &guid2, &interface2, | |
296 | NULL); | |
297 | if (ret != EFI_SUCCESS) { | |
77425e73 HS |
298 | efi_st_error("UninstallMultipleProtocolInterfaces failed\n"); |
299 | return EFI_ST_FAILURE; | |
927ca890 HS |
300 | } |
301 | /* | |
302 | * Check that the protocols are really uninstalled. | |
303 | */ | |
304 | count = buffer_size; | |
305 | ret = boottime->locate_handle_buffer(BY_PROTOCOL, &guid1, NULL, | |
306 | &count, &buffer); | |
307 | if (ret != EFI_SUCCESS) { | |
308 | efi_st_error("LocateHandleBuffer failed\n"); | |
309 | return EFI_ST_FAILURE; | |
310 | } | |
311 | if (count != 1) { | |
77425e73 HS |
312 | efi_st_error("UninstallMultipleProtocolInterfaces failed to uninstall protocols\n"); |
313 | return EFI_ST_FAILURE; | |
927ca890 HS |
314 | } |
315 | ret = find_in_buffer(handle1, count, buffer); | |
316 | if (ret != EFI_SUCCESS) { | |
317 | efi_st_error("Failed to locate new handle\n"); | |
318 | return EFI_ST_FAILURE; | |
319 | } | |
320 | boottime->set_mem(buffer, sizeof(efi_handle_t) * buffer_size, 0); | |
321 | ||
322 | /* | |
323 | * Test ProtocolsPerHandle | |
324 | */ | |
325 | ret = boottime->protocols_per_handle(handle1, | |
326 | &prot_buffer, &prot_count); | |
327 | if (ret != EFI_SUCCESS) { | |
328 | efi_st_error("Failed to get protocols per handle\n"); | |
329 | return EFI_ST_FAILURE; | |
330 | } | |
331 | if (prot_count != 2) { | |
332 | efi_st_error("Failed to get protocols per handle\n"); | |
333 | return EFI_ST_FAILURE; | |
334 | } | |
8101dd3d HS |
335 | if (memcmp(prot_buffer[0], &guid1, 16) && |
336 | memcmp(prot_buffer[1], &guid1, 16)) { | |
927ca890 HS |
337 | efi_st_error("Failed to get protocols per handle\n"); |
338 | return EFI_ST_FAILURE; | |
339 | } | |
8101dd3d HS |
340 | if (memcmp(prot_buffer[0], &guid3, 16) && |
341 | memcmp(prot_buffer[1], &guid3, 16)) { | |
927ca890 HS |
342 | efi_st_error("Failed to get protocols per handle\n"); |
343 | return EFI_ST_FAILURE; | |
344 | } | |
e470efd2 HS |
345 | /* Release buffer */ |
346 | ret = boottime->free_pool(prot_buffer); | |
347 | if (ret != EFI_SUCCESS) { | |
348 | efi_st_error("FreePool failed\n"); | |
349 | return EFI_ST_FAILURE; | |
350 | } | |
927ca890 HS |
351 | |
352 | /* | |
353 | * Uninstall remaining protocols | |
354 | */ | |
355 | ret = boottime->uninstall_protocol_interface(handle1, &guid1, | |
356 | &interface1); | |
357 | if (ret != EFI_SUCCESS) { | |
77425e73 HS |
358 | efi_st_error("UninstallProtocolInterface failed\n"); |
359 | return EFI_ST_FAILURE; | |
927ca890 HS |
360 | } |
361 | ret = boottime->handle_protocol(handle1, &guid1, (void **)&interface); | |
362 | if (ret == EFI_SUCCESS) { | |
77425e73 HS |
363 | efi_st_error("UninstallProtocolInterface failed\n"); |
364 | return EFI_ST_FAILURE; | |
927ca890 HS |
365 | } |
366 | ret = boottime->uninstall_protocol_interface(handle1, &guid3, | |
0d6ea050 | 367 | &interface3); |
927ca890 | 368 | if (ret != EFI_SUCCESS) { |
77425e73 HS |
369 | efi_st_error("UninstallProtocolInterface failed\n"); |
370 | return EFI_ST_FAILURE; | |
927ca890 HS |
371 | } |
372 | ||
373 | return EFI_ST_SUCCESS; | |
374 | } | |
375 | ||
376 | EFI_UNIT_TEST(protserv) = { | |
377 | .name = "manage protocols", | |
378 | .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT, | |
379 | .setup = setup, | |
380 | .execute = execute, | |
381 | .teardown = teardown, | |
382 | }; |