]> git.sur5r.net Git - u-boot/blob - lib/efi_selftest/efi_selftest_controllers.c
SPDX: Convert all of our single license tags to Linux Kernel style
[u-boot] / 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 <xypron.glpk@gmx.de>
6  *
7  * This unit test checks the following protocol services:
8  * ConnectController, DisconnectController,
9  * InstallProtocol, UninstallProtocol,
10  * OpenProtocol, CloseProtcol, OpenProtocolInformation
11  */
12
13 #include <efi_selftest.h>
14
15 #define NUMBER_OF_CHILD_CONTROLLERS 4
16
17 static struct efi_boot_services *boottime;
18 const efi_guid_t guid_driver_binding_protocol =
19                         EFI_DRIVER_BINDING_PROTOCOL_GUID;
20 static efi_guid_t guid_controller =
21         EFI_GUID(0xe6ab1d96, 0x6bff, 0xdb42,
22                  0xaa, 0x05, 0xc8, 0x1f, 0x7f, 0x45, 0x26, 0x34);
23 static efi_guid_t guid_child_controller =
24         EFI_GUID(0x1d41f6f5, 0x2c41, 0xddfb,
25                  0xe2, 0x9b, 0xb8, 0x0e, 0x2e, 0xe8, 0x3a, 0x85);
26 static efi_handle_t handle_controller;
27 static efi_handle_t handle_child_controller[NUMBER_OF_CHILD_CONTROLLERS];
28 static efi_handle_t handle_driver;
29
30 /*
31  * Count child controllers
32  *
33  * @handle      handle on which child controllers are installed
34  * @protocol    protocol for which the child controlles where installed
35  * @count       number of child controllers
36  * @return      status code
37  */
38 static efi_status_t count_child_controllers(efi_handle_t handle,
39                                             efi_guid_t *protocol,
40                                             efi_uintn_t *count)
41 {
42         efi_status_t ret;
43         efi_uintn_t entry_count;
44         struct efi_open_protocol_info_entry *entry_buffer;
45
46         *count = 0;
47         ret = boottime->open_protocol_information(handle, protocol,
48                                                   &entry_buffer, &entry_count);
49         if (ret != EFI_SUCCESS)
50                 return ret;
51         if (!entry_count)
52                 return EFI_SUCCESS;
53         while (entry_count) {
54                 if (entry_buffer[--entry_count].attributes &
55                     EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER)
56                         ++*count;
57         }
58         ret = boottime->free_pool(entry_buffer);
59         if (ret != EFI_SUCCESS)
60                 efi_st_error("Cannot free buffer\n");
61         return ret;
62 }
63
64 /*
65  * Check if the driver supports the controller.
66  *
67  * @this                        driver binding protocol
68  * @controller_handle           handle of the controller
69  * @remaining_device_path       path specifying the child controller
70  * @return                      status code
71  */
72 static efi_status_t EFIAPI supported(
73                 struct efi_driver_binding_protocol *this,
74                 efi_handle_t controller_handle,
75                 struct efi_device_path *remaining_device_path)
76 {
77         efi_status_t ret;
78         void *interface;
79
80         ret = boottime->open_protocol(
81                         controller_handle, &guid_controller,
82                         &interface, handle_driver,
83                         controller_handle, EFI_OPEN_PROTOCOL_BY_DRIVER);
84         switch (ret) {
85         case EFI_ACCESS_DENIED:
86         case EFI_ALREADY_STARTED:
87                 return ret;
88         case EFI_SUCCESS:
89                 break;
90         default:
91                 return EFI_UNSUPPORTED;
92         }
93         ret = boottime->close_protocol(
94                                 controller_handle, &guid_controller,
95                                 handle_driver, controller_handle);
96         if (ret != EFI_SUCCESS)
97                 ret = EFI_UNSUPPORTED;
98         return ret;
99 }
100
101 /*
102  * Create child controllers and attach driver.
103  *
104  * @this                        driver binding protocol
105  * @controller_handle           handle of the controller
106  * @remaining_device_path       path specifying the child controller
107  * @return                      status code
108  */
109 static efi_status_t EFIAPI start(
110                 struct efi_driver_binding_protocol *this,
111                 efi_handle_t controller_handle,
112                 struct efi_device_path *remaining_device_path)
113 {
114         size_t i;
115         efi_status_t ret;
116         void *interface;
117
118         /* Attach driver to controller */
119         ret = boottime->open_protocol(
120                         controller_handle, &guid_controller,
121                         &interface, handle_driver,
122                         controller_handle, EFI_OPEN_PROTOCOL_BY_DRIVER);
123         switch (ret) {
124         case EFI_ACCESS_DENIED:
125         case EFI_ALREADY_STARTED:
126                 return ret;
127         case EFI_SUCCESS:
128                 break;
129         default:
130                 return EFI_UNSUPPORTED;
131         }
132
133         /* Create child controllers */
134         for (i = 0; i < NUMBER_OF_CHILD_CONTROLLERS; ++i) {
135                 ret = boottime->install_protocol_interface(
136                         &handle_child_controller[i], &guid_child_controller,
137                         EFI_NATIVE_INTERFACE, NULL);
138                 if (ret != EFI_SUCCESS) {
139                         efi_st_error("InstallProtocolInterface failed\n");
140                         return EFI_ST_FAILURE;
141                 }
142                 ret = boottime->open_protocol(
143                         controller_handle, &guid_controller,
144                         &interface, handle_child_controller[i],
145                         handle_child_controller[i],
146                         EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER);
147                 if (ret != EFI_SUCCESS) {
148                         efi_st_error("OpenProtocol failed\n");
149                         return EFI_ST_FAILURE;
150                 }
151         }
152         return ret;
153 }
154
155 /*
156  * Remove a single child controller from the parent controller.
157  *
158  * @controller_handle   parent controller
159  * @child_handle        child controller
160  * @return              status code
161  */
162 static efi_status_t disconnect_child(efi_handle_t controller_handle,
163                                      efi_handle_t child_handle)
164 {
165         efi_status_t ret;
166
167         ret = boottime->close_protocol(
168                                 controller_handle, &guid_controller,
169                                 child_handle, child_handle);
170         if (ret != EFI_SUCCESS) {
171                 efi_st_error("Cannot close protocol\n");
172                 return ret;
173         }
174         ret = boottime->uninstall_protocol_interface(
175                                 child_handle, &guid_child_controller, NULL);
176         if (ret != EFI_SUCCESS) {
177                 efi_st_error("Cannot uninstall protocol interface\n");
178                 return ret;
179         }
180         return ret;
181 }
182
183 /*
184  * Remove child controllers and disconnect the controller.
185  *
186  * @this                        driver binding protocol
187  * @controller_handle           handle of the controller
188  * @number_of_children          number of child controllers to remove
189  * @child_handle_buffer         handles of the child controllers to remove
190  * @return                      status code
191  */
192 static efi_status_t EFIAPI stop(
193                 struct efi_driver_binding_protocol *this,
194                 efi_handle_t controller_handle,
195                 size_t number_of_children,
196                 efi_handle_t *child_handle_buffer)
197 {
198         efi_status_t ret;
199         efi_uintn_t count;
200         struct efi_open_protocol_info_entry *entry_buffer;
201
202         /* Destroy provided child controllers */
203         if (number_of_children) {
204                 efi_uintn_t i;
205
206                 for (i = 0; i < number_of_children; ++i) {
207                         ret = disconnect_child(controller_handle,
208                                                child_handle_buffer[i]);
209                         if (ret != EFI_SUCCESS)
210                                 return ret;
211                 }
212                 return EFI_SUCCESS;
213         }
214
215         /* Destroy all children */
216         ret = boottime->open_protocol_information(
217                                         controller_handle, &guid_controller,
218                                         &entry_buffer, &count);
219         if (ret != EFI_SUCCESS) {
220                 efi_st_error("OpenProtocolInformation failed\n");
221                 return ret;
222         }
223         while (count) {
224                 if (entry_buffer[--count].attributes &
225                     EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) {
226                         ret = disconnect_child(
227                                         controller_handle,
228                                         entry_buffer[count].agent_handle);
229                         if (ret != EFI_SUCCESS)
230                                 return ret;
231                 }
232         }
233         ret = boottime->free_pool(entry_buffer);
234         if (ret != EFI_SUCCESS)
235                 efi_st_error("Cannot free buffer\n");
236
237         /* Detach driver from controller */
238         ret = boottime->close_protocol(
239                         controller_handle, &guid_controller,
240                         handle_driver, controller_handle);
241         if (ret != EFI_SUCCESS) {
242                 efi_st_error("Cannot close protocol\n");
243                 return ret;
244         }
245         return EFI_SUCCESS;
246 }
247
248 /* Driver binding protocol interface */
249 static struct efi_driver_binding_protocol binding_interface = {
250         supported,
251         start,
252         stop,
253         0xffffffff,
254         NULL,
255         NULL,
256         };
257
258 /*
259  * Setup unit test.
260  *
261  * @handle      handle of the loaded image
262  * @systable    system table
263  */
264 static int setup(const efi_handle_t img_handle,
265                  const struct efi_system_table *systable)
266 {
267         efi_status_t ret;
268
269         boottime = systable->boottime;
270
271         /* Create controller handle */
272         ret = boottime->install_protocol_interface(
273                         &handle_controller, &guid_controller,
274                         EFI_NATIVE_INTERFACE, NULL);
275         if (ret != EFI_SUCCESS) {
276                 efi_st_error("InstallProtocolInterface failed\n");
277                 return EFI_ST_FAILURE;
278         }
279         /* Create driver handle */
280         ret = boottime->install_protocol_interface(
281                         &handle_driver,  &guid_driver_binding_protocol,
282                         EFI_NATIVE_INTERFACE, &binding_interface);
283         if (ret != EFI_SUCCESS) {
284                 efi_st_error("InstallProtocolInterface failed\n");
285                 return EFI_ST_FAILURE;
286         }
287
288         return EFI_ST_SUCCESS;
289 }
290
291 /*
292  * Execute unit test.
293  *
294  * The number of child controllers is checked after each of the following
295  * actions:
296  *
297  * Connect a controller to a driver.
298  * Disconnect and destroy a child controller.
299  * Disconnect and destroy the remaining child controllers.
300  *
301  * Connect a controller to a driver.
302  * Uninstall the driver protocol from the controller.
303  */
304 static int execute(void)
305 {
306         efi_status_t ret;
307         efi_uintn_t count;
308
309         /* Connect controller to driver */
310         ret = boottime->connect_controller(handle_controller, NULL, NULL, 1);
311         if (ret != EFI_SUCCESS) {
312                 efi_st_error("Failed to connect controller\n");
313                 return EFI_ST_FAILURE;
314         }
315         /* Check number of child controllers */
316         ret = count_child_controllers(handle_controller, &guid_controller,
317                                       &count);
318         if (ret != EFI_SUCCESS || count != NUMBER_OF_CHILD_CONTROLLERS) {
319                 efi_st_error("Number of children %u != %u\n",
320                              (unsigned int)count, NUMBER_OF_CHILD_CONTROLLERS);
321         }
322         /* Destroy second child controller */
323         ret = boottime->disconnect_controller(handle_controller,
324                                               handle_driver,
325                                               handle_child_controller[1]);
326         if (ret != EFI_SUCCESS) {
327                 efi_st_error("Failed to disconnect child controller\n");
328                 return EFI_ST_FAILURE;
329         }
330         /* Check number of child controllers */
331         ret = count_child_controllers(handle_controller, &guid_controller,
332                                       &count);
333         if (ret != EFI_SUCCESS || count != NUMBER_OF_CHILD_CONTROLLERS - 1) {
334                 efi_st_error("Destroying single child controller failed\n");
335                 return EFI_ST_FAILURE;
336         }
337         /* Destroy remaining child controllers and disconnect controller */
338         ret = boottime->disconnect_controller(handle_controller, NULL, NULL);
339         if (ret != EFI_SUCCESS) {
340                 efi_st_error("Failed to disconnect controller\n");
341                 return EFI_ST_FAILURE;
342         }
343         /* Check number of child controllers */
344         ret = count_child_controllers(handle_controller, &guid_controller,
345                                       &count);
346         if (ret != EFI_SUCCESS || count) {
347                 efi_st_error("Destroying child controllers failed\n");
348                 return EFI_ST_FAILURE;
349         }
350
351         /* Connect controller to driver */
352         ret = boottime->connect_controller(handle_controller, NULL, NULL, 1);
353         if (ret != EFI_SUCCESS) {
354                 efi_st_error("Failed to connect controller\n");
355                 return EFI_ST_FAILURE;
356         }
357         /* Check number of child controllers */
358         ret = count_child_controllers(handle_controller, &guid_controller,
359                                       &count);
360         if (ret != EFI_SUCCESS || count != NUMBER_OF_CHILD_CONTROLLERS) {
361                 efi_st_error("Number of children %u != %u\n",
362                              (unsigned int)count, NUMBER_OF_CHILD_CONTROLLERS);
363         }
364         /* Uninstall controller protocol */
365         ret = boottime->uninstall_protocol_interface(handle_controller,
366                                                      &guid_controller, NULL);
367         if (ret != EFI_SUCCESS) {
368                 efi_st_error("Failed to uninstall protocols\n");
369                 return EFI_ST_FAILURE;
370         }
371         /* Check number of child controllers */
372         ret = count_child_controllers(handle_controller, &guid_controller,
373                                       &count);
374         if (ret == EFI_SUCCESS)
375                 efi_st_error("Uninstall failed\n");
376         return EFI_ST_SUCCESS;
377 }
378
379 EFI_UNIT_TEST(controllers) = {
380         .name = "controllers",
381         .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT,
382         .setup = setup,
383         .execute = execute,
384 };