@@ -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,
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(-)