blob: 495be53cb77a9804dd87f848e926d8ff59702c9b [file] [log] [blame]
Tom Rini70df9d62018-05-07 17:02:21 -04001// SPDX-License-Identifier: GPL-2.0+
Heinrich Schuchardt11206f42018-01-21 19:29:30 +01002/*
3 * Uclass for EFI drivers
4 *
5 * Copyright (c) 2017 Heinrich Schuchardt
6 *
Heinrich Schuchardt11206f42018-01-21 19:29:30 +01007 * For each EFI driver the uclass
8 * - creates a handle
9 * - installs the driver binding protocol
10 *
11 * The uclass provides the bind, start, and stop entry points for the driver
12 * binding protocol.
13 *
Heinrich Schuchardt3f712db2022-10-03 10:35:35 +020014 * In supported() and bind() it checks if the controller implements the protocol
Heinrich Schuchardt11206f42018-01-21 19:29:30 +010015 * supported by the EFI driver. In the start() function it calls the bind()
16 * function of the EFI driver. In the stop() function it destroys the child
17 * controllers.
18 */
19
Heinrich Schuchardt955a3212025-01-16 20:26:59 +010020#define LOG_CATEGORY LOGC_EFI
21
Simon Glassf6977c12020-07-19 10:15:43 -060022#include <dm.h>
Heinrich Schuchardt11206f42018-01-21 19:29:30 +010023#include <efi_driver.h>
Simon Glass0f2af882020-05-10 11:40:05 -060024#include <log.h>
Simon Glass9bc15642020-02-03 07:36:16 -070025#include <malloc.h>
Heinrich Schuchardt11206f42018-01-21 19:29:30 +010026
Heinrich Schuchardt55de1002018-09-18 18:52:46 +020027/**
28 * check_node_type() - check node type
Heinrich Schuchardt11206f42018-01-21 19:29:30 +010029 *
Heinrich Schuchardt55de1002018-09-18 18:52:46 +020030 * We do not support partitions as controller handles.
31 *
32 * @handle: handle to be checked
33 * Return: status code
Heinrich Schuchardt11206f42018-01-21 19:29:30 +010034 */
35static efi_status_t check_node_type(efi_handle_t handle)
36{
37 efi_status_t r, ret = EFI_SUCCESS;
38 const struct efi_device_path *dp;
39
40 /* Open the device path protocol */
41 r = EFI_CALL(systab.boottime->open_protocol(
42 handle, &efi_guid_device_path, (void **)&dp,
43 NULL, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL));
44 if (r == EFI_SUCCESS && dp) {
45 /* Get the last node */
46 const struct efi_device_path *node = efi_dp_last_node(dp);
47 /* We do not support partitions as controller */
48 if (!node || node->type == DEVICE_PATH_TYPE_MEDIA_DEVICE)
49 ret = EFI_UNSUPPORTED;
50 }
51 return ret;
52}
53
Heinrich Schuchardt55de1002018-09-18 18:52:46 +020054/**
55 * efi_uc_supported() - check if the driver supports the controller
Heinrich Schuchardt11206f42018-01-21 19:29:30 +010056 *
Heinrich Schuchardt55de1002018-09-18 18:52:46 +020057 * @this: driver binding protocol
58 * @controller_handle: handle of the controller
59 * @remaining_device_path: path specifying the child controller
60 * Return: status code
Heinrich Schuchardt11206f42018-01-21 19:29:30 +010061 */
62static efi_status_t EFIAPI efi_uc_supported(
63 struct efi_driver_binding_protocol *this,
64 efi_handle_t controller_handle,
65 struct efi_device_path *remaining_device_path)
66{
67 efi_status_t r, ret;
68 void *interface;
69 struct efi_driver_binding_extended_protocol *bp =
70 (struct efi_driver_binding_extended_protocol *)this;
71
72 EFI_ENTRY("%p, %p, %ls", this, controller_handle,
73 efi_dp_str(remaining_device_path));
74
Heinrich Schuchardt4fdaaf92022-09-09 06:57:58 +000075 /*
76 * U-Boot internal devices install protocols interfaces without calling
77 * ConnectController(). Hence we should not bind an extra driver.
78 */
79 if (controller_handle->dev) {
80 ret = EFI_UNSUPPORTED;
81 goto out;
82 }
83
Heinrich Schuchardt11206f42018-01-21 19:29:30 +010084 ret = EFI_CALL(systab.boottime->open_protocol(
85 controller_handle, bp->ops->protocol,
86 &interface, this->driver_binding_handle,
87 controller_handle, EFI_OPEN_PROTOCOL_BY_DRIVER));
88 switch (ret) {
89 case EFI_ACCESS_DENIED:
90 case EFI_ALREADY_STARTED:
91 goto out;
92 case EFI_SUCCESS:
93 break;
94 default:
95 ret = EFI_UNSUPPORTED;
96 goto out;
97 }
98
99 ret = check_node_type(controller_handle);
100
Heinrich Schuchardt64304a12022-10-07 16:12:54 +0200101 r = efi_close_protocol(controller_handle, bp->ops->protocol,
102 this->driver_binding_handle,
103 controller_handle);
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100104 if (r != EFI_SUCCESS)
105 ret = EFI_UNSUPPORTED;
106out:
107 return EFI_EXIT(ret);
108}
109
Heinrich Schuchardt55de1002018-09-18 18:52:46 +0200110/**
111 * efi_uc_start() - create child controllers and attach driver
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100112 *
Heinrich Schuchardt55de1002018-09-18 18:52:46 +0200113 * @this: driver binding protocol
114 * @controller_handle: handle of the controller
115 * @remaining_device_path: path specifying the child controller
116 * Return: status code
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100117 */
118static efi_status_t EFIAPI efi_uc_start(
119 struct efi_driver_binding_protocol *this,
120 efi_handle_t controller_handle,
121 struct efi_device_path *remaining_device_path)
122{
123 efi_status_t r, ret;
124 void *interface = NULL;
125 struct efi_driver_binding_extended_protocol *bp =
126 (struct efi_driver_binding_extended_protocol *)this;
127
Heinrich Schuchardt64dc7af2020-01-10 12:33:16 +0100128 EFI_ENTRY("%p, %p, %ls", this, controller_handle,
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100129 efi_dp_str(remaining_device_path));
130
131 /* Attach driver to controller */
132 ret = EFI_CALL(systab.boottime->open_protocol(
133 controller_handle, bp->ops->protocol,
134 &interface, this->driver_binding_handle,
135 controller_handle, EFI_OPEN_PROTOCOL_BY_DRIVER));
136 switch (ret) {
137 case EFI_ACCESS_DENIED:
138 case EFI_ALREADY_STARTED:
139 goto out;
140 case EFI_SUCCESS:
141 break;
142 default:
143 ret = EFI_UNSUPPORTED;
144 goto out;
145 }
146 ret = check_node_type(controller_handle);
Heinrich Schuchardt3f712db2022-10-03 10:35:35 +0200147 if (ret != EFI_SUCCESS)
148 goto err;
Heinrich Schuchardtff1d50b2022-10-04 19:12:59 +0200149 ret = bp->ops->bind(bp, controller_handle, interface);
Heinrich Schuchardt3f712db2022-10-03 10:35:35 +0200150 if (ret == EFI_SUCCESS)
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100151 goto out;
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100152
Heinrich Schuchardt3f712db2022-10-03 10:35:35 +0200153err:
Heinrich Schuchardt64304a12022-10-07 16:12:54 +0200154 r = efi_close_protocol(controller_handle, bp->ops->protocol,
155 this->driver_binding_handle,
156 controller_handle);
Heinrich Schuchardt3f712db2022-10-03 10:35:35 +0200157 if (r != EFI_SUCCESS)
158 EFI_PRINT("Failure to close handle\n");
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100159
160out:
161 return EFI_EXIT(ret);
162}
163
Heinrich Schuchardt55de1002018-09-18 18:52:46 +0200164/**
165 * disconnect_child() - remove a single child controller from the parent
166 * controller
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100167 *
Heinrich Schuchardt55de1002018-09-18 18:52:46 +0200168 * @controller_handle: parent controller
169 * @child_handle: child controller
170 * Return: status code
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100171 */
172static efi_status_t disconnect_child(efi_handle_t controller_handle,
173 efi_handle_t child_handle)
174{
175 efi_status_t ret;
176 efi_guid_t *guid_controller = NULL;
177 efi_guid_t *guid_child_controller = NULL;
178
Heinrich Schuchardt64304a12022-10-07 16:12:54 +0200179 ret = efi_close_protocol(controller_handle, guid_controller,
180 child_handle, child_handle);
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100181 if (ret != EFI_SUCCESS) {
182 EFI_PRINT("Cannot close protocol\n");
183 return ret;
184 }
185 ret = EFI_CALL(systab.boottime->uninstall_protocol_interface(
186 child_handle, guid_child_controller, NULL));
187 if (ret != EFI_SUCCESS) {
188 EFI_PRINT("Cannot uninstall protocol interface\n");
189 return ret;
190 }
191 return ret;
192}
193
Heinrich Schuchardt55de1002018-09-18 18:52:46 +0200194/**
195 * efi_uc_stop() - Remove child controllers and disconnect the controller
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100196 *
Heinrich Schuchardt55de1002018-09-18 18:52:46 +0200197 * @this: driver binding protocol
198 * @controller_handle: handle of the controller
199 * @number_of_children: number of child controllers to remove
200 * @child_handle_buffer: handles of the child controllers to remove
201 * Return: status code
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100202 */
203static efi_status_t EFIAPI efi_uc_stop(
204 struct efi_driver_binding_protocol *this,
205 efi_handle_t controller_handle,
206 size_t number_of_children,
207 efi_handle_t *child_handle_buffer)
208{
209 efi_status_t ret;
210 efi_uintn_t count;
211 struct efi_open_protocol_info_entry *entry_buffer;
Heinrich Schuchardta3a4a9c2020-01-09 23:26:43 +0100212 struct efi_driver_binding_extended_protocol *bp =
213 (struct efi_driver_binding_extended_protocol *)this;
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100214
Heinrich Schuchardt64dc7af2020-01-10 12:33:16 +0100215 EFI_ENTRY("%p, %p, %zu, %p", this, controller_handle,
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100216 number_of_children, child_handle_buffer);
217
218 /* Destroy provided child controllers */
219 if (number_of_children) {
220 efi_uintn_t i;
221
222 for (i = 0; i < number_of_children; ++i) {
223 ret = disconnect_child(controller_handle,
224 child_handle_buffer[i]);
225 if (ret != EFI_SUCCESS)
Heinrich Schuchardtadbbe1c2022-10-07 23:53:38 +0200226 goto out;
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100227 }
Heinrich Schuchardtadbbe1c2022-10-07 23:53:38 +0200228 ret = EFI_SUCCESS;
229 goto out;
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100230 }
231
232 /* Destroy all children */
233 ret = EFI_CALL(systab.boottime->open_protocol_information(
Heinrich Schuchardta3a4a9c2020-01-09 23:26:43 +0100234 controller_handle, bp->ops->protocol,
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100235 &entry_buffer, &count));
236 if (ret != EFI_SUCCESS)
237 goto out;
238 while (count) {
239 if (entry_buffer[--count].attributes &
240 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) {
241 ret = disconnect_child(
242 controller_handle,
243 entry_buffer[count].agent_handle);
244 if (ret != EFI_SUCCESS)
245 goto out;
246 }
247 }
Heinrich Schuchardt8a7112e2022-10-04 12:50:51 +0200248 ret = efi_free_pool(entry_buffer);
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100249 if (ret != EFI_SUCCESS)
Heinrich Schuchardt42c8ba22020-12-01 09:06:29 +0100250 log_err("Cannot free EFI memory pool\n");
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100251
252 /* Detach driver from controller */
Heinrich Schuchardt64304a12022-10-07 16:12:54 +0200253 ret = efi_close_protocol(controller_handle, bp->ops->protocol,
254 this->driver_binding_handle,
255 controller_handle);
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100256out:
257 return EFI_EXIT(ret);
258}
259
Heinrich Schuchardt55de1002018-09-18 18:52:46 +0200260/**
261 * efi_add_driver() - add driver
262 *
263 * @drv: driver to add
264 * Return: status code
265 */
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100266static efi_status_t efi_add_driver(struct driver *drv)
267{
268 efi_status_t ret;
269 const struct efi_driver_ops *ops = drv->ops;
270 struct efi_driver_binding_extended_protocol *bp;
271
Heinrich Schuchardt42c8ba22020-12-01 09:06:29 +0100272 log_debug("Adding EFI driver '%s'\n", drv->name);
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100273 if (!ops->protocol) {
Heinrich Schuchardt42c8ba22020-12-01 09:06:29 +0100274 log_err("EFI protocol GUID missing for driver '%s'\n",
275 drv->name);
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100276 return EFI_INVALID_PARAMETER;
277 }
278 bp = calloc(1, sizeof(struct efi_driver_binding_extended_protocol));
279 if (!bp)
280 return EFI_OUT_OF_RESOURCES;
281
282 bp->bp.supported = efi_uc_supported;
283 bp->bp.start = efi_uc_start;
284 bp->bp.stop = efi_uc_stop;
285 bp->bp.version = 0xffffffff;
Heinrich Schuchardt6c5fd212022-10-05 11:28:47 +0200286 bp->ops = ops;
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100287
288 ret = efi_create_handle(&bp->bp.driver_binding_handle);
Ilias Apalodimasb09ecf12023-07-24 13:17:36 +0300289 if (ret != EFI_SUCCESS)
290 goto err;
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100291 bp->bp.image_handle = bp->bp.driver_binding_handle;
292 ret = efi_add_protocol(bp->bp.driver_binding_handle,
293 &efi_guid_driver_binding_protocol, bp);
Heinrich Schuchardt6c5fd212022-10-05 11:28:47 +0200294 if (ret != EFI_SUCCESS)
295 goto err;
296 if (ops->init) {
297 ret = ops->init(bp);
298 if (ret != EFI_SUCCESS)
299 goto err;
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100300 }
Heinrich Schuchardt6c5fd212022-10-05 11:28:47 +0200301
Ilias Apalodimasb09ecf12023-07-24 13:17:36 +0300302 return ret;
Heinrich Schuchardt6c5fd212022-10-05 11:28:47 +0200303err:
Ilias Apalodimasb09ecf12023-07-24 13:17:36 +0300304 if (bp->bp.driver_binding_handle)
305 efi_delete_handle(bp->bp.driver_binding_handle);
Heinrich Schuchardt6c5fd212022-10-05 11:28:47 +0200306 free(bp);
307 return ret;
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100308}
309
Heinrich Schuchardt55de1002018-09-18 18:52:46 +0200310/**
311 * efi_driver_init() - initialize the EFI drivers
312 *
313 * Called by efi_init_obj_list().
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100314 *
Heinrich Schuchardt55de1002018-09-18 18:52:46 +0200315 * Return: 0 = success, any other value will stop further execution
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100316 */
Heinrich Schuchardt8f3cc5b2018-02-01 12:53:32 +0100317efi_status_t efi_driver_init(void)
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100318{
319 struct driver *drv;
Heinrich Schuchardt8f3cc5b2018-02-01 12:53:32 +0100320 efi_status_t ret = EFI_SUCCESS;
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100321
Heinrich Schuchardt42c8ba22020-12-01 09:06:29 +0100322 log_debug("Initializing EFI driver framework\n");
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100323 for (drv = ll_entry_start(struct driver, driver);
324 drv < ll_entry_end(struct driver, driver); ++drv) {
Simon Glass15c4d672021-12-04 08:56:30 -0700325 if (drv->id == UCLASS_EFI_LOADER) {
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100326 ret = efi_add_driver(drv);
Heinrich Schuchardt8f3cc5b2018-02-01 12:53:32 +0100327 if (ret != EFI_SUCCESS) {
Heinrich Schuchardt42c8ba22020-12-01 09:06:29 +0100328 log_err("Failed to add EFI driver %s\n",
329 drv->name);
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100330 break;
331 }
332 }
333 }
334 return ret;
335}
336
Heinrich Schuchardt55de1002018-09-18 18:52:46 +0200337/**
338 * efi_uc_init() - initialize the EFI uclass
339 *
340 * @class: the EFI uclass
341 * Return: 0 = success
342 */
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100343static int efi_uc_init(struct uclass *class)
344{
Simon Glass15c4d672021-12-04 08:56:30 -0700345 log_debug("Initializing UCLASS_EFI_LOADER\n");
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100346 return 0;
347}
348
Heinrich Schuchardt55de1002018-09-18 18:52:46 +0200349/**
350 * efi_uc_destroy() - destroy the EFI uclass
351 *
352 * @class: the EFI uclass
353 * Return: 0 = success
354 */
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100355static int efi_uc_destroy(struct uclass *class)
356{
Simon Glass15c4d672021-12-04 08:56:30 -0700357 log_debug("Destroying UCLASS_EFI_LOADER\n");
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100358 return 0;
359}
360
361UCLASS_DRIVER(efi) = {
362 .name = "efi",
Simon Glass15c4d672021-12-04 08:56:30 -0700363 .id = UCLASS_EFI_LOADER,
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100364 .init = efi_uc_init,
365 .destroy = efi_uc_destroy,
366};