Merge tag 'efi-2020-07-rc3-2' of https://gitlab.denx.de/u-boot/custodians/u-boot-efi
[oweals/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 bind() and stop() 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 <efi_driver.h>
21 #include <log.h>
22 #include <malloc.h>
23
24 /**
25  * check_node_type() - check node type
26  *
27  * We do not support partitions as controller handles.
28  *
29  * @handle:     handle to be checked
30  * Return:      status code
31  */
32 static efi_status_t check_node_type(efi_handle_t handle)
33 {
34         efi_status_t r, ret = EFI_SUCCESS;
35         const struct efi_device_path *dp;
36
37         /* Open the device path protocol */
38         r = EFI_CALL(systab.boottime->open_protocol(
39                         handle, &efi_guid_device_path, (void **)&dp,
40                         NULL, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL));
41         if (r == EFI_SUCCESS && dp) {
42                 /* Get the last node */
43                 const struct efi_device_path *node = efi_dp_last_node(dp);
44                 /* We do not support partitions as controller */
45                 if (!node || node->type == DEVICE_PATH_TYPE_MEDIA_DEVICE)
46                         ret = EFI_UNSUPPORTED;
47         }
48         return ret;
49 }
50
51 /**
52  * efi_uc_supported() - check if the driver supports the controller
53  *
54  * @this:                       driver binding protocol
55  * @controller_handle:          handle of the controller
56  * @remaining_device_path:      path specifying the child controller
57  * Return:                      status code
58  */
59 static efi_status_t EFIAPI efi_uc_supported(
60                 struct efi_driver_binding_protocol *this,
61                 efi_handle_t controller_handle,
62                 struct efi_device_path *remaining_device_path)
63 {
64         efi_status_t r, ret;
65         void *interface;
66         struct efi_driver_binding_extended_protocol *bp =
67                         (struct efi_driver_binding_extended_protocol *)this;
68
69         EFI_ENTRY("%p, %p, %ls", this, controller_handle,
70                   efi_dp_str(remaining_device_path));
71
72         ret = EFI_CALL(systab.boottime->open_protocol(
73                         controller_handle, bp->ops->protocol,
74                         &interface, this->driver_binding_handle,
75                         controller_handle, EFI_OPEN_PROTOCOL_BY_DRIVER));
76         switch (ret) {
77         case EFI_ACCESS_DENIED:
78         case EFI_ALREADY_STARTED:
79                 goto out;
80         case EFI_SUCCESS:
81                 break;
82         default:
83                 ret = EFI_UNSUPPORTED;
84                 goto out;
85         }
86
87         ret = check_node_type(controller_handle);
88
89         r = EFI_CALL(systab.boottime->close_protocol(
90                                 controller_handle, bp->ops->protocol,
91                                 this->driver_binding_handle,
92                                 controller_handle));
93         if (r != EFI_SUCCESS)
94                 ret = EFI_UNSUPPORTED;
95 out:
96         return EFI_EXIT(ret);
97 }
98
99 /**
100  * efi_uc_start() - create child controllers and attach driver
101  *
102  * @this:                       driver binding protocol
103  * @controller_handle:          handle of the controller
104  * @remaining_device_path:      path specifying the child controller
105  * Return:                      status code
106  */
107 static efi_status_t EFIAPI efi_uc_start(
108                 struct efi_driver_binding_protocol *this,
109                 efi_handle_t controller_handle,
110                 struct efi_device_path *remaining_device_path)
111 {
112         efi_status_t r, ret;
113         void *interface = NULL;
114         struct efi_driver_binding_extended_protocol *bp =
115                         (struct efi_driver_binding_extended_protocol *)this;
116
117         EFI_ENTRY("%p, %p, %ls", this, controller_handle,
118                   efi_dp_str(remaining_device_path));
119
120         /* Attach driver to controller */
121         ret = EFI_CALL(systab.boottime->open_protocol(
122                         controller_handle, bp->ops->protocol,
123                         &interface, this->driver_binding_handle,
124                         controller_handle, EFI_OPEN_PROTOCOL_BY_DRIVER));
125         switch (ret) {
126         case EFI_ACCESS_DENIED:
127         case EFI_ALREADY_STARTED:
128                 goto out;
129         case EFI_SUCCESS:
130                 break;
131         default:
132                 ret =  EFI_UNSUPPORTED;
133                 goto out;
134         }
135         ret = check_node_type(controller_handle);
136         if (ret != EFI_SUCCESS) {
137                 r = EFI_CALL(systab.boottime->close_protocol(
138                                 controller_handle, bp->ops->protocol,
139                                 this->driver_binding_handle,
140                                 controller_handle));
141                 if (r != EFI_SUCCESS)
142                         EFI_PRINT("Failure to close handle\n");
143                 goto out;
144         }
145
146         /* TODO: driver specific stuff */
147         bp->ops->bind(controller_handle, interface);
148
149 out:
150         return EFI_EXIT(ret);
151 }
152
153 /**
154  * disconnect_child() - remove a single child controller from the parent
155  *                      controller
156  *
157  * @controller_handle:  parent controller
158  * @child_handle:       child controller
159  * Return:              status code
160  */
161 static efi_status_t disconnect_child(efi_handle_t controller_handle,
162                                      efi_handle_t child_handle)
163 {
164         efi_status_t ret;
165         efi_guid_t *guid_controller = NULL;
166         efi_guid_t *guid_child_controller = NULL;
167
168         ret = EFI_CALL(systab.boottime->close_protocol(
169                                 controller_handle, guid_controller,
170                                 child_handle, child_handle));
171         if (ret != EFI_SUCCESS) {
172                 EFI_PRINT("Cannot close protocol\n");
173                 return ret;
174         }
175         ret = EFI_CALL(systab.boottime->uninstall_protocol_interface(
176                                 child_handle, guid_child_controller, NULL));
177         if (ret != EFI_SUCCESS) {
178                 EFI_PRINT("Cannot uninstall protocol interface\n");
179                 return ret;
180         }
181         return ret;
182 }
183
184 /**
185  * efi_uc_stop() - Remove child controllers and disconnect the controller
186  *
187  * @this:                       driver binding protocol
188  * @controller_handle:          handle of the controller
189  * @number_of_children:         number of child controllers to remove
190  * @child_handle_buffer:        handles of the child controllers to remove
191  * Return:                      status code
192  */
193 static efi_status_t EFIAPI efi_uc_stop(
194                 struct efi_driver_binding_protocol *this,
195                 efi_handle_t controller_handle,
196                 size_t number_of_children,
197                 efi_handle_t *child_handle_buffer)
198 {
199         efi_status_t ret;
200         efi_uintn_t count;
201         struct efi_open_protocol_info_entry *entry_buffer;
202         struct efi_driver_binding_extended_protocol *bp =
203                         (struct efi_driver_binding_extended_protocol *)this;
204
205         EFI_ENTRY("%p, %p, %zu, %p", this, controller_handle,
206                   number_of_children, child_handle_buffer);
207
208         /* Destroy provided child controllers */
209         if (number_of_children) {
210                 efi_uintn_t i;
211
212                 for (i = 0; i < number_of_children; ++i) {
213                         ret = disconnect_child(controller_handle,
214                                                child_handle_buffer[i]);
215                         if (ret != EFI_SUCCESS)
216                                 return ret;
217                 }
218                 return EFI_SUCCESS;
219         }
220
221         /* Destroy all children */
222         ret = EFI_CALL(systab.boottime->open_protocol_information(
223                                         controller_handle, bp->ops->protocol,
224                                         &entry_buffer, &count));
225         if (ret != EFI_SUCCESS)
226                 goto out;
227         while (count) {
228                 if (entry_buffer[--count].attributes &
229                     EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) {
230                         ret = disconnect_child(
231                                         controller_handle,
232                                         entry_buffer[count].agent_handle);
233                         if (ret != EFI_SUCCESS)
234                                 goto out;
235                 }
236         }
237         ret = EFI_CALL(systab.boottime->free_pool(entry_buffer));
238         if (ret != EFI_SUCCESS)
239                 printf("%s: ERROR: Cannot free pool\n", __func__);
240
241         /* Detach driver from controller */
242         ret = EFI_CALL(systab.boottime->close_protocol(
243                         controller_handle, bp->ops->protocol,
244                         this->driver_binding_handle, controller_handle));
245 out:
246         return EFI_EXIT(ret);
247 }
248
249 /**
250  * efi_add_driver() - add driver
251  *
252  * @drv:                driver to add
253  * Return:              status code
254  */
255 static efi_status_t efi_add_driver(struct driver *drv)
256 {
257         efi_status_t ret;
258         const struct efi_driver_ops *ops = drv->ops;
259         struct efi_driver_binding_extended_protocol *bp;
260
261         debug("EFI: Adding driver '%s'\n", drv->name);
262         if (!ops->protocol) {
263                 printf("EFI: ERROR: protocol GUID missing for driver '%s'\n",
264                        drv->name);
265                 return EFI_INVALID_PARAMETER;
266         }
267         bp = calloc(1, sizeof(struct efi_driver_binding_extended_protocol));
268         if (!bp)
269                 return EFI_OUT_OF_RESOURCES;
270
271         bp->bp.supported = efi_uc_supported;
272         bp->bp.start = efi_uc_start;
273         bp->bp.stop = efi_uc_stop;
274         bp->bp.version = 0xffffffff;
275         bp->ops = drv->ops;
276
277         ret = efi_create_handle(&bp->bp.driver_binding_handle);
278         if (ret != EFI_SUCCESS) {
279                 free(bp);
280                 goto out;
281         }
282         bp->bp.image_handle = bp->bp.driver_binding_handle;
283         ret = efi_add_protocol(bp->bp.driver_binding_handle,
284                                &efi_guid_driver_binding_protocol, bp);
285         if (ret != EFI_SUCCESS) {
286                 efi_delete_handle(bp->bp.driver_binding_handle);
287                 free(bp);
288                 goto out;
289         }
290 out:
291         return ret;
292 }
293
294 /**
295  * efi_driver_init() - initialize the EFI drivers
296  *
297  * Called by efi_init_obj_list().
298  *
299  * Return:      0 = success, any other value will stop further execution
300  */
301 efi_status_t efi_driver_init(void)
302 {
303         struct driver *drv;
304         efi_status_t ret = EFI_SUCCESS;
305
306         debug("EFI: Initializing EFI driver framework\n");
307         for (drv = ll_entry_start(struct driver, driver);
308              drv < ll_entry_end(struct driver, driver); ++drv) {
309                 if (drv->id == UCLASS_EFI) {
310                         ret = efi_add_driver(drv);
311                         if (ret != EFI_SUCCESS) {
312                                 printf("EFI: ERROR: failed to add driver %s\n",
313                                        drv->name);
314                                 break;
315                         }
316                 }
317         }
318         return ret;
319 }
320
321 /**
322  * efi_uc_init() - initialize the EFI uclass
323  *
324  * @class:      the EFI uclass
325  * Return:      0 = success
326  */
327 static int efi_uc_init(struct uclass *class)
328 {
329         printf("EFI: Initializing UCLASS_EFI\n");
330         return 0;
331 }
332
333 /**
334  * efi_uc_destroy() - destroy the EFI uclass
335  *
336  * @class:      the EFI uclass
337  * Return:      0 = success
338  */
339 static int efi_uc_destroy(struct uclass *class)
340 {
341         printf("Destroying  UCLASS_EFI\n");
342         return 0;
343 }
344
345 UCLASS_DRIVER(efi) = {
346         .name           = "efi",
347         .id             = UCLASS_EFI,
348         .init           = efi_uc_init,
349         .destroy        = efi_uc_destroy,
350 };