blob: e1e28df20b2c47768377e09c961cc7c9f2624e91 [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
Simon Glassf6977c12020-07-19 10:15:43 -060020#include <dm.h>
Heinrich Schuchardt11206f42018-01-21 19:29:30 +010021#include <efi_driver.h>
Simon Glass0f2af882020-05-10 11:40:05 -060022#include <log.h>
Simon Glass9bc15642020-02-03 07:36:16 -070023#include <malloc.h>
Heinrich Schuchardt11206f42018-01-21 19:29:30 +010024
Heinrich Schuchardt55de1002018-09-18 18:52:46 +020025/**
26 * check_node_type() - check node type
Heinrich Schuchardt11206f42018-01-21 19:29:30 +010027 *
Heinrich Schuchardt55de1002018-09-18 18:52:46 +020028 * We do not support partitions as controller handles.
29 *
30 * @handle: handle to be checked
31 * Return: status code
Heinrich Schuchardt11206f42018-01-21 19:29:30 +010032 */
33static efi_status_t check_node_type(efi_handle_t handle)
34{
35 efi_status_t r, ret = EFI_SUCCESS;
36 const struct efi_device_path *dp;
37
38 /* Open the device path protocol */
39 r = EFI_CALL(systab.boottime->open_protocol(
40 handle, &efi_guid_device_path, (void **)&dp,
41 NULL, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL));
42 if (r == EFI_SUCCESS && dp) {
43 /* Get the last node */
44 const struct efi_device_path *node = efi_dp_last_node(dp);
45 /* We do not support partitions as controller */
46 if (!node || node->type == DEVICE_PATH_TYPE_MEDIA_DEVICE)
47 ret = EFI_UNSUPPORTED;
48 }
49 return ret;
50}
51
Heinrich Schuchardt55de1002018-09-18 18:52:46 +020052/**
53 * efi_uc_supported() - check if the driver supports the controller
Heinrich Schuchardt11206f42018-01-21 19:29:30 +010054 *
Heinrich Schuchardt55de1002018-09-18 18:52:46 +020055 * @this: driver binding protocol
56 * @controller_handle: handle of the controller
57 * @remaining_device_path: path specifying the child controller
58 * Return: status code
Heinrich Schuchardt11206f42018-01-21 19:29:30 +010059 */
60static efi_status_t EFIAPI efi_uc_supported(
61 struct efi_driver_binding_protocol *this,
62 efi_handle_t controller_handle,
63 struct efi_device_path *remaining_device_path)
64{
65 efi_status_t r, ret;
66 void *interface;
67 struct efi_driver_binding_extended_protocol *bp =
68 (struct efi_driver_binding_extended_protocol *)this;
69
70 EFI_ENTRY("%p, %p, %ls", this, controller_handle,
71 efi_dp_str(remaining_device_path));
72
Heinrich Schuchardt4fdaaf92022-09-09 06:57:58 +000073 /*
74 * U-Boot internal devices install protocols interfaces without calling
75 * ConnectController(). Hence we should not bind an extra driver.
76 */
77 if (controller_handle->dev) {
78 ret = EFI_UNSUPPORTED;
79 goto out;
80 }
81
Heinrich Schuchardt11206f42018-01-21 19:29:30 +010082 ret = EFI_CALL(systab.boottime->open_protocol(
83 controller_handle, bp->ops->protocol,
84 &interface, this->driver_binding_handle,
85 controller_handle, EFI_OPEN_PROTOCOL_BY_DRIVER));
86 switch (ret) {
87 case EFI_ACCESS_DENIED:
88 case EFI_ALREADY_STARTED:
89 goto out;
90 case EFI_SUCCESS:
91 break;
92 default:
93 ret = EFI_UNSUPPORTED;
94 goto out;
95 }
96
97 ret = check_node_type(controller_handle);
98
Heinrich Schuchardt64304a12022-10-07 16:12:54 +020099 r = efi_close_protocol(controller_handle, bp->ops->protocol,
100 this->driver_binding_handle,
101 controller_handle);
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100102 if (r != EFI_SUCCESS)
103 ret = EFI_UNSUPPORTED;
104out:
105 return EFI_EXIT(ret);
106}
107
Heinrich Schuchardt55de1002018-09-18 18:52:46 +0200108/**
109 * efi_uc_start() - create child controllers and attach driver
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100110 *
Heinrich Schuchardt55de1002018-09-18 18:52:46 +0200111 * @this: driver binding protocol
112 * @controller_handle: handle of the controller
113 * @remaining_device_path: path specifying the child controller
114 * Return: status code
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100115 */
116static efi_status_t EFIAPI efi_uc_start(
117 struct efi_driver_binding_protocol *this,
118 efi_handle_t controller_handle,
119 struct efi_device_path *remaining_device_path)
120{
121 efi_status_t r, ret;
122 void *interface = NULL;
123 struct efi_driver_binding_extended_protocol *bp =
124 (struct efi_driver_binding_extended_protocol *)this;
125
Heinrich Schuchardt64dc7af2020-01-10 12:33:16 +0100126 EFI_ENTRY("%p, %p, %ls", this, controller_handle,
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100127 efi_dp_str(remaining_device_path));
128
129 /* Attach driver to controller */
130 ret = EFI_CALL(systab.boottime->open_protocol(
131 controller_handle, bp->ops->protocol,
132 &interface, this->driver_binding_handle,
133 controller_handle, EFI_OPEN_PROTOCOL_BY_DRIVER));
134 switch (ret) {
135 case EFI_ACCESS_DENIED:
136 case EFI_ALREADY_STARTED:
137 goto out;
138 case EFI_SUCCESS:
139 break;
140 default:
141 ret = EFI_UNSUPPORTED;
142 goto out;
143 }
144 ret = check_node_type(controller_handle);
Heinrich Schuchardt3f712db2022-10-03 10:35:35 +0200145 if (ret != EFI_SUCCESS)
146 goto err;
Heinrich Schuchardtff1d50b2022-10-04 19:12:59 +0200147 ret = bp->ops->bind(bp, controller_handle, interface);
Heinrich Schuchardt3f712db2022-10-03 10:35:35 +0200148 if (ret == EFI_SUCCESS)
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100149 goto out;
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100150
Heinrich Schuchardt3f712db2022-10-03 10:35:35 +0200151err:
Heinrich Schuchardt64304a12022-10-07 16:12:54 +0200152 r = efi_close_protocol(controller_handle, bp->ops->protocol,
153 this->driver_binding_handle,
154 controller_handle);
Heinrich Schuchardt3f712db2022-10-03 10:35:35 +0200155 if (r != EFI_SUCCESS)
156 EFI_PRINT("Failure to close handle\n");
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100157
158out:
159 return EFI_EXIT(ret);
160}
161
Heinrich Schuchardt55de1002018-09-18 18:52:46 +0200162/**
163 * disconnect_child() - remove a single child controller from the parent
164 * controller
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100165 *
Heinrich Schuchardt55de1002018-09-18 18:52:46 +0200166 * @controller_handle: parent controller
167 * @child_handle: child controller
168 * Return: status code
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100169 */
170static efi_status_t disconnect_child(efi_handle_t controller_handle,
171 efi_handle_t child_handle)
172{
173 efi_status_t ret;
174 efi_guid_t *guid_controller = NULL;
175 efi_guid_t *guid_child_controller = NULL;
176
Heinrich Schuchardt64304a12022-10-07 16:12:54 +0200177 ret = efi_close_protocol(controller_handle, guid_controller,
178 child_handle, child_handle);
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100179 if (ret != EFI_SUCCESS) {
180 EFI_PRINT("Cannot close protocol\n");
181 return ret;
182 }
183 ret = EFI_CALL(systab.boottime->uninstall_protocol_interface(
184 child_handle, guid_child_controller, NULL));
185 if (ret != EFI_SUCCESS) {
186 EFI_PRINT("Cannot uninstall protocol interface\n");
187 return ret;
188 }
189 return ret;
190}
191
Heinrich Schuchardt55de1002018-09-18 18:52:46 +0200192/**
193 * efi_uc_stop() - Remove child controllers and disconnect the controller
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100194 *
Heinrich Schuchardt55de1002018-09-18 18:52:46 +0200195 * @this: driver binding protocol
196 * @controller_handle: handle of the controller
197 * @number_of_children: number of child controllers to remove
198 * @child_handle_buffer: handles of the child controllers to remove
199 * Return: status code
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100200 */
201static efi_status_t EFIAPI efi_uc_stop(
202 struct efi_driver_binding_protocol *this,
203 efi_handle_t controller_handle,
204 size_t number_of_children,
205 efi_handle_t *child_handle_buffer)
206{
207 efi_status_t ret;
208 efi_uintn_t count;
209 struct efi_open_protocol_info_entry *entry_buffer;
Heinrich Schuchardta3a4a9c2020-01-09 23:26:43 +0100210 struct efi_driver_binding_extended_protocol *bp =
211 (struct efi_driver_binding_extended_protocol *)this;
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100212
Heinrich Schuchardt64dc7af2020-01-10 12:33:16 +0100213 EFI_ENTRY("%p, %p, %zu, %p", this, controller_handle,
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100214 number_of_children, child_handle_buffer);
215
216 /* Destroy provided child controllers */
217 if (number_of_children) {
218 efi_uintn_t i;
219
220 for (i = 0; i < number_of_children; ++i) {
221 ret = disconnect_child(controller_handle,
222 child_handle_buffer[i]);
223 if (ret != EFI_SUCCESS)
Heinrich Schuchardtadbbe1c2022-10-07 23:53:38 +0200224 goto out;
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100225 }
Heinrich Schuchardtadbbe1c2022-10-07 23:53:38 +0200226 ret = EFI_SUCCESS;
227 goto out;
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100228 }
229
230 /* Destroy all children */
231 ret = EFI_CALL(systab.boottime->open_protocol_information(
Heinrich Schuchardta3a4a9c2020-01-09 23:26:43 +0100232 controller_handle, bp->ops->protocol,
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100233 &entry_buffer, &count));
234 if (ret != EFI_SUCCESS)
235 goto out;
236 while (count) {
237 if (entry_buffer[--count].attributes &
238 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) {
239 ret = disconnect_child(
240 controller_handle,
241 entry_buffer[count].agent_handle);
242 if (ret != EFI_SUCCESS)
243 goto out;
244 }
245 }
Heinrich Schuchardt8a7112e2022-10-04 12:50:51 +0200246 ret = efi_free_pool(entry_buffer);
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100247 if (ret != EFI_SUCCESS)
Heinrich Schuchardt42c8ba22020-12-01 09:06:29 +0100248 log_err("Cannot free EFI memory pool\n");
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100249
250 /* Detach driver from controller */
Heinrich Schuchardt64304a12022-10-07 16:12:54 +0200251 ret = efi_close_protocol(controller_handle, bp->ops->protocol,
252 this->driver_binding_handle,
253 controller_handle);
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100254out:
255 return EFI_EXIT(ret);
256}
257
Heinrich Schuchardt55de1002018-09-18 18:52:46 +0200258/**
259 * efi_add_driver() - add driver
260 *
261 * @drv: driver to add
262 * Return: status code
263 */
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100264static efi_status_t efi_add_driver(struct driver *drv)
265{
266 efi_status_t ret;
267 const struct efi_driver_ops *ops = drv->ops;
268 struct efi_driver_binding_extended_protocol *bp;
269
Heinrich Schuchardt42c8ba22020-12-01 09:06:29 +0100270 log_debug("Adding EFI driver '%s'\n", drv->name);
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100271 if (!ops->protocol) {
Heinrich Schuchardt42c8ba22020-12-01 09:06:29 +0100272 log_err("EFI protocol GUID missing for driver '%s'\n",
273 drv->name);
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100274 return EFI_INVALID_PARAMETER;
275 }
276 bp = calloc(1, sizeof(struct efi_driver_binding_extended_protocol));
277 if (!bp)
278 return EFI_OUT_OF_RESOURCES;
279
280 bp->bp.supported = efi_uc_supported;
281 bp->bp.start = efi_uc_start;
282 bp->bp.stop = efi_uc_stop;
283 bp->bp.version = 0xffffffff;
Heinrich Schuchardt6c5fd212022-10-05 11:28:47 +0200284 bp->ops = ops;
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100285
286 ret = efi_create_handle(&bp->bp.driver_binding_handle);
Ilias Apalodimasb09ecf12023-07-24 13:17:36 +0300287 if (ret != EFI_SUCCESS)
288 goto err;
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100289 bp->bp.image_handle = bp->bp.driver_binding_handle;
290 ret = efi_add_protocol(bp->bp.driver_binding_handle,
291 &efi_guid_driver_binding_protocol, bp);
Heinrich Schuchardt6c5fd212022-10-05 11:28:47 +0200292 if (ret != EFI_SUCCESS)
293 goto err;
294 if (ops->init) {
295 ret = ops->init(bp);
296 if (ret != EFI_SUCCESS)
297 goto err;
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100298 }
Heinrich Schuchardt6c5fd212022-10-05 11:28:47 +0200299
Ilias Apalodimasb09ecf12023-07-24 13:17:36 +0300300 return ret;
Heinrich Schuchardt6c5fd212022-10-05 11:28:47 +0200301err:
Ilias Apalodimasb09ecf12023-07-24 13:17:36 +0300302 if (bp->bp.driver_binding_handle)
303 efi_delete_handle(bp->bp.driver_binding_handle);
Heinrich Schuchardt6c5fd212022-10-05 11:28:47 +0200304 free(bp);
305 return ret;
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100306}
307
Heinrich Schuchardt55de1002018-09-18 18:52:46 +0200308/**
309 * efi_driver_init() - initialize the EFI drivers
310 *
311 * Called by efi_init_obj_list().
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100312 *
Heinrich Schuchardt55de1002018-09-18 18:52:46 +0200313 * Return: 0 = success, any other value will stop further execution
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100314 */
Heinrich Schuchardt8f3cc5b2018-02-01 12:53:32 +0100315efi_status_t efi_driver_init(void)
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100316{
317 struct driver *drv;
Heinrich Schuchardt8f3cc5b2018-02-01 12:53:32 +0100318 efi_status_t ret = EFI_SUCCESS;
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100319
Heinrich Schuchardt42c8ba22020-12-01 09:06:29 +0100320 log_debug("Initializing EFI driver framework\n");
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100321 for (drv = ll_entry_start(struct driver, driver);
322 drv < ll_entry_end(struct driver, driver); ++drv) {
Simon Glass15c4d672021-12-04 08:56:30 -0700323 if (drv->id == UCLASS_EFI_LOADER) {
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100324 ret = efi_add_driver(drv);
Heinrich Schuchardt8f3cc5b2018-02-01 12:53:32 +0100325 if (ret != EFI_SUCCESS) {
Heinrich Schuchardt42c8ba22020-12-01 09:06:29 +0100326 log_err("Failed to add EFI driver %s\n",
327 drv->name);
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100328 break;
329 }
330 }
331 }
332 return ret;
333}
334
Heinrich Schuchardt55de1002018-09-18 18:52:46 +0200335/**
336 * efi_uc_init() - initialize the EFI uclass
337 *
338 * @class: the EFI uclass
339 * Return: 0 = success
340 */
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100341static int efi_uc_init(struct uclass *class)
342{
Simon Glass15c4d672021-12-04 08:56:30 -0700343 log_debug("Initializing UCLASS_EFI_LOADER\n");
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100344 return 0;
345}
346
Heinrich Schuchardt55de1002018-09-18 18:52:46 +0200347/**
348 * efi_uc_destroy() - destroy the EFI uclass
349 *
350 * @class: the EFI uclass
351 * Return: 0 = success
352 */
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100353static int efi_uc_destroy(struct uclass *class)
354{
Simon Glass15c4d672021-12-04 08:56:30 -0700355 log_debug("Destroying UCLASS_EFI_LOADER\n");
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100356 return 0;
357}
358
359UCLASS_DRIVER(efi) = {
360 .name = "efi",
Simon Glass15c4d672021-12-04 08:56:30 -0700361 .id = UCLASS_EFI_LOADER,
Heinrich Schuchardt11206f42018-01-21 19:29:30 +0100362 .init = efi_uc_init,
363 .destroy = efi_uc_destroy,
364};