1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3 * efi_selftest_controllers
4 *
5 * Copyright (c) 2017 Heinrich Schuchardt <xypron.glpk@gmx.de>
6 *
7 * This unit test checks the following protocol services:
8 * ConnectController, DisconnectController,
9 * InstallProtocol, ReinstallProtocol, UninstallProtocol,
10 * OpenProtocol, CloseProtcol, OpenProtocolInformation
11 */
12
13 #include <efi_selftest.h>
14
15 #define NUMBER_OF_CHILD_CONTROLLERS 4
16
17 static int interface1 = 1;
18 static int interface2 = 2;
19 static struct efi_boot_services *boottime;
20 const efi_guid_t guid_driver_binding_protocol =
21 EFI_DRIVER_BINDING_PROTOCOL_GUID;
22 static efi_guid_t guid_controller =
23 EFI_GUID(0xe6ab1d96, 0x6bff, 0xdb42,
24 0xaa, 0x05, 0xc8, 0x1f, 0x7f, 0x45, 0x26, 0x34);
25 static efi_guid_t guid_child_controller =
26 EFI_GUID(0x1d41f6f5, 0x2c41, 0xddfb,
27 0xe2, 0x9b, 0xb8, 0x0e, 0x2e, 0xe8, 0x3a, 0x85);
28 static efi_handle_t handle_controller;
29 static efi_handle_t handle_child_controller[NUMBER_OF_CHILD_CONTROLLERS];
30 static efi_handle_t handle_driver;
31 static bool allow_removal;
32
33 /*
34 * Count child controllers
35 *
36 * @handle handle on which child controllers are installed
37 * @protocol protocol for which the child controllers were installed
38 * @count number of child controllers
39 * Return: status code
40 */
count_child_controllers(efi_handle_t handle,efi_guid_t * protocol,efi_uintn_t * count)41 static efi_status_t count_child_controllers(efi_handle_t handle,
42 efi_guid_t *protocol,
43 efi_uintn_t *count)
44 {
45 efi_status_t ret;
46 efi_uintn_t entry_count;
47 struct efi_open_protocol_info_entry *entry_buffer;
48
49 *count = 0;
50 ret = boottime->open_protocol_information(handle, protocol,
51 &entry_buffer, &entry_count);
52 if (ret != EFI_SUCCESS)
53 return ret;
54 if (!entry_count)
55 return EFI_SUCCESS;
56 while (entry_count) {
57 if (entry_buffer[--entry_count].attributes &
58 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER)
59 ++*count;
60 }
61 ret = boottime->free_pool(entry_buffer);
62 if (ret != EFI_SUCCESS)
63 efi_st_error("Cannot free buffer\n");
64 return ret;
65 }
66
67 /*
68 * Check if the driver supports the controller.
69 *
70 * @this driver binding protocol
71 * @controller_handle handle of the controller
72 * @remaining_device_path path specifying the child controller
73 * Return: status code
74 */
supported(struct efi_driver_binding_protocol * this,efi_handle_t controller_handle,struct efi_device_path * remaining_device_path)75 static efi_status_t EFIAPI supported(
76 struct efi_driver_binding_protocol *this,
77 efi_handle_t controller_handle,
78 struct efi_device_path *remaining_device_path)
79 {
80 efi_status_t ret;
81 void *interface;
82
83 ret = boottime->open_protocol(
84 controller_handle, &guid_controller,
85 &interface, handle_driver,
86 controller_handle, EFI_OPEN_PROTOCOL_BY_DRIVER);
87 switch (ret) {
88 case EFI_ACCESS_DENIED:
89 return ret;
90 case EFI_ALREADY_STARTED:
91 case EFI_SUCCESS:
92 break;
93 default:
94 return EFI_UNSUPPORTED;
95 }
96 ret = boottime->close_protocol(
97 controller_handle, &guid_controller,
98 handle_driver, controller_handle);
99 if (ret != EFI_SUCCESS)
100 ret = EFI_UNSUPPORTED;
101 return ret;
102 }
103
104 /*
105 * Create child controllers and attach driver.
106 *
107 * @this driver binding protocol
108 * @controller_handle handle of the controller
109 * @remaining_device_path path specifying the child controller
110 * Return: status code
111 */
start(struct efi_driver_binding_protocol * this,efi_handle_t controller_handle,struct efi_device_path * remaining_device_path)112 static efi_status_t EFIAPI start(
113 struct efi_driver_binding_protocol *this,
114 efi_handle_t controller_handle,
115 struct efi_device_path *remaining_device_path)
116 {
117 size_t i;
118 efi_status_t ret;
119 void *interface;
120
121 /* Attach driver to controller */
122 ret = boottime->open_protocol(
123 controller_handle, &guid_controller,
124 &interface, handle_driver,
125 controller_handle, EFI_OPEN_PROTOCOL_BY_DRIVER);
126 switch (ret) {
127 case EFI_ACCESS_DENIED:
128 return ret;
129 case EFI_ALREADY_STARTED:
130 case EFI_SUCCESS:
131 break;
132 default:
133 return EFI_UNSUPPORTED;
134 }
135
136 /* Create child controllers */
137 for (i = 0; i < NUMBER_OF_CHILD_CONTROLLERS; ++i) {
138 /* Creating a new handle for the child controller */
139 handle_child_controller[i] = 0;
140 ret = boottime->install_protocol_interface(
141 &handle_child_controller[i], &guid_child_controller,
142 EFI_NATIVE_INTERFACE, NULL);
143 if (ret != EFI_SUCCESS) {
144 efi_st_error("InstallProtocolInterface failed\n");
145 return EFI_ST_FAILURE;
146 }
147 ret = boottime->open_protocol(
148 controller_handle, &guid_controller,
149 &interface, handle_child_controller[i],
150 handle_child_controller[i],
151 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER);
152 if (ret != EFI_SUCCESS) {
153 efi_st_error("OpenProtocol failed\n");
154 return EFI_ST_FAILURE;
155 }
156 }
157 return ret;
158 }
159
160 /*
161 * Remove a single child controller from the parent controller.
162 *
163 * @controller_handle parent controller
164 * @child_handle child controller
165 * Return: status code
166 */
disconnect_child(efi_handle_t controller_handle,efi_handle_t child_handle)167 static efi_status_t disconnect_child(efi_handle_t controller_handle,
168 efi_handle_t child_handle)
169 {
170 efi_status_t ret;
171
172 ret = boottime->close_protocol(
173 controller_handle, &guid_controller,
174 child_handle, child_handle);
175 if (ret != EFI_SUCCESS) {
176 efi_st_error("Cannot close protocol\n");
177 return ret;
178 }
179 ret = boottime->uninstall_protocol_interface(
180 child_handle, &guid_child_controller, NULL);
181 if (ret != EFI_SUCCESS) {
182 efi_st_error("Cannot uninstall protocol interface\n");
183 return ret;
184 }
185 return ret;
186 }
187
188 /*
189 * Remove child controllers and disconnect the controller.
190 *
191 * @this driver binding protocol
192 * @controller_handle handle of the controller
193 * @number_of_children number of child controllers to remove
194 * @child_handle_buffer handles of the child controllers to remove
195 * Return: status code
196 */
stop(struct efi_driver_binding_protocol * this,efi_handle_t controller_handle,size_t number_of_children,efi_handle_t * child_handle_buffer)197 static efi_status_t EFIAPI stop(
198 struct efi_driver_binding_protocol *this,
199 efi_handle_t controller_handle,
200 size_t number_of_children,
201 efi_handle_t *child_handle_buffer)
202 {
203 efi_status_t ret;
204 efi_uintn_t count;
205 struct efi_open_protocol_info_entry *entry_buffer;
206
207 /* Destroy provided child controllers */
208 if (number_of_children) {
209 efi_uintn_t i;
210
211 for (i = 0; i < number_of_children; ++i) {
212 ret = disconnect_child(controller_handle,
213 child_handle_buffer[i]);
214 if (ret != EFI_SUCCESS)
215 return ret;
216 }
217 return EFI_SUCCESS;
218 }
219
220 /* Destroy all children */
221 ret = boottime->open_protocol_information(
222 controller_handle, &guid_controller,
223 &entry_buffer, &count);
224 if (ret != EFI_SUCCESS) {
225 efi_st_error("OpenProtocolInformation failed\n");
226 return ret;
227 }
228 while (count) {
229 if (entry_buffer[--count].attributes &
230 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) {
231 ret = disconnect_child(
232 controller_handle,
233 entry_buffer[count].agent_handle);
234 if (ret != EFI_SUCCESS)
235 return ret;
236 }
237 }
238 ret = boottime->free_pool(entry_buffer);
239 if (ret != EFI_SUCCESS)
240 efi_st_error("Cannot free buffer\n");
241
242 if (!allow_removal)
243 return EFI_DEVICE_ERROR;
244
245 /* Detach driver from controller */
246 ret = boottime->close_protocol(
247 controller_handle, &guid_controller,
248 handle_driver, controller_handle);
249 if (ret != EFI_SUCCESS) {
250 efi_st_error("Cannot close protocol\n");
251 return ret;
252 }
253 return EFI_SUCCESS;
254 }
255
256 /* Driver binding protocol interface */
257 static struct efi_driver_binding_protocol binding_interface = {
258 supported,
259 start,
260 stop,
261 0xffffffff,
262 NULL,
263 NULL,
264 };
265
266 /*
267 * Setup unit test.
268 *
269 * @handle handle of the loaded image
270 * @systable system table
271 */
setup(const efi_handle_t img_handle,const struct efi_system_table * systable)272 static int setup(const efi_handle_t img_handle,
273 const struct efi_system_table *systable)
274 {
275 efi_status_t ret;
276
277 boottime = systable->boottime;
278 handle_controller = NULL;
279 handle_driver = NULL;
280
281 /* Create controller handle */
282 ret = boottime->install_protocol_interface(
283 &handle_controller, &guid_controller,
284 EFI_NATIVE_INTERFACE, &interface1);
285 if (ret != EFI_SUCCESS) {
286 efi_st_error("InstallProtocolInterface failed\n");
287 return EFI_ST_FAILURE;
288 }
289 /* Create driver handle */
290 ret = boottime->install_protocol_interface(
291 &handle_driver, &guid_driver_binding_protocol,
292 EFI_NATIVE_INTERFACE, &binding_interface);
293 if (ret != EFI_SUCCESS) {
294 efi_st_error("InstallProtocolInterface failed\n");
295 return EFI_ST_FAILURE;
296 }
297
298 return EFI_ST_SUCCESS;
299 }
300
301 /*
302 * Execute unit test.
303 *
304 * The number of child controllers is checked after each of the following
305 * actions:
306 *
307 * Connect a controller to a driver.
308 * Disconnect and destroy a child controller.
309 * Disconnect and destroy the remaining child controllers.
310 *
311 * Connect a controller to a driver.
312 * Reinstall the driver protocol on the controller.
313 * Uninstall the driver protocol from the controller.
314 */
execute(void)315 static int execute(void)
316 {
317 efi_status_t ret;
318 efi_uintn_t count;
319
320 /* Connect controller to driver */
321 ret = boottime->connect_controller(handle_controller, NULL, NULL, 1);
322 if (ret != EFI_SUCCESS) {
323 efi_st_error("Failed to connect controller\n");
324 return EFI_ST_FAILURE;
325 }
326 /* Check number of child controllers */
327 ret = count_child_controllers(handle_controller, &guid_controller,
328 &count);
329 if (ret != EFI_SUCCESS || count != NUMBER_OF_CHILD_CONTROLLERS) {
330 efi_st_error("Number of children %u != %u\n",
331 (unsigned int)count, NUMBER_OF_CHILD_CONTROLLERS);
332 }
333 /* Destroy second child controller */
334 ret = boottime->disconnect_controller(handle_controller,
335 handle_driver,
336 handle_child_controller[1]);
337 if (ret != EFI_SUCCESS) {
338 efi_st_error("Failed to disconnect child controller\n");
339 return EFI_ST_FAILURE;
340 }
341 /* Check number of child controllers */
342 ret = count_child_controllers(handle_controller, &guid_controller,
343 &count);
344 if (ret != EFI_SUCCESS || count != NUMBER_OF_CHILD_CONTROLLERS - 1) {
345 efi_st_error("Destroying single child controller failed\n");
346 return EFI_ST_FAILURE;
347 }
348 /* Destroy remaining child controllers and disconnect controller */
349 allow_removal = true;
350 ret = boottime->disconnect_controller(handle_controller, NULL, NULL);
351 if (ret != EFI_SUCCESS) {
352 efi_st_error("Failed to disconnect controller\n");
353 return EFI_ST_FAILURE;
354 }
355 /* Check number of child controllers */
356 ret = count_child_controllers(handle_controller, &guid_controller,
357 &count);
358 if (ret != EFI_SUCCESS || count) {
359 efi_st_error("Destroying child controllers failed\n");
360 return EFI_ST_FAILURE;
361 }
362
363 /* Connect controller to driver */
364 ret = boottime->connect_controller(handle_controller, NULL, NULL, 1);
365 if (ret != EFI_SUCCESS) {
366 efi_st_error("Failed to connect controller\n");
367 return EFI_ST_FAILURE;
368 }
369 /* Check number of child controllers */
370 ret = count_child_controllers(handle_controller, &guid_controller,
371 &count);
372 if (ret != EFI_SUCCESS || count != NUMBER_OF_CHILD_CONTROLLERS) {
373 efi_st_error("Number of children %u != %u\n",
374 (unsigned int)count, NUMBER_OF_CHILD_CONTROLLERS);
375 }
376 /* Try to uninstall controller protocol using the wrong interface */
377 ret = boottime->uninstall_protocol_interface(handle_controller,
378 &guid_controller,
379 &interface2);
380 if (ret == EFI_SUCCESS) {
381 efi_st_error(
382 "Interface not checked when uninstalling protocol\n");
383 return EFI_ST_FAILURE;
384 }
385 /* Reinstall controller protocol */
386 ret = boottime->reinstall_protocol_interface(handle_controller,
387 &guid_controller,
388 &interface1,
389 &interface2);
390 if (ret != EFI_SUCCESS) {
391 efi_st_error("Failed to reinstall protocols\n");
392 return EFI_ST_FAILURE;
393 }
394 /* Check number of child controllers */
395 ret = count_child_controllers(handle_controller, &guid_controller,
396 &count);
397 if (ret != EFI_SUCCESS || count != NUMBER_OF_CHILD_CONTROLLERS) {
398 efi_st_error("Number of children %u != %u\n",
399 (unsigned int)count, NUMBER_OF_CHILD_CONTROLLERS);
400 }
401
402 allow_removal = false;
403 /* Try to uninstall controller protocol using the wrong interface */
404 ret = boottime->uninstall_protocol_interface(handle_controller,
405 &guid_controller,
406 &interface1);
407 if (ret != EFI_NOT_FOUND) {
408 efi_st_error("Interface not checked when uninstalling protocol\n");
409 return EFI_ST_FAILURE;
410 }
411
412 /*
413 * Uninstall a protocol while Disconnect controller won't
414 * allow it.
415 */
416 ret = boottime->uninstall_protocol_interface(handle_controller,
417 &guid_controller,
418 &interface2);
419 if (ret != EFI_ACCESS_DENIED) {
420 efi_st_error("Uninstall protocol interface failed\n");
421 return EFI_ST_FAILURE;
422 }
423 /*
424 * Check number of child controllers and make sure children have
425 * been reconnected
426 */
427 ret = count_child_controllers(handle_controller, &guid_controller,
428 &count);
429 if (ret != EFI_SUCCESS || count != NUMBER_OF_CHILD_CONTROLLERS) {
430 efi_st_error("Number of children %u != %u\n",
431 (unsigned int)count, NUMBER_OF_CHILD_CONTROLLERS);
432 }
433
434 allow_removal = true;
435 ret = boottime->uninstall_protocol_interface(handle_controller,
436 &guid_controller,
437 &interface2);
438 if (ret != EFI_SUCCESS) {
439 efi_st_error("Failed to uninstall protocols\n");
440 return EFI_ST_FAILURE;
441 }
442 /* Check number of child controllers */
443 ret = count_child_controllers(handle_controller, &guid_controller,
444 &count);
445 if (ret == EFI_SUCCESS || count) {
446 efi_st_error("Uninstall failed\n");
447 return EFI_ST_FAILURE;
448 }
449
450 return EFI_ST_SUCCESS;
451 }
452
453 /*
454 * Tear down unit test.
455 *
456 */
teardown(void)457 static int teardown(void)
458 {
459 efi_status_t ret;
460 /* Uninstall binding protocol */
461 ret = boottime->uninstall_protocol_interface(handle_driver,
462 &guid_driver_binding_protocol,
463 &binding_interface);
464 if (ret != EFI_SUCCESS)
465 efi_st_error("Failed to uninstall protocols\n");
466
467 return ret;
468 }
469
470 EFI_UNIT_TEST(controllers) = {
471 .name = "controllers",
472 .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT,
473 .setup = setup,
474 .execute = execute,
475 .teardown = teardown,
476 };
477