xref: /openbmc/u-boot/lib/efi_driver/efi_uclass.c (revision 4f6c7b12)
1 /*
2  *  Uclass for EFI drivers
3  *
4  *  Copyright (c) 2017 Heinrich Schuchardt
5  *
6  *  SPDX-License-Identifier:     GPL-2.0+
7  *
8  * For each EFI driver the uclass
9  * - creates a handle
10  * - installs the driver binding protocol
11  *
12  * The uclass provides the bind, start, and stop entry points for the driver
13  * binding protocol.
14  *
15  * In bind() and stop() it checks if the controller implements the protocol
16  * supported by the EFI driver. In the start() function it calls the bind()
17  * function of the EFI driver. In the stop() function it destroys the child
18  * controllers.
19  */
20 
21 #include <efi_driver.h>
22 
23 /*
24  * Check node type. We do not support partitions as controller handles.
25  *
26  * @handle	handle to be checked
27  * @return	status code
28  */
29 static efi_status_t check_node_type(efi_handle_t handle)
30 {
31 	efi_status_t r, ret = EFI_SUCCESS;
32 	const struct efi_device_path *dp;
33 
34 	/* Open the device path protocol */
35 	r = EFI_CALL(systab.boottime->open_protocol(
36 			handle, &efi_guid_device_path, (void **)&dp,
37 			NULL, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL));
38 	if (r == EFI_SUCCESS && dp) {
39 		/* Get the last node */
40 		const struct efi_device_path *node = efi_dp_last_node(dp);
41 		/* We do not support partitions as controller */
42 		if (!node || node->type == DEVICE_PATH_TYPE_MEDIA_DEVICE)
43 			ret = EFI_UNSUPPORTED;
44 	}
45 	return ret;
46 }
47 
48 /*
49  * Check if the driver supports the controller.
50  *
51  * @this			driver binding protocol
52  * @controller_handle		handle of the controller
53  * @remaining_device_path	path specifying the child controller
54  * @return			status code
55  */
56 static efi_status_t EFIAPI efi_uc_supported(
57 		struct efi_driver_binding_protocol *this,
58 		efi_handle_t controller_handle,
59 		struct efi_device_path *remaining_device_path)
60 {
61 	efi_status_t r, ret;
62 	void *interface;
63 	struct efi_driver_binding_extended_protocol *bp =
64 			(struct efi_driver_binding_extended_protocol *)this;
65 
66 	EFI_ENTRY("%p, %p, %ls", this, controller_handle,
67 		  efi_dp_str(remaining_device_path));
68 
69 	ret = EFI_CALL(systab.boottime->open_protocol(
70 			controller_handle, bp->ops->protocol,
71 			&interface, this->driver_binding_handle,
72 			controller_handle, EFI_OPEN_PROTOCOL_BY_DRIVER));
73 	switch (ret) {
74 	case EFI_ACCESS_DENIED:
75 	case EFI_ALREADY_STARTED:
76 		goto out;
77 	case EFI_SUCCESS:
78 		break;
79 	default:
80 		ret = EFI_UNSUPPORTED;
81 		goto out;
82 	}
83 
84 	ret = check_node_type(controller_handle);
85 
86 	r = EFI_CALL(systab.boottime->close_protocol(
87 				controller_handle, bp->ops->protocol,
88 				this->driver_binding_handle,
89 				controller_handle));
90 	if (r != EFI_SUCCESS)
91 		ret = EFI_UNSUPPORTED;
92 out:
93 	return EFI_EXIT(ret);
94 }
95 
96 /*
97  * Create child controllers and attach driver.
98  *
99  * @this			driver binding protocol
100  * @controller_handle		handle of the controller
101  * @remaining_device_path	path specifying the child controller
102  * @return			status code
103  */
104 static efi_status_t EFIAPI efi_uc_start(
105 		struct efi_driver_binding_protocol *this,
106 		efi_handle_t controller_handle,
107 		struct efi_device_path *remaining_device_path)
108 {
109 	efi_status_t r, ret;
110 	void *interface = NULL;
111 	struct efi_driver_binding_extended_protocol *bp =
112 			(struct efi_driver_binding_extended_protocol *)this;
113 
114 	EFI_ENTRY("%p, %pUl, %ls", this, controller_handle,
115 		  efi_dp_str(remaining_device_path));
116 
117 	/* Attach driver to controller */
118 	ret = EFI_CALL(systab.boottime->open_protocol(
119 			controller_handle, bp->ops->protocol,
120 			&interface, this->driver_binding_handle,
121 			controller_handle, EFI_OPEN_PROTOCOL_BY_DRIVER));
122 	switch (ret) {
123 	case EFI_ACCESS_DENIED:
124 	case EFI_ALREADY_STARTED:
125 		goto out;
126 	case EFI_SUCCESS:
127 		break;
128 	default:
129 		ret =  EFI_UNSUPPORTED;
130 		goto out;
131 	}
132 	ret = check_node_type(controller_handle);
133 	if (ret != EFI_SUCCESS) {
134 		r = EFI_CALL(systab.boottime->close_protocol(
135 				controller_handle, bp->ops->protocol,
136 				this->driver_binding_handle,
137 				controller_handle));
138 		if (r != EFI_SUCCESS)
139 			EFI_PRINT("Failure to close handle\n");
140 		goto out;
141 	}
142 
143 	/* TODO: driver specific stuff */
144 	bp->ops->bind(controller_handle, interface);
145 
146 out:
147 	return EFI_EXIT(ret);
148 }
149 
150 /*
151  * Remove a single child controller from the parent controller.
152  *
153  * @controller_handle	parent controller
154  * @child_handle	child controller
155  * @return		status code
156  */
157 static efi_status_t disconnect_child(efi_handle_t controller_handle,
158 				     efi_handle_t child_handle)
159 {
160 	efi_status_t ret;
161 	efi_guid_t *guid_controller = NULL;
162 	efi_guid_t *guid_child_controller = NULL;
163 
164 	ret = EFI_CALL(systab.boottime->close_protocol(
165 				controller_handle, guid_controller,
166 				child_handle, child_handle));
167 	if (ret != EFI_SUCCESS) {
168 		EFI_PRINT("Cannot close protocol\n");
169 		return ret;
170 	}
171 	ret = EFI_CALL(systab.boottime->uninstall_protocol_interface(
172 				child_handle, guid_child_controller, NULL));
173 	if (ret != EFI_SUCCESS) {
174 		EFI_PRINT("Cannot uninstall protocol interface\n");
175 		return ret;
176 	}
177 	return ret;
178 }
179 
180 /*
181  * Remove child controllers and disconnect the controller.
182  *
183  * @this			driver binding protocol
184  * @controller_handle		handle of the controller
185  * @number_of_children		number of child controllers to remove
186  * @child_handle_buffer		handles of the child controllers to remove
187  * @return			status code
188  */
189 static efi_status_t EFIAPI efi_uc_stop(
190 		struct efi_driver_binding_protocol *this,
191 		efi_handle_t controller_handle,
192 		size_t number_of_children,
193 		efi_handle_t *child_handle_buffer)
194 {
195 	efi_status_t ret;
196 	efi_uintn_t count;
197 	struct efi_open_protocol_info_entry *entry_buffer;
198 	efi_guid_t *guid_controller = NULL;
199 
200 	EFI_ENTRY("%p, %pUl, %zu, %p", this, controller_handle,
201 		  number_of_children, child_handle_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 = EFI_CALL(systab.boottime->open_protocol_information(
218 					controller_handle, guid_controller,
219 					&entry_buffer, &count));
220 	if (ret != EFI_SUCCESS)
221 		goto out;
222 	while (count) {
223 		if (entry_buffer[--count].attributes &
224 		    EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) {
225 			ret = disconnect_child(
226 					controller_handle,
227 					entry_buffer[count].agent_handle);
228 			if (ret != EFI_SUCCESS)
229 				goto out;
230 		}
231 	}
232 	ret = EFI_CALL(systab.boottime->free_pool(entry_buffer));
233 	if (ret != EFI_SUCCESS)
234 		printf("%s(%u) %s: ERROR: Cannot free pool\n",
235 		       __FILE__, __LINE__, __func__);
236 
237 	/* Detach driver from controller */
238 	ret = EFI_CALL(systab.boottime->close_protocol(
239 			controller_handle, guid_controller,
240 			this->driver_binding_handle, controller_handle));
241 out:
242 	return EFI_EXIT(ret);
243 }
244 
245 static efi_status_t efi_add_driver(struct driver *drv)
246 {
247 	efi_status_t ret;
248 	const struct efi_driver_ops *ops = drv->ops;
249 	struct efi_driver_binding_extended_protocol *bp;
250 
251 	debug("EFI: Adding driver '%s'\n", drv->name);
252 	if (!ops->protocol) {
253 		printf("EFI: ERROR: protocol GUID missing for driver '%s'\n",
254 		       drv->name);
255 		return EFI_INVALID_PARAMETER;
256 	}
257 	bp = calloc(1, sizeof(struct efi_driver_binding_extended_protocol));
258 	if (!bp)
259 		return EFI_OUT_OF_RESOURCES;
260 
261 	bp->bp.supported = efi_uc_supported;
262 	bp->bp.start = efi_uc_start;
263 	bp->bp.stop = efi_uc_stop;
264 	bp->bp.version = 0xffffffff;
265 	bp->ops = drv->ops;
266 
267 	ret = efi_create_handle(&bp->bp.driver_binding_handle);
268 	if (ret != EFI_SUCCESS) {
269 		free(bp);
270 		goto out;
271 	}
272 	bp->bp.image_handle = bp->bp.driver_binding_handle;
273 	ret = efi_add_protocol(bp->bp.driver_binding_handle,
274 			       &efi_guid_driver_binding_protocol, bp);
275 	if (ret != EFI_SUCCESS) {
276 		efi_delete_handle(bp->bp.driver_binding_handle);
277 		free(bp);
278 		goto out;
279 	}
280 out:
281 	return ret;
282 }
283 
284 /*
285  * Initialize the EFI drivers.
286  * Called by board_init_r().
287  *
288  * @return	0 = success, any other value will stop further execution
289  */
290 int efi_driver_init(void)
291 {
292 	struct driver *drv;
293 	int ret = 0;
294 
295 	/* Save 'gd' pointer */
296 	efi_save_gd();
297 
298 	debug("EFI: Initializing EFI driver framework\n");
299 	for (drv = ll_entry_start(struct driver, driver);
300 	     drv < ll_entry_end(struct driver, driver); ++drv) {
301 		if (drv->id == UCLASS_EFI) {
302 			ret = efi_add_driver(drv);
303 			if (ret) {
304 				printf("EFI: ERROR: failed to add driver %s\n",
305 				       drv->name);
306 				break;
307 			}
308 		}
309 	}
310 	return ret;
311 }
312 
313 static int efi_uc_init(struct uclass *class)
314 {
315 	printf("EFI: Initializing UCLASS_EFI\n");
316 	return 0;
317 }
318 
319 static int efi_uc_destroy(struct uclass *class)
320 {
321 	printf("Destroying  UCLASS_EFI\n");
322 	return 0;
323 }
324 
325 UCLASS_DRIVER(efi) = {
326 	.name		= "efi",
327 	.id		= UCLASS_EFI,
328 	.init		= efi_uc_init,
329 	.destroy	= efi_uc_destroy,
330 };
331