1 // SPDX-License-Identifier: GPL-2.0+
3 * efi_selftest_controllers
7 * This unit test checks the following protocol services:
8 * ConnectController, DisconnectController,
9 * InstallProtocol, ReinstallProtocol, UninstallProtocol,
10 * OpenProtocol, CloseProtcol, OpenProtocolInformation
13 #include <efi_selftest.h>
15 #define NUMBER_OF_CHILD_CONTROLLERS 4
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;
33 * Count child controllers
35 * @handle handle on which child controllers are installed
36 * @protocol protocol for which the child controllers were installed
37 * @count number of child controllers
40 static efi_status_t count_child_controllers(efi_handle_t handle,
45 efi_uintn_t entry_count;
46 struct efi_open_protocol_info_entry *entry_buffer;
49 ret = boottime->open_protocol_information(handle, protocol,
50 &entry_buffer, &entry_count);
51 if (ret != EFI_SUCCESS)
56 if (entry_buffer[--entry_count].attributes &
57 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER)
60 ret = boottime->free_pool(entry_buffer);
61 if (ret != EFI_SUCCESS)
62 efi_st_error("Cannot free buffer\n");
67 * Check if the driver supports the controller.
69 * @this driver binding protocol
70 * @controller_handle handle of the controller
71 * @remaining_device_path path specifying the child controller
74 static 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)
82 ret = boottime->open_protocol(
83 controller_handle, &guid_controller,
84 &interface, handle_driver,
85 controller_handle, EFI_OPEN_PROTOCOL_BY_DRIVER);
87 case EFI_ACCESS_DENIED:
88 case EFI_ALREADY_STARTED:
93 return EFI_UNSUPPORTED;
95 ret = boottime->close_protocol(
96 controller_handle, &guid_controller,
97 handle_driver, controller_handle);
98 if (ret != EFI_SUCCESS)
99 ret = EFI_UNSUPPORTED;
104 * Create child controllers and attach driver.
106 * @this driver binding protocol
107 * @controller_handle handle of the controller
108 * @remaining_device_path path specifying the child controller
109 * Return: status code
111 static 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)
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);
126 case EFI_ACCESS_DENIED:
127 case EFI_ALREADY_STARTED:
132 return EFI_UNSUPPORTED;
135 /* Create child controllers */
136 for (i = 0; i < NUMBER_OF_CHILD_CONTROLLERS; ++i) {
137 /* Creating a new handle for the child controller */
138 handle_child_controller[i] = 0;
139 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;
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;
160 * Remove a single child controller from the parent controller.
162 * @controller_handle parent controller
163 * @child_handle child controller
164 * Return: status code
166 static efi_status_t disconnect_child(efi_handle_t controller_handle,
167 efi_handle_t child_handle)
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");
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");
188 * Remove child controllers and disconnect the controller.
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
194 * Return: status code
196 static 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)
204 struct efi_open_protocol_info_entry *entry_buffer;
206 /* Destroy provided child controllers */
207 if (number_of_children) {
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)
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");
228 if (entry_buffer[--count].attributes &
229 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) {
230 ret = disconnect_child(
232 entry_buffer[count].agent_handle);
233 if (ret != EFI_SUCCESS)
237 ret = boottime->free_pool(entry_buffer);
238 if (ret != EFI_SUCCESS)
239 efi_st_error("Cannot free buffer\n");
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");
252 /* Driver binding protocol interface */
253 static struct efi_driver_binding_protocol binding_interface = {
265 * @handle handle of the loaded image
266 * @systable system table
268 static int setup(const efi_handle_t img_handle,
269 const struct efi_system_table *systable)
273 boottime = systable->boottime;
275 /* Create controller handle */
276 ret = boottime->install_protocol_interface(
277 &handle_controller, &guid_controller,
278 EFI_NATIVE_INTERFACE, &interface1);
279 if (ret != EFI_SUCCESS) {
280 efi_st_error("InstallProtocolInterface failed\n");
281 return EFI_ST_FAILURE;
283 /* Create driver handle */
284 ret = boottime->install_protocol_interface(
285 &handle_driver, &guid_driver_binding_protocol,
286 EFI_NATIVE_INTERFACE, &binding_interface);
287 if (ret != EFI_SUCCESS) {
288 efi_st_error("InstallProtocolInterface failed\n");
289 return EFI_ST_FAILURE;
292 return EFI_ST_SUCCESS;
298 * The number of child controllers is checked after each of the following
301 * Connect a controller to a driver.
302 * Disconnect and destroy a child controller.
303 * Disconnect and destroy the remaining child controllers.
305 * Connect a controller to a driver.
306 * Reinstall the driver protocol on the controller.
307 * Uninstall the driver protocol from the controller.
309 static int execute(void)
314 /* Connect controller to driver */
315 ret = boottime->connect_controller(handle_controller, NULL, NULL, 1);
316 if (ret != EFI_SUCCESS) {
317 efi_st_error("Failed to connect controller\n");
318 return EFI_ST_FAILURE;
320 /* Check number of child controllers */
321 ret = count_child_controllers(handle_controller, &guid_controller,
323 if (ret != EFI_SUCCESS || count != NUMBER_OF_CHILD_CONTROLLERS) {
324 efi_st_error("Number of children %u != %u\n",
325 (unsigned int)count, NUMBER_OF_CHILD_CONTROLLERS);
327 /* Destroy second child controller */
328 ret = boottime->disconnect_controller(handle_controller,
330 handle_child_controller[1]);
331 if (ret != EFI_SUCCESS) {
332 efi_st_error("Failed to disconnect child controller\n");
333 return EFI_ST_FAILURE;
335 /* Check number of child controllers */
336 ret = count_child_controllers(handle_controller, &guid_controller,
338 if (ret != EFI_SUCCESS || count != NUMBER_OF_CHILD_CONTROLLERS - 1) {
339 efi_st_error("Destroying single child controller failed\n");
340 return EFI_ST_FAILURE;
342 /* Destroy remaining child controllers and disconnect controller */
343 ret = boottime->disconnect_controller(handle_controller, NULL, NULL);
344 if (ret != EFI_SUCCESS) {
345 efi_st_error("Failed to disconnect controller\n");
346 return EFI_ST_FAILURE;
348 /* Check number of child controllers */
349 ret = count_child_controllers(handle_controller, &guid_controller,
351 if (ret != EFI_SUCCESS || count) {
352 efi_st_error("Destroying child controllers failed\n");
353 return EFI_ST_FAILURE;
356 /* Connect controller to driver */
357 ret = boottime->connect_controller(handle_controller, NULL, NULL, 1);
358 if (ret != EFI_SUCCESS) {
359 efi_st_error("Failed to connect controller\n");
360 return EFI_ST_FAILURE;
362 /* Check number of child controllers */
363 ret = count_child_controllers(handle_controller, &guid_controller,
365 if (ret != EFI_SUCCESS || count != NUMBER_OF_CHILD_CONTROLLERS) {
366 efi_st_error("Number of children %u != %u\n",
367 (unsigned int)count, NUMBER_OF_CHILD_CONTROLLERS);
369 /* Try to uninstall controller protocol using the wrong interface */
370 ret = boottime->uninstall_protocol_interface(handle_controller,
373 if (ret == EFI_SUCCESS) {
375 "Interface not checked when uninstalling protocol\n");
376 return EFI_ST_FAILURE;
378 /* Reinstall controller protocol */
379 ret = boottime->reinstall_protocol_interface(handle_controller,
383 if (ret != EFI_SUCCESS) {
384 efi_st_error("Failed to reinstall protocols\n");
385 return EFI_ST_FAILURE;
387 /* Check number of child controllers */
388 ret = count_child_controllers(handle_controller, &guid_controller,
390 if (ret != EFI_SUCCESS || count != NUMBER_OF_CHILD_CONTROLLERS) {
391 efi_st_error("Number of children %u != %u\n",
392 (unsigned int)count, NUMBER_OF_CHILD_CONTROLLERS);
394 /* Uninstall controller protocol */
395 ret = boottime->uninstall_protocol_interface(handle_controller,
398 if (ret != EFI_SUCCESS) {
399 efi_st_error("Failed to uninstall protocols\n");
400 return EFI_ST_FAILURE;
402 /* Check number of child controllers */
403 ret = count_child_controllers(handle_controller, &guid_controller,
405 if (ret == EFI_SUCCESS)
406 efi_st_error("Uninstall failed\n");
407 return EFI_ST_SUCCESS;
410 EFI_UNIT_TEST(controllers) = {
411 .name = "controllers",
412 .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT,