1 /*
2  * efi_selftest_controllers
3  *
4  * Copyright (c) 2017 Heinrich Schuchardt <xypron.glpk@gmx.de>
5  *
6  * SPDX-License-Identifier:     GPL-2.0+
7  *
8  * This unit test checks the following protocol services:
9  * ConnectController, DisconnectController,
10  * InstallProtocol, UninstallProtocol,
11  * OpenProtocol, CloseProtcol, OpenProtocolInformation
12  */
13 
14 #include <efi_selftest.h>
15 
16 #define NUMBER_OF_CHILD_CONTROLLERS 4
17 
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;
30 
31 /*
32  * Count child controllers
33  *
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
37  * @return	status code
38  */
39 static efi_status_t count_child_controllers(efi_handle_t handle,
40 					    efi_guid_t *protocol,
41 					    efi_uintn_t *count)
42 {
43 	efi_status_t ret;
44 	efi_uintn_t entry_count;
45 	struct efi_open_protocol_info_entry *entry_buffer;
46 
47 	*count = 0;
48 	ret = boottime->open_protocol_information(handle, protocol,
49 						  &entry_buffer, &entry_count);
50 	if (ret != EFI_SUCCESS)
51 		return ret;
52 	if (!entry_count)
53 		return EFI_SUCCESS;
54 	while (entry_count) {
55 		if (entry_buffer[--entry_count].attributes &
56 		    EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER)
57 			++*count;
58 	}
59 	ret = boottime->free_pool(entry_buffer);
60 	if (ret != EFI_SUCCESS)
61 		efi_st_error("Cannot free buffer\n");
62 	return ret;
63 }
64 
65 /*
66  * Check if the driver supports the controller.
67  *
68  * @this			driver binding protocol
69  * @controller_handle		handle of the controller
70  * @remaining_device_path	path specifying the child controller
71  * @return			status code
72  */
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)
77 {
78 	efi_status_t ret;
79 	void *interface;
80 
81 	ret = boottime->open_protocol(
82 			controller_handle, &guid_controller,
83 			&interface, handle_driver,
84 			controller_handle, EFI_OPEN_PROTOCOL_BY_DRIVER);
85 	switch (ret) {
86 	case EFI_ACCESS_DENIED:
87 	case EFI_ALREADY_STARTED:
88 		return ret;
89 	case EFI_SUCCESS:
90 		break;
91 	default:
92 		return EFI_UNSUPPORTED;
93 	}
94 	ret = boottime->close_protocol(
95 				controller_handle, &guid_controller,
96 				handle_driver, controller_handle);
97 	if (ret != EFI_SUCCESS)
98 		ret = EFI_UNSUPPORTED;
99 	return ret;
100 }
101 
102 /*
103  * Create child controllers and attach driver.
104  *
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
109  */
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)
114 {
115 	size_t i;
116 	efi_status_t ret;
117 	void *interface;
118 
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);
124 	switch (ret) {
125 	case EFI_ACCESS_DENIED:
126 	case EFI_ALREADY_STARTED:
127 		return ret;
128 	case EFI_SUCCESS:
129 		break;
130 	default:
131 		return EFI_UNSUPPORTED;
132 	}
133 
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;
142 		}
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;
151 		}
152 	}
153 	return ret;
154 }
155 
156 /*
157  * Remove a single child controller from the parent controller.
158  *
159  * @controller_handle	parent controller
160  * @child_handle	child controller
161  * @return		status code
162  */
163 static efi_status_t disconnect_child(efi_handle_t controller_handle,
164 				     efi_handle_t child_handle)
165 {
166 	efi_status_t ret;
167 
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");
173 		return ret;
174 	}
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");
179 		return ret;
180 	}
181 	return ret;
182 }
183 
184 /*
185  * Remove child controllers and disconnect the controller.
186  *
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
192  */
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)
198 {
199 	efi_status_t ret;
200 	efi_uintn_t count;
201 	struct efi_open_protocol_info_entry *entry_buffer;
202 
203 	/* Destroy provided child controllers */
204 	if (number_of_children) {
205 		efi_uintn_t i;
206 
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)
211 				return ret;
212 		}
213 		return EFI_SUCCESS;
214 	}
215 
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");
222 		return ret;
223 	}
224 	while (count) {
225 		if (entry_buffer[--count].attributes &
226 		    EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) {
227 			ret = disconnect_child(
228 					controller_handle,
229 					entry_buffer[count].agent_handle);
230 			if (ret != EFI_SUCCESS)
231 				return ret;
232 		}
233 	}
234 	ret = boottime->free_pool(entry_buffer);
235 	if (ret != EFI_SUCCESS)
236 		efi_st_error("Cannot free buffer\n");
237 
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");
244 		return ret;
245 	}
246 	return EFI_SUCCESS;
247 }
248 
249 /* Driver binding protocol interface */
250 static struct efi_driver_binding_protocol binding_interface = {
251 	supported,
252 	start,
253 	stop,
254 	0xffffffff,
255 	NULL,
256 	NULL,
257 	};
258 
259 /*
260  * Setup unit test.
261  *
262  * @handle	handle of the loaded image
263  * @systable	system table
264  */
265 static int setup(const efi_handle_t img_handle,
266 		 const struct efi_system_table *systable)
267 {
268 	efi_status_t ret;
269 
270 	boottime = systable->boottime;
271 
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;
279 	}
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;
287 	}
288 
289 	return EFI_ST_SUCCESS;
290 }
291 
292 /*
293  * Execute unit test.
294  *
295  * The number of child controllers is checked after each of the following
296  * actions:
297  *
298  * Connect a controller to a driver.
299  * Disconnect and destroy a child controller.
300  * Disconnect and destroy the remaining child controllers.
301  *
302  * Connect a controller to a driver.
303  * Uninstall the driver protocol from the controller.
304  */
305 static int execute(void)
306 {
307 	efi_status_t ret;
308 	efi_uintn_t count;
309 
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;
315 	}
316 	/* Check number of child controllers */
317 	ret = count_child_controllers(handle_controller, &guid_controller,
318 				      &count);
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);
322 	}
323 	/* Destroy second child controller */
324 	ret = boottime->disconnect_controller(handle_controller,
325 					      handle_driver,
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;
330 	}
331 	/* Check number of child controllers */
332 	ret = count_child_controllers(handle_controller, &guid_controller,
333 				      &count);
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;
337 	}
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;
343 	}
344 	/* Check number of child controllers */
345 	ret = count_child_controllers(handle_controller, &guid_controller,
346 				      &count);
347 	if (ret != EFI_SUCCESS || count) {
348 		efi_st_error("Destroying child controllers failed\n");
349 		return EFI_ST_FAILURE;
350 	}
351 
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;
357 	}
358 	/* Check number of child controllers */
359 	ret = count_child_controllers(handle_controller, &guid_controller,
360 				      &count);
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);
364 	}
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;
371 	}
372 	/* Check number of child controllers */
373 	ret = count_child_controllers(handle_controller, &guid_controller,
374 				      &count);
375 	if (ret == EFI_SUCCESS)
376 		efi_st_error("Uninstall failed\n");
377 	return EFI_ST_SUCCESS;
378 }
379 
380 EFI_UNIT_TEST(controllers) = {
381 	.name = "controllers",
382 	.phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT,
383 	.setup = setup,
384 	.execute = execute,
385 };
386