
We recently fixed a few issues wrt to controller handling. Add a few test cases to cover the new code. - add a second driver in the same controller handle which will refuse to unbind on the first protocol removal - add tests to verify controllers are reconnected when uninstalling a protocol fails - add tests to make sure EFI_NOT_FOUND is returned if a non existent interface is being removed
Signed-off-by: Ilias Apalodimas ilias.apalodimas@linaro.org --- lib/efi_selftest/efi_selftest_controllers.c | 221 ++++++++++++++++++-- 1 file changed, 198 insertions(+), 23 deletions(-)
diff --git a/lib/efi_selftest/efi_selftest_controllers.c b/lib/efi_selftest/efi_selftest_controllers.c index 79bc86fb0c3a..d2a974079329 100644 --- a/lib/efi_selftest/efi_selftest_controllers.c +++ b/lib/efi_selftest/efi_selftest_controllers.c @@ -13,6 +13,8 @@ #include <efi_selftest.h>
#define NUMBER_OF_CHILD_CONTROLLERS 4 +#define CONTROLLER1_DRIVERS (1 + NUMBER_OF_CHILD_CONTROLLERS) +#define CONTROLLER2_DRIVERS 1
static int interface1 = 1; static int interface2 = 2; @@ -22,24 +24,32 @@ const efi_guid_t guid_driver_binding_protocol = static efi_guid_t guid_controller = EFI_GUID(0xe6ab1d96, 0x6bff, 0xdb42, 0xaa, 0x05, 0xc8, 0x1f, 0x7f, 0x45, 0x26, 0x34); + +static efi_guid_t guid_controller2 = + EFI_GUID(0xe6ab1d96, 0x6bff, 0xdb42, + 0xaa, 0x50, 0x8c, 0xf1, 0xf7, 0x54, 0x62, 0x43); + 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; +static efi_handle_t handle_driver2; + +static bool allow_remove;
/* - * Count child controllers + * Count controllers * - * @handle handle on which child controllers are installed + * @handle handle on which controllers and children are installed * @protocol protocol for which the child controllers were installed * @count number of child controllers + * @children: count children only * Return: status code */ -static efi_status_t count_child_controllers(efi_handle_t handle, - efi_guid_t *protocol, - efi_uintn_t *count) +static efi_status_t count_controllers(efi_handle_t handle, efi_guid_t *protocol, + efi_uintn_t *count, bool children) { efi_status_t ret; efi_uintn_t entry_count; @@ -52,10 +62,14 @@ static efi_status_t count_child_controllers(efi_handle_t handle, return ret; if (!entry_count) return EFI_SUCCESS; - while (entry_count) { - if (entry_buffer[--entry_count].attributes & - EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) - ++*count; + if (!children) { + *count = entry_count; + } else { + 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) @@ -153,6 +167,22 @@ static efi_status_t EFIAPI start( return EFI_ST_FAILURE; } } + + /* Attach driver to controller */ + ret = boottime->open_protocol(controller_handle, &guid_controller2, + &interface, handle_driver2, + controller_handle, + EFI_OPEN_PROTOCOL_BY_DRIVER); + switch (ret) { + case EFI_SUCCESS: + return EFI_SUCCESS; + case EFI_ALREADY_STARTED: + case EFI_ACCESS_DENIED: + return ret; + default: + return EFI_UNSUPPORTED; + } + return ret; }
@@ -249,6 +279,50 @@ static efi_status_t EFIAPI stop( return EFI_SUCCESS; }
+/* + * 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 supported2(struct efi_driver_binding_protocol *this, + efi_handle_t controller_handle, + struct efi_device_path *remaining_dp) +{ + return EFI_SUCCESS; +} + +/* + * Refuse to 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 stop2(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; + + if (!allow_remove) + return EFI_DEVICE_ERROR; + + /* Detach driver from controller */ + ret = boottime->close_protocol(controller_handle, &guid_controller2, + handle_driver2, 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, @@ -259,6 +333,15 @@ static struct efi_driver_binding_protocol binding_interface = { NULL, };
+static struct efi_driver_binding_protocol binding_interface2 = { + supported2, + start, + stop2, + 0xffffffff, + NULL, + NULL, + }; + /* * Setup unit test. * @@ -273,6 +356,18 @@ static int setup(const efi_handle_t img_handle, boottime = systable->boottime; handle_controller = NULL; handle_driver = NULL; + handle_driver2 = NULL; + allow_remove = false; + + /* Create controller handles */ + ret = boottime->install_protocol_interface(&handle_controller, + &guid_controller2, + EFI_NATIVE_INTERFACE, + &interface1); + if (ret != EFI_SUCCESS) { + efi_st_error("InstallProtocolInterface failed\n"); + return EFI_ST_FAILURE; + }
/* Create controller handle */ ret = boottime->install_protocol_interface( @@ -291,6 +386,16 @@ static int setup(const efi_handle_t img_handle, return EFI_ST_FAILURE; }
+ /* Create driver handle which will fail on stop() */ + ret = boottime->install_protocol_interface(&handle_driver2, + &guid_driver_binding_protocol, + EFI_NATIVE_INTERFACE, + &binding_interface2); + if (ret != EFI_SUCCESS) { + efi_st_error("InstallProtocolInterface failed\n"); + return EFI_ST_FAILURE; + } + return EFI_ST_SUCCESS; }
@@ -310,7 +415,7 @@ static int setup(const efi_handle_t img_handle, */ static int execute(void) { - efi_status_t ret; + efi_status_t ret = EFI_SUCCESS; efi_uintn_t count;
/* Connect controller to driver */ @@ -319,9 +424,79 @@ static int execute(void) efi_st_error("Failed to connect controller\n"); return EFI_ST_FAILURE; } + /* Check number of drivers */ + ret = count_controllers(handle_controller, &guid_controller2, + &count, false); + if (ret != EFI_SUCCESS || count != CONTROLLER2_DRIVERS) { + efi_st_error("Failed to connect controller\n"); + return EFI_ST_FAILURE; + } + ret = count_controllers(handle_controller, &guid_controller, + &count, false); + if (ret != EFI_SUCCESS || count != CONTROLLER1_DRIVERS) { + efi_st_error("Failed to connect controller\n"); + return EFI_ST_FAILURE; + } + + /* Try to uninstall controller protocol which doesn't exist */ + ret = boottime->uninstall_protocol_interface(handle_controller, + &guid_controller2, + &interface2); + if (ret != EFI_NOT_FOUND) { + efi_st_error("Interface not checked when uninstalling protocol\n"); + return EFI_ST_FAILURE; + } + + /* Try to uninstall controller protocol which can't be stopped */ + ret = boottime->uninstall_protocol_interface(handle_controller, + &guid_controller, + &interface1); + if (ret != EFI_DEVICE_ERROR) { + efi_st_error("EFI_DRIVER_BINDING_PROTOCOL.Stop() not checked\n"); + return EFI_ST_FAILURE; + } + /* Check number of drivers again to make sure controolers reconnected */ + ret = count_controllers(handle_controller, &guid_controller2, + &count, false); + if (ret != EFI_SUCCESS || count != CONTROLLER2_DRIVERS) { + efi_st_error("Failed to reconnect controller\n"); + return EFI_ST_FAILURE; + } + ret = count_controllers(handle_controller, &guid_controller, + &count, false); + if (ret != EFI_SUCCESS || count != CONTROLLER1_DRIVERS) { + efi_st_error("Failed to reconnect controller\n"); + return EFI_ST_FAILURE; + } + + /* Try to uninstall controller protocol which can't be stopped */ + ret = boottime->uninstall_protocol_interface(handle_controller, + &guid_controller2, + &interface1); + if (ret != EFI_DEVICE_ERROR) { + efi_st_error("EFI_DRIVER_BINDING_PROTOCOL.Stop() not checked\n"); + return EFI_ST_FAILURE; + } + + /* Check number of drivers again to make sure controllers reconnected */ + ret = count_controllers(handle_controller, &guid_controller2, + &count, false); + if (ret != EFI_SUCCESS || count != CONTROLLER2_DRIVERS) { + efi_st_error("Failed to reconnect controller\n"); + return EFI_ST_FAILURE; + } + ret = count_controllers(handle_controller, &guid_controller, + &count, false); + if (ret != EFI_SUCCESS || count != CONTROLLER1_DRIVERS) { + efi_st_error("Failed to reconnect controller\n"); + return EFI_ST_FAILURE; + } + + allow_remove = true; + /* Check number of child controllers */ - ret = count_child_controllers(handle_controller, &guid_controller, - &count); + ret = count_controllers(handle_controller, &guid_controller, + &count, true); 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); @@ -335,8 +510,8 @@ static int execute(void) return EFI_ST_FAILURE; } /* Check number of child controllers */ - ret = count_child_controllers(handle_controller, &guid_controller, - &count); + ret = count_controllers(handle_controller, &guid_controller, + &count, true); if (ret != EFI_SUCCESS || count != NUMBER_OF_CHILD_CONTROLLERS - 1) { efi_st_error("Destroying single child controller failed\n"); return EFI_ST_FAILURE; @@ -348,8 +523,8 @@ static int execute(void) return EFI_ST_FAILURE; } /* Check number of child controllers */ - ret = count_child_controllers(handle_controller, &guid_controller, - &count); + ret = count_controllers(handle_controller, &guid_controller, + &count, true); if (ret != EFI_SUCCESS || count) { efi_st_error("Destroying child controllers failed\n"); return EFI_ST_FAILURE; @@ -362,8 +537,8 @@ static int execute(void) return EFI_ST_FAILURE; } /* Check number of child controllers */ - ret = count_child_controllers(handle_controller, &guid_controller, - &count); + ret = count_controllers(handle_controller, &guid_controller, + &count, true); 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); @@ -387,8 +562,8 @@ static int execute(void) return EFI_ST_FAILURE; } /* Check number of child controllers */ - ret = count_child_controllers(handle_controller, &guid_controller, - &count); + ret = count_controllers(handle_controller, &guid_controller, + &count, true); 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); @@ -402,14 +577,13 @@ static int execute(void) return EFI_ST_FAILURE; } /* Check number of child controllers */ - ret = count_child_controllers(handle_controller, &guid_controller, - &count); + ret = count_controllers(handle_controller, &guid_controller, + &count, true); if (ret == EFI_SUCCESS || count != 0) { efi_st_error("Uninstall failed\n"); return EFI_ST_FAILURE; }
- return EFI_ST_SUCCESS; }
@@ -420,6 +594,7 @@ static int execute(void) static int teardown(void) { efi_status_t ret; + /* Uninstall binding protocol */ ret = boottime->uninstall_protocol_interface(handle_driver, &guid_driver_binding_protocol,