1 // SPDX-License-Identifier: GPL-2.0+
3 * Uclass for EFI drivers
5 * Copyright (c) 2017 Heinrich Schuchardt
7 * For each EFI driver the uclass
9 * - installs the driver binding protocol
11 * The uclass provides the bind, start, and stop entry points for the driver
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
20 #include <efi_driver.h>
23 * Check node type. We do not support partitions as controller handles.
25 * @handle handle to be checked
28 static efi_status_t check_node_type(efi_handle_t handle)
30 efi_status_t r, ret = EFI_SUCCESS;
31 const struct efi_device_path *dp;
33 /* Open the device path protocol */
34 r = EFI_CALL(systab.boottime->open_protocol(
35 handle, &efi_guid_device_path, (void **)&dp,
36 NULL, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL));
37 if (r == EFI_SUCCESS && dp) {
38 /* Get the last node */
39 const struct efi_device_path *node = efi_dp_last_node(dp);
40 /* We do not support partitions as controller */
41 if (!node || node->type == DEVICE_PATH_TYPE_MEDIA_DEVICE)
42 ret = EFI_UNSUPPORTED;
48 * Check if the driver supports the controller.
50 * @this driver binding protocol
51 * @controller_handle handle of the controller
52 * @remaining_device_path path specifying the child controller
55 static efi_status_t EFIAPI efi_uc_supported(
56 struct efi_driver_binding_protocol *this,
57 efi_handle_t controller_handle,
58 struct efi_device_path *remaining_device_path)
62 struct efi_driver_binding_extended_protocol *bp =
63 (struct efi_driver_binding_extended_protocol *)this;
65 EFI_ENTRY("%p, %p, %ls", this, controller_handle,
66 efi_dp_str(remaining_device_path));
68 ret = EFI_CALL(systab.boottime->open_protocol(
69 controller_handle, bp->ops->protocol,
70 &interface, this->driver_binding_handle,
71 controller_handle, EFI_OPEN_PROTOCOL_BY_DRIVER));
73 case EFI_ACCESS_DENIED:
74 case EFI_ALREADY_STARTED:
79 ret = EFI_UNSUPPORTED;
83 ret = check_node_type(controller_handle);
85 r = EFI_CALL(systab.boottime->close_protocol(
86 controller_handle, bp->ops->protocol,
87 this->driver_binding_handle,
90 ret = EFI_UNSUPPORTED;
96 * Create child controllers and attach driver.
98 * @this driver binding protocol
99 * @controller_handle handle of the controller
100 * @remaining_device_path path specifying the child controller
101 * @return status code
103 static efi_status_t EFIAPI efi_uc_start(
104 struct efi_driver_binding_protocol *this,
105 efi_handle_t controller_handle,
106 struct efi_device_path *remaining_device_path)
109 void *interface = NULL;
110 struct efi_driver_binding_extended_protocol *bp =
111 (struct efi_driver_binding_extended_protocol *)this;
113 EFI_ENTRY("%p, %pUl, %ls", this, controller_handle,
114 efi_dp_str(remaining_device_path));
116 /* Attach driver to controller */
117 ret = EFI_CALL(systab.boottime->open_protocol(
118 controller_handle, bp->ops->protocol,
119 &interface, this->driver_binding_handle,
120 controller_handle, EFI_OPEN_PROTOCOL_BY_DRIVER));
122 case EFI_ACCESS_DENIED:
123 case EFI_ALREADY_STARTED:
128 ret = EFI_UNSUPPORTED;
131 ret = check_node_type(controller_handle);
132 if (ret != EFI_SUCCESS) {
133 r = EFI_CALL(systab.boottime->close_protocol(
134 controller_handle, bp->ops->protocol,
135 this->driver_binding_handle,
137 if (r != EFI_SUCCESS)
138 EFI_PRINT("Failure to close handle\n");
142 /* TODO: driver specific stuff */
143 bp->ops->bind(controller_handle, interface);
146 return EFI_EXIT(ret);
150 * Remove a single child controller from the parent controller.
152 * @controller_handle parent controller
153 * @child_handle child controller
154 * @return status code
156 static efi_status_t disconnect_child(efi_handle_t controller_handle,
157 efi_handle_t child_handle)
160 efi_guid_t *guid_controller = NULL;
161 efi_guid_t *guid_child_controller = NULL;
163 ret = EFI_CALL(systab.boottime->close_protocol(
164 controller_handle, guid_controller,
165 child_handle, child_handle));
166 if (ret != EFI_SUCCESS) {
167 EFI_PRINT("Cannot close protocol\n");
170 ret = EFI_CALL(systab.boottime->uninstall_protocol_interface(
171 child_handle, guid_child_controller, NULL));
172 if (ret != EFI_SUCCESS) {
173 EFI_PRINT("Cannot uninstall protocol interface\n");
180 * Remove child controllers and disconnect the controller.
182 * @this driver binding protocol
183 * @controller_handle handle of the controller
184 * @number_of_children number of child controllers to remove
185 * @child_handle_buffer handles of the child controllers to remove
186 * @return status code
188 static efi_status_t EFIAPI efi_uc_stop(
189 struct efi_driver_binding_protocol *this,
190 efi_handle_t controller_handle,
191 size_t number_of_children,
192 efi_handle_t *child_handle_buffer)
196 struct efi_open_protocol_info_entry *entry_buffer;
197 efi_guid_t *guid_controller = NULL;
199 EFI_ENTRY("%p, %pUl, %zu, %p", this, controller_handle,
200 number_of_children, child_handle_buffer);
202 /* Destroy provided child controllers */
203 if (number_of_children) {
206 for (i = 0; i < number_of_children; ++i) {
207 ret = disconnect_child(controller_handle,
208 child_handle_buffer[i]);
209 if (ret != EFI_SUCCESS)
215 /* Destroy all children */
216 ret = EFI_CALL(systab.boottime->open_protocol_information(
217 controller_handle, guid_controller,
218 &entry_buffer, &count));
219 if (ret != EFI_SUCCESS)
222 if (entry_buffer[--count].attributes &
223 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) {
224 ret = disconnect_child(
226 entry_buffer[count].agent_handle);
227 if (ret != EFI_SUCCESS)
231 ret = EFI_CALL(systab.boottime->free_pool(entry_buffer));
232 if (ret != EFI_SUCCESS)
233 printf("%s(%u) %s: ERROR: Cannot free pool\n",
234 __FILE__, __LINE__, __func__);
236 /* Detach driver from controller */
237 ret = EFI_CALL(systab.boottime->close_protocol(
238 controller_handle, guid_controller,
239 this->driver_binding_handle, controller_handle));
241 return EFI_EXIT(ret);
244 static efi_status_t efi_add_driver(struct driver *drv)
247 const struct efi_driver_ops *ops = drv->ops;
248 struct efi_driver_binding_extended_protocol *bp;
250 debug("EFI: Adding driver '%s'\n", drv->name);
251 if (!ops->protocol) {
252 printf("EFI: ERROR: protocol GUID missing for driver '%s'\n",
254 return EFI_INVALID_PARAMETER;
256 bp = calloc(1, sizeof(struct efi_driver_binding_extended_protocol));
258 return EFI_OUT_OF_RESOURCES;
260 bp->bp.supported = efi_uc_supported;
261 bp->bp.start = efi_uc_start;
262 bp->bp.stop = efi_uc_stop;
263 bp->bp.version = 0xffffffff;
266 ret = efi_create_handle(&bp->bp.driver_binding_handle);
267 if (ret != EFI_SUCCESS) {
271 bp->bp.image_handle = bp->bp.driver_binding_handle;
272 ret = efi_add_protocol(bp->bp.driver_binding_handle,
273 &efi_guid_driver_binding_protocol, bp);
274 if (ret != EFI_SUCCESS) {
275 efi_delete_handle(bp->bp.driver_binding_handle);
284 * Initialize the EFI drivers.
285 * Called by board_init_r().
287 * @return 0 = success, any other value will stop further execution
289 efi_status_t efi_driver_init(void)
292 efi_status_t ret = EFI_SUCCESS;
294 /* Save 'gd' pointer */
297 debug("EFI: Initializing EFI driver framework\n");
298 for (drv = ll_entry_start(struct driver, driver);
299 drv < ll_entry_end(struct driver, driver); ++drv) {
300 if (drv->id == UCLASS_EFI) {
301 ret = efi_add_driver(drv);
302 if (ret != EFI_SUCCESS) {
303 printf("EFI: ERROR: failed to add driver %s\n",
312 static int efi_uc_init(struct uclass *class)
314 printf("EFI: Initializing UCLASS_EFI\n");
318 static int efi_uc_destroy(struct uclass *class)
320 printf("Destroying UCLASS_EFI\n");
324 UCLASS_DRIVER(efi) = {
328 .destroy = efi_uc_destroy,