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
  48struct efi_device_path_to_text_protocol *device_path_to_text;
  49
  50/*
  51 * Setup unit test.
  52 *
  53 * Create three handles. Install a new protocol on two of them and
  54 * provide device paths.
  55 *
  56 * handle1
  57 *   guid interface
  58 * handle2
  59 *   guid interface
  60 * handle3
  61 *
  62 * @handle:     handle of the loaded image
  63 * @systable:   system table
  64 */
  65static int setup(const efi_handle_t img_handle,
  66                 const struct efi_system_table *systable)
  67{
  68        struct efi_device_path_vendor vendor_node;
  69        struct efi_device_path end_node;
  70        efi_status_t ret;
  71
  72        boottime = systable->boottime;
  73
  74        ret = boottime->locate_protocol(&guid_device_path_to_text_protocol,
  75                                        NULL, (void **)&device_path_to_text);
  76        if (ret != EFI_SUCCESS) {
  77                device_path_to_text = NULL;
  78                efi_st_error(
  79                        "Device path to text protocol is not available.\n");
  80                return EFI_ST_FAILURE;
  81        }
  82
  83        ret = boottime->allocate_pool(EFI_LOADER_DATA,
  84                                      sizeof(struct efi_device_path_vendor) +
  85                                      sizeof(struct efi_device_path),
  86                                      (void **)&dp1);
  87        if (ret != EFI_SUCCESS)
  88                goto out_of_memory;
  89
  90        ret = boottime->allocate_pool(EFI_LOADER_DATA, 2 *
  91                                      sizeof(struct efi_device_path_vendor) +
  92                                      sizeof(struct efi_device_path),
  93                                      (void **)&dp2);
  94        if (ret != EFI_SUCCESS)
  95                goto out_of_memory;
  96
  97        ret = boottime->allocate_pool(EFI_LOADER_DATA, 3 *
  98                                      sizeof(struct efi_device_path_vendor) +
  99                                      sizeof(struct efi_device_path),
 100                                      (void **)&dp3);
 101        if (ret != EFI_SUCCESS)
 102                goto out_of_memory;
 103
 104        vendor_node.dp.type = DEVICE_PATH_TYPE_HARDWARE_DEVICE;
 105        vendor_node.dp.sub_type = DEVICE_PATH_SUB_TYPE_VENDOR;
 106        vendor_node.dp.length = sizeof(struct efi_device_path_vendor);
 107
 108        boottime->copy_mem(&vendor_node.guid, &guid_vendor1,
 109                           sizeof(efi_guid_t));
 110        boottime->copy_mem(dp1, &vendor_node,
 111                           sizeof(struct efi_device_path_vendor));
 112        boottime->copy_mem(dp2, &vendor_node,
 113                           sizeof(struct efi_device_path_vendor));
 114        boottime->copy_mem(dp3, &vendor_node,
 115                           sizeof(struct efi_device_path_vendor));
 116
 117        boottime->copy_mem(&vendor_node.guid, &guid_vendor2,
 118                           sizeof(efi_guid_t));
 119        boottime->copy_mem(dp2 + sizeof(struct efi_device_path_vendor),
 120                           &vendor_node, sizeof(struct efi_device_path_vendor));
 121        boottime->copy_mem(dp3 + sizeof(struct efi_device_path_vendor),
 122                           &vendor_node, sizeof(struct efi_device_path_vendor));
 123
 124        boottime->copy_mem(&vendor_node.guid, &guid_vendor3,
 125                           sizeof(efi_guid_t));
 126        boottime->copy_mem(dp3 + 2 * sizeof(struct efi_device_path_vendor),
 127                           &vendor_node, sizeof(struct efi_device_path_vendor));
 128
 129        end_node.type = DEVICE_PATH_TYPE_END;
 130        end_node.sub_type = DEVICE_PATH_SUB_TYPE_END;
 131        end_node.length = sizeof(struct efi_device_path);
 132        boottime->copy_mem(dp1 + sizeof(struct efi_device_path_vendor),
 133                           &end_node, sizeof(struct efi_device_path));
 134        boottime->copy_mem(dp2 + 2 * sizeof(struct efi_device_path_vendor),
 135                           &end_node, sizeof(struct efi_device_path));
 136        boottime->copy_mem(dp3 + 3 * sizeof(struct efi_device_path_vendor),
 137                           &end_node, sizeof(struct efi_device_path));
 138
 139        ret = boottime->install_protocol_interface(&handle1,
 140                                                   &guid_device_path,
 141                                                   EFI_NATIVE_INTERFACE,
 142                                                   dp1);
 143        if (ret != EFI_SUCCESS) {
 144                efi_st_error("InstallProtocolInterface failed\n");
 145                return EFI_ST_FAILURE;
 146        }
 147        ret = boottime->install_protocol_interface(&handle1,
 148                                                   &guid_protocol,
 149                                                   EFI_NATIVE_INTERFACE,
 150                                                   &interface);
 151        if (ret != EFI_SUCCESS) {
 152                efi_st_error("InstallProtocolInterface failed\n");
 153                return EFI_ST_FAILURE;
 154        }
 155        ret = boottime->install_protocol_interface(&handle2,
 156                                                   &guid_device_path,
 157                                                   EFI_NATIVE_INTERFACE,
 158                                                   dp2);
 159        if (ret != EFI_SUCCESS) {
 160                efi_st_error("InstallProtocolInterface failed\n");
 161                return EFI_ST_FAILURE;
 162        }
 163        ret = boottime->install_protocol_interface(&handle2,
 164                                                   &guid_protocol,
 165                                                   EFI_NATIVE_INTERFACE,
 166                                                   &interface);
 167        if (ret != EFI_SUCCESS) {
 168                efi_st_error("InstallProtocolInterface failed\n");
 169                return EFI_ST_FAILURE;
 170        }
 171        ret = boottime->install_protocol_interface(&handle3,
 172                                                   &guid_device_path,
 173                                                   EFI_NATIVE_INTERFACE,
 174                                                   dp3);
 175        if (ret != EFI_SUCCESS) {
 176                efi_st_error("InstallProtocolInterface failed\n");
 177                return EFI_ST_FAILURE;
 178        }
 179        return EFI_ST_SUCCESS;
 180
 181out_of_memory:
 182        efi_st_error("Out of memory\n");
 183        return EFI_ST_FAILURE;
 184}
 185
 186/*
 187 * Tear down unit test.
 188 *
 189 */
 190static int teardown(void)
 191{
 192        efi_status_t ret;
 193
 194        ret = boottime->uninstall_protocol_interface(handle1,
 195                                                     &guid_device_path,
 196                                                     dp1);
 197        if (ret != EFI_SUCCESS) {
 198                efi_st_error("UninstallProtocolInterface failed\n");
 199                return EFI_ST_FAILURE;
 200        }
 201        ret = boottime->uninstall_protocol_interface(handle1,
 202                                                     &guid_protocol,
 203                                                     &interface);
 204        if (ret != EFI_SUCCESS) {
 205                efi_st_error("UninstallProtocolInterface failed\n");
 206                return EFI_ST_FAILURE;
 207        }
 208        ret = boottime->uninstall_protocol_interface(handle2,
 209                                                     &guid_device_path,
 210                                                     dp2);
 211        if (ret != EFI_SUCCESS) {
 212                efi_st_error("UninstallProtocolInterface failed\n");
 213                return EFI_ST_FAILURE;
 214        }
 215        ret = boottime->uninstall_protocol_interface(handle2,
 216                                                     &guid_protocol,
 217                                                     &interface);
 218        if (ret != EFI_SUCCESS) {
 219                efi_st_error("UninstallProtocolInterface failed\n");
 220                return EFI_ST_FAILURE;
 221        }
 222        ret = boottime->uninstall_protocol_interface(handle3,
 223                                                     &guid_device_path,
 224                                                     dp3);
 225        if (ret != EFI_SUCCESS) {
 226                efi_st_error("UninstallProtocolInterface failed\n");
 227                return EFI_ST_FAILURE;
 228        }
 229        if (dp1) {
 230                ret = boottime->free_pool(dp1);
 231                if (ret != EFI_SUCCESS) {
 232                        efi_st_error("FreePool failed\n");
 233                        return EFI_ST_FAILURE;
 234                }
 235        }
 236        if (dp2) {
 237                ret = boottime->free_pool(dp2);
 238                if (ret != EFI_SUCCESS) {
 239                        efi_st_error("FreePool failed\n");
 240                        return EFI_ST_FAILURE;
 241                }
 242        }
 243        if (dp3) {
 244                ret = boottime->free_pool(dp3);
 245                if (ret != EFI_SUCCESS) {
 246                        efi_st_error("FreePool failed\n");
 247                        return EFI_ST_FAILURE;
 248                }
 249        }
 250        return EFI_ST_SUCCESS;
 251}
 252
 253/*
 254 * Execute unit test.
 255 *
 256 */
 257static int execute(void)
 258{
 259        struct efi_device_path *remaining_dp;
 260        efi_handle_t handle;
 261        /*
 262         * This device path node ends with the letter 't' of 'u-boot'.
 263         * The following '.bin' does not belong to the node but is
 264         * helps to test the correct truncation.
 265         */
 266        struct {
 267                struct efi_device_path dp;
 268                u16 text[12];
 269        } __packed dp_node = {
 270                        { DEVICE_PATH_TYPE_MEDIA_DEVICE,
 271                          DEVICE_PATH_SUB_TYPE_FILE_PATH,
 272                          sizeof(struct efi_device_path) + 12},
 273                        L"u-boot.bin",
 274                };
 275        u16 *string;
 276        efi_status_t ret;
 277        efi_uintn_t i, no_handles;
 278        efi_handle_t *handles;
 279        struct efi_device_path *dp;
 280
 281        /* Display all available device paths */
 282        ret = boottime->locate_handle_buffer(BY_PROTOCOL,
 283                                             &guid_device_path,
 284                                             NULL, &no_handles, &handles);
 285        if (ret != EFI_SUCCESS) {
 286                efi_st_error("Cannot retrieve device path protocols.\n");
 287                return EFI_ST_FAILURE;
 288        }
 289
 290        efi_st_printf("Installed device path protocols:\n");
 291        for (i = 0; i < no_handles; ++i) {
 292                ret = boottime->open_protocol(handles[i], &guid_device_path,
 293                                              (void **)&dp, NULL, NULL,
 294                                              EFI_OPEN_PROTOCOL_GET_PROTOCOL);
 295                if (ret != EFI_SUCCESS) {
 296                        efi_st_error("Cannot open device path protocol.\n");
 297                        return EFI_ST_FAILURE;
 298                }
 299                string = device_path_to_text->convert_device_path_to_text(
 300                                        dp, true, false);
 301                if (!string) {
 302                        efi_st_error("ConvertDevicePathToText failed\n");
 303                        return EFI_ST_FAILURE;
 304                }
 305                efi_st_printf("%ps\n", string);
 306                ret = boottime->free_pool(string);
 307                if (ret != EFI_SUCCESS) {
 308                        efi_st_error("FreePool failed\n");
 309                        return EFI_ST_FAILURE;
 310                }
 311                /*
 312                 * CloseProtocol cannot be called without agent handle.
 313                 * There is no need to close the device path protocol.
 314                 */
 315        }
 316        ret = boottime->free_pool(handles);
 317        if (ret != EFI_SUCCESS) {
 318                efi_st_error("FreePool failed\n");
 319                return EFI_ST_FAILURE;
 320        }
 321
 322        /* Test ConvertDevicePathToText */
 323        string = device_path_to_text->convert_device_path_to_text(
 324                        (struct efi_device_path *)dp2, true, false);
 325        if (!string) {
 326                efi_st_error("ConvertDevicePathToText failed\n");
 327                return EFI_ST_FAILURE;
 328        }
 329        if (efi_st_strcmp_16_8(
 330                string,
 331                "/VenHw(dbca4c98-6cb0-694d-0872-819c650cbbb1)/VenHw(dbca4c98-6cb0-694d-0872-819c650cbba2)")
 332            ) {
 333                efi_st_printf("dp2: %ps\n", string);
 334                efi_st_error("Incorrect text from ConvertDevicePathToText\n");
 335                return EFI_ST_FAILURE;
 336        }
 337        ret = boottime->free_pool(string);
 338        if (ret != EFI_SUCCESS) {
 339                efi_st_error("FreePool failed\n");
 340                return EFI_ST_FAILURE;
 341        }
 342
 343        /* Test ConvertDeviceNodeToText */
 344        string = device_path_to_text->convert_device_node_to_text(
 345                        (struct efi_device_path *)&dp_node, true, false);
 346        if (!string) {
 347                efi_st_error("ConvertDeviceNodeToText failed\n");
 348                return EFI_ST_FAILURE;
 349        }
 350        if (efi_st_strcmp_16_8(string, "u-boot")) {
 351                efi_st_printf("dp_node: %ps\n", string);
 352                efi_st_error(
 353                        "Incorrect conversion by ConvertDeviceNodeToText\n");
 354                return EFI_ST_FAILURE;
 355        }
 356        ret = boottime->free_pool(string);
 357        if (ret != EFI_SUCCESS) {
 358                efi_st_error("FreePool failed\n");
 359                return EFI_ST_FAILURE;
 360        }
 361
 362        /* Test LocateDevicePath */
 363        remaining_dp = (struct efi_device_path *)dp3;
 364        ret = boottime->locate_device_path(&guid_protocol, &remaining_dp,
 365                                           &handle);
 366        if (ret != EFI_SUCCESS) {
 367                efi_st_error("LocateDevicePath failed\n");
 368                return EFI_ST_FAILURE;
 369        }
 370        if (handle != handle2) {
 371                efi_st_error("LocateDevicePath returned wrong handle\n");
 372                return EFI_ST_FAILURE;
 373        }
 374        string = device_path_to_text->convert_device_path_to_text(remaining_dp,
 375                                                                  true, false);
 376        if (!string) {
 377                efi_st_error("ConvertDevicePathToText failed\n");
 378                return EFI_ST_FAILURE;
 379        }
 380        if (efi_st_strcmp_16_8(string,
 381                               "/VenHw(dbca4c98-6cb0-694d-0872-819c650cbbc3)")
 382            ) {
 383                efi_st_printf("remaining device path: %ps\n", string);
 384                efi_st_error("LocateDevicePath: wrong remaining device path\n");
 385                return EFI_ST_FAILURE;
 386        }
 387        ret = boottime->free_pool(string);
 388        if (ret != EFI_SUCCESS) {
 389                efi_st_error("FreePool failed\n");
 390                return EFI_ST_FAILURE;
 391        }
 392
 393        return EFI_ST_SUCCESS;
 394}
 395
 396EFI_UNIT_TEST(devicepath) = {
 397        .name = "device path",
 398        .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT,
 399        .setup = setup,
 400        .execute = execute,
 401        .teardown = teardown,
 402};
 403