mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-11-25 22:20:45 +00:00
efi_loader: open_info in OpenProtocol
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@gmx.de> Signed-off-by: Alexander Graf <agraf@suse.de>
This commit is contained in:
parent
fe1599daf5
commit
191a41cc32
1 changed files with 103 additions and 4 deletions
|
@ -2120,6 +2120,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.
|
||||
*
|
||||
|
@ -2161,12 +2256,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:
|
||||
|
@ -2177,8 +2276,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);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue