uboot/lib/efi_driver/efi_uclass.c
<<
>>
Prefs
   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 */
  34static 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 */
  61static 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;
 105out:
 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 */
 117static 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
 152err:
 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
 159out:
 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 */
 171static 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 */
 202static 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);
 255out:
 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 */
 265static 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                free(bp);
 290                goto out;
 291        }
 292        bp->bp.image_handle = bp->bp.driver_binding_handle;
 293        ret = efi_add_protocol(bp->bp.driver_binding_handle,
 294                               &efi_guid_driver_binding_protocol, bp);
 295        if (ret != EFI_SUCCESS)
 296                goto err;
 297        if (ops->init) {
 298                ret = ops->init(bp);
 299                if (ret != EFI_SUCCESS)
 300                        goto err;
 301        }
 302out:
 303        return ret;
 304
 305err:
 306        efi_delete_handle(bp->bp.driver_binding_handle);
 307        free(bp);
 308        return ret;
 309}
 310
 311/**
 312 * efi_driver_init() - initialize the EFI drivers
 313 *
 314 * Called by efi_init_obj_list().
 315 *
 316 * Return:      0 = success, any other value will stop further execution
 317 */
 318efi_status_t efi_driver_init(void)
 319{
 320        struct driver *drv;
 321        efi_status_t ret = EFI_SUCCESS;
 322
 323        log_debug("Initializing EFI driver framework\n");
 324        for (drv = ll_entry_start(struct driver, driver);
 325             drv < ll_entry_end(struct driver, driver); ++drv) {
 326                if (drv->id == UCLASS_EFI_LOADER) {
 327                        ret = efi_add_driver(drv);
 328                        if (ret != EFI_SUCCESS) {
 329                                log_err("Failed to add EFI driver %s\n",
 330                                        drv->name);
 331                                break;
 332                        }
 333                }
 334        }
 335        return ret;
 336}
 337
 338/**
 339 * efi_uc_init() - initialize the EFI uclass
 340 *
 341 * @class:      the EFI uclass
 342 * Return:      0 = success
 343 */
 344static int efi_uc_init(struct uclass *class)
 345{
 346        log_debug("Initializing UCLASS_EFI_LOADER\n");
 347        return 0;
 348}
 349
 350/**
 351 * efi_uc_destroy() - destroy the EFI uclass
 352 *
 353 * @class:      the EFI uclass
 354 * Return:      0 = success
 355 */
 356static int efi_uc_destroy(struct uclass *class)
 357{
 358        log_debug("Destroying UCLASS_EFI_LOADER\n");
 359        return 0;
 360}
 361
 362UCLASS_DRIVER(efi) = {
 363        .name           = "efi",
 364        .id             = UCLASS_EFI_LOADER,
 365        .init           = efi_uc_init,
 366        .destroy        = efi_uc_destroy,
 367};
 368