blob: 66a45e156d60fb85f79d38089d832a29e6abfb57 [file] [log] [blame]
Tom Rinif739fcd2018-05-07 17:02:21 -04001// SPDX-License-Identifier: GPL-2.0+
Heinrich Schuchardt05ef48a2018-01-21 19:29:30 +01002/*
3 * Uclass for EFI drivers
4 *
5 * Copyright (c) 2017 Heinrich Schuchardt
6 *
Heinrich Schuchardt05ef48a2018-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 Schuchardt43a58912022-10-03 10:35:35 +020014 * In supported() and bind() it checks if the controller implements the protocol
Heinrich Schuchardt05ef48a2018-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 Glasse1e10f22020-07-19 10:15:43 -060020#include <common.h>
21#include <dm.h>
Heinrich Schuchardt05ef48a2018-01-21 19:29:30 +010022#include <efi_driver.h>
Simon Glassf7ae49f2020-05-10 11:40:05 -060023#include <log.h>
Simon Glass336d4612020-02-03 07:36:16 -070024#include <malloc.h>
Heinrich Schuchardt05ef48a2018-01-21 19:29:30 +010025
Heinrich Schuchardtea808852018-09-18 18:52:46 +020026/**
27 * check_node_type() - check node type
Heinrich Schuchardt05ef48a2018-01-21 19:29:30 +010028 *
Heinrich Schuchardtea808852018-09-18 18:52:46 +020029 * We do not support partitions as controller handles.
30 *
31 * @handle: handle to be checked
32 * Return: status code
Heinrich Schuchardt05ef48a2018-01-21 19:29:30 +010033 */
34static efi_status_t check_node_type(efi_handle_t handle)
35{
36 efi_status_t r, ret = EFI_SUCCESS;
37 const struct efi_device_path *dp;
38
39 /* Open the device path protocol */
40 r = EFI_CALL(systab.boottime->open_protocol(
41 handle, &efi_guid_device_path, (void **)&dp,
42 NULL, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL));
43 if (r == EFI_SUCCESS && dp) {
44 /* Get the last node */
45 const struct efi_device_path *node = efi_dp_last_node(dp);
46 /* We do not support partitions as controller */
47 if (!node || node->type == DEVICE_PATH_TYPE_MEDIA_DEVICE)
48 ret = EFI_UNSUPPORTED;
49 }
50 return ret;
51}
52
Heinrich Schuchardtea808852018-09-18 18:52:46 +020053/**
54 * efi_uc_supported() - check if the driver supports the controller
Heinrich Schuchardt05ef48a2018-01-21 19:29:30 +010055 *
Heinrich Schuchardtea808852018-09-18 18:52:46 +020056 * @this: driver binding protocol
57 * @controller_handle: handle of the controller
58 * @remaining_device_path: path specifying the child controller
59 * Return: status code
Heinrich Schuchardt05ef48a2018-01-21 19:29:30 +010060 */
61static efi_status_t EFIAPI efi_uc_supported(
62 struct efi_driver_binding_protocol *this,
63 efi_handle_t controller_handle,
64 struct efi_device_path *remaining_device_path)
65{
66 efi_status_t r, ret;
67 void *interface;
68 struct efi_driver_binding_extended_protocol *bp =
69 (struct efi_driver_binding_extended_protocol *)this;
70
71 EFI_ENTRY("%p, %p, %ls", this, controller_handle,
72 efi_dp_str(remaining_device_path));
73
Heinrich Schuchardt8cf8ad32022-09-09 06:57:58 +000074 /*
75 * U-Boot internal devices install protocols interfaces without calling
76 * ConnectController(). Hence we should not bind an extra driver.
77 */
78 if (controller_handle->dev) {
79 ret = EFI_UNSUPPORTED;
80 goto out;
81 }
82
Heinrich Schuchardt05ef48a2018-01-21 19:29:30 +010083 ret = EFI_CALL(systab.boottime->open_protocol(
84 controller_handle, bp->ops->protocol,
85 &interface, this->driver_binding_handle,
86 controller_handle, EFI_OPEN_PROTOCOL_BY_DRIVER));
87 switch (ret) {
88 case EFI_ACCESS_DENIED:
89 case EFI_ALREADY_STARTED:
90 goto out;
91 case EFI_SUCCESS:
92 break;
93 default:
94 ret = EFI_UNSUPPORTED;
95 goto out;
96 }
97
98 ret = check_node_type(controller_handle);
99
Heinrich Schuchardt7605c922022-10-07 16:12:54 +0200100 r = efi_close_protocol(controller_handle, bp->ops->protocol,
101 this->driver_binding_handle,
102 controller_handle);
Heinrich Schuchardt05ef48a2018-01-21 19:29:30 +0100103 if (r != EFI_SUCCESS)
104 ret = EFI_UNSUPPORTED;
105out:
106 return EFI_EXIT(ret);
107}
108
Heinrich Schuchardtea808852018-09-18 18:52:46 +0200109/**
110 * efi_uc_start() - create child controllers and attach driver
Heinrich Schuchardt05ef48a2018-01-21 19:29:30 +0100111 *
Heinrich Schuchardtea808852018-09-18 18:52:46 +0200112 * @this: driver binding protocol
113 * @controller_handle: handle of the controller
114 * @remaining_device_path: path specifying the child controller
115 * Return: status code
Heinrich Schuchardt05ef48a2018-01-21 19:29:30 +0100116 */
117static efi_status_t EFIAPI efi_uc_start(
118 struct efi_driver_binding_protocol *this,
119 efi_handle_t controller_handle,
120 struct efi_device_path *remaining_device_path)
121{
122 efi_status_t r, ret;
123 void *interface = NULL;
124 struct efi_driver_binding_extended_protocol *bp =
125 (struct efi_driver_binding_extended_protocol *)this;
126
Heinrich Schuchardt30ed1d42020-01-10 12:33:16 +0100127 EFI_ENTRY("%p, %p, %ls", this, controller_handle,
Heinrich Schuchardt05ef48a2018-01-21 19:29:30 +0100128 efi_dp_str(remaining_device_path));
129
130 /* Attach driver to controller */
131 ret = EFI_CALL(systab.boottime->open_protocol(
132 controller_handle, bp->ops->protocol,
133 &interface, this->driver_binding_handle,
134 controller_handle, EFI_OPEN_PROTOCOL_BY_DRIVER));
135 switch (ret) {
136 case EFI_ACCESS_DENIED:
137 case EFI_ALREADY_STARTED:
138 goto out;
139 case EFI_SUCCESS:
140 break;
141 default:
142 ret = EFI_UNSUPPORTED;
143 goto out;
144 }
145 ret = check_node_type(controller_handle);
Heinrich Schuchardt43a58912022-10-03 10:35:35 +0200146 if (ret != EFI_SUCCESS)
147 goto err;
Heinrich Schuchardtec4f6752022-10-04 19:12:59 +0200148 ret = bp->ops->bind(bp, controller_handle, interface);
Heinrich Schuchardt43a58912022-10-03 10:35:35 +0200149 if (ret == EFI_SUCCESS)
Heinrich Schuchardt05ef48a2018-01-21 19:29:30 +0100150 goto out;
Heinrich Schuchardt05ef48a2018-01-21 19:29:30 +0100151
Heinrich Schuchardt43a58912022-10-03 10:35:35 +0200152err:
Heinrich Schuchardt7605c922022-10-07 16:12:54 +0200153 r = efi_close_protocol(controller_handle, bp->ops->protocol,
154 this->driver_binding_handle,
155 controller_handle);
Heinrich Schuchardt43a58912022-10-03 10:35:35 +0200156 if (r != EFI_SUCCESS)
157 EFI_PRINT("Failure to close handle\n");
Heinrich Schuchardt05ef48a2018-01-21 19:29:30 +0100158
159out:
160 return EFI_EXIT(ret);
161}
162
Heinrich Schuchardtea808852018-09-18 18:52:46 +0200163/**
164 * disconnect_child() - remove a single child controller from the parent
165 * controller
Heinrich Schuchardt05ef48a2018-01-21 19:29:30 +0100166 *
Heinrich Schuchardtea808852018-09-18 18:52:46 +0200167 * @controller_handle: parent controller
168 * @child_handle: child controller
169 * Return: status code
Heinrich Schuchardt05ef48a2018-01-21 19:29:30 +0100170 */
171static efi_status_t disconnect_child(efi_handle_t controller_handle,
172 efi_handle_t child_handle)
173{
174 efi_status_t ret;
175 efi_guid_t *guid_controller = NULL;
176 efi_guid_t *guid_child_controller = NULL;
177
Heinrich Schuchardt7605c922022-10-07 16:12:54 +0200178 ret = efi_close_protocol(controller_handle, guid_controller,
179 child_handle, child_handle);
Heinrich Schuchardt05ef48a2018-01-21 19:29:30 +0100180 if (ret != EFI_SUCCESS) {
181 EFI_PRINT("Cannot close protocol\n");
182 return ret;
183 }
184 ret = EFI_CALL(systab.boottime->uninstall_protocol_interface(
185 child_handle, guid_child_controller, NULL));
186 if (ret != EFI_SUCCESS) {
187 EFI_PRINT("Cannot uninstall protocol interface\n");
188 return ret;
189 }
190 return ret;
191}
192
Heinrich Schuchardtea808852018-09-18 18:52:46 +0200193/**
194 * efi_uc_stop() - Remove child controllers and disconnect the controller
Heinrich Schuchardt05ef48a2018-01-21 19:29:30 +0100195 *
Heinrich Schuchardtea808852018-09-18 18:52:46 +0200196 * @this: driver binding protocol
197 * @controller_handle: handle of the controller
198 * @number_of_children: number of child controllers to remove
199 * @child_handle_buffer: handles of the child controllers to remove
200 * Return: status code
Heinrich Schuchardt05ef48a2018-01-21 19:29:30 +0100201 */
202static efi_status_t EFIAPI efi_uc_stop(
203 struct efi_driver_binding_protocol *this,
204 efi_handle_t controller_handle,
205 size_t number_of_children,
206 efi_handle_t *child_handle_buffer)
207{
208 efi_status_t ret;
209 efi_uintn_t count;
210 struct efi_open_protocol_info_entry *entry_buffer;
Heinrich Schuchardtd7431042020-01-09 23:26:43 +0100211 struct efi_driver_binding_extended_protocol *bp =
212 (struct efi_driver_binding_extended_protocol *)this;
Heinrich Schuchardt05ef48a2018-01-21 19:29:30 +0100213
Heinrich Schuchardt30ed1d42020-01-10 12:33:16 +0100214 EFI_ENTRY("%p, %p, %zu, %p", this, controller_handle,
Heinrich Schuchardt05ef48a2018-01-21 19:29:30 +0100215 number_of_children, child_handle_buffer);
216
217 /* Destroy provided child controllers */
218 if (number_of_children) {
219 efi_uintn_t i;
220
221 for (i = 0; i < number_of_children; ++i) {
222 ret = disconnect_child(controller_handle,
223 child_handle_buffer[i]);
224 if (ret != EFI_SUCCESS)
Heinrich Schuchardtfcdf5312022-10-07 23:53:38 +0200225 goto out;
Heinrich Schuchardt05ef48a2018-01-21 19:29:30 +0100226 }
Heinrich Schuchardtfcdf5312022-10-07 23:53:38 +0200227 ret = EFI_SUCCESS;
228 goto out;
Heinrich Schuchardt05ef48a2018-01-21 19:29:30 +0100229 }
230
231 /* Destroy all children */
232 ret = EFI_CALL(systab.boottime->open_protocol_information(
Heinrich Schuchardtd7431042020-01-09 23:26:43 +0100233 controller_handle, bp->ops->protocol,
Heinrich Schuchardt05ef48a2018-01-21 19:29:30 +0100234 &entry_buffer, &count));
235 if (ret != EFI_SUCCESS)
236 goto out;
237 while (count) {
238 if (entry_buffer[--count].attributes &
239 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) {
240 ret = disconnect_child(
241 controller_handle,
242 entry_buffer[count].agent_handle);
243 if (ret != EFI_SUCCESS)
244 goto out;
245 }
246 }
Heinrich Schuchardt8b164162022-10-04 12:50:51 +0200247 ret = efi_free_pool(entry_buffer);
Heinrich Schuchardt05ef48a2018-01-21 19:29:30 +0100248 if (ret != EFI_SUCCESS)
Heinrich Schuchardtfc364422020-12-01 09:06:29 +0100249 log_err("Cannot free EFI memory pool\n");
Heinrich Schuchardt05ef48a2018-01-21 19:29:30 +0100250
251 /* Detach driver from controller */
Heinrich Schuchardt7605c922022-10-07 16:12:54 +0200252 ret = efi_close_protocol(controller_handle, bp->ops->protocol,
253 this->driver_binding_handle,
254 controller_handle);
Heinrich Schuchardt05ef48a2018-01-21 19:29:30 +0100255out:
256 return EFI_EXIT(ret);
257}
258
Heinrich Schuchardtea808852018-09-18 18:52:46 +0200259/**
260 * efi_add_driver() - add driver
261 *
262 * @drv: driver to add
263 * Return: status code
264 */
Heinrich Schuchardt05ef48a2018-01-21 19:29:30 +0100265static efi_status_t efi_add_driver(struct driver *drv)
266{
267 efi_status_t ret;
268 const struct efi_driver_ops *ops = drv->ops;
269 struct efi_driver_binding_extended_protocol *bp;
270
Heinrich Schuchardtfc364422020-12-01 09:06:29 +0100271 log_debug("Adding EFI driver '%s'\n", drv->name);
Heinrich Schuchardt05ef48a2018-01-21 19:29:30 +0100272 if (!ops->protocol) {
Heinrich Schuchardtfc364422020-12-01 09:06:29 +0100273 log_err("EFI protocol GUID missing for driver '%s'\n",
274 drv->name);
Heinrich Schuchardt05ef48a2018-01-21 19:29:30 +0100275 return EFI_INVALID_PARAMETER;
276 }
277 bp = calloc(1, sizeof(struct efi_driver_binding_extended_protocol));
278 if (!bp)
279 return EFI_OUT_OF_RESOURCES;
280
281 bp->bp.supported = efi_uc_supported;
282 bp->bp.start = efi_uc_start;
283 bp->bp.stop = efi_uc_stop;
284 bp->bp.version = 0xffffffff;
Heinrich Schuchardt8f8fe1d2022-10-05 11:28:47 +0200285 bp->ops = ops;
Heinrich Schuchardt05ef48a2018-01-21 19:29:30 +0100286
287 ret = efi_create_handle(&bp->bp.driver_binding_handle);
Ilias Apalodimas54edc372023-07-24 13:17:36 +0300288 if (ret != EFI_SUCCESS)
289 goto err;
Heinrich Schuchardt05ef48a2018-01-21 19:29:30 +0100290 bp->bp.image_handle = bp->bp.driver_binding_handle;
291 ret = efi_add_protocol(bp->bp.driver_binding_handle,
292 &efi_guid_driver_binding_protocol, bp);
Heinrich Schuchardt8f8fe1d2022-10-05 11:28:47 +0200293 if (ret != EFI_SUCCESS)
294 goto err;
295 if (ops->init) {
296 ret = ops->init(bp);
297 if (ret != EFI_SUCCESS)
298 goto err;
Heinrich Schuchardt05ef48a2018-01-21 19:29:30 +0100299 }
Heinrich Schuchardt8f8fe1d2022-10-05 11:28:47 +0200300
Ilias Apalodimas54edc372023-07-24 13:17:36 +0300301 return ret;
Heinrich Schuchardt8f8fe1d2022-10-05 11:28:47 +0200302err:
Ilias Apalodimas54edc372023-07-24 13:17:36 +0300303 if (bp->bp.driver_binding_handle)
304 efi_delete_handle(bp->bp.driver_binding_handle);
Heinrich Schuchardt8f8fe1d2022-10-05 11:28:47 +0200305 free(bp);
306 return ret;
Heinrich Schuchardt05ef48a2018-01-21 19:29:30 +0100307}
308
Heinrich Schuchardtea808852018-09-18 18:52:46 +0200309/**
310 * efi_driver_init() - initialize the EFI drivers
Heinrich Schuchardt05ef48a2018-01-21 19:29:30 +0100311 *
Heinrich Schuchardtea808852018-09-18 18:52:46 +0200312 * Called by efi_init_obj_list().
313 *
314 * Return: 0 = success, any other value will stop further execution
Heinrich Schuchardt05ef48a2018-01-21 19:29:30 +0100315 */
Heinrich Schuchardt038782a2018-02-01 12:53:32 +0100316efi_status_t efi_driver_init(void)
Heinrich Schuchardt05ef48a2018-01-21 19:29:30 +0100317{
318 struct driver *drv;
Heinrich Schuchardt038782a2018-02-01 12:53:32 +0100319 efi_status_t ret = EFI_SUCCESS;
Heinrich Schuchardt05ef48a2018-01-21 19:29:30 +0100320
Heinrich Schuchardtfc364422020-12-01 09:06:29 +0100321 log_debug("Initializing EFI driver framework\n");
Heinrich Schuchardt05ef48a2018-01-21 19:29:30 +0100322 for (drv = ll_entry_start(struct driver, driver);
323 drv < ll_entry_end(struct driver, driver); ++drv) {
Simon Glass2abd8d12021-12-04 08:56:30 -0700324 if (drv->id == UCLASS_EFI_LOADER) {
Heinrich Schuchardt05ef48a2018-01-21 19:29:30 +0100325 ret = efi_add_driver(drv);
Heinrich Schuchardt038782a2018-02-01 12:53:32 +0100326 if (ret != EFI_SUCCESS) {
Heinrich Schuchardtfc364422020-12-01 09:06:29 +0100327 log_err("Failed to add EFI driver %s\n",
328 drv->name);
Heinrich Schuchardt05ef48a2018-01-21 19:29:30 +0100329 break;
330 }
331 }
332 }
333 return ret;
334}
335
Heinrich Schuchardtea808852018-09-18 18:52:46 +0200336/**
337 * efi_uc_init() - initialize the EFI uclass
338 *
339 * @class: the EFI uclass
340 * Return: 0 = success
341 */
Heinrich Schuchardt05ef48a2018-01-21 19:29:30 +0100342static int efi_uc_init(struct uclass *class)
343{
Simon Glass2abd8d12021-12-04 08:56:30 -0700344 log_debug("Initializing UCLASS_EFI_LOADER\n");
Heinrich Schuchardt05ef48a2018-01-21 19:29:30 +0100345 return 0;
346}
347
Heinrich Schuchardtea808852018-09-18 18:52:46 +0200348/**
349 * efi_uc_destroy() - destroy the EFI uclass
350 *
351 * @class: the EFI uclass
352 * Return: 0 = success
353 */
Heinrich Schuchardt05ef48a2018-01-21 19:29:30 +0100354static int efi_uc_destroy(struct uclass *class)
355{
Simon Glass2abd8d12021-12-04 08:56:30 -0700356 log_debug("Destroying UCLASS_EFI_LOADER\n");
Heinrich Schuchardt05ef48a2018-01-21 19:29:30 +0100357 return 0;
358}
359
360UCLASS_DRIVER(efi) = {
361 .name = "efi",
Simon Glass2abd8d12021-12-04 08:56:30 -0700362 .id = UCLASS_EFI_LOADER,
Heinrich Schuchardt05ef48a2018-01-21 19:29:30 +0100363 .init = efi_uc_init,
364 .destroy = efi_uc_destroy,
365};