]>
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 <xypron.glpk@gmx.de> | |
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 | } | |
182 | boottime->set_mem(buffer, sizeof(efi_handle_t) * buffer_size, 0); | |
183 | ||
184 | /* | |
185 | * Test error handling in UninstallMultipleProtocols | |
186 | * | |
187 | * Try to uninstall more protocols than there are installed. | |
188 | */ | |
189 | ret = boottime->uninstall_multiple_protocol_interfaces( | |
190 | handle2, | |
191 | &guid1, &interface4, | |
192 | &guid2, &interface2, | |
193 | &guid3, &interface3, | |
194 | NULL); | |
195 | if (ret == EFI_SUCCESS) { | |
77425e73 | 196 | efi_st_error("UninstallMultipleProtocolInterfaces did not catch error\n"); |
927ca890 HS |
197 | return EFI_ST_FAILURE; |
198 | } | |
199 | ||
200 | /* | |
201 | * Test LocateHandleBuffer with ByProtocol | |
202 | */ | |
203 | count = buffer_size; | |
204 | ret = boottime->locate_handle_buffer(BY_PROTOCOL, &guid1, NULL, | |
205 | &count, &buffer); | |
206 | if (ret != EFI_SUCCESS) { | |
207 | efi_st_error("LocateHandleBuffer failed to locate new handles\n"); | |
208 | return EFI_ST_FAILURE; | |
209 | } | |
210 | if (count != 2) { | |
211 | efi_st_error("LocateHandleBuffer failed to locate new handles\n"); | |
212 | return EFI_ST_FAILURE; | |
213 | } | |
214 | ret = find_in_buffer(handle1, count, buffer); | |
215 | if (ret != EFI_SUCCESS) { | |
216 | efi_st_error("LocateHandleBuffer failed to locate new handle\n"); | |
217 | return EFI_ST_FAILURE; | |
218 | } | |
219 | ret = find_in_buffer(handle2, count, buffer); | |
220 | if (ret != EFI_SUCCESS) { | |
221 | efi_st_error("LocateHandleBuffer failed to locate new handle\n"); | |
222 | return EFI_ST_FAILURE; | |
223 | } | |
224 | boottime->set_mem(buffer, sizeof(efi_handle_t) * buffer_size, 0); | |
225 | ||
226 | /* | |
227 | * Test LocateHandle with ByProtocol | |
228 | */ | |
229 | count = buffer_size * sizeof(efi_handle_t); | |
230 | ret = boottime->locate_handle(BY_PROTOCOL, &guid1, NULL, | |
231 | &count, buffer); | |
232 | if (ret != EFI_SUCCESS) { | |
233 | efi_st_error("LocateHandle with ByProtocol failed\n"); | |
234 | return EFI_ST_FAILURE; | |
235 | } | |
236 | if (count / sizeof(efi_handle_t) != 2) { | |
237 | efi_st_error("LocateHandle failed to locate new handles\n"); | |
238 | return EFI_ST_FAILURE; | |
239 | } | |
240 | buffer_size = count; | |
241 | ret = find_in_buffer(handle1, count, buffer); | |
242 | if (ret != EFI_SUCCESS) { | |
243 | efi_st_error("LocateHandle failed to locate new handles\n"); | |
244 | return EFI_ST_FAILURE; | |
245 | } | |
246 | ret = find_in_buffer(handle2, count, buffer); | |
247 | if (ret != EFI_SUCCESS) { | |
248 | efi_st_error("LocateHandle failed to locate new handles\n"); | |
249 | return EFI_ST_FAILURE; | |
250 | } | |
251 | boottime->set_mem(buffer, sizeof(efi_handle_t) * buffer_size, 0); | |
252 | ||
253 | /* | |
254 | * Test LocateProtocol | |
255 | */ | |
256 | ret = boottime->locate_protocol(&guid1, NULL, (void **)&interface); | |
257 | if (ret != EFI_SUCCESS) { | |
258 | efi_st_error("LocateProtocol failed\n"); | |
259 | return EFI_ST_FAILURE; | |
260 | } | |
261 | if (interface != &interface1 && interface != &interface4) { | |
262 | efi_st_error("LocateProtocol failed to locate protocol\n"); | |
263 | return EFI_ST_FAILURE; | |
264 | } | |
265 | ||
266 | /* | |
267 | * Test UninstallMultipleProtocols | |
268 | */ | |
269 | ret = boottime->uninstall_multiple_protocol_interfaces( | |
270 | handle2, | |
271 | &guid1, &interface4, | |
272 | &guid2, &interface2, | |
273 | NULL); | |
274 | if (ret != EFI_SUCCESS) { | |
77425e73 HS |
275 | efi_st_error("UninstallMultipleProtocolInterfaces failed\n"); |
276 | return EFI_ST_FAILURE; | |
927ca890 HS |
277 | } |
278 | /* | |
279 | * Check that the protocols are really uninstalled. | |
280 | */ | |
281 | count = buffer_size; | |
282 | ret = boottime->locate_handle_buffer(BY_PROTOCOL, &guid1, NULL, | |
283 | &count, &buffer); | |
284 | if (ret != EFI_SUCCESS) { | |
285 | efi_st_error("LocateHandleBuffer failed\n"); | |
286 | return EFI_ST_FAILURE; | |
287 | } | |
288 | if (count != 1) { | |
77425e73 HS |
289 | efi_st_error("UninstallMultipleProtocolInterfaces failed to uninstall protocols\n"); |
290 | return EFI_ST_FAILURE; | |
927ca890 HS |
291 | } |
292 | ret = find_in_buffer(handle1, count, buffer); | |
293 | if (ret != EFI_SUCCESS) { | |
294 | efi_st_error("Failed to locate new handle\n"); | |
295 | return EFI_ST_FAILURE; | |
296 | } | |
297 | boottime->set_mem(buffer, sizeof(efi_handle_t) * buffer_size, 0); | |
298 | ||
299 | /* | |
300 | * Test ProtocolsPerHandle | |
301 | */ | |
302 | ret = boottime->protocols_per_handle(handle1, | |
303 | &prot_buffer, &prot_count); | |
304 | if (ret != EFI_SUCCESS) { | |
305 | efi_st_error("Failed to get protocols per handle\n"); | |
306 | return EFI_ST_FAILURE; | |
307 | } | |
308 | if (prot_count != 2) { | |
309 | efi_st_error("Failed to get protocols per handle\n"); | |
310 | return EFI_ST_FAILURE; | |
311 | } | |
312 | if (efi_st_memcmp(prot_buffer[0], &guid1, 16) && | |
313 | efi_st_memcmp(prot_buffer[1], &guid1, 16)) { | |
314 | efi_st_error("Failed to get protocols per handle\n"); | |
315 | return EFI_ST_FAILURE; | |
316 | } | |
317 | if (efi_st_memcmp(prot_buffer[0], &guid3, 16) && | |
318 | efi_st_memcmp(prot_buffer[1], &guid3, 16)) { | |
319 | efi_st_error("Failed to get protocols per handle\n"); | |
320 | return EFI_ST_FAILURE; | |
321 | } | |
322 | ||
323 | /* | |
324 | * Uninstall remaining protocols | |
325 | */ | |
326 | ret = boottime->uninstall_protocol_interface(handle1, &guid1, | |
327 | &interface1); | |
328 | if (ret != EFI_SUCCESS) { | |
77425e73 HS |
329 | efi_st_error("UninstallProtocolInterface failed\n"); |
330 | return EFI_ST_FAILURE; | |
927ca890 HS |
331 | } |
332 | ret = boottime->handle_protocol(handle1, &guid1, (void **)&interface); | |
333 | if (ret == EFI_SUCCESS) { | |
77425e73 HS |
334 | efi_st_error("UninstallProtocolInterface failed\n"); |
335 | return EFI_ST_FAILURE; | |
927ca890 HS |
336 | } |
337 | ret = boottime->uninstall_protocol_interface(handle1, &guid3, | |
338 | &interface1); | |
339 | if (ret != EFI_SUCCESS) { | |
77425e73 HS |
340 | efi_st_error("UninstallProtocolInterface failed\n"); |
341 | return EFI_ST_FAILURE; | |
927ca890 HS |
342 | } |
343 | ||
344 | return EFI_ST_SUCCESS; | |
345 | } | |
346 | ||
347 | EFI_UNIT_TEST(protserv) = { | |
348 | .name = "manage protocols", | |
349 | .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT, | |
350 | .setup = setup, | |
351 | .execute = execute, | |
352 | .teardown = teardown, | |
353 | }; |