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