uboot/lib/efi_selftest/efi_selftest_block_device.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * efi_selftest_block
   4 *
   5 * Copyright (c) 2017 Heinrich Schuchardt <xypron.glpk@gmx.de>
   6 *
   7 * This test checks the driver for block IO devices.
   8 * A disk image is created in memory.
   9 * A handle is created for the new block IO device.
  10 * The block I/O protocol is installed on the handle.
  11 * ConnectController is used to setup partitions and to install the simple
  12 * file protocol.
  13 * A known file is read from the file system and verified.
  14 */
  15
  16#include <efi_selftest.h>
  17#include "efi_selftest_disk_image.h"
  18#include <asm/cache.h>
  19
  20/* Block size of compressed disk image */
  21#define COMPRESSED_DISK_IMAGE_BLOCK_SIZE 8
  22
  23/* Binary logarithm of the block size */
  24#define LB_BLOCK_SIZE 9
  25
  26static struct efi_boot_services *boottime;
  27
  28static const efi_guid_t block_io_protocol_guid = EFI_BLOCK_IO_PROTOCOL_GUID;
  29static const efi_guid_t guid_device_path = EFI_DEVICE_PATH_PROTOCOL_GUID;
  30static const efi_guid_t guid_simple_file_system_protocol =
  31                                        EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID;
  32static const efi_guid_t guid_file_system_info = EFI_FILE_SYSTEM_INFO_GUID;
  33static efi_guid_t guid_vendor =
  34        EFI_GUID(0xdbca4c98, 0x6cb0, 0x694d,
  35                 0x08, 0x72, 0x81, 0x9c, 0x65, 0x0c, 0xb7, 0xb8);
  36
  37static struct efi_device_path *dp;
  38
  39/* One 8 byte block of the compressed disk image */
  40struct line {
  41        size_t addr;
  42        char *line;
  43};
  44
  45/* Compressed disk image */
  46struct compressed_disk_image {
  47        size_t length;
  48        struct line lines[];
  49};
  50
  51static const struct compressed_disk_image img = EFI_ST_DISK_IMG;
  52
  53/* Decompressed disk image */
  54static u8 *image;
  55
  56/*
  57 * Reset service of the block IO protocol.
  58 *
  59 * @this        block IO protocol
  60 * @return      status code
  61 */
  62static efi_status_t EFIAPI reset(
  63                        struct efi_block_io *this,
  64                        char extended_verification)
  65{
  66        return EFI_SUCCESS;
  67}
  68
  69/*
  70 * Read service of the block IO protocol.
  71 *
  72 * @this        block IO protocol
  73 * @media_id    media id
  74 * @lba         start of the read in logical blocks
  75 * @buffer_size number of bytes to read
  76 * @buffer      target buffer
  77 * @return      status code
  78 */
  79static efi_status_t EFIAPI read_blocks(
  80                        struct efi_block_io *this, u32 media_id, u64 lba,
  81                        efi_uintn_t buffer_size, void *buffer)
  82{
  83        u8 *start;
  84
  85        if ((lba << LB_BLOCK_SIZE) + buffer_size > img.length)
  86                return EFI_INVALID_PARAMETER;
  87        start = image + (lba << LB_BLOCK_SIZE);
  88
  89        boottime->copy_mem(buffer, start, buffer_size);
  90
  91        return EFI_SUCCESS;
  92}
  93
  94/*
  95 * Write service of the block IO protocol.
  96 *
  97 * @this        block IO protocol
  98 * @media_id    media id
  99 * @lba         start of the write in logical blocks
 100 * @buffer_size number of bytes to read
 101 * @buffer      source buffer
 102 * @return      status code
 103 */
 104static efi_status_t EFIAPI write_blocks(
 105                        struct efi_block_io *this, u32 media_id, u64 lba,
 106                        efi_uintn_t buffer_size, void *buffer)
 107{
 108        u8 *start;
 109
 110        if ((lba << LB_BLOCK_SIZE) + buffer_size > img.length)
 111                return EFI_INVALID_PARAMETER;
 112        start = image + (lba << LB_BLOCK_SIZE);
 113
 114        boottime->copy_mem(start, buffer, buffer_size);
 115
 116        return EFI_SUCCESS;
 117}
 118
 119/*
 120 * Flush service of the block IO protocol.
 121 *
 122 * @this        block IO protocol
 123 * @return      status code
 124 */
 125static efi_status_t EFIAPI flush_blocks(struct efi_block_io *this)
 126{
 127        return EFI_SUCCESS;
 128}
 129
 130/*
 131 * Decompress the disk image.
 132 *
 133 * @image       decompressed disk image
 134 * @return      status code
 135 */
 136static efi_status_t decompress(u8 **image)
 137{
 138        u8 *buf;
 139        size_t i;
 140        size_t addr;
 141        size_t len;
 142        efi_status_t ret;
 143
 144        ret = boottime->allocate_pool(EFI_LOADER_DATA, img.length,
 145                                      (void **)&buf);
 146        if (ret != EFI_SUCCESS) {
 147                efi_st_error("Out of memory\n");
 148                return ret;
 149        }
 150        boottime->set_mem(buf, img.length, 0);
 151
 152        for (i = 0; ; ++i) {
 153                if (!img.lines[i].line)
 154                        break;
 155                addr = img.lines[i].addr;
 156                len = COMPRESSED_DISK_IMAGE_BLOCK_SIZE;
 157                if (addr + len > img.length)
 158                        len = img.length - addr;
 159                boottime->copy_mem(buf + addr, img.lines[i].line, len);
 160        }
 161        *image = buf;
 162        return ret;
 163}
 164
 165static struct efi_block_io_media media;
 166
 167static struct efi_block_io block_io = {
 168        .media = &media,
 169        .reset = reset,
 170        .read_blocks = read_blocks,
 171        .write_blocks = write_blocks,
 172        .flush_blocks = flush_blocks,
 173};
 174
 175/* Handle for the block IO device */
 176static efi_handle_t disk_handle;
 177
 178/*
 179 * Setup unit test.
 180 *
 181 * @handle:     handle of the loaded image
 182 * @systable:   system table
 183 * @return:     EFI_ST_SUCCESS for success
 184 */
 185static int setup(const efi_handle_t handle,
 186                 const struct efi_system_table *systable)
 187{
 188        efi_status_t ret;
 189        struct efi_device_path_vendor vendor_node;
 190        struct efi_device_path end_node;
 191
 192        boottime = systable->boottime;
 193
 194        decompress(&image);
 195
 196        block_io.media->block_size = 1 << LB_BLOCK_SIZE;
 197        block_io.media->last_block = img.length >> LB_BLOCK_SIZE;
 198
 199        ret = boottime->install_protocol_interface(
 200                                &disk_handle, &block_io_protocol_guid,
 201                                EFI_NATIVE_INTERFACE, &block_io);
 202        if (ret != EFI_SUCCESS) {
 203                efi_st_error("Failed to install block I/O protocol\n");
 204                return EFI_ST_FAILURE;
 205        }
 206
 207        ret = boottime->allocate_pool(EFI_LOADER_DATA,
 208                                      sizeof(struct efi_device_path_vendor) +
 209                                      sizeof(struct efi_device_path),
 210                                      (void **)&dp);
 211        if (ret != EFI_SUCCESS) {
 212                efi_st_error("Out of memory\n");
 213                return EFI_ST_FAILURE;
 214        }
 215        vendor_node.dp.type = DEVICE_PATH_TYPE_HARDWARE_DEVICE;
 216        vendor_node.dp.sub_type = DEVICE_PATH_SUB_TYPE_VENDOR;
 217        vendor_node.dp.length = sizeof(struct efi_device_path_vendor);
 218
 219        boottime->copy_mem(&vendor_node.guid, &guid_vendor,
 220                           sizeof(efi_guid_t));
 221        boottime->copy_mem(dp, &vendor_node,
 222                           sizeof(struct efi_device_path_vendor));
 223        end_node.type = DEVICE_PATH_TYPE_END;
 224        end_node.sub_type = DEVICE_PATH_SUB_TYPE_END;
 225        end_node.length = sizeof(struct efi_device_path);
 226
 227        boottime->copy_mem((char *)dp + sizeof(struct efi_device_path_vendor),
 228                           &end_node, sizeof(struct efi_device_path));
 229        ret = boottime->install_protocol_interface(&disk_handle,
 230                                                   &guid_device_path,
 231                                                   EFI_NATIVE_INTERFACE,
 232                                                   dp);
 233        if (ret != EFI_SUCCESS) {
 234                efi_st_error("InstallProtocolInterface failed\n");
 235                return EFI_ST_FAILURE;
 236        }
 237        return EFI_ST_SUCCESS;
 238}
 239
 240/*
 241 * Tear down unit test.
 242 *
 243 * @return:     EFI_ST_SUCCESS for success
 244 */
 245static int teardown(void)
 246{
 247        efi_status_t r = EFI_ST_SUCCESS;
 248
 249        if (disk_handle) {
 250                r = boottime->uninstall_protocol_interface(disk_handle,
 251                                                           &guid_device_path,
 252                                                           dp);
 253                if (r != EFI_SUCCESS) {
 254                        efi_st_error("Uninstall device path failed\n");
 255                        return EFI_ST_FAILURE;
 256                }
 257                r = boottime->uninstall_protocol_interface(
 258                                disk_handle, &block_io_protocol_guid,
 259                                &block_io);
 260                if (r != EFI_SUCCESS) {
 261                        efi_st_error(
 262                                "Failed to uninstall block I/O protocol\n");
 263                        return EFI_ST_FAILURE;
 264                }
 265        }
 266
 267        if (image) {
 268                r = boottime->free_pool(image);
 269                if (r != EFI_SUCCESS) {
 270                        efi_st_error("Failed to free image\n");
 271                        return EFI_ST_FAILURE;
 272                }
 273        }
 274        return r;
 275}
 276
 277/*
 278 * Get length of device path without end tag.
 279 *
 280 * @dp          device path
 281 * @return      length of device path in bytes
 282 */
 283static efi_uintn_t dp_size(struct efi_device_path *dp)
 284{
 285        struct efi_device_path *pos = dp;
 286
 287        while (pos->type != DEVICE_PATH_TYPE_END)
 288                pos = (struct efi_device_path *)((char *)pos + pos->length);
 289        return (char *)pos - (char *)dp;
 290}
 291
 292/*
 293 * Execute unit test.
 294 *
 295 * @return:     EFI_ST_SUCCESS for success
 296 */
 297static int execute(void)
 298{
 299        efi_status_t ret;
 300        efi_uintn_t no_handles, i, len;
 301        efi_handle_t *handles;
 302        efi_handle_t handle_partition = NULL;
 303        struct efi_device_path *dp_partition;
 304        struct efi_simple_file_system_protocol *file_system;
 305        struct efi_file_handle *root, *file;
 306        struct {
 307                struct efi_file_system_info info;
 308                u16 label[12];
 309        } system_info;
 310        efi_uintn_t buf_size;
 311        char buf[16] __aligned(ARCH_DMA_MINALIGN);
 312        u64 pos;
 313
 314        /* Connect controller to virtual disk */
 315        ret = boottime->connect_controller(disk_handle, NULL, NULL, 1);
 316        if (ret != EFI_SUCCESS) {
 317                efi_st_error("Failed to connect controller\n");
 318                return EFI_ST_FAILURE;
 319        }
 320
 321        /* Get the handle for the partition */
 322        ret = boottime->locate_handle_buffer(
 323                                BY_PROTOCOL, &guid_device_path, NULL,
 324                                &no_handles, &handles);
 325        if (ret != EFI_SUCCESS) {
 326                efi_st_error("Failed to locate handles\n");
 327                return EFI_ST_FAILURE;
 328        }
 329        len = dp_size(dp);
 330        for (i = 0; i < no_handles; ++i) {
 331                ret = boottime->open_protocol(handles[i], &guid_device_path,
 332                                              (void **)&dp_partition,
 333                                              NULL, NULL,
 334                                              EFI_OPEN_PROTOCOL_GET_PROTOCOL);
 335                if (ret != EFI_SUCCESS) {
 336                        efi_st_error("Failed to open device path protocol\n");
 337                        return EFI_ST_FAILURE;
 338                }
 339                if (len >= dp_size(dp_partition))
 340                        continue;
 341                if (memcmp(dp, dp_partition, len))
 342                        continue;
 343                handle_partition = handles[i];
 344                break;
 345        }
 346        ret = boottime->free_pool(handles);
 347        if (ret != EFI_SUCCESS) {
 348                efi_st_error("Failed to free pool memory\n");
 349                return EFI_ST_FAILURE;
 350        }
 351        if (!handle_partition) {
 352                efi_st_error("Partition handle not found\n");
 353                return EFI_ST_FAILURE;
 354        }
 355
 356        /* Open the simple file system protocol */
 357        ret = boottime->open_protocol(handle_partition,
 358                                      &guid_simple_file_system_protocol,
 359                                      (void **)&file_system, NULL, NULL,
 360                                      EFI_OPEN_PROTOCOL_GET_PROTOCOL);
 361        if (ret != EFI_SUCCESS) {
 362                efi_st_error("Failed to open simple file system protocol\n");
 363                return EFI_ST_FAILURE;
 364        }
 365
 366        /* Open volume */
 367        ret = file_system->open_volume(file_system, &root);
 368        if (ret != EFI_SUCCESS) {
 369                efi_st_error("Failed to open volume\n");
 370                return EFI_ST_FAILURE;
 371        }
 372        buf_size = sizeof(system_info);
 373        ret = root->getinfo(root, &guid_file_system_info, &buf_size,
 374                            &system_info);
 375        if (ret != EFI_SUCCESS) {
 376                efi_st_error("Failed to get file system info\n");
 377                return EFI_ST_FAILURE;
 378        }
 379        if (system_info.info.block_size != 512) {
 380                efi_st_error("Wrong block size %u, expected 512\n",
 381                             system_info.info.block_size);
 382                return EFI_ST_FAILURE;
 383        }
 384        if (efi_st_strcmp_16_8(system_info.info.volume_label, "U-BOOT TEST")) {
 385                efi_st_todo(
 386                        "Wrong volume label '%ps', expected 'U-BOOT TEST'\n",
 387                        system_info.info.volume_label);
 388        }
 389
 390        /* Read file */
 391        ret = root->open(root, &file, L"hello.txt", EFI_FILE_MODE_READ,
 392                         0);
 393        if (ret != EFI_SUCCESS) {
 394                efi_st_error("Failed to open file\n");
 395                return EFI_ST_FAILURE;
 396        }
 397        ret = file->setpos(file, 1);
 398        if (ret != EFI_SUCCESS) {
 399                efi_st_error("SetPosition failed\n");
 400                return EFI_ST_FAILURE;
 401        }
 402        buf_size = sizeof(buf) - 1;
 403        ret = file->read(file, &buf_size, buf);
 404        if (ret != EFI_SUCCESS) {
 405                efi_st_error("Failed to read file\n");
 406                return EFI_ST_FAILURE;
 407        }
 408        if (buf_size != 12) {
 409                efi_st_error("Wrong number of bytes read: %u\n",
 410                             (unsigned int)buf_size);
 411                return EFI_ST_FAILURE;
 412        }
 413        if (memcmp(buf, "ello world!", 11)) {
 414                efi_st_error("Unexpected file content\n");
 415                return EFI_ST_FAILURE;
 416        }
 417        ret = file->getpos(file, &pos);
 418        if (ret != EFI_SUCCESS) {
 419                efi_st_error("GetPosition failed\n");
 420                return EFI_ST_FAILURE;
 421        }
 422        if (pos != 13) {
 423                efi_st_error("GetPosition returned %u, expected 13\n",
 424                             (unsigned int)pos);
 425                return EFI_ST_FAILURE;
 426        }
 427        ret = file->close(file);
 428        if (ret != EFI_SUCCESS) {
 429                efi_st_error("Failed to close file\n");
 430                return EFI_ST_FAILURE;
 431        }
 432
 433#ifdef CONFIG_FAT_WRITE
 434        /* Write file */
 435        ret = root->open(root, &file, L"u-boot.txt", EFI_FILE_MODE_READ |
 436                         EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE, 0);
 437        if (ret != EFI_SUCCESS) {
 438                efi_st_error("Failed to open file\n");
 439                return EFI_ST_FAILURE;
 440        }
 441        buf_size = 7;
 442        boottime->set_mem(buf, sizeof(buf), 0);
 443        boottime->copy_mem(buf, "U-Boot", buf_size);
 444        ret = file->write(file, &buf_size, buf);
 445        if (ret != EFI_SUCCESS || buf_size != 7) {
 446                efi_st_error("Failed to write file\n");
 447                return EFI_ST_FAILURE;
 448        }
 449        ret = file->getpos(file, &pos);
 450        if (ret != EFI_SUCCESS) {
 451                efi_st_error("GetPosition failed\n");
 452                return EFI_ST_FAILURE;
 453        }
 454        if (pos != 7) {
 455                efi_st_error("GetPosition returned %u, expected 7\n",
 456                             (unsigned int)pos);
 457                return EFI_ST_FAILURE;
 458        }
 459        ret = file->close(file);
 460        if (ret != EFI_SUCCESS) {
 461                efi_st_error("Failed to close file\n");
 462                return EFI_ST_FAILURE;
 463        }
 464
 465        /* Verify file */
 466        boottime->set_mem(buf, sizeof(buf), 0);
 467        ret = root->open(root, &file, L"u-boot.txt", EFI_FILE_MODE_READ,
 468                         0);
 469        if (ret != EFI_SUCCESS) {
 470                efi_st_error("Failed to open file\n");
 471                return EFI_ST_FAILURE;
 472        }
 473        buf_size = sizeof(buf) - 1;
 474        ret = file->read(file, &buf_size, buf);
 475        if (ret != EFI_SUCCESS) {
 476                efi_st_error("Failed to read file\n");
 477                return EFI_ST_FAILURE;
 478        }
 479        if (buf_size != 7) {
 480                efi_st_error("Wrong number of bytes read: %u\n",
 481                             (unsigned int)buf_size);
 482                return EFI_ST_FAILURE;
 483        }
 484        if (memcmp(buf, "U-Boot", 7)) {
 485                efi_st_error("Unexpected file content %s\n", buf);
 486                return EFI_ST_FAILURE;
 487        }
 488        ret = file->close(file);
 489        if (ret != EFI_SUCCESS) {
 490                efi_st_error("Failed to close file\n");
 491                return EFI_ST_FAILURE;
 492        }
 493#else
 494        efi_st_todo("CONFIG_FAT_WRITE is not set\n");
 495#endif /* CONFIG_FAT_WRITE */
 496
 497        /* Close volume */
 498        ret = root->close(root);
 499        if (ret != EFI_SUCCESS) {
 500                efi_st_error("Failed to close volume\n");
 501                return EFI_ST_FAILURE;
 502        }
 503
 504        return EFI_ST_SUCCESS;
 505}
 506
 507EFI_UNIT_TEST(blkdev) = {
 508        .name = "block device",
 509        .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT,
 510        .setup = setup,
 511        .execute = execute,
 512        .teardown = teardown,
 513};
 514