uboot/lib/efi_selftest/efi_selftest_devicepath.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * efi_selftest_devicepath
   4 *
   5 * Copyright (c) 2017 Heinrich Schuchardt <xypron.glpk@gmx.de>
   6 *
   7 * This unit test checks the following protocol services:
   8 * DevicePathToText
   9 */
  10
  11#include <efi_selftest.h>
  12
  13static struct efi_boot_services *boottime;
  14
  15static efi_handle_t handle1;
  16static efi_handle_t handle2;
  17static efi_handle_t handle3;
  18
  19struct interface {
  20        void (EFIAPI * inc)(void);
  21} interface;
  22
  23static efi_guid_t guid_device_path = EFI_DEVICE_PATH_PROTOCOL_GUID;
  24
  25static efi_guid_t guid_device_path_to_text_protocol =
  26        EFI_DEVICE_PATH_TO_TEXT_PROTOCOL_GUID;
  27
  28static efi_guid_t guid_protocol =
  29        EFI_GUID(0xdbca4c98, 0x6cb0, 0x694d,
  30                 0x08, 0x72, 0x81, 0x9c, 0x65, 0x0c, 0xbb, 0x7d);
  31
  32static efi_guid_t guid_vendor1 =
  33        EFI_GUID(0xdbca4c98, 0x6cb0, 0x694d,
  34                 0x08, 0x72, 0x81, 0x9c, 0x65, 0x0c, 0xbb, 0xb1);
  35
  36static efi_guid_t guid_vendor2 =
  37        EFI_GUID(0xdbca4c98, 0x6cb0, 0x694d,
  38                 0x08, 0x72, 0x81, 0x9c, 0x65, 0x0c, 0xbb, 0xa2);
  39
  40static efi_guid_t guid_vendor3 =
  41        EFI_GUID(0xdbca4c98, 0x6cb0, 0x694d,
  42                 0x08, 0x72, 0x81, 0x9c, 0x65, 0x0c, 0xbb, 0xc3);
  43
  44static u8 *dp1;
  45static u8 *dp2;
  46static u8 *dp3;
  47
  48static struct {
  49        struct efi_device_path_sd_mmc_path sd1;
  50        struct efi_device_path sep1;
  51        struct efi_device_path_sd_mmc_path sd2;
  52        struct efi_device_path sep2;
  53        struct efi_device_path_sd_mmc_path sd3;
  54        struct efi_device_path end;
  55} multi_part_dp = {
  56        {
  57                {
  58                        DEVICE_PATH_TYPE_MESSAGING_DEVICE,
  59                        DEVICE_PATH_SUB_TYPE_MSG_SD,
  60                        sizeof(struct efi_device_path_sd_mmc_path),
  61                },
  62                0,
  63        },
  64        {
  65                DEVICE_PATH_TYPE_END,
  66                DEVICE_PATH_SUB_TYPE_INSTANCE_END,
  67                sizeof(struct efi_device_path),
  68        },
  69        {
  70                {
  71                        DEVICE_PATH_TYPE_MESSAGING_DEVICE,
  72                        DEVICE_PATH_SUB_TYPE_MSG_SD,
  73                        sizeof(struct efi_device_path_sd_mmc_path),
  74                },
  75                1,
  76        },
  77        {
  78                DEVICE_PATH_TYPE_END,
  79                DEVICE_PATH_SUB_TYPE_INSTANCE_END,
  80                sizeof(struct efi_device_path),
  81        },
  82        {
  83                {
  84                        DEVICE_PATH_TYPE_MESSAGING_DEVICE,
  85                        DEVICE_PATH_SUB_TYPE_MSG_SD,
  86                        sizeof(struct efi_device_path_sd_mmc_path),
  87                },
  88                2,
  89        },
  90        {
  91                DEVICE_PATH_TYPE_END,
  92                DEVICE_PATH_SUB_TYPE_END,
  93                sizeof(struct efi_device_path),
  94        },
  95};
  96
  97struct efi_device_path_to_text_protocol *device_path_to_text;
  98
  99/*
 100 * Setup unit test.
 101 *
 102 * Create three handles. Install a new protocol on two of them and
 103 * provide device paths.
 104 *
 105 * handle1
 106 *   guid interface
 107 * handle2
 108 *   guid interface
 109 * handle3
 110 *
 111 * @handle:     handle of the loaded image
 112 * @systable:   system table
 113 */
 114static int setup(const efi_handle_t img_handle,
 115                 const struct efi_system_table *systable)
 116{
 117        struct efi_device_path_vendor vendor_node;
 118        struct efi_device_path end_node;
 119        efi_status_t ret;
 120
 121        boottime = systable->boottime;
 122
 123        ret = boottime->locate_protocol(&guid_device_path_to_text_protocol,
 124                                        NULL, (void **)&device_path_to_text);
 125        if (ret != EFI_SUCCESS) {
 126                device_path_to_text = NULL;
 127                efi_st_error(
 128                        "Device path to text protocol is not available.\n");
 129                return EFI_ST_FAILURE;
 130        }
 131
 132        ret = boottime->allocate_pool(EFI_LOADER_DATA,
 133                                      sizeof(struct efi_device_path_vendor) +
 134                                      sizeof(struct efi_device_path),
 135                                      (void **)&dp1);
 136        if (ret != EFI_SUCCESS)
 137                goto out_of_memory;
 138
 139        ret = boottime->allocate_pool(EFI_LOADER_DATA, 2 *
 140                                      sizeof(struct efi_device_path_vendor) +
 141                                      sizeof(struct efi_device_path),
 142                                      (void **)&dp2);
 143        if (ret != EFI_SUCCESS)
 144                goto out_of_memory;
 145
 146        ret = boottime->allocate_pool(EFI_LOADER_DATA, 3 *
 147                                      sizeof(struct efi_device_path_vendor) +
 148                                      sizeof(struct efi_device_path),
 149                                      (void **)&dp3);
 150        if (ret != EFI_SUCCESS)
 151                goto out_of_memory;
 152
 153        vendor_node.dp.type = DEVICE_PATH_TYPE_HARDWARE_DEVICE;
 154        vendor_node.dp.sub_type = DEVICE_PATH_SUB_TYPE_VENDOR;
 155        vendor_node.dp.length = sizeof(struct efi_device_path_vendor);
 156
 157        boottime->copy_mem(&vendor_node.guid, &guid_vendor1,
 158                           sizeof(efi_guid_t));
 159        boottime->copy_mem(dp1, &vendor_node,
 160                           sizeof(struct efi_device_path_vendor));
 161        boottime->copy_mem(dp2, &vendor_node,
 162                           sizeof(struct efi_device_path_vendor));
 163        boottime->copy_mem(dp3, &vendor_node,
 164                           sizeof(struct efi_device_path_vendor));
 165
 166        boottime->copy_mem(&vendor_node.guid, &guid_vendor2,
 167                           sizeof(efi_guid_t));
 168        boottime->copy_mem(dp2 + sizeof(struct efi_device_path_vendor),
 169                           &vendor_node, sizeof(struct efi_device_path_vendor));
 170        boottime->copy_mem(dp3 + sizeof(struct efi_device_path_vendor),
 171                           &vendor_node, sizeof(struct efi_device_path_vendor));
 172
 173        boottime->copy_mem(&vendor_node.guid, &guid_vendor3,
 174                           sizeof(efi_guid_t));
 175        boottime->copy_mem(dp3 + 2 * sizeof(struct efi_device_path_vendor),
 176                           &vendor_node, sizeof(struct efi_device_path_vendor));
 177
 178        end_node.type = DEVICE_PATH_TYPE_END;
 179        end_node.sub_type = DEVICE_PATH_SUB_TYPE_END;
 180        end_node.length = sizeof(struct efi_device_path);
 181        boottime->copy_mem(dp1 + sizeof(struct efi_device_path_vendor),
 182                           &end_node, sizeof(struct efi_device_path));
 183        boottime->copy_mem(dp2 + 2 * sizeof(struct efi_device_path_vendor),
 184                           &end_node, sizeof(struct efi_device_path));
 185        boottime->copy_mem(dp3 + 3 * sizeof(struct efi_device_path_vendor),
 186                           &end_node, sizeof(struct efi_device_path));
 187
 188        ret = boottime->install_protocol_interface(&handle1,
 189                                                   &guid_device_path,
 190                                                   EFI_NATIVE_INTERFACE,
 191                                                   dp1);
 192        if (ret != EFI_SUCCESS) {
 193                efi_st_error("InstallProtocolInterface failed\n");
 194                return EFI_ST_FAILURE;
 195        }
 196        ret = boottime->install_protocol_interface(&handle1,
 197                                                   &guid_protocol,
 198                                                   EFI_NATIVE_INTERFACE,
 199                                                   &interface);
 200        if (ret != EFI_SUCCESS) {
 201                efi_st_error("InstallProtocolInterface failed\n");
 202                return EFI_ST_FAILURE;
 203        }
 204        ret = boottime->install_protocol_interface(&handle2,
 205                                                   &guid_device_path,
 206                                                   EFI_NATIVE_INTERFACE,
 207                                                   dp2);
 208        if (ret != EFI_SUCCESS) {
 209                efi_st_error("InstallProtocolInterface failed\n");
 210                return EFI_ST_FAILURE;
 211        }
 212        ret = boottime->install_protocol_interface(&handle2,
 213                                                   &guid_protocol,
 214                                                   EFI_NATIVE_INTERFACE,
 215                                                   &interface);
 216        if (ret != EFI_SUCCESS) {
 217                efi_st_error("InstallProtocolInterface failed\n");
 218                return EFI_ST_FAILURE;
 219        }
 220        ret = boottime->install_protocol_interface(&handle3,
 221                                                   &guid_device_path,
 222                                                   EFI_NATIVE_INTERFACE,
 223                                                   dp3);
 224        if (ret != EFI_SUCCESS) {
 225                efi_st_error("InstallProtocolInterface failed\n");
 226                return EFI_ST_FAILURE;
 227        }
 228        return EFI_ST_SUCCESS;
 229
 230out_of_memory:
 231        efi_st_error("Out of memory\n");
 232        return EFI_ST_FAILURE;
 233}
 234
 235/*
 236 * Tear down unit test.
 237 *
 238 */
 239static int teardown(void)
 240{
 241        efi_status_t ret;
 242
 243        ret = boottime->uninstall_protocol_interface(handle1,
 244                                                     &guid_device_path,
 245                                                     dp1);
 246        if (ret != EFI_SUCCESS) {
 247                efi_st_error("UninstallProtocolInterface failed\n");
 248                return EFI_ST_FAILURE;
 249        }
 250        ret = boottime->uninstall_protocol_interface(handle1,
 251                                                     &guid_protocol,
 252                                                     &interface);
 253        if (ret != EFI_SUCCESS) {
 254                efi_st_error("UninstallProtocolInterface failed\n");
 255                return EFI_ST_FAILURE;
 256        }
 257        ret = boottime->uninstall_protocol_interface(handle2,
 258                                                     &guid_device_path,
 259                                                     dp2);
 260        if (ret != EFI_SUCCESS) {
 261                efi_st_error("UninstallProtocolInterface failed\n");
 262                return EFI_ST_FAILURE;
 263        }
 264        ret = boottime->uninstall_protocol_interface(handle2,
 265                                                     &guid_protocol,
 266                                                     &interface);
 267        if (ret != EFI_SUCCESS) {
 268                efi_st_error("UninstallProtocolInterface failed\n");
 269                return EFI_ST_FAILURE;
 270        }
 271        ret = boottime->uninstall_protocol_interface(handle3,
 272                                                     &guid_device_path,
 273                                                     dp3);
 274        if (ret != EFI_SUCCESS) {
 275                efi_st_error("UninstallProtocolInterface failed\n");
 276                return EFI_ST_FAILURE;
 277        }
 278        if (dp1) {
 279                ret = boottime->free_pool(dp1);
 280                if (ret != EFI_SUCCESS) {
 281                        efi_st_error("FreePool failed\n");
 282                        return EFI_ST_FAILURE;
 283                }
 284        }
 285        if (dp2) {
 286                ret = boottime->free_pool(dp2);
 287                if (ret != EFI_SUCCESS) {
 288                        efi_st_error("FreePool failed\n");
 289                        return EFI_ST_FAILURE;
 290                }
 291        }
 292        if (dp3) {
 293                ret = boottime->free_pool(dp3);
 294                if (ret != EFI_SUCCESS) {
 295                        efi_st_error("FreePool failed\n");
 296                        return EFI_ST_FAILURE;
 297                }
 298        }
 299        return EFI_ST_SUCCESS;
 300}
 301
 302/*
 303 * Execute unit test.
 304 *
 305 */
 306static int execute(void)
 307{
 308        struct efi_device_path *remaining_dp;
 309        efi_handle_t handle;
 310        /*
 311         * This device path node ends with the letter 't' of 'u-boot'.
 312         * The following '.bin' does not belong to the node but is
 313         * helps to test the correct truncation.
 314         */
 315        struct {
 316                struct efi_device_path dp;
 317                u16 text[12];
 318        } __packed dp_node = {
 319                        { DEVICE_PATH_TYPE_MEDIA_DEVICE,
 320                          DEVICE_PATH_SUB_TYPE_FILE_PATH,
 321                          sizeof(struct efi_device_path) + 12},
 322                        L"u-boot.bin",
 323                };
 324        u16 *string;
 325        efi_status_t ret;
 326        efi_uintn_t i, no_handles;
 327        efi_handle_t *handles;
 328        struct efi_device_path *dp;
 329
 330        /* Display all available device paths */
 331        ret = boottime->locate_handle_buffer(BY_PROTOCOL,
 332                                             &guid_device_path,
 333                                             NULL, &no_handles, &handles);
 334        if (ret != EFI_SUCCESS) {
 335                efi_st_error("Cannot retrieve device path protocols.\n");
 336                return EFI_ST_FAILURE;
 337        }
 338
 339        efi_st_printf("Installed device path protocols:\n");
 340        for (i = 0; i < no_handles; ++i) {
 341                ret = boottime->open_protocol(handles[i], &guid_device_path,
 342                                              (void **)&dp, NULL, NULL,
 343                                              EFI_OPEN_PROTOCOL_GET_PROTOCOL);
 344                if (ret != EFI_SUCCESS) {
 345                        efi_st_error("Cannot open device path protocol.\n");
 346                        return EFI_ST_FAILURE;
 347                }
 348                string = device_path_to_text->convert_device_path_to_text(
 349                                        dp, true, false);
 350                if (!string) {
 351                        efi_st_error("ConvertDevicePathToText failed\n");
 352                        return EFI_ST_FAILURE;
 353                }
 354                efi_st_printf("%ps\n", string);
 355                ret = boottime->free_pool(string);
 356                if (ret != EFI_SUCCESS) {
 357                        efi_st_error("FreePool failed\n");
 358                        return EFI_ST_FAILURE;
 359                }
 360                /*
 361                 * CloseProtocol cannot be called without agent handle.
 362                 * There is no need to close the device path protocol.
 363                 */
 364        }
 365        ret = boottime->free_pool(handles);
 366        if (ret != EFI_SUCCESS) {
 367                efi_st_error("FreePool failed\n");
 368                return EFI_ST_FAILURE;
 369        }
 370
 371        /* Test ConvertDevicePathToText */
 372        string = device_path_to_text->convert_device_path_to_text(
 373                        (struct efi_device_path *)dp2, true, false);
 374        if (!string) {
 375                efi_st_error("ConvertDevicePathToText failed\n");
 376                return EFI_ST_FAILURE;
 377        }
 378        if (efi_st_strcmp_16_8(
 379                string,
 380                "/VenHw(dbca4c98-6cb0-694d-0872-819c650cbbb1)/VenHw(dbca4c98-6cb0-694d-0872-819c650cbba2)")
 381            ) {
 382                efi_st_printf("dp2: %ps\n", string);
 383                efi_st_error("Incorrect text from ConvertDevicePathToText\n");
 384                return EFI_ST_FAILURE;
 385        }
 386        ret = boottime->free_pool(string);
 387        if (ret != EFI_SUCCESS) {
 388                efi_st_error("FreePool failed\n");
 389                return EFI_ST_FAILURE;
 390        }
 391
 392        string = device_path_to_text->convert_device_path_to_text(
 393                        (struct efi_device_path *)&multi_part_dp, true, false);
 394        if (efi_st_strcmp_16_8(
 395                string,
 396                "/SD(0),/SD(1),/SD(2)")
 397            ) {
 398                efi_st_printf("multi_part_dp: %ps\n", string);
 399                efi_st_error("Incorrect text from ConvertDevicePathToText\n");
 400                return EFI_ST_FAILURE;
 401        }
 402        ret = boottime->free_pool(string);
 403        if (ret != EFI_SUCCESS) {
 404                efi_st_error("FreePool failed\n");
 405                return EFI_ST_FAILURE;
 406        }
 407
 408        /* Test ConvertDeviceNodeToText */
 409        string = device_path_to_text->convert_device_node_to_text(
 410                        (struct efi_device_path *)&dp_node, true, false);
 411        if (!string) {
 412                efi_st_error("ConvertDeviceNodeToText failed\n");
 413                return EFI_ST_FAILURE;
 414        }
 415        if (efi_st_strcmp_16_8(string, "u-boot")) {
 416                efi_st_printf("dp_node: %ps\n", string);
 417                efi_st_error(
 418                        "Incorrect conversion by ConvertDeviceNodeToText\n");
 419                return EFI_ST_FAILURE;
 420        }
 421        ret = boottime->free_pool(string);
 422        if (ret != EFI_SUCCESS) {
 423                efi_st_error("FreePool failed\n");
 424                return EFI_ST_FAILURE;
 425        }
 426
 427        /* Test LocateDevicePath */
 428        remaining_dp = (struct efi_device_path *)dp3;
 429        ret = boottime->locate_device_path(&guid_protocol, &remaining_dp,
 430                                           &handle);
 431        if (ret != EFI_SUCCESS) {
 432                efi_st_error("LocateDevicePath failed\n");
 433                return EFI_ST_FAILURE;
 434        }
 435        if (handle != handle2) {
 436                efi_st_error("LocateDevicePath returned wrong handle\n");
 437                return EFI_ST_FAILURE;
 438        }
 439        string = device_path_to_text->convert_device_path_to_text(remaining_dp,
 440                                                                  true, false);
 441        if (!string) {
 442                efi_st_error("ConvertDevicePathToText failed\n");
 443                return EFI_ST_FAILURE;
 444        }
 445        if (efi_st_strcmp_16_8(string,
 446                               "/VenHw(dbca4c98-6cb0-694d-0872-819c650cbbc3)")
 447            ) {
 448                efi_st_printf("remaining device path: %ps\n", string);
 449                efi_st_error("LocateDevicePath: wrong remaining device path\n");
 450                return EFI_ST_FAILURE;
 451        }
 452        ret = boottime->free_pool(string);
 453        if (ret != EFI_SUCCESS) {
 454                efi_st_error("FreePool failed\n");
 455                return EFI_ST_FAILURE;
 456        }
 457
 458        return EFI_ST_SUCCESS;
 459}
 460
 461EFI_UNIT_TEST(devicepath) = {
 462        .name = "device path",
 463        .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT,
 464        .setup = setup,
 465        .execute = execute,
 466        .teardown = teardown,
 467};
 468