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