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