]> Git Repo - u-boot.git/blob - lib/efi_driver/efi_uclass.c
Merge branch 'master' of https://source.denx.de/u-boot/custodians/u-boot-sh
[u-boot.git] / lib / efi_driver / efi_uclass.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  *  Uclass for EFI drivers
4  *
5  *  Copyright (c) 2017 Heinrich Schuchardt
6  *
7  * 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  *
14  * In supported() and bind() it checks if the controller implements the protocol
15  * 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
20 #define LOG_CATEGORY LOGC_EFI
21
22 #include <dm.h>
23 #include <efi_driver.h>
24 #include <log.h>
25 #include <malloc.h>
26
27 /**
28  * check_node_type() - check node type
29  *
30  * We do not support partitions as controller handles.
31  *
32  * @handle:     handle to be checked
33  * Return:      status code
34  */
35 static 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
54 /**
55  * efi_uc_supported() - check if the driver supports the controller
56  *
57  * @this:                       driver binding protocol
58  * @controller_handle:          handle of the controller
59  * @remaining_device_path:      path specifying the child controller
60  * Return:                      status code
61  */
62 static 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
75         /*
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
84         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
101         r = efi_close_protocol(controller_handle, bp->ops->protocol,
102                                this->driver_binding_handle,
103                                controller_handle);
104         if (r != EFI_SUCCESS)
105                 ret = EFI_UNSUPPORTED;
106 out:
107         return EFI_EXIT(ret);
108 }
109
110 /**
111  * efi_uc_start() - create child controllers and attach driver
112  *
113  * @this:                       driver binding protocol
114  * @controller_handle:          handle of the controller
115  * @remaining_device_path:      path specifying the child controller
116  * Return:                      status code
117  */
118 static 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
128         EFI_ENTRY("%p, %p, %ls", this, controller_handle,
129                   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);
147         if (ret != EFI_SUCCESS)
148                 goto err;
149         ret = bp->ops->bind(bp, controller_handle, interface);
150         if (ret == EFI_SUCCESS)
151                 goto out;
152
153 err:
154         r = efi_close_protocol(controller_handle, bp->ops->protocol,
155                                this->driver_binding_handle,
156                                controller_handle);
157         if (r != EFI_SUCCESS)
158                 EFI_PRINT("Failure to close handle\n");
159
160 out:
161         return EFI_EXIT(ret);
162 }
163
164 /**
165  * disconnect_child() - remove a single child controller from the parent
166  *                      controller
167  *
168  * @controller_handle:  parent controller
169  * @child_handle:       child controller
170  * Return:              status code
171  */
172 static 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
179         ret = efi_close_protocol(controller_handle, guid_controller,
180                                  child_handle, child_handle);
181         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
194 /**
195  * efi_uc_stop() - Remove child controllers and disconnect the controller
196  *
197  * @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
202  */
203 static 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;
212         struct efi_driver_binding_extended_protocol *bp =
213                         (struct efi_driver_binding_extended_protocol *)this;
214
215         EFI_ENTRY("%p, %p, %zu, %p", this, controller_handle,
216                   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)
226                                 goto out;
227                 }
228                 ret = EFI_SUCCESS;
229                         goto out;
230         }
231
232         /* Destroy all children */
233         ret = EFI_CALL(systab.boottime->open_protocol_information(
234                                         controller_handle, bp->ops->protocol,
235                                         &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         }
248         ret = efi_free_pool(entry_buffer);
249         if (ret != EFI_SUCCESS)
250                 log_err("Cannot free EFI memory pool\n");
251
252         /* Detach driver from controller */
253         ret = efi_close_protocol(controller_handle, bp->ops->protocol,
254                                  this->driver_binding_handle,
255                                  controller_handle);
256 out:
257         return EFI_EXIT(ret);
258 }
259
260 /**
261  * efi_add_driver() - add driver
262  *
263  * @drv:                driver to add
264  * Return:              status code
265  */
266 static 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
272         log_debug("Adding EFI driver '%s'\n", drv->name);
273         if (!ops->protocol) {
274                 log_err("EFI protocol GUID missing for driver '%s'\n",
275                         drv->name);
276                 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;
286         bp->ops = ops;
287
288         ret = efi_create_handle(&bp->bp.driver_binding_handle);
289         if (ret != EFI_SUCCESS)
290                 goto err;
291         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);
294         if (ret != EFI_SUCCESS)
295                 goto err;
296         if (ops->init) {
297                 ret = ops->init(bp);
298                 if (ret != EFI_SUCCESS)
299                         goto err;
300         }
301
302         return ret;
303 err:
304         if (bp->bp.driver_binding_handle)
305                 efi_delete_handle(bp->bp.driver_binding_handle);
306         free(bp);
307         return ret;
308 }
309
310 /**
311  * efi_driver_init() - initialize the EFI drivers
312  *
313  * Called by efi_init_obj_list().
314  *
315  * Return:      0 = success, any other value will stop further execution
316  */
317 efi_status_t efi_driver_init(void)
318 {
319         struct driver *drv;
320         efi_status_t ret = EFI_SUCCESS;
321
322         log_debug("Initializing EFI driver framework\n");
323         for (drv = ll_entry_start(struct driver, driver);
324              drv < ll_entry_end(struct driver, driver); ++drv) {
325                 if (drv->id == UCLASS_EFI_LOADER) {
326                         ret = efi_add_driver(drv);
327                         if (ret != EFI_SUCCESS) {
328                                 log_err("Failed to add EFI driver %s\n",
329                                         drv->name);
330                                 break;
331                         }
332                 }
333         }
334         return ret;
335 }
336
337 /**
338  * efi_uc_init() - initialize the EFI uclass
339  *
340  * @class:      the EFI uclass
341  * Return:      0 = success
342  */
343 static int efi_uc_init(struct uclass *class)
344 {
345         log_debug("Initializing UCLASS_EFI_LOADER\n");
346         return 0;
347 }
348
349 /**
350  * efi_uc_destroy() - destroy the EFI uclass
351  *
352  * @class:      the EFI uclass
353  * Return:      0 = success
354  */
355 static int efi_uc_destroy(struct uclass *class)
356 {
357         log_debug("Destroying UCLASS_EFI_LOADER\n");
358         return 0;
359 }
360
361 UCLASS_DRIVER(efi) = {
362         .name           = "efi",
363         .id             = UCLASS_EFI_LOADER,
364         .init           = efi_uc_init,
365         .destroy        = efi_uc_destroy,
366 };
This page took 0.0482 seconds and 4 git commands to generate.