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