[U-Boot] [PATCH v3 05/16] efi_loader: open_info in OpenProtocol
Heinrich Schuchardt
xypron.glpk at gmx.de
Thu Jan 11 07:15:58 UTC 2018
efi_open_protocol has to keep track of opened protocols.
OpenProtocol enters the agent and controller handle
information into this list.
A unit test is supplied with a subsequent patch.
Signed-off-by: Heinrich Schuchardt <xypron.glpk at gmx.de>
---
v3
no change
v2
no change
---
lib/efi_loader/efi_boottime.c | 107 ++++++++++++++++++++++++++++++++++++++++--
1 file changed, 103 insertions(+), 4 deletions(-)
diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c
index f5ec2a8866..bb80c6066a 100644
--- a/lib/efi_loader/efi_boottime.c
+++ b/lib/efi_loader/efi_boottime.c
@@ -2100,6 +2100,101 @@ static void EFIAPI efi_set_mem(void *buffer, size_t size, uint8_t value)
EFI_EXIT(EFI_SUCCESS);
}
+/*
+ * Open protocol interface on a handle.
+ *
+ * @handler handler of a protocol
+ * @protocol_interface interface implementing the protocol
+ * @agent_handle handle of the driver
+ * @controller_handle handle of the controller
+ * @attributes attributes indicating how to open the protocol
+ * @return status code
+ */
+static efi_status_t efi_protocol_open(
+ struct efi_handler *handler,
+ void **protocol_interface, void *agent_handle,
+ void *controller_handle, uint32_t attributes)
+{
+ struct efi_open_protocol_info_item *item;
+ struct efi_open_protocol_info_entry *match = NULL;
+ bool opened_by_driver = false;
+ bool opened_exclusive = false;
+
+ /* If there is no agent, only return the interface */
+ if (!agent_handle)
+ goto out;
+
+ /* For TEST_PROTOCOL ignore interface attribute */
+ if (attributes != EFI_OPEN_PROTOCOL_TEST_PROTOCOL)
+ *protocol_interface = NULL;
+
+ /*
+ * Check if the protocol is already opened by a driver with the same
+ * attributes or opened exclusively
+ */
+ list_for_each_entry(item, &handler->open_infos, link) {
+ if (item->info.agent_handle == agent_handle) {
+ if ((attributes & EFI_OPEN_PROTOCOL_BY_DRIVER) &&
+ (item->info.attributes == attributes))
+ return EFI_ALREADY_STARTED;
+ }
+ if (item->info.attributes & EFI_OPEN_PROTOCOL_EXCLUSIVE)
+ opened_exclusive = true;
+ }
+
+ /* Only one controller can open the protocol exclusively */
+ if (opened_exclusive && attributes &
+ (EFI_OPEN_PROTOCOL_EXCLUSIVE | EFI_OPEN_PROTOCOL_BY_DRIVER))
+ return EFI_ACCESS_DENIED;
+
+ /* Prepare exclusive opening */
+ if (attributes & EFI_OPEN_PROTOCOL_EXCLUSIVE) {
+ /* Try to disconnect controllers */
+ list_for_each_entry(item, &handler->open_infos, link) {
+ if (item->info.attributes ==
+ EFI_OPEN_PROTOCOL_BY_DRIVER)
+ EFI_CALL(efi_disconnect_controller(
+ item->info.controller_handle,
+ item->info.agent_handle,
+ NULL));
+ }
+ opened_by_driver = false;
+ /* Check if all controllers are disconnected */
+ list_for_each_entry(item, &handler->open_infos, link) {
+ if (item->info.attributes & EFI_OPEN_PROTOCOL_BY_DRIVER)
+ opened_by_driver = true;
+ }
+ /* Only one controller can be conncected */
+ if (opened_by_driver)
+ return EFI_ACCESS_DENIED;
+ }
+
+ /* Find existing entry */
+ list_for_each_entry(item, &handler->open_infos, link) {
+ if (item->info.agent_handle == agent_handle &&
+ item->info.controller_handle == controller_handle)
+ match = &item->info;
+ }
+ /* None found, create one */
+ if (!match) {
+ match = efi_create_open_info(handler);
+ if (!match)
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ match->agent_handle = agent_handle;
+ match->controller_handle = controller_handle;
+ match->attributes = attributes;
+ match->open_count++;
+
+out:
+ /* For TEST_PROTOCOL ignore interface attribute. */
+ if (attributes != EFI_OPEN_PROTOCOL_TEST_PROTOCOL)
+ *protocol_interface = handler->protocol_interface;
+
+ return EFI_SUCCESS;
+}
+
/*
* Open protocol interface on a handle.
*
@@ -2141,12 +2236,16 @@ static efi_status_t EFIAPI efi_open_protocol(
case EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER:
if (controller_handle == handle)
goto out;
+ /* fall-through */
case EFI_OPEN_PROTOCOL_BY_DRIVER:
case EFI_OPEN_PROTOCOL_BY_DRIVER | EFI_OPEN_PROTOCOL_EXCLUSIVE:
- if (controller_handle == NULL)
+ /* Check that the controller handle is valid */
+ if (!efi_search_obj(controller_handle))
goto out;
+ /* fall-through */
case EFI_OPEN_PROTOCOL_EXCLUSIVE:
- if (agent_handle == NULL)
+ /* Check that the agent handle is valid */
+ if (!efi_search_obj(agent_handle))
goto out;
break;
default:
@@ -2157,8 +2256,8 @@ static efi_status_t EFIAPI efi_open_protocol(
if (r != EFI_SUCCESS)
goto out;
- if (attributes != EFI_OPEN_PROTOCOL_TEST_PROTOCOL)
- *protocol_interface = handler->protocol_interface;
+ r = efi_protocol_open(handler, protocol_interface, agent_handle,
+ controller_handle, attributes);
out:
return EFI_EXIT(r);
}
--
2.14.2
More information about the U-Boot
mailing list