uboot/lib/efi_selftest/efi_selftest_controllers.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * efi_selftest_controllers
   4 *
   5 * Copyright (c) 2017 Heinrich Schuchardt <xypron.glpk@gmx.de>
   6 *
   7 * This unit test checks the following protocol services:
   8 * ConnectController, DisconnectController,
   9 * InstallProtocol, ReinstallProtocol, UninstallProtocol,
  10 * OpenProtocol, CloseProtcol, OpenProtocolInformation
  11 */
  12
  13#include <efi_selftest.h>
  14
  15#define NUMBER_OF_CHILD_CONTROLLERS 4
  16
  17static int interface1 = 1;
  18static int interface2 = 2;
  19static struct efi_boot_services *boottime;
  20const efi_guid_t guid_driver_binding_protocol =
  21                        EFI_DRIVER_BINDING_PROTOCOL_GUID;
  22static efi_guid_t guid_controller =
  23        EFI_GUID(0xe6ab1d96, 0x6bff, 0xdb42,
  24                 0xaa, 0x05, 0xc8, 0x1f, 0x7f, 0x45, 0x26, 0x34);
  25static efi_guid_t guid_child_controller =
  26        EFI_GUID(0x1d41f6f5, 0x2c41, 0xddfb,
  27                 0xe2, 0x9b, 0xb8, 0x0e, 0x2e, 0xe8, 0x3a, 0x85);
  28static efi_handle_t handle_controller;
  29static efi_handle_t handle_child_controller[NUMBER_OF_CHILD_CONTROLLERS];
  30static efi_handle_t handle_driver;
  31
  32/*
  33 * Count child controllers
  34 *
  35 * @handle      handle on which child controllers are installed
  36 * @protocol    protocol for which the child controllers were installed
  37 * @count       number of child controllers
  38 * @return      status code
  39 */
  40static efi_status_t count_child_controllers(efi_handle_t handle,
  41                                            efi_guid_t *protocol,
  42                                            efi_uintn_t *count)
  43{
  44        efi_status_t ret;
  45        efi_uintn_t entry_count;
  46        struct efi_open_protocol_info_entry *entry_buffer;
  47
  48        *count = 0;
  49        ret = boottime->open_protocol_information(handle, protocol,
  50                                                  &entry_buffer, &entry_count);
  51        if (ret != EFI_SUCCESS)
  52                return ret;
  53        if (!entry_count)
  54                return EFI_SUCCESS;
  55        while (entry_count) {
  56                if (entry_buffer[--entry_count].attributes &
  57                    EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER)
  58                        ++*count;
  59        }
  60        ret = boottime->free_pool(entry_buffer);
  61        if (ret != EFI_SUCCESS)
  62                efi_st_error("Cannot free buffer\n");
  63        return ret;
  64}
  65
  66/*
  67 * Check if the driver supports the controller.
  68 *
  69 * @this                        driver binding protocol
  70 * @controller_handle           handle of the controller
  71 * @remaining_device_path       path specifying the child controller
  72 * @return                      status code
  73 */
  74static efi_status_t EFIAPI supported(
  75                struct efi_driver_binding_protocol *this,
  76                efi_handle_t controller_handle,
  77                struct efi_device_path *remaining_device_path)
  78{
  79        efi_status_t ret;
  80        void *interface;
  81
  82        ret = boottime->open_protocol(
  83                        controller_handle, &guid_controller,
  84                        &interface, handle_driver,
  85                        controller_handle, EFI_OPEN_PROTOCOL_BY_DRIVER);
  86        switch (ret) {
  87        case EFI_ACCESS_DENIED:
  88        case EFI_ALREADY_STARTED:
  89                return ret;
  90        case EFI_SUCCESS:
  91                break;
  92        default:
  93                return EFI_UNSUPPORTED;
  94        }
  95        ret = boottime->close_protocol(
  96                                controller_handle, &guid_controller,
  97                                handle_driver, controller_handle);
  98        if (ret != EFI_SUCCESS)
  99                ret = EFI_UNSUPPORTED;
 100        return ret;
 101}
 102
 103/*
 104 * Create child controllers and attach driver.
 105 *
 106 * @this                        driver binding protocol
 107 * @controller_handle           handle of the controller
 108 * @remaining_device_path       path specifying the child controller
 109 * @return                      status code
 110 */
 111static efi_status_t EFIAPI start(
 112                struct efi_driver_binding_protocol *this,
 113                efi_handle_t controller_handle,
 114                struct efi_device_path *remaining_device_path)
 115{
 116        size_t i;
 117        efi_status_t ret;
 118        void *interface;
 119
 120        /* Attach driver to controller */
 121        ret = boottime->open_protocol(
 122                        controller_handle, &guid_controller,
 123                        &interface, handle_driver,
 124                        controller_handle, EFI_OPEN_PROTOCOL_BY_DRIVER);
 125        switch (ret) {
 126        case EFI_ACCESS_DENIED:
 127        case EFI_ALREADY_STARTED:
 128                return ret;
 129        case EFI_SUCCESS:
 130                break;
 131        default:
 132                return EFI_UNSUPPORTED;
 133        }
 134
 135        /* Create child controllers */
 136        for (i = 0; i < NUMBER_OF_CHILD_CONTROLLERS; ++i) {
 137                /* Creating a new handle for the child controller */
 138                handle_child_controller[i] = 0;
 139                ret = boottime->install_protocol_interface(
 140                        &handle_child_controller[i], &guid_child_controller,
 141                        EFI_NATIVE_INTERFACE, NULL);
 142                if (ret != EFI_SUCCESS) {
 143                        efi_st_error("InstallProtocolInterface failed\n");
 144                        return EFI_ST_FAILURE;
 145                }
 146                ret = boottime->open_protocol(
 147                        controller_handle, &guid_controller,
 148                        &interface, handle_child_controller[i],
 149                        handle_child_controller[i],
 150                        EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER);
 151                if (ret != EFI_SUCCESS) {
 152                        efi_st_error("OpenProtocol failed\n");
 153                        return EFI_ST_FAILURE;
 154                }
 155        }
 156        return ret;
 157}
 158
 159/*
 160 * Remove a single child controller from the parent controller.
 161 *
 162 * @controller_handle   parent controller
 163 * @child_handle        child controller
 164 * @return              status code
 165 */
 166static efi_status_t disconnect_child(efi_handle_t controller_handle,
 167                                     efi_handle_t child_handle)
 168{
 169        efi_status_t ret;
 170
 171        ret = boottime->close_protocol(
 172                                controller_handle, &guid_controller,
 173                                child_handle, child_handle);
 174        if (ret != EFI_SUCCESS) {
 175                efi_st_error("Cannot close protocol\n");
 176                return ret;
 177        }
 178        ret = boottime->uninstall_protocol_interface(
 179                                child_handle, &guid_child_controller, NULL);
 180        if (ret != EFI_SUCCESS) {
 181                efi_st_error("Cannot uninstall protocol interface\n");
 182                return ret;
 183        }
 184        return ret;
 185}
 186
 187/*
 188 * Remove child controllers and disconnect the controller.
 189 *
 190 * @this                        driver binding protocol
 191 * @controller_handle           handle of the controller
 192 * @number_of_children          number of child controllers to remove
 193 * @child_handle_buffer         handles of the child controllers to remove
 194 * @return                      status code
 195 */
 196static efi_status_t EFIAPI stop(
 197                struct efi_driver_binding_protocol *this,
 198                efi_handle_t controller_handle,
 199                size_t number_of_children,
 200                efi_handle_t *child_handle_buffer)
 201{
 202        efi_status_t ret;
 203        efi_uintn_t count;
 204        struct efi_open_protocol_info_entry *entry_buffer;
 205
 206        /* Destroy provided child controllers */
 207        if (number_of_children) {
 208                efi_uintn_t i;
 209
 210                for (i = 0; i < number_of_children; ++i) {
 211                        ret = disconnect_child(controller_handle,
 212                                               child_handle_buffer[i]);
 213                        if (ret != EFI_SUCCESS)
 214                                return ret;
 215                }
 216                return EFI_SUCCESS;
 217        }
 218
 219        /* Destroy all children */
 220        ret = boottime->open_protocol_information(
 221                                        controller_handle, &guid_controller,
 222                                        &entry_buffer, &count);
 223        if (ret != EFI_SUCCESS) {
 224                efi_st_error("OpenProtocolInformation failed\n");
 225                return ret;
 226        }
 227        while (count) {
 228                if (entry_buffer[--count].attributes &
 229                    EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) {
 230                        ret = disconnect_child(
 231                                        controller_handle,
 232                                        entry_buffer[count].agent_handle);
 233                        if (ret != EFI_SUCCESS)
 234                                return ret;
 235                }
 236        }
 237        ret = boottime->free_pool(entry_buffer);
 238        if (ret != EFI_SUCCESS)
 239                efi_st_error("Cannot free buffer\n");
 240
 241        /* Detach driver from controller */
 242        ret = boottime->close_protocol(
 243                        controller_handle, &guid_controller,
 244                        handle_driver, controller_handle);
 245        if (ret != EFI_SUCCESS) {
 246                efi_st_error("Cannot close protocol\n");
 247                return ret;
 248        }
 249        return EFI_SUCCESS;
 250}
 251
 252/* Driver binding protocol interface */
 253static struct efi_driver_binding_protocol binding_interface = {
 254        supported,
 255        start,
 256        stop,
 257        0xffffffff,
 258        NULL,
 259        NULL,
 260        };
 261
 262/*
 263 * Setup unit test.
 264 *
 265 * @handle      handle of the loaded image
 266 * @systable    system table
 267 */
 268static int setup(const efi_handle_t img_handle,
 269                 const struct efi_system_table *systable)
 270{
 271        efi_status_t ret;
 272
 273        boottime = systable->boottime;
 274
 275        /* Create controller handle */
 276        ret = boottime->install_protocol_interface(
 277                        &handle_controller, &guid_controller,
 278                        EFI_NATIVE_INTERFACE, &interface1);
 279        if (ret != EFI_SUCCESS) {
 280                efi_st_error("InstallProtocolInterface failed\n");
 281                return EFI_ST_FAILURE;
 282        }
 283        /* Create driver handle */
 284        ret = boottime->install_protocol_interface(
 285                        &handle_driver,  &guid_driver_binding_protocol,
 286                        EFI_NATIVE_INTERFACE, &binding_interface);
 287        if (ret != EFI_SUCCESS) {
 288                efi_st_error("InstallProtocolInterface failed\n");
 289                return EFI_ST_FAILURE;
 290        }
 291
 292        return EFI_ST_SUCCESS;
 293}
 294
 295/*
 296 * Execute unit test.
 297 *
 298 * The number of child controllers is checked after each of the following
 299 * actions:
 300 *
 301 * Connect a controller to a driver.
 302 * Disconnect and destroy a child controller.
 303 * Disconnect and destroy the remaining child controllers.
 304 *
 305 * Connect a controller to a driver.
 306 * Reinstall the driver protocol on the controller.
 307 * Uninstall the driver protocol from the controller.
 308 */
 309static int execute(void)
 310{
 311        efi_status_t ret;
 312        efi_uintn_t count;
 313
 314        /* Connect controller to driver */
 315        ret = boottime->connect_controller(handle_controller, NULL, NULL, 1);
 316        if (ret != EFI_SUCCESS) {
 317                efi_st_error("Failed to connect controller\n");
 318                return EFI_ST_FAILURE;
 319        }
 320        /* Check number of child controllers */
 321        ret = count_child_controllers(handle_controller, &guid_controller,
 322                                      &count);
 323        if (ret != EFI_SUCCESS || count != NUMBER_OF_CHILD_CONTROLLERS) {
 324                efi_st_error("Number of children %u != %u\n",
 325                             (unsigned int)count, NUMBER_OF_CHILD_CONTROLLERS);
 326        }
 327        /* Destroy second child controller */
 328        ret = boottime->disconnect_controller(handle_controller,
 329                                              handle_driver,
 330                                              handle_child_controller[1]);
 331        if (ret != EFI_SUCCESS) {
 332                efi_st_error("Failed to disconnect child controller\n");
 333                return EFI_ST_FAILURE;
 334        }
 335        /* Check number of child controllers */
 336        ret = count_child_controllers(handle_controller, &guid_controller,
 337                                      &count);
 338        if (ret != EFI_SUCCESS || count != NUMBER_OF_CHILD_CONTROLLERS - 1) {
 339                efi_st_error("Destroying single child controller failed\n");
 340                return EFI_ST_FAILURE;
 341        }
 342        /* Destroy remaining child controllers and disconnect controller */
 343        ret = boottime->disconnect_controller(handle_controller, NULL, NULL);
 344        if (ret != EFI_SUCCESS) {
 345                efi_st_error("Failed to disconnect controller\n");
 346                return EFI_ST_FAILURE;
 347        }
 348        /* Check number of child controllers */
 349        ret = count_child_controllers(handle_controller, &guid_controller,
 350                                      &count);
 351        if (ret != EFI_SUCCESS || count) {
 352                efi_st_error("Destroying child controllers failed\n");
 353                return EFI_ST_FAILURE;
 354        }
 355
 356        /* Connect controller to driver */
 357        ret = boottime->connect_controller(handle_controller, NULL, NULL, 1);
 358        if (ret != EFI_SUCCESS) {
 359                efi_st_error("Failed to connect controller\n");
 360                return EFI_ST_FAILURE;
 361        }
 362        /* Check number of child controllers */
 363        ret = count_child_controllers(handle_controller, &guid_controller,
 364                                      &count);
 365        if (ret != EFI_SUCCESS || count != NUMBER_OF_CHILD_CONTROLLERS) {
 366                efi_st_error("Number of children %u != %u\n",
 367                             (unsigned int)count, NUMBER_OF_CHILD_CONTROLLERS);
 368        }
 369        /* Try to uninstall controller protocol using the wrong interface */
 370        ret = boottime->uninstall_protocol_interface(handle_controller,
 371                                                     &guid_controller,
 372                                                     &interface2);
 373        if (ret == EFI_SUCCESS) {
 374                efi_st_error(
 375                        "Interface not checked when uninstalling protocol\n");
 376                return EFI_ST_FAILURE;
 377        }
 378        /* Reinstall controller protocol */
 379        ret = boottime->reinstall_protocol_interface(handle_controller,
 380                                                     &guid_controller,
 381                                                     &interface1,
 382                                                     &interface2);
 383        if (ret != EFI_SUCCESS) {
 384                efi_st_error("Failed to reinstall protocols\n");
 385                return EFI_ST_FAILURE;
 386        }
 387        /* Check number of child controllers */
 388        ret = count_child_controllers(handle_controller, &guid_controller,
 389                                      &count);
 390        if (ret != EFI_SUCCESS || count != NUMBER_OF_CHILD_CONTROLLERS) {
 391                efi_st_error("Number of children %u != %u\n",
 392                             (unsigned int)count, NUMBER_OF_CHILD_CONTROLLERS);
 393        }
 394        /* Uninstall controller protocol */
 395        ret = boottime->uninstall_protocol_interface(handle_controller,
 396                                                     &guid_controller,
 397                                                     &interface2);
 398        if (ret != EFI_SUCCESS) {
 399                efi_st_error("Failed to uninstall protocols\n");
 400                return EFI_ST_FAILURE;
 401        }
 402        /* Check number of child controllers */
 403        ret = count_child_controllers(handle_controller, &guid_controller,
 404                                      &count);
 405        if (ret == EFI_SUCCESS)
 406                efi_st_error("Uninstall failed\n");
 407        return EFI_ST_SUCCESS;
 408}
 409
 410EFI_UNIT_TEST(controllers) = {
 411        .name = "controllers",
 412        .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT,
 413        .setup = setup,
 414        .execute = execute,
 415};
 416