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
,