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