blob: 7392c60f0f98d4c7d24dba556e1e50a2aba5a8e6 [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>
Simon Glass37972f42025-05-24 11:28:21 -060023#include <efi_device_path.h>
Heinrich Schuchardt11206f42018-01-21 19:29:30 +010024#include <efi_driver.h>
Simon Glass0f2af882020-05-10 11:40:05 -060025#include <log.h>
Simon Glass9bc15642020-02-03 07:36:16 -070026#include <malloc.h>
Heinrich Schuchardt11206f42018-01-21 19:29:30 +010027
Heinrich Schuchardt55de1002018-09-18 18:52:46 +020028/**
29 * check_node_type() - check node type
Heinrich Schuchardt11206f42018-01-21 19:29:30 +010030 *
Heinrich Schuchardt55de1002018-09-18 18:52:46 +020031 * We do not support partitions as controller handles.
32 *
33 * @handle: handle to be checked
34 * Return: status code
Heinrich Schuchardt11206f42018-01-21 19:29:30 +010035 */
36static efi_status_t check_node_type(efi_handle_t handle)
37{
38 efi_status_t r, ret = EFI_SUCCESS;
39 const struct efi_device_path *dp;
40
41 /* Open the device path protocol */
42 r = EFI_CALL(systab.boottime->open_protocol(
43 handle, &efi_guid_device_path, (void **)&dp,
44 NULL, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL));
45 if (r == EFI_SUCCESS && dp) {
46 /* Get the last node */
47 const struct efi_device_path *node = efi_dp_last_node(dp);
48 /* We do not support partitions as controller */
49 if (!node || node->type == DEVICE_PATH_TYPE_MEDIA_DEVICE)
50 ret = EFI_UNSUPPORTED;
51 }
52 return ret;
53}
54
Heinrich Schuchardt55de1002018-09-18 18:52:46 +020055/**
56 * efi_uc_supported() - check if the driver supports the controller
Heinrich Schuchardt11206f42018-01-21 19:29:30 +010057 *
Heinrich Schuchardt55de1002018-09-18 18:52:46 +020058 * @this: driver binding protocol
59 * @controller_handle: handle of the controller
60 * @remaining_device_path: path specifying the child controller
61 * Return: status code
Heinrich Schuchardt11206f42018-01-21 19:29:30 +010062 */
63static efi_status_t EFIAPI efi_uc_supported(
64 struct efi_driver_binding_protocol *this,
65 efi_handle_t controller_handle,
66 struct efi_device_path *remaining_device_path)
67{
68 efi_status_t r, ret;
69 void *interface;
70 struct efi_driver_binding_extended_protocol *bp =
71 (struct efi_driver_binding_extended_protocol *)this;
72
73 EFI_ENTRY("%p, %p, %ls", this, controller_handle,
74 efi_dp_str(remaining_device_path));
75
Heinrich Schuchardt4fdaaf92022-09-09 06:57:58 +000076 /*
77 * U-Boot internal devices install protocols interfaces without calling
78 * ConnectController(). Hence we should not bind an extra driver.
79 */
80 if (controller_handle->dev) {
81 ret = EFI_UNSUPPORTED;
82 goto out;
83 }
84
Heinrich Schuchardt11206f42018-01-21 19:29:30 +010085 ret = EFI_CALL(systab.boottime->open_protocol(
86 controller_handle, bp->ops->protocol,
87 &interface, this->driver_binding_handle,
88 controller_handle, EFI_OPEN_PROTOCOL_BY_DRIVER));
89 switch (ret) {
90 case EFI_ACCESS_DENIED:
91 case EFI_ALREADY_STARTED:
92 goto out;
93 case EFI_SUCCESS:
94 break;
95 default:
96 ret = EFI_UNSUPPORTED;
97 goto out;
98 }
99
100 ret = check_node_type(controller_handle);
101
Heinrich Schuchardt64304a12022-10-07 16:12:54 +0200102 r = efi_close_protocol(controller_handle, bp->ops->protocol,
103 this->driver_binding_handle,
104 controller_handle);
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100105 if (r != EFI_SUCCESS)
106 ret = EFI_UNSUPPORTED;
107out:
108 return EFI_EXIT(ret);
109}
110
Heinrich Schuchardt55de1002018-09-18 18:52:46 +0200111/**
112 * efi_uc_start() - create child controllers and attach driver
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100113 *
Heinrich Schuchardt55de1002018-09-18 18:52:46 +0200114 * @this: driver binding protocol
115 * @controller_handle: handle of the controller
116 * @remaining_device_path: path specifying the child controller
117 * Return: status code
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100118 */
119static efi_status_t EFIAPI efi_uc_start(
120 struct efi_driver_binding_protocol *this,
121 efi_handle_t controller_handle,
122 struct efi_device_path *remaining_device_path)
123{
124 efi_status_t r, ret;
125 void *interface = NULL;
126 struct efi_driver_binding_extended_protocol *bp =
127 (struct efi_driver_binding_extended_protocol *)this;
128
Heinrich Schuchardt64dc7af2020-01-10 12:33:16 +0100129 EFI_ENTRY("%p, %p, %ls", this, controller_handle,
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100130 efi_dp_str(remaining_device_path));
131
132 /* Attach driver to controller */
133 ret = EFI_CALL(systab.boottime->open_protocol(
134 controller_handle, bp->ops->protocol,
135 &interface, this->driver_binding_handle,
136 controller_handle, EFI_OPEN_PROTOCOL_BY_DRIVER));
137 switch (ret) {
138 case EFI_ACCESS_DENIED:
139 case EFI_ALREADY_STARTED:
140 goto out;
141 case EFI_SUCCESS:
142 break;
143 default:
144 ret = EFI_UNSUPPORTED;
145 goto out;
146 }
147 ret = check_node_type(controller_handle);
Heinrich Schuchardt3f712db2022-10-03 10:35:35 +0200148 if (ret != EFI_SUCCESS)
149 goto err;
Heinrich Schuchardtff1d50b2022-10-04 19:12:59 +0200150 ret = bp->ops->bind(bp, controller_handle, interface);
Heinrich Schuchardt3f712db2022-10-03 10:35:35 +0200151 if (ret == EFI_SUCCESS)
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100152 goto out;
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100153
Heinrich Schuchardt3f712db2022-10-03 10:35:35 +0200154err:
Heinrich Schuchardt64304a12022-10-07 16:12:54 +0200155 r = efi_close_protocol(controller_handle, bp->ops->protocol,
156 this->driver_binding_handle,
157 controller_handle);
Heinrich Schuchardt3f712db2022-10-03 10:35:35 +0200158 if (r != EFI_SUCCESS)
159 EFI_PRINT("Failure to close handle\n");
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100160
161out:
162 return EFI_EXIT(ret);
163}
164
Heinrich Schuchardt55de1002018-09-18 18:52:46 +0200165/**
166 * disconnect_child() - remove a single child controller from the parent
167 * controller
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100168 *
Heinrich Schuchardt55de1002018-09-18 18:52:46 +0200169 * @controller_handle: parent controller
170 * @child_handle: child controller
171 * Return: status code
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100172 */
173static efi_status_t disconnect_child(efi_handle_t controller_handle,
174 efi_handle_t child_handle)
175{
176 efi_status_t ret;
177 efi_guid_t *guid_controller = NULL;
178 efi_guid_t *guid_child_controller = NULL;
179
Heinrich Schuchardt64304a12022-10-07 16:12:54 +0200180 ret = efi_close_protocol(controller_handle, guid_controller,
181 child_handle, child_handle);
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100182 if (ret != EFI_SUCCESS) {
183 EFI_PRINT("Cannot close protocol\n");
184 return ret;
185 }
186 ret = EFI_CALL(systab.boottime->uninstall_protocol_interface(
187 child_handle, guid_child_controller, NULL));
188 if (ret != EFI_SUCCESS) {
189 EFI_PRINT("Cannot uninstall protocol interface\n");
190 return ret;
191 }
192 return ret;
193}
194
Heinrich Schuchardt55de1002018-09-18 18:52:46 +0200195/**
196 * efi_uc_stop() - Remove child controllers and disconnect the controller
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100197 *
Heinrich Schuchardt55de1002018-09-18 18:52:46 +0200198 * @this: driver binding protocol
199 * @controller_handle: handle of the controller
200 * @number_of_children: number of child controllers to remove
201 * @child_handle_buffer: handles of the child controllers to remove
202 * Return: status code
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100203 */
204static efi_status_t EFIAPI efi_uc_stop(
205 struct efi_driver_binding_protocol *this,
206 efi_handle_t controller_handle,
207 size_t number_of_children,
208 efi_handle_t *child_handle_buffer)
209{
210 efi_status_t ret;
211 efi_uintn_t count;
212 struct efi_open_protocol_info_entry *entry_buffer;
Heinrich Schuchardta3a4a9c2020-01-09 23:26:43 +0100213 struct efi_driver_binding_extended_protocol *bp =
214 (struct efi_driver_binding_extended_protocol *)this;
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100215
Heinrich Schuchardt64dc7af2020-01-10 12:33:16 +0100216 EFI_ENTRY("%p, %p, %zu, %p", this, controller_handle,
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100217 number_of_children, child_handle_buffer);
218
219 /* Destroy provided child controllers */
220 if (number_of_children) {
221 efi_uintn_t i;
222
223 for (i = 0; i < number_of_children; ++i) {
224 ret = disconnect_child(controller_handle,
225 child_handle_buffer[i]);
226 if (ret != EFI_SUCCESS)
Heinrich Schuchardtadbbe1c2022-10-07 23:53:38 +0200227 goto out;
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100228 }
Heinrich Schuchardtadbbe1c2022-10-07 23:53:38 +0200229 ret = EFI_SUCCESS;
230 goto out;
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100231 }
232
233 /* Destroy all children */
234 ret = EFI_CALL(systab.boottime->open_protocol_information(
Heinrich Schuchardta3a4a9c2020-01-09 23:26:43 +0100235 controller_handle, bp->ops->protocol,
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100236 &entry_buffer, &count));
237 if (ret != EFI_SUCCESS)
238 goto out;
239 while (count) {
240 if (entry_buffer[--count].attributes &
241 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) {
242 ret = disconnect_child(
243 controller_handle,
244 entry_buffer[count].agent_handle);
245 if (ret != EFI_SUCCESS)
246 goto out;
247 }
248 }
Heinrich Schuchardt8a7112e2022-10-04 12:50:51 +0200249 ret = efi_free_pool(entry_buffer);
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100250 if (ret != EFI_SUCCESS)
Heinrich Schuchardt42c8ba22020-12-01 09:06:29 +0100251 log_err("Cannot free EFI memory pool\n");
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100252
253 /* Detach driver from controller */
Heinrich Schuchardt64304a12022-10-07 16:12:54 +0200254 ret = efi_close_protocol(controller_handle, bp->ops->protocol,
255 this->driver_binding_handle,
256 controller_handle);
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100257out:
258 return EFI_EXIT(ret);
259}
260
Heinrich Schuchardt55de1002018-09-18 18:52:46 +0200261/**
262 * efi_add_driver() - add driver
263 *
264 * @drv: driver to add
265 * Return: status code
266 */
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100267static efi_status_t efi_add_driver(struct driver *drv)
268{
269 efi_status_t ret;
270 const struct efi_driver_ops *ops = drv->ops;
271 struct efi_driver_binding_extended_protocol *bp;
272
Heinrich Schuchardt42c8ba22020-12-01 09:06:29 +0100273 log_debug("Adding EFI driver '%s'\n", drv->name);
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100274 if (!ops->protocol) {
Heinrich Schuchardt42c8ba22020-12-01 09:06:29 +0100275 log_err("EFI protocol GUID missing for driver '%s'\n",
276 drv->name);
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100277 return EFI_INVALID_PARAMETER;
278 }
279 bp = calloc(1, sizeof(struct efi_driver_binding_extended_protocol));
280 if (!bp)
281 return EFI_OUT_OF_RESOURCES;
282
283 bp->bp.supported = efi_uc_supported;
284 bp->bp.start = efi_uc_start;
285 bp->bp.stop = efi_uc_stop;
286 bp->bp.version = 0xffffffff;
Heinrich Schuchardt6c5fd212022-10-05 11:28:47 +0200287 bp->ops = ops;
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100288
289 ret = efi_create_handle(&bp->bp.driver_binding_handle);
Ilias Apalodimasb09ecf12023-07-24 13:17:36 +0300290 if (ret != EFI_SUCCESS)
291 goto err;
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100292 bp->bp.image_handle = bp->bp.driver_binding_handle;
293 ret = efi_add_protocol(bp->bp.driver_binding_handle,
294 &efi_guid_driver_binding_protocol, bp);
Heinrich Schuchardt6c5fd212022-10-05 11:28:47 +0200295 if (ret != EFI_SUCCESS)
296 goto err;
297 if (ops->init) {
298 ret = ops->init(bp);
299 if (ret != EFI_SUCCESS)
300 goto err;
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100301 }
Heinrich Schuchardt6c5fd212022-10-05 11:28:47 +0200302
Ilias Apalodimasb09ecf12023-07-24 13:17:36 +0300303 return ret;
Heinrich Schuchardt6c5fd212022-10-05 11:28:47 +0200304err:
Ilias Apalodimasb09ecf12023-07-24 13:17:36 +0300305 if (bp->bp.driver_binding_handle)
306 efi_delete_handle(bp->bp.driver_binding_handle);
Heinrich Schuchardt6c5fd212022-10-05 11:28:47 +0200307 free(bp);
308 return ret;
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100309}
310
Heinrich Schuchardt55de1002018-09-18 18:52:46 +0200311/**
312 * efi_driver_init() - initialize the EFI drivers
313 *
314 * Called by efi_init_obj_list().
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100315 *
Heinrich Schuchardt55de1002018-09-18 18:52:46 +0200316 * Return: 0 = success, any other value will stop further execution
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100317 */
Heinrich Schuchardt8f3cc5b2018-02-01 12:53:32 +0100318efi_status_t efi_driver_init(void)
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100319{
320 struct driver *drv;
Heinrich Schuchardt8f3cc5b2018-02-01 12:53:32 +0100321 efi_status_t ret = EFI_SUCCESS;
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100322
Heinrich Schuchardt42c8ba22020-12-01 09:06:29 +0100323 log_debug("Initializing EFI driver framework\n");
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100324 for (drv = ll_entry_start(struct driver, driver);
325 drv < ll_entry_end(struct driver, driver); ++drv) {
Simon Glass15c4d672021-12-04 08:56:30 -0700326 if (drv->id == UCLASS_EFI_LOADER) {
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100327 ret = efi_add_driver(drv);
Heinrich Schuchardt8f3cc5b2018-02-01 12:53:32 +0100328 if (ret != EFI_SUCCESS) {
Heinrich Schuchardt42c8ba22020-12-01 09:06:29 +0100329 log_err("Failed to add EFI driver %s\n",
330 drv->name);
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100331 break;
332 }
333 }
334 }
335 return ret;
336}
337
Heinrich Schuchardt55de1002018-09-18 18:52:46 +0200338/**
339 * efi_uc_init() - initialize the EFI uclass
340 *
341 * @class: the EFI uclass
342 * Return: 0 = success
343 */
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100344static int efi_uc_init(struct uclass *class)
345{
Simon Glass15c4d672021-12-04 08:56:30 -0700346 log_debug("Initializing UCLASS_EFI_LOADER\n");
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100347 return 0;
348}
349
Heinrich Schuchardt55de1002018-09-18 18:52:46 +0200350/**
351 * efi_uc_destroy() - destroy the EFI uclass
352 *
353 * @class: the EFI uclass
354 * Return: 0 = success
355 */
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100356static int efi_uc_destroy(struct uclass *class)
357{
Simon Glass15c4d672021-12-04 08:56:30 -0700358 log_debug("Destroying UCLASS_EFI_LOADER\n");
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100359 return 0;
360}
361
362UCLASS_DRIVER(efi) = {
363 .name = "efi",
Simon Glass15c4d672021-12-04 08:56:30 -0700364 .id = UCLASS_EFI_LOADER,
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100365 .init = efi_uc_init,
366 .destroy = efi_uc_destroy,
367};