blob: ceefa03444fc18787343e810d825981d42bac84f [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
36 * @protocol protocol for which the child controlles where installed
37 * @count number of child controllers
38 * @return status code
39 */
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
72 * @return status code
73 */
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
109 * @return status code
110 */
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) {
137 ret = boottime->install_protocol_interface(
138 &handle_child_controller[i], &guid_child_controller,
139 EFI_NATIVE_INTERFACE, NULL);
140 if (ret != EFI_SUCCESS) {
141 efi_st_error("InstallProtocolInterface failed\n");
142 return EFI_ST_FAILURE;
143 }
144 ret = boottime->open_protocol(
145 controller_handle, &guid_controller,
146 &interface, handle_child_controller[i],
147 handle_child_controller[i],
148 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER);
149 if (ret != EFI_SUCCESS) {
150 efi_st_error("OpenProtocol failed\n");
151 return EFI_ST_FAILURE;
152 }
153 }
154 return ret;
155}
156
157/*
158 * Remove a single child controller from the parent controller.
159 *
160 * @controller_handle parent controller
161 * @child_handle child controller
162 * @return status code
163 */
164static efi_status_t disconnect_child(efi_handle_t controller_handle,
165 efi_handle_t child_handle)
166{
167 efi_status_t ret;
168
169 ret = boottime->close_protocol(
170 controller_handle, &guid_controller,
171 child_handle, child_handle);
172 if (ret != EFI_SUCCESS) {
173 efi_st_error("Cannot close protocol\n");
174 return ret;
175 }
176 ret = boottime->uninstall_protocol_interface(
177 child_handle, &guid_child_controller, NULL);
178 if (ret != EFI_SUCCESS) {
179 efi_st_error("Cannot uninstall protocol interface\n");
180 return ret;
181 }
182 return ret;
183}
184
185/*
186 * Remove child controllers and disconnect the controller.
187 *
188 * @this driver binding protocol
189 * @controller_handle handle of the controller
190 * @number_of_children number of child controllers to remove
191 * @child_handle_buffer handles of the child controllers to remove
192 * @return status code
193 */
194static efi_status_t EFIAPI stop(
195 struct efi_driver_binding_protocol *this,
196 efi_handle_t controller_handle,
197 size_t number_of_children,
198 efi_handle_t *child_handle_buffer)
199{
200 efi_status_t ret;
201 efi_uintn_t count;
202 struct efi_open_protocol_info_entry *entry_buffer;
203
204 /* Destroy provided child controllers */
205 if (number_of_children) {
206 efi_uintn_t i;
207
208 for (i = 0; i < number_of_children; ++i) {
209 ret = disconnect_child(controller_handle,
210 child_handle_buffer[i]);
211 if (ret != EFI_SUCCESS)
212 return ret;
213 }
214 return EFI_SUCCESS;
215 }
216
217 /* Destroy all children */
218 ret = boottime->open_protocol_information(
219 controller_handle, &guid_controller,
220 &entry_buffer, &count);
221 if (ret != EFI_SUCCESS) {
222 efi_st_error("OpenProtocolInformation failed\n");
223 return ret;
224 }
225 while (count) {
226 if (entry_buffer[--count].attributes &
227 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) {
228 ret = disconnect_child(
229 controller_handle,
230 entry_buffer[count].agent_handle);
231 if (ret != EFI_SUCCESS)
232 return ret;
233 }
234 }
235 ret = boottime->free_pool(entry_buffer);
236 if (ret != EFI_SUCCESS)
237 efi_st_error("Cannot free buffer\n");
238
239 /* Detach driver from controller */
240 ret = boottime->close_protocol(
241 controller_handle, &guid_controller,
242 handle_driver, controller_handle);
243 if (ret != EFI_SUCCESS) {
244 efi_st_error("Cannot close protocol\n");
245 return ret;
246 }
247 return EFI_SUCCESS;
248}
249
250/* Driver binding protocol interface */
251static struct efi_driver_binding_protocol binding_interface = {
252 supported,
253 start,
254 stop,
255 0xffffffff,
256 NULL,
257 NULL,
258 };
259
260/*
261 * Setup unit test.
262 *
263 * @handle handle of the loaded image
264 * @systable system table
265 */
266static int setup(const efi_handle_t img_handle,
267 const struct efi_system_table *systable)
268{
269 efi_status_t ret;
270
271 boottime = systable->boottime;
272
273 /* Create controller handle */
274 ret = boottime->install_protocol_interface(
275 &handle_controller, &guid_controller,
Heinrich Schuchardt3fba0cd2018-05-11 12:09:23 +0200276 EFI_NATIVE_INTERFACE, &interface1);
Heinrich Schuchardt22703d32018-01-11 08:16:08 +0100277 if (ret != EFI_SUCCESS) {
278 efi_st_error("InstallProtocolInterface failed\n");
279 return EFI_ST_FAILURE;
280 }
281 /* Create driver handle */
282 ret = boottime->install_protocol_interface(
283 &handle_driver, &guid_driver_binding_protocol,
284 EFI_NATIVE_INTERFACE, &binding_interface);
285 if (ret != EFI_SUCCESS) {
286 efi_st_error("InstallProtocolInterface failed\n");
287 return EFI_ST_FAILURE;
288 }
289
290 return EFI_ST_SUCCESS;
291}
292
293/*
294 * Execute unit test.
295 *
296 * The number of child controllers is checked after each of the following
297 * actions:
298 *
299 * Connect a controller to a driver.
300 * Disconnect and destroy a child controller.
301 * Disconnect and destroy the remaining child controllers.
302 *
303 * Connect a controller to a driver.
Heinrich Schuchardt3fba0cd2018-05-11 12:09:23 +0200304 * Reinstall the driver protocol on the controller.
Heinrich Schuchardt22703d32018-01-11 08:16:08 +0100305 * Uninstall the driver protocol from the controller.
306 */
307static int execute(void)
308{
309 efi_status_t ret;
310 efi_uintn_t count;
311
312 /* Connect controller to driver */
313 ret = boottime->connect_controller(handle_controller, NULL, NULL, 1);
314 if (ret != EFI_SUCCESS) {
315 efi_st_error("Failed to connect controller\n");
316 return EFI_ST_FAILURE;
317 }
318 /* Check number of child controllers */
319 ret = count_child_controllers(handle_controller, &guid_controller,
320 &count);
321 if (ret != EFI_SUCCESS || count != NUMBER_OF_CHILD_CONTROLLERS) {
322 efi_st_error("Number of children %u != %u\n",
323 (unsigned int)count, NUMBER_OF_CHILD_CONTROLLERS);
324 }
325 /* Destroy second child controller */
326 ret = boottime->disconnect_controller(handle_controller,
327 handle_driver,
328 handle_child_controller[1]);
329 if (ret != EFI_SUCCESS) {
330 efi_st_error("Failed to disconnect child controller\n");
331 return EFI_ST_FAILURE;
332 }
333 /* Check number of child controllers */
334 ret = count_child_controllers(handle_controller, &guid_controller,
335 &count);
336 if (ret != EFI_SUCCESS || count != NUMBER_OF_CHILD_CONTROLLERS - 1) {
337 efi_st_error("Destroying single child controller failed\n");
338 return EFI_ST_FAILURE;
339 }
340 /* Destroy remaining child controllers and disconnect controller */
341 ret = boottime->disconnect_controller(handle_controller, NULL, NULL);
342 if (ret != EFI_SUCCESS) {
343 efi_st_error("Failed to disconnect controller\n");
344 return EFI_ST_FAILURE;
345 }
346 /* Check number of child controllers */
347 ret = count_child_controllers(handle_controller, &guid_controller,
348 &count);
349 if (ret != EFI_SUCCESS || count) {
350 efi_st_error("Destroying child controllers failed\n");
351 return EFI_ST_FAILURE;
352 }
353
354 /* Connect controller to driver */
355 ret = boottime->connect_controller(handle_controller, NULL, NULL, 1);
356 if (ret != EFI_SUCCESS) {
357 efi_st_error("Failed to connect controller\n");
358 return EFI_ST_FAILURE;
359 }
360 /* Check number of child controllers */
361 ret = count_child_controllers(handle_controller, &guid_controller,
362 &count);
363 if (ret != EFI_SUCCESS || count != NUMBER_OF_CHILD_CONTROLLERS) {
364 efi_st_error("Number of children %u != %u\n",
365 (unsigned int)count, NUMBER_OF_CHILD_CONTROLLERS);
366 }
Heinrich Schuchardt3fba0cd2018-05-11 12:09:23 +0200367 /* Try to uninstall controller protocol using the wrong interface */
368 ret = boottime->uninstall_protocol_interface(handle_controller,
369 &guid_controller,
370 &interface2);
371 if (ret == EFI_SUCCESS) {
372 efi_st_error(
373 "Interface not checked when uninstalling protocol\n");
374 return EFI_ST_FAILURE;
375 }
376 /* Reinstall controller protocol */
377 ret = boottime->reinstall_protocol_interface(handle_controller,
378 &guid_controller,
379 &interface1,
380 &interface2);
381 if (ret != EFI_SUCCESS) {
382 efi_st_error("Failed to reinstall protocols\n");
383 return EFI_ST_FAILURE;
384 }
385 /* Check number of child controllers */
386 ret = count_child_controllers(handle_controller, &guid_controller,
387 &count);
388 if (ret != EFI_SUCCESS || count != NUMBER_OF_CHILD_CONTROLLERS) {
389 efi_st_error("Number of children %u != %u\n",
390 (unsigned int)count, NUMBER_OF_CHILD_CONTROLLERS);
391 }
Heinrich Schuchardt22703d32018-01-11 08:16:08 +0100392 /* Uninstall controller protocol */
393 ret = boottime->uninstall_protocol_interface(handle_controller,
Heinrich Schuchardt3fba0cd2018-05-11 12:09:23 +0200394 &guid_controller,
395 &interface2);
Heinrich Schuchardt22703d32018-01-11 08:16:08 +0100396 if (ret != EFI_SUCCESS) {
397 efi_st_error("Failed to uninstall protocols\n");
398 return EFI_ST_FAILURE;
399 }
400 /* Check number of child controllers */
401 ret = count_child_controllers(handle_controller, &guid_controller,
402 &count);
403 if (ret == EFI_SUCCESS)
404 efi_st_error("Uninstall failed\n");
405 return EFI_ST_SUCCESS;
406}
407
408EFI_UNIT_TEST(controllers) = {
409 .name = "controllers",
410 .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT,
411 .setup = setup,
412 .execute = execute,
413};