uboot/lib/efi_loader/efi_disk.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 *  EFI application disk support
   4 *
   5 *  Copyright (c) 2016 Alexander Graf
   6 */
   7
   8#define LOG_CATEGORY LOGC_EFI
   9
  10#include <common.h>
  11#include <blk.h>
  12#include <dm.h>
  13#include <dm/device-internal.h>
  14#include <dm/tag.h>
  15#include <event.h>
  16#include <efi_driver.h>
  17#include <efi_loader.h>
  18#include <fs.h>
  19#include <log.h>
  20#include <part.h>
  21#include <malloc.h>
  22
  23struct efi_system_partition efi_system_partition = {
  24        .uclass_id = UCLASS_INVALID,
  25};
  26
  27const efi_guid_t efi_block_io_guid = EFI_BLOCK_IO_PROTOCOL_GUID;
  28const efi_guid_t efi_system_partition_guid = PARTITION_SYSTEM_GUID;
  29
  30/**
  31 * struct efi_disk_obj - EFI disk object
  32 *
  33 * @header:     EFI object header
  34 * @ops:        EFI disk I/O protocol interface
  35 * @dev_index:  device index of block device
  36 * @media:      block I/O media information
  37 * @dp:         device path to the block device
  38 * @part:       partition
  39 * @volume:     simple file system protocol of the partition
  40 * @dev:        associated DM device
  41 */
  42struct efi_disk_obj {
  43        struct efi_object header;
  44        struct efi_block_io ops;
  45        int dev_index;
  46        struct efi_block_io_media media;
  47        struct efi_device_path *dp;
  48        unsigned int part;
  49        struct efi_simple_file_system_protocol *volume;
  50};
  51
  52/**
  53 * efi_disk_reset() - reset block device
  54 *
  55 * This function implements the Reset service of the EFI_BLOCK_IO_PROTOCOL.
  56 *
  57 * As U-Boot's block devices do not have a reset function simply return
  58 * EFI_SUCCESS.
  59 *
  60 * See the Unified Extensible Firmware Interface (UEFI) specification for
  61 * details.
  62 *
  63 * @this:                       pointer to the BLOCK_IO_PROTOCOL
  64 * @extended_verification:      extended verification
  65 * Return:                      status code
  66 */
  67static efi_status_t EFIAPI efi_disk_reset(struct efi_block_io *this,
  68                        char extended_verification)
  69{
  70        EFI_ENTRY("%p, %x", this, extended_verification);
  71        return EFI_EXIT(EFI_SUCCESS);
  72}
  73
  74/**
  75 * efi_disk_is_removable() - check if the device is removable media
  76 * @handle:             efi object handle;
  77 *
  78 * Examine the device and determine if the device is a local block device
  79 * and removable media.
  80 *
  81 * Return:              true if removable, false otherwise
  82 */
  83bool efi_disk_is_removable(efi_handle_t handle)
  84{
  85        struct efi_handler *handler;
  86        struct efi_block_io *io;
  87        efi_status_t ret;
  88
  89        ret = efi_search_protocol(handle, &efi_block_io_guid, &handler);
  90        if (ret != EFI_SUCCESS)
  91                return false;
  92
  93        io = handler->protocol_interface;
  94
  95        if (!io || !io->media)
  96                return false;
  97
  98        return (bool)io->media->removable_media;
  99}
 100
 101enum efi_disk_direction {
 102        EFI_DISK_READ,
 103        EFI_DISK_WRITE,
 104};
 105
 106static efi_status_t efi_disk_rw_blocks(struct efi_block_io *this,
 107                        u32 media_id, u64 lba, unsigned long buffer_size,
 108                        void *buffer, enum efi_disk_direction direction)
 109{
 110        struct efi_disk_obj *diskobj;
 111        int blksz;
 112        int blocks;
 113        unsigned long n;
 114
 115        diskobj = container_of(this, struct efi_disk_obj, ops);
 116        blksz = diskobj->media.block_size;
 117        blocks = buffer_size / blksz;
 118
 119        EFI_PRINT("blocks=%x lba=%llx blksz=%x dir=%d\n",
 120                  blocks, lba, blksz, direction);
 121
 122        /* We only support full block access */
 123        if (buffer_size & (blksz - 1))
 124                return EFI_BAD_BUFFER_SIZE;
 125
 126        if (CONFIG_IS_ENABLED(PARTITIONS) &&
 127            device_get_uclass_id(diskobj->header.dev) == UCLASS_PARTITION) {
 128                if (direction == EFI_DISK_READ)
 129                        n = disk_blk_read(diskobj->header.dev, lba, blocks,
 130                                          buffer);
 131                else
 132                        n = disk_blk_write(diskobj->header.dev, lba, blocks,
 133                                           buffer);
 134        } else {
 135                /* dev is a block device (UCLASS_BLK) */
 136                struct blk_desc *desc;
 137
 138                desc = dev_get_uclass_plat(diskobj->header.dev);
 139                if (direction == EFI_DISK_READ)
 140                        n = blk_dread(desc, lba, blocks, buffer);
 141                else
 142                        n = blk_dwrite(desc, lba, blocks, buffer);
 143        }
 144
 145        /* We don't do interrupts, so check for timers cooperatively */
 146        efi_timer_check();
 147
 148        EFI_PRINT("n=%lx blocks=%x\n", n, blocks);
 149
 150        if (n != blocks)
 151                return EFI_DEVICE_ERROR;
 152
 153        return EFI_SUCCESS;
 154}
 155
 156/**
 157 * efi_disk_read_blocks() - reads blocks from device
 158 *
 159 * This function implements the ReadBlocks service of the EFI_BLOCK_IO_PROTOCOL.
 160 *
 161 * See the Unified Extensible Firmware Interface (UEFI) specification for
 162 * details.
 163 *
 164 * @this:                       pointer to the BLOCK_IO_PROTOCOL
 165 * @media_id:                   id of the medium to be read from
 166 * @lba:                        starting logical block for reading
 167 * @buffer_size:                size of the read buffer
 168 * @buffer:                     pointer to the destination buffer
 169 * Return:                      status code
 170 */
 171static efi_status_t EFIAPI efi_disk_read_blocks(struct efi_block_io *this,
 172                        u32 media_id, u64 lba, efi_uintn_t buffer_size,
 173                        void *buffer)
 174{
 175        void *real_buffer = buffer;
 176        efi_status_t r;
 177
 178        if (!this)
 179                return EFI_INVALID_PARAMETER;
 180        /* TODO: check for media changes */
 181        if (media_id != this->media->media_id)
 182                return EFI_MEDIA_CHANGED;
 183        if (!this->media->media_present)
 184                return EFI_NO_MEDIA;
 185        /* media->io_align is a power of 2 or 0 */
 186        if (this->media->io_align &&
 187            (uintptr_t)buffer & (this->media->io_align - 1))
 188                return EFI_INVALID_PARAMETER;
 189        if (lba * this->media->block_size + buffer_size >
 190            (this->media->last_block + 1) * this->media->block_size)
 191                return EFI_INVALID_PARAMETER;
 192
 193#ifdef CONFIG_EFI_LOADER_BOUNCE_BUFFER
 194        if (buffer_size > EFI_LOADER_BOUNCE_BUFFER_SIZE) {
 195                r = efi_disk_read_blocks(this, media_id, lba,
 196                        EFI_LOADER_BOUNCE_BUFFER_SIZE, buffer);
 197                if (r != EFI_SUCCESS)
 198                        return r;
 199                return efi_disk_read_blocks(this, media_id, lba +
 200                        EFI_LOADER_BOUNCE_BUFFER_SIZE / this->media->block_size,
 201                        buffer_size - EFI_LOADER_BOUNCE_BUFFER_SIZE,
 202                        buffer + EFI_LOADER_BOUNCE_BUFFER_SIZE);
 203        }
 204
 205        real_buffer = efi_bounce_buffer;
 206#endif
 207
 208        EFI_ENTRY("%p, %x, %llx, %zx, %p", this, media_id, lba,
 209                  buffer_size, buffer);
 210
 211        r = efi_disk_rw_blocks(this, media_id, lba, buffer_size, real_buffer,
 212                               EFI_DISK_READ);
 213
 214        /* Copy from bounce buffer to real buffer if necessary */
 215        if ((r == EFI_SUCCESS) && (real_buffer != buffer))
 216                memcpy(buffer, real_buffer, buffer_size);
 217
 218        return EFI_EXIT(r);
 219}
 220
 221/**
 222 * efi_disk_write_blocks() - writes blocks to device
 223 *
 224 * This function implements the WriteBlocks service of the
 225 * EFI_BLOCK_IO_PROTOCOL.
 226 *
 227 * See the Unified Extensible Firmware Interface (UEFI) specification for
 228 * details.
 229 *
 230 * @this:                       pointer to the BLOCK_IO_PROTOCOL
 231 * @media_id:                   id of the medium to be written to
 232 * @lba:                        starting logical block for writing
 233 * @buffer_size:                size of the write buffer
 234 * @buffer:                     pointer to the source buffer
 235 * Return:                      status code
 236 */
 237static efi_status_t EFIAPI efi_disk_write_blocks(struct efi_block_io *this,
 238                        u32 media_id, u64 lba, efi_uintn_t buffer_size,
 239                        void *buffer)
 240{
 241        void *real_buffer = buffer;
 242        efi_status_t r;
 243
 244        if (!this)
 245                return EFI_INVALID_PARAMETER;
 246        if (this->media->read_only)
 247                return EFI_WRITE_PROTECTED;
 248        /* TODO: check for media changes */
 249        if (media_id != this->media->media_id)
 250                return EFI_MEDIA_CHANGED;
 251        if (!this->media->media_present)
 252                return EFI_NO_MEDIA;
 253        /* media->io_align is a power of 2 or 0 */
 254        if (this->media->io_align &&
 255            (uintptr_t)buffer & (this->media->io_align - 1))
 256                return EFI_INVALID_PARAMETER;
 257        if (lba * this->media->block_size + buffer_size >
 258            (this->media->last_block + 1) * this->media->block_size)
 259                return EFI_INVALID_PARAMETER;
 260
 261#ifdef CONFIG_EFI_LOADER_BOUNCE_BUFFER
 262        if (buffer_size > EFI_LOADER_BOUNCE_BUFFER_SIZE) {
 263                r = efi_disk_write_blocks(this, media_id, lba,
 264                        EFI_LOADER_BOUNCE_BUFFER_SIZE, buffer);
 265                if (r != EFI_SUCCESS)
 266                        return r;
 267                return efi_disk_write_blocks(this, media_id, lba +
 268                        EFI_LOADER_BOUNCE_BUFFER_SIZE / this->media->block_size,
 269                        buffer_size - EFI_LOADER_BOUNCE_BUFFER_SIZE,
 270                        buffer + EFI_LOADER_BOUNCE_BUFFER_SIZE);
 271        }
 272
 273        real_buffer = efi_bounce_buffer;
 274#endif
 275
 276        EFI_ENTRY("%p, %x, %llx, %zx, %p", this, media_id, lba,
 277                  buffer_size, buffer);
 278
 279        /* Populate bounce buffer if necessary */
 280        if (real_buffer != buffer)
 281                memcpy(real_buffer, buffer, buffer_size);
 282
 283        r = efi_disk_rw_blocks(this, media_id, lba, buffer_size, real_buffer,
 284                               EFI_DISK_WRITE);
 285
 286        return EFI_EXIT(r);
 287}
 288
 289/**
 290 * efi_disk_flush_blocks() - flushes modified data to the device
 291 *
 292 * This function implements the FlushBlocks service of the
 293 * EFI_BLOCK_IO_PROTOCOL.
 294 *
 295 * As we always write synchronously nothing is done here.
 296 *
 297 * See the Unified Extensible Firmware Interface (UEFI) specification for
 298 * details.
 299 *
 300 * @this:                       pointer to the BLOCK_IO_PROTOCOL
 301 * Return:                      status code
 302 */
 303static efi_status_t EFIAPI efi_disk_flush_blocks(struct efi_block_io *this)
 304{
 305        EFI_ENTRY("%p", this);
 306        return EFI_EXIT(EFI_SUCCESS);
 307}
 308
 309static const struct efi_block_io block_io_disk_template = {
 310        .reset = &efi_disk_reset,
 311        .read_blocks = &efi_disk_read_blocks,
 312        .write_blocks = &efi_disk_write_blocks,
 313        .flush_blocks = &efi_disk_flush_blocks,
 314};
 315
 316/**
 317 * efi_fs_from_path() - retrieve simple file system protocol
 318 *
 319 * Gets the simple file system protocol for a file device path.
 320 *
 321 * The full path provided is split into device part and into a file
 322 * part. The device part is used to find the handle on which the
 323 * simple file system protocol is installed.
 324 *
 325 * @full_path:  device path including device and file
 326 * Return:      simple file system protocol
 327 */
 328struct efi_simple_file_system_protocol *
 329efi_fs_from_path(struct efi_device_path *full_path)
 330{
 331        struct efi_object *efiobj;
 332        struct efi_handler *handler;
 333        struct efi_device_path *device_path;
 334        struct efi_device_path *file_path;
 335        efi_status_t ret;
 336
 337        /* Split the path into a device part and a file part */
 338        ret = efi_dp_split_file_path(full_path, &device_path, &file_path);
 339        if (ret != EFI_SUCCESS)
 340                return NULL;
 341        efi_free_pool(file_path);
 342
 343        /* Get the EFI object for the partition */
 344        efiobj = efi_dp_find_obj(device_path, NULL, NULL);
 345        efi_free_pool(device_path);
 346        if (!efiobj)
 347                return NULL;
 348
 349        /* Find the simple file system protocol */
 350        ret = efi_search_protocol(efiobj, &efi_simple_file_system_protocol_guid,
 351                                  &handler);
 352        if (ret != EFI_SUCCESS)
 353                return NULL;
 354
 355        /* Return the simple file system protocol for the partition */
 356        return handler->protocol_interface;
 357}
 358
 359/**
 360 * efi_fs_exists() - check if a partition bears a file system
 361 *
 362 * @desc:       block device descriptor
 363 * @part:       partition number
 364 * Return:      1 if a file system exists on the partition
 365 *              0 otherwise
 366 */
 367static int efi_fs_exists(struct blk_desc *desc, int part)
 368{
 369        if (fs_set_blk_dev_with_part(desc, part))
 370                return 0;
 371
 372        if (fs_get_type() == FS_TYPE_ANY)
 373                return 0;
 374
 375        fs_close();
 376
 377        return 1;
 378}
 379
 380/**
 381 * efi_disk_add_dev() - create a handle for a partition or disk
 382 *
 383 * @parent:             parent handle
 384 * @dp_parent:          parent device path
 385 * @desc:               internal block device
 386 * @dev_index:          device index for block device
 387 * @part_info:          partition info
 388 * @part:               partition
 389 * @disk:               pointer to receive the created handle
 390 * @agent_handle:       handle of the EFI block driver
 391 * Return:              disk object
 392 */
 393static efi_status_t efi_disk_add_dev(
 394                                efi_handle_t parent,
 395                                struct efi_device_path *dp_parent,
 396                                struct blk_desc *desc,
 397                                int dev_index,
 398                                struct disk_partition *part_info,
 399                                unsigned int part,
 400                                struct efi_disk_obj **disk,
 401                                efi_handle_t agent_handle)
 402{
 403        struct efi_disk_obj *diskobj;
 404        struct efi_object *handle;
 405        const efi_guid_t *esp_guid = NULL;
 406        efi_status_t ret;
 407
 408        /* Don't add empty devices */
 409        if (!desc->lba)
 410                return EFI_NOT_READY;
 411
 412        diskobj = calloc(1, sizeof(*diskobj));
 413        if (!diskobj)
 414                return EFI_OUT_OF_RESOURCES;
 415
 416        /* Hook up to the device list */
 417        efi_add_handle(&diskobj->header);
 418
 419        /* Fill in object data */
 420        if (part_info) {
 421                struct efi_device_path *node = efi_dp_part_node(desc, part);
 422                struct efi_handler *handler;
 423                void *protocol_interface;
 424
 425                if (!node) {
 426                        ret = EFI_OUT_OF_RESOURCES;
 427                        log_debug("no node\n");
 428                        goto error;
 429                }
 430
 431                /* Parent must expose EFI_BLOCK_IO_PROTOCOL */
 432                ret = efi_search_protocol(parent, &efi_block_io_guid, &handler);
 433                if (ret != EFI_SUCCESS) {
 434                        log_debug("search failed\n");
 435                        goto error;
 436                }
 437
 438                /*
 439                 * Link the partition (child controller) to the block device
 440                 * (controller).
 441                 */
 442                ret = efi_protocol_open(handler, &protocol_interface, NULL,
 443                                        &diskobj->header,
 444                                        EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER);
 445                if (ret != EFI_SUCCESS) {
 446                        log_debug("prot open failed\n");
 447                        goto error;
 448                }
 449
 450                diskobj->dp = efi_dp_append_node(dp_parent, node);
 451                efi_free_pool(node);
 452                diskobj->media.last_block = part_info->size - 1;
 453                if (part_info->bootable & PART_EFI_SYSTEM_PARTITION)
 454                        esp_guid = &efi_system_partition_guid;
 455        } else {
 456                diskobj->dp = efi_dp_from_part(desc, part);
 457                diskobj->media.last_block = desc->lba - 1;
 458        }
 459        diskobj->part = part;
 460
 461        /*
 462         * Install the device path and the block IO protocol.
 463         *
 464         * InstallMultipleProtocolInterfaces() checks if the device path is
 465         * already installed on an other handle and returns EFI_ALREADY_STARTED
 466         * in this case.
 467         */
 468        handle = &diskobj->header;
 469        ret = efi_install_multiple_protocol_interfaces(
 470                                        &handle,
 471                                        &efi_guid_device_path, diskobj->dp,
 472                                        &efi_block_io_guid, &diskobj->ops,
 473                                        /*
 474                                         * esp_guid must be last entry as it
 475                                         * can be NULL. Its interface is NULL.
 476                                         */
 477                                        esp_guid, NULL,
 478                                        NULL);
 479        if (ret != EFI_SUCCESS) {
 480                log_debug("install failed %lx\n", ret);
 481                goto error;
 482        }
 483
 484        /*
 485         * On partitions or whole disks without partitions install the
 486         * simple file system protocol if a file system is available.
 487         */
 488        if ((part || desc->part_type == PART_TYPE_UNKNOWN) &&
 489            efi_fs_exists(desc, part)) {
 490                diskobj->volume = efi_simple_file_system(desc, part,
 491                                                         diskobj->dp);
 492                ret = efi_add_protocol(&diskobj->header,
 493                                       &efi_simple_file_system_protocol_guid,
 494                                       diskobj->volume);
 495                if (ret != EFI_SUCCESS) {
 496                        log_debug("simple FS failed\n");
 497                        return ret;
 498                }
 499        }
 500        diskobj->ops = block_io_disk_template;
 501        diskobj->dev_index = dev_index;
 502
 503        /* Fill in EFI IO Media info (for read/write callbacks) */
 504        diskobj->media.removable_media = desc->removable;
 505        diskobj->media.media_present = 1;
 506        /*
 507         * MediaID is just an arbitrary counter.
 508         * We have to change it if the medium is removed or changed.
 509         */
 510        diskobj->media.media_id = 1;
 511        diskobj->media.block_size = desc->blksz;
 512        diskobj->media.io_align = desc->blksz;
 513        if (part)
 514                diskobj->media.logical_partition = 1;
 515        diskobj->ops.media = &diskobj->media;
 516        if (disk)
 517                *disk = diskobj;
 518
 519        EFI_PRINT("BlockIO: part %u, present %d, logical %d, removable %d"
 520                  ", last_block %llu\n",
 521                  diskobj->part,
 522                  diskobj->media.media_present,
 523                  diskobj->media.logical_partition,
 524                  diskobj->media.removable_media,
 525                  diskobj->media.last_block);
 526
 527        /* Store first EFI system partition */
 528        if (part && efi_system_partition.uclass_id == UCLASS_INVALID) {
 529                if (part_info->bootable & PART_EFI_SYSTEM_PARTITION) {
 530                        efi_system_partition.uclass_id = desc->uclass_id;
 531                        efi_system_partition.devnum = desc->devnum;
 532                        efi_system_partition.part = part;
 533                        EFI_PRINT("EFI system partition: %s %x:%x\n",
 534                                  blk_get_uclass_name(desc->uclass_id),
 535                                  desc->devnum, part);
 536                }
 537        }
 538        return EFI_SUCCESS;
 539error:
 540        efi_delete_handle(&diskobj->header);
 541        return ret;
 542}
 543
 544/**
 545 * efi_disk_create_raw() - create a handle for a whole raw disk
 546 *
 547 * @dev:                udevice (UCLASS_BLK)
 548 * @agent_handle:       handle of the EFI block driver
 549 *
 550 * Create an efi_disk object which is associated with @dev.
 551 * The type of @dev must be UCLASS_BLK.
 552 *
 553 * Return:              0 on success, -1 otherwise
 554 */
 555static int efi_disk_create_raw(struct udevice *dev, efi_handle_t agent_handle)
 556{
 557        struct efi_disk_obj *disk;
 558        struct blk_desc *desc;
 559        int diskid;
 560        efi_status_t ret;
 561
 562        desc = dev_get_uclass_plat(dev);
 563        diskid = desc->devnum;
 564
 565        ret = efi_disk_add_dev(NULL, NULL, desc,
 566                               diskid, NULL, 0, &disk, agent_handle);
 567        if (ret != EFI_SUCCESS) {
 568                if (ret == EFI_NOT_READY) {
 569                        log_notice("Disk %s not ready\n", dev->name);
 570                        ret = -EBUSY;
 571                } else {
 572                        log_err("Adding disk for %s failed (err=%ld/%#lx)\n", dev->name, ret, ret);
 573                        ret = -ENOENT;
 574                }
 575
 576                return ret;
 577        }
 578        if (efi_link_dev(&disk->header, dev)) {
 579                efi_free_pool(disk->dp);
 580                efi_delete_handle(&disk->header);
 581
 582                return -EINVAL;
 583        }
 584
 585        return 0;
 586}
 587
 588/**
 589 * efi_disk_create_part() - create a handle for a disk partition
 590 *
 591 * @dev:                udevice (UCLASS_PARTITION)
 592 * @agent_handle:       handle of the EFI block driver
 593 *
 594 * Create an efi_disk object which is associated with @dev.
 595 * The type of @dev must be UCLASS_PARTITION.
 596 *
 597 * Return:              0 on success, -1 otherwise
 598 */
 599static int efi_disk_create_part(struct udevice *dev, efi_handle_t agent_handle)
 600{
 601        efi_handle_t parent;
 602        struct blk_desc *desc;
 603        struct disk_part *part_data;
 604        struct disk_partition *info;
 605        unsigned int part;
 606        int diskid;
 607        struct efi_handler *handler;
 608        struct efi_device_path *dp_parent;
 609        struct efi_disk_obj *disk;
 610        efi_status_t ret;
 611
 612        if (dev_tag_get_ptr(dev_get_parent(dev), DM_TAG_EFI, (void **)&parent))
 613                return -1;
 614
 615        desc = dev_get_uclass_plat(dev_get_parent(dev));
 616        diskid = desc->devnum;
 617
 618        part_data = dev_get_uclass_plat(dev);
 619        part = part_data->partnum;
 620        info = &part_data->gpt_part_info;
 621
 622        ret = efi_search_protocol(parent, &efi_guid_device_path, &handler);
 623        if (ret != EFI_SUCCESS)
 624                return -1;
 625        dp_parent = (struct efi_device_path *)handler->protocol_interface;
 626
 627        ret = efi_disk_add_dev(parent, dp_parent, desc, diskid,
 628                               info, part, &disk, agent_handle);
 629        if (ret != EFI_SUCCESS) {
 630                log_err("Adding partition for %s failed\n", dev->name);
 631                return -1;
 632        }
 633        if (efi_link_dev(&disk->header, dev)) {
 634                efi_free_pool(disk->dp);
 635                efi_delete_handle(&disk->header);
 636
 637                return -1;
 638        }
 639
 640        return 0;
 641}
 642
 643/**
 644 * efi_disk_probe() - create efi_disk objects for a block device
 645 *
 646 * @ctx:        event context - driver binding protocol
 647 * @event:      EV_PM_POST_PROBE event
 648 *
 649 * Create efi_disk objects for partitions as well as a raw disk
 650 * which is associated with @dev.
 651 * The type of @dev must be UCLASS_BLK.
 652 * This function is expected to be called at EV_PM_POST_PROBE.
 653 *
 654 * Return:      0 on success, -1 otherwise
 655 */
 656int efi_disk_probe(void *ctx, struct event *event)
 657{
 658        struct udevice *dev;
 659        enum uclass_id id;
 660        struct blk_desc *desc;
 661        struct udevice *child;
 662        struct efi_driver_binding_extended_protocol *db_prot = ctx;
 663        efi_handle_t agent_handle = db_prot->bp.driver_binding_handle;
 664        int ret;
 665
 666        dev = event->data.dm.dev;
 667        id = device_get_uclass_id(dev);
 668
 669        /* We won't support partitions in a partition */
 670        if (id != UCLASS_BLK)
 671                return 0;
 672
 673        /*
 674         * Avoid creating duplicated objects now that efi_driver
 675         * has already created an efi_disk at this moment.
 676         */
 677        desc = dev_get_uclass_plat(dev);
 678        if (desc->uclass_id != UCLASS_EFI_LOADER) {
 679                ret = efi_disk_create_raw(dev, agent_handle);
 680                if (ret)
 681                        return -1;
 682        }
 683
 684        device_foreach_child(child, dev) {
 685                ret = efi_disk_create_part(child, agent_handle);
 686                if (ret)
 687                        return -1;
 688        }
 689
 690        return 0;
 691}
 692
 693/**
 694 * efi_disk_remove - delete an efi_disk object for a block device or partition
 695 *
 696 * @ctx:        event context: driver binding protocol
 697 * @event:      EV_PM_PRE_REMOVE event
 698 *
 699 * Delete an efi_disk object which is associated with the UCLASS_BLK or
 700 * UCLASS_PARTITION device for which the EV_PM_PRE_REMOVE event is raised.
 701 *
 702 * Return:      0 on success, -1 otherwise
 703 */
 704int efi_disk_remove(void *ctx, struct event *event)
 705{
 706        enum uclass_id id;
 707        struct udevice *dev = event->data.dm.dev;
 708        efi_handle_t handle;
 709        struct blk_desc *desc;
 710        struct efi_disk_obj *diskobj = NULL;
 711
 712        if (dev_tag_get_ptr(dev, DM_TAG_EFI, (void **)&handle))
 713                return 0;
 714
 715        id = device_get_uclass_id(dev);
 716        switch (id) {
 717        case UCLASS_BLK:
 718                desc = dev_get_uclass_plat(dev);
 719                if (desc && desc->uclass_id != UCLASS_EFI_LOADER)
 720                        diskobj = container_of(handle, struct efi_disk_obj,
 721                                               header);
 722                break;
 723        case UCLASS_PARTITION:
 724                diskobj = container_of(handle, struct efi_disk_obj, header);
 725                break;
 726        default:
 727                return 0;
 728        }
 729
 730        if (diskobj)
 731                efi_free_pool(diskobj->dp);
 732
 733        efi_delete_handle(handle);
 734        dev_tag_del(dev, DM_TAG_EFI);
 735
 736        return 0;
 737}
 738
 739/**
 740 * efi_disk_get_device_name() - get U-Boot device name associated with EFI handle
 741 *
 742 * @handle:     pointer to the EFI handle
 743 * @buf:        pointer to the buffer to store the string
 744 * @size:       size of buffer
 745 * Return:      status code
 746 */
 747efi_status_t efi_disk_get_device_name(const efi_handle_t handle, char *buf, int size)
 748{
 749        int count;
 750        int diskid;
 751        enum uclass_id id;
 752        unsigned int part;
 753        struct udevice *dev;
 754        struct blk_desc *desc;
 755        const char *if_typename;
 756        bool is_partition = false;
 757        struct disk_part *part_data;
 758
 759        if (!handle || !buf || !size)
 760                return EFI_INVALID_PARAMETER;
 761
 762        dev = handle->dev;
 763        id = device_get_uclass_id(dev);
 764        if (id == UCLASS_BLK) {
 765                desc = dev_get_uclass_plat(dev);
 766        } else if (id == UCLASS_PARTITION) {
 767                desc = dev_get_uclass_plat(dev_get_parent(dev));
 768                is_partition = true;
 769        } else {
 770                return EFI_INVALID_PARAMETER;
 771        }
 772        if_typename = blk_get_uclass_name(desc->uclass_id);
 773        diskid = desc->devnum;
 774
 775        if (is_partition) {
 776                part_data = dev_get_uclass_plat(dev);
 777                part = part_data->partnum;
 778                count = snprintf(buf, size, "%s %d:%u", if_typename, diskid,
 779                                 part);
 780        } else {
 781                count = snprintf(buf, size, "%s %d", if_typename, diskid);
 782        }
 783
 784        if (count < 0 || (count + 1) > size)
 785                return EFI_INVALID_PARAMETER;
 786
 787        return EFI_SUCCESS;
 788}
 789
 790/**
 791 * efi_disks_register() - ensure all block devices are available in UEFI
 792 *
 793 * The function probes all block devices. As we store UEFI variables on the
 794 * EFI system partition this function has to be called before enabling
 795 * variable services.
 796 */
 797efi_status_t efi_disks_register(void)
 798{
 799        struct udevice *dev;
 800
 801        uclass_foreach_dev_probe(UCLASS_BLK, dev) {
 802        }
 803
 804        return EFI_SUCCESS;
 805}
 806