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 <efi_driver.h>
  21
  22/*
  23 * Check node type. We do not support partitions as controller handles.
  24 *
  25 * @handle      handle to be checked
  26 * @return      status code
  27 */
  28static efi_status_t check_node_type(efi_handle_t handle)
  29{
  30        efi_status_t r, ret = EFI_SUCCESS;
  31        const struct efi_device_path *dp;
  32
  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;
  43        }
  44        return ret;
  45}
  46
  47/*
  48 * Check if the driver supports the controller.
  49 *
  50 * @this                        driver binding protocol
  51 * @controller_handle           handle of the controller
  52 * @remaining_device_path       path specifying the child controller
  53 * @return                      status code
  54 */
  55static 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)
  59{
  60        efi_status_t r, ret;
  61        void *interface;
  62        struct efi_driver_binding_extended_protocol *bp =
  63                        (struct efi_driver_binding_extended_protocol *)this;
  64
  65        EFI_ENTRY("%p, %p, %ls", this, controller_handle,
  66                  efi_dp_str(remaining_device_path));
  67
  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));
  72        switch (ret) {
  73        case EFI_ACCESS_DENIED:
  74        case EFI_ALREADY_STARTED:
  75                goto out;
  76        case EFI_SUCCESS:
  77                break;
  78        default:
  79                ret = EFI_UNSUPPORTED;
  80                goto out;
  81        }
  82
  83        ret = check_node_type(controller_handle);
  84
  85        r = EFI_CALL(systab.boottime->close_protocol(
  86                                controller_handle, bp->ops->protocol,
  87                                this->driver_binding_handle,
  88                                controller_handle));
  89        if (r != EFI_SUCCESS)
  90                ret = EFI_UNSUPPORTED;
  91out:
  92        return EFI_EXIT(ret);
  93}
  94
  95/*
  96 * Create child controllers and attach driver.
  97 *
  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
 102 */
 103static 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)
 107{
 108        efi_status_t r, ret;
 109        void *interface = NULL;
 110        struct efi_driver_binding_extended_protocol *bp =
 111                        (struct efi_driver_binding_extended_protocol *)this;
 112
 113        EFI_ENTRY("%p, %pUl, %ls", this, controller_handle,
 114                  efi_dp_str(remaining_device_path));
 115
 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));
 121        switch (ret) {
 122        case EFI_ACCESS_DENIED:
 123        case EFI_ALREADY_STARTED:
 124                goto out;
 125        case EFI_SUCCESS:
 126                break;
 127        default:
 128                ret =  EFI_UNSUPPORTED;
 129                goto out;
 130        }
 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,
 136                                controller_handle));
 137                if (r != EFI_SUCCESS)
 138                        EFI_PRINT("Failure to close handle\n");
 139                goto out;
 140        }
 141
 142        /* TODO: driver specific stuff */
 143        bp->ops->bind(controller_handle, interface);
 144
 145out:
 146        return EFI_EXIT(ret);
 147}
 148
 149/*
 150 * Remove a single child controller from the parent controller.
 151 *
 152 * @controller_handle   parent controller
 153 * @child_handle        child controller
 154 * @return              status code
 155 */
 156static efi_status_t disconnect_child(efi_handle_t controller_handle,
 157                                     efi_handle_t child_handle)
 158{
 159        efi_status_t ret;
 160        efi_guid_t *guid_controller = NULL;
 161        efi_guid_t *guid_child_controller = NULL;
 162
 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");
 168                return ret;
 169        }
 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");
 174                return ret;
 175        }
 176        return ret;
 177}
 178
 179/*
 180 * Remove child controllers and disconnect the controller.
 181 *
 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
 187 */
 188static 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)
 193{
 194        efi_status_t ret;
 195        efi_uintn_t count;
 196        struct efi_open_protocol_info_entry *entry_buffer;
 197        efi_guid_t *guid_controller = NULL;
 198
 199        EFI_ENTRY("%p, %pUl, %zu, %p", this, controller_handle,
 200                  number_of_children, child_handle_buffer);
 201
 202        /* Destroy provided child controllers */
 203        if (number_of_children) {
 204                efi_uintn_t i;
 205
 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)
 210                                return ret;
 211                }
 212                return EFI_SUCCESS;
 213        }
 214
 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)
 220                goto out;
 221        while (count) {
 222                if (entry_buffer[--count].attributes &
 223                    EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) {
 224                        ret = disconnect_child(
 225                                        controller_handle,
 226                                        entry_buffer[count].agent_handle);
 227                        if (ret != EFI_SUCCESS)
 228                                goto out;
 229                }
 230        }
 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__);
 235
 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));
 240out:
 241        return EFI_EXIT(ret);
 242}
 243
 244static efi_status_t efi_add_driver(struct driver *drv)
 245{
 246        efi_status_t ret;
 247        const struct efi_driver_ops *ops = drv->ops;
 248        struct efi_driver_binding_extended_protocol *bp;
 249
 250        debug("EFI: Adding driver '%s'\n", drv->name);
 251        if (!ops->protocol) {
 252                printf("EFI: ERROR: protocol GUID missing for driver '%s'\n",
 253                       drv->name);
 254                return EFI_INVALID_PARAMETER;
 255        }
 256        bp = calloc(1, sizeof(struct efi_driver_binding_extended_protocol));
 257        if (!bp)
 258                return EFI_OUT_OF_RESOURCES;
 259
 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;
 264        bp->ops = drv->ops;
 265
 266        ret = efi_create_handle(&bp->bp.driver_binding_handle);
 267        if (ret != EFI_SUCCESS) {
 268                free(bp);
 269                goto out;
 270        }
 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);
 276                free(bp);
 277                goto out;
 278        }
 279out:
 280        return ret;
 281}
 282
 283/*
 284 * Initialize the EFI drivers.
 285 * Called by board_init_r().
 286 *
 287 * @return      0 = success, any other value will stop further execution
 288 */
 289efi_status_t efi_driver_init(void)
 290{
 291        struct driver *drv;
 292        efi_status_t ret = EFI_SUCCESS;
 293
 294        /* Save 'gd' pointer */
 295        efi_save_gd();
 296
 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",
 304                                       drv->name);
 305                                break;
 306                        }
 307                }
 308        }
 309        return ret;
 310}
 311
 312static int efi_uc_init(struct uclass *class)
 313{
 314        printf("EFI: Initializing UCLASS_EFI\n");
 315        return 0;
 316}
 317
 318static int efi_uc_destroy(struct uclass *class)
 319{
 320        printf("Destroying  UCLASS_EFI\n");
 321        return 0;
 322}
 323
 324UCLASS_DRIVER(efi) = {
 325        .name           = "efi",
 326        .id             = UCLASS_EFI,
 327        .init           = efi_uc_init,
 328        .destroy        = efi_uc_destroy,
 329};
 330