123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415 |
- // SPDX-License-Identifier: GPL-2.0+
- /*
- * efi_selftest_controllers
- *
- * Copyright (c) 2017 Heinrich Schuchardt <xypron.glpk@gmx.de>
- *
- * This unit test checks the following protocol services:
- * ConnectController, DisconnectController,
- * InstallProtocol, ReinstallProtocol, UninstallProtocol,
- * OpenProtocol, CloseProtcol, OpenProtocolInformation
- */
- #include <efi_selftest.h>
- #define NUMBER_OF_CHILD_CONTROLLERS 4
- static int interface1 = 1;
- static int interface2 = 2;
- static struct efi_boot_services *boottime;
- const efi_guid_t guid_driver_binding_protocol =
- EFI_DRIVER_BINDING_PROTOCOL_GUID;
- static efi_guid_t guid_controller =
- EFI_GUID(0xe6ab1d96, 0x6bff, 0xdb42,
- 0xaa, 0x05, 0xc8, 0x1f, 0x7f, 0x45, 0x26, 0x34);
- static efi_guid_t guid_child_controller =
- EFI_GUID(0x1d41f6f5, 0x2c41, 0xddfb,
- 0xe2, 0x9b, 0xb8, 0x0e, 0x2e, 0xe8, 0x3a, 0x85);
- static efi_handle_t handle_controller;
- static efi_handle_t handle_child_controller[NUMBER_OF_CHILD_CONTROLLERS];
- static efi_handle_t handle_driver;
- /*
- * Count child controllers
- *
- * @handle handle on which child controllers are installed
- * @protocol protocol for which the child controlles where installed
- * @count number of child controllers
- * @return status code
- */
- static efi_status_t count_child_controllers(efi_handle_t handle,
- efi_guid_t *protocol,
- efi_uintn_t *count)
- {
- efi_status_t ret;
- efi_uintn_t entry_count;
- struct efi_open_protocol_info_entry *entry_buffer;
- *count = 0;
- ret = boottime->open_protocol_information(handle, protocol,
- &entry_buffer, &entry_count);
- if (ret != EFI_SUCCESS)
- return ret;
- if (!entry_count)
- return EFI_SUCCESS;
- while (entry_count) {
- if (entry_buffer[--entry_count].attributes &
- EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER)
- ++*count;
- }
- ret = boottime->free_pool(entry_buffer);
- if (ret != EFI_SUCCESS)
- efi_st_error("Cannot free buffer\n");
- return ret;
- }
- /*
- * Check if the driver supports the controller.
- *
- * @this driver binding protocol
- * @controller_handle handle of the controller
- * @remaining_device_path path specifying the child controller
- * @return status code
- */
- static efi_status_t EFIAPI supported(
- struct efi_driver_binding_protocol *this,
- efi_handle_t controller_handle,
- struct efi_device_path *remaining_device_path)
- {
- efi_status_t ret;
- void *interface;
- ret = boottime->open_protocol(
- controller_handle, &guid_controller,
- &interface, handle_driver,
- controller_handle, EFI_OPEN_PROTOCOL_BY_DRIVER);
- switch (ret) {
- case EFI_ACCESS_DENIED:
- case EFI_ALREADY_STARTED:
- return ret;
- case EFI_SUCCESS:
- break;
- default:
- return EFI_UNSUPPORTED;
- }
- ret = boottime->close_protocol(
- controller_handle, &guid_controller,
- handle_driver, controller_handle);
- if (ret != EFI_SUCCESS)
- ret = EFI_UNSUPPORTED;
- return ret;
- }
- /*
- * Create child controllers and attach driver.
- *
- * @this driver binding protocol
- * @controller_handle handle of the controller
- * @remaining_device_path path specifying the child controller
- * @return status code
- */
- static efi_status_t EFIAPI start(
- struct efi_driver_binding_protocol *this,
- efi_handle_t controller_handle,
- struct efi_device_path *remaining_device_path)
- {
- size_t i;
- efi_status_t ret;
- void *interface;
- /* Attach driver to controller */
- ret = boottime->open_protocol(
- controller_handle, &guid_controller,
- &interface, handle_driver,
- controller_handle, EFI_OPEN_PROTOCOL_BY_DRIVER);
- switch (ret) {
- case EFI_ACCESS_DENIED:
- case EFI_ALREADY_STARTED:
- return ret;
- case EFI_SUCCESS:
- break;
- default:
- return EFI_UNSUPPORTED;
- }
- /* Create child controllers */
- for (i = 0; i < NUMBER_OF_CHILD_CONTROLLERS; ++i) {
- /* Creating a new handle for the child controller */
- handle_child_controller[i] = 0;
- ret = boottime->install_protocol_interface(
- &handle_child_controller[i], &guid_child_controller,
- EFI_NATIVE_INTERFACE, NULL);
- if (ret != EFI_SUCCESS) {
- efi_st_error("InstallProtocolInterface failed\n");
- return EFI_ST_FAILURE;
- }
- ret = boottime->open_protocol(
- controller_handle, &guid_controller,
- &interface, handle_child_controller[i],
- handle_child_controller[i],
- EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER);
- if (ret != EFI_SUCCESS) {
- efi_st_error("OpenProtocol failed\n");
- return EFI_ST_FAILURE;
- }
- }
- return ret;
- }
- /*
- * Remove a single child controller from the parent controller.
- *
- * @controller_handle parent controller
- * @child_handle child controller
- * @return status code
- */
- static efi_status_t disconnect_child(efi_handle_t controller_handle,
- efi_handle_t child_handle)
- {
- efi_status_t ret;
- ret = boottime->close_protocol(
- controller_handle, &guid_controller,
- child_handle, child_handle);
- if (ret != EFI_SUCCESS) {
- efi_st_error("Cannot close protocol\n");
- return ret;
- }
- ret = boottime->uninstall_protocol_interface(
- child_handle, &guid_child_controller, NULL);
- if (ret != EFI_SUCCESS) {
- efi_st_error("Cannot uninstall protocol interface\n");
- return ret;
- }
- return ret;
- }
- /*
- * Remove child controllers and disconnect the controller.
- *
- * @this driver binding protocol
- * @controller_handle handle of the controller
- * @number_of_children number of child controllers to remove
- * @child_handle_buffer handles of the child controllers to remove
- * @return status code
- */
- static efi_status_t EFIAPI stop(
- struct efi_driver_binding_protocol *this,
- efi_handle_t controller_handle,
- size_t number_of_children,
- efi_handle_t *child_handle_buffer)
- {
- efi_status_t ret;
- efi_uintn_t count;
- struct efi_open_protocol_info_entry *entry_buffer;
- /* Destroy provided child controllers */
- if (number_of_children) {
- efi_uintn_t i;
- for (i = 0; i < number_of_children; ++i) {
- ret = disconnect_child(controller_handle,
- child_handle_buffer[i]);
- if (ret != EFI_SUCCESS)
- return ret;
- }
- return EFI_SUCCESS;
- }
- /* Destroy all children */
- ret = boottime->open_protocol_information(
- controller_handle, &guid_controller,
- &entry_buffer, &count);
- if (ret != EFI_SUCCESS) {
- efi_st_error("OpenProtocolInformation failed\n");
- return ret;
- }
- while (count) {
- if (entry_buffer[--count].attributes &
- EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) {
- ret = disconnect_child(
- controller_handle,
- entry_buffer[count].agent_handle);
- if (ret != EFI_SUCCESS)
- return ret;
- }
- }
- ret = boottime->free_pool(entry_buffer);
- if (ret != EFI_SUCCESS)
- efi_st_error("Cannot free buffer\n");
- /* Detach driver from controller */
- ret = boottime->close_protocol(
- controller_handle, &guid_controller,
- handle_driver, controller_handle);
- if (ret != EFI_SUCCESS) {
- efi_st_error("Cannot close protocol\n");
- return ret;
- }
- return EFI_SUCCESS;
- }
- /* Driver binding protocol interface */
- static struct efi_driver_binding_protocol binding_interface = {
- supported,
- start,
- stop,
- 0xffffffff,
- NULL,
- NULL,
- };
- /*
- * Setup unit test.
- *
- * @handle handle of the loaded image
- * @systable system table
- */
- static int setup(const efi_handle_t img_handle,
- const struct efi_system_table *systable)
- {
- efi_status_t ret;
- boottime = systable->boottime;
- /* Create controller handle */
- ret = boottime->install_protocol_interface(
- &handle_controller, &guid_controller,
- EFI_NATIVE_INTERFACE, &interface1);
- if (ret != EFI_SUCCESS) {
- efi_st_error("InstallProtocolInterface failed\n");
- return EFI_ST_FAILURE;
- }
- /* Create driver handle */
- ret = boottime->install_protocol_interface(
- &handle_driver, &guid_driver_binding_protocol,
- EFI_NATIVE_INTERFACE, &binding_interface);
- if (ret != EFI_SUCCESS) {
- efi_st_error("InstallProtocolInterface failed\n");
- return EFI_ST_FAILURE;
- }
- return EFI_ST_SUCCESS;
- }
- /*
- * Execute unit test.
- *
- * The number of child controllers is checked after each of the following
- * actions:
- *
- * Connect a controller to a driver.
- * Disconnect and destroy a child controller.
- * Disconnect and destroy the remaining child controllers.
- *
- * Connect a controller to a driver.
- * Reinstall the driver protocol on the controller.
- * Uninstall the driver protocol from the controller.
- */
- static int execute(void)
- {
- efi_status_t ret;
- efi_uintn_t count;
- /* Connect controller to driver */
- ret = boottime->connect_controller(handle_controller, NULL, NULL, 1);
- if (ret != EFI_SUCCESS) {
- efi_st_error("Failed to connect controller\n");
- return EFI_ST_FAILURE;
- }
- /* Check number of child controllers */
- ret = count_child_controllers(handle_controller, &guid_controller,
- &count);
- if (ret != EFI_SUCCESS || count != NUMBER_OF_CHILD_CONTROLLERS) {
- efi_st_error("Number of children %u != %u\n",
- (unsigned int)count, NUMBER_OF_CHILD_CONTROLLERS);
- }
- /* Destroy second child controller */
- ret = boottime->disconnect_controller(handle_controller,
- handle_driver,
- handle_child_controller[1]);
- if (ret != EFI_SUCCESS) {
- efi_st_error("Failed to disconnect child controller\n");
- return EFI_ST_FAILURE;
- }
- /* Check number of child controllers */
- ret = count_child_controllers(handle_controller, &guid_controller,
- &count);
- if (ret != EFI_SUCCESS || count != NUMBER_OF_CHILD_CONTROLLERS - 1) {
- efi_st_error("Destroying single child controller failed\n");
- return EFI_ST_FAILURE;
- }
- /* Destroy remaining child controllers and disconnect controller */
- ret = boottime->disconnect_controller(handle_controller, NULL, NULL);
- if (ret != EFI_SUCCESS) {
- efi_st_error("Failed to disconnect controller\n");
- return EFI_ST_FAILURE;
- }
- /* Check number of child controllers */
- ret = count_child_controllers(handle_controller, &guid_controller,
- &count);
- if (ret != EFI_SUCCESS || count) {
- efi_st_error("Destroying child controllers failed\n");
- return EFI_ST_FAILURE;
- }
- /* Connect controller to driver */
- ret = boottime->connect_controller(handle_controller, NULL, NULL, 1);
- if (ret != EFI_SUCCESS) {
- efi_st_error("Failed to connect controller\n");
- return EFI_ST_FAILURE;
- }
- /* Check number of child controllers */
- ret = count_child_controllers(handle_controller, &guid_controller,
- &count);
- if (ret != EFI_SUCCESS || count != NUMBER_OF_CHILD_CONTROLLERS) {
- efi_st_error("Number of children %u != %u\n",
- (unsigned int)count, NUMBER_OF_CHILD_CONTROLLERS);
- }
- /* Try to uninstall controller protocol using the wrong interface */
- ret = boottime->uninstall_protocol_interface(handle_controller,
- &guid_controller,
- &interface2);
- if (ret == EFI_SUCCESS) {
- efi_st_error(
- "Interface not checked when uninstalling protocol\n");
- return EFI_ST_FAILURE;
- }
- /* Reinstall controller protocol */
- ret = boottime->reinstall_protocol_interface(handle_controller,
- &guid_controller,
- &interface1,
- &interface2);
- if (ret != EFI_SUCCESS) {
- efi_st_error("Failed to reinstall protocols\n");
- return EFI_ST_FAILURE;
- }
- /* Check number of child controllers */
- ret = count_child_controllers(handle_controller, &guid_controller,
- &count);
- if (ret != EFI_SUCCESS || count != NUMBER_OF_CHILD_CONTROLLERS) {
- efi_st_error("Number of children %u != %u\n",
- (unsigned int)count, NUMBER_OF_CHILD_CONTROLLERS);
- }
- /* Uninstall controller protocol */
- ret = boottime->uninstall_protocol_interface(handle_controller,
- &guid_controller,
- &interface2);
- if (ret != EFI_SUCCESS) {
- efi_st_error("Failed to uninstall protocols\n");
- return EFI_ST_FAILURE;
- }
- /* Check number of child controllers */
- ret = count_child_controllers(handle_controller, &guid_controller,
- &count);
- if (ret == EFI_SUCCESS)
- efi_st_error("Uninstall failed\n");
- return EFI_ST_SUCCESS;
- }
- EFI_UNIT_TEST(controllers) = {
- .name = "controllers",
- .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT,
- .setup = setup,
- .execute = execute,
- };
|