]> Git Repo - u-boot.git/blob - lib/efi_selftest/efi_selftest_controllers.c
Merge branch 'master' of https://source.denx.de/u-boot/custodians/u-boot-sh
[u-boot.git] / lib / efi_selftest / efi_selftest_controllers.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * efi_selftest_controllers
4  *
5  * Copyright (c) 2017 Heinrich Schuchardt <[email protected]>
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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    */
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 };
This page took 0.052825 seconds and 4 git commands to generate.