2 * efi_selftest_controllers
4 * Copyright (c) 2017 Heinrich Schuchardt <xypron.glpk@gmx.de>
6 * SPDX-License-Identifier: GPL-2.0+
8 * This unit test checks the following protocol services:
9 * ConnectController, DisconnectController,
10 * InstallProtocol, UninstallProtocol,
11 * OpenProtocol, CloseProtcol, OpenProtocolInformation
14 #include <efi_selftest.h>
16 #define NUMBER_OF_CHILD_CONTROLLERS 4
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;
32 * Count child controllers
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
39 static efi_status_t count_child_controllers(efi_handle_t handle,
44 efi_uintn_t entry_count;
45 struct efi_open_protocol_info_entry *entry_buffer;
48 ret = boottime->open_protocol_information(handle, protocol,
49 &entry_buffer, &entry_count);
50 if (ret != EFI_SUCCESS)
55 if (entry_buffer[--entry_count].attributes &
56 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER)
59 ret = boottime->free_pool(entry_buffer);
60 if (ret != EFI_SUCCESS)
61 efi_st_error("Cannot free buffer\n");
66 * Check if the driver supports the controller.
68 * @this driver binding protocol
69 * @controller_handle handle of the controller
70 * @remaining_device_path path specifying the child controller
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)
81 ret = boottime->open_protocol(
82 controller_handle, &guid_controller,
83 &interface, handle_driver,
84 controller_handle, EFI_OPEN_PROTOCOL_BY_DRIVER);
86 case EFI_ACCESS_DENIED:
87 case EFI_ALREADY_STARTED:
92 return EFI_UNSUPPORTED;
94 ret = boottime->close_protocol(
95 controller_handle, &guid_controller,
96 handle_driver, controller_handle);
97 if (ret != EFI_SUCCESS)
98 ret = EFI_UNSUPPORTED;
103 * Create child controllers and attach driver.
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
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)
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);
125 case EFI_ACCESS_DENIED:
126 case EFI_ALREADY_STARTED:
131 return EFI_UNSUPPORTED;
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;
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;
157 * Remove a single child controller from the parent controller.
159 * @controller_handle parent controller
160 * @child_handle child controller
161 * @return status code
163 static efi_status_t disconnect_child(efi_handle_t controller_handle,
164 efi_handle_t child_handle)
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");
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");
185 * Remove child controllers and disconnect the controller.
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
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)
201 struct efi_open_protocol_info_entry *entry_buffer;
203 /* Destroy provided child controllers */
204 if (number_of_children) {
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)
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");
225 if (entry_buffer[--count].attributes &
226 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) {
227 ret = disconnect_child(
229 entry_buffer[count].agent_handle);
230 if (ret != EFI_SUCCESS)
234 ret = boottime->free_pool(entry_buffer);
235 if (ret != EFI_SUCCESS)
236 efi_st_error("Cannot free buffer\n");
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");
249 /* Driver binding protocol interface */
250 static struct efi_driver_binding_protocol binding_interface = {
262 * @handle handle of the loaded image
263 * @systable system table
265 static int setup(const efi_handle_t img_handle,
266 const struct efi_system_table *systable)
270 boottime = systable->boottime;
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;
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;
289 return EFI_ST_SUCCESS;
295 * The number of child controllers is checked after each of the following
298 * Connect a controller to a driver.
299 * Disconnect and destroy a child controller.
300 * Disconnect and destroy the remaining child controllers.
302 * Connect a controller to a driver.
303 * Uninstall the driver protocol from the controller.
305 static int execute(void)
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;
316 /* Check number of child controllers */
317 ret = count_child_controllers(handle_controller, &guid_controller,
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);
323 /* Destroy second child controller */
324 ret = boottime->disconnect_controller(handle_controller,
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;
331 /* Check number of child controllers */
332 ret = count_child_controllers(handle_controller, &guid_controller,
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;
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;
344 /* Check number of child controllers */
345 ret = count_child_controllers(handle_controller, &guid_controller,
347 if (ret != EFI_SUCCESS || count) {
348 efi_st_error("Destroying child controllers failed\n");
349 return EFI_ST_FAILURE;
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;
358 /* Check number of child controllers */
359 ret = count_child_controllers(handle_controller, &guid_controller,
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);
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;
372 /* Check number of child controllers */
373 ret = count_child_controllers(handle_controller, &guid_controller,
375 if (ret == EFI_SUCCESS)
376 efi_st_error("Uninstall failed\n");
377 return EFI_ST_SUCCESS;
380 EFI_UNIT_TEST(controllers) = {
381 .name = "controllers",
382 .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT,