]> git.ipfire.org Git - people/ms/u-boot.git/blob - lib/efi_selftest/efi_selftest_controllers.c
efi_selftest: test for (Dis)ConnectController
[people/ms/u-boot.git] / 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 };