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
					
				| 
						 | 
					@ -2120,6 +2120,101 @@ static void EFIAPI efi_set_mem(void *buffer, size_t size, uint8_t value)
 | 
				
			||||||
	EFI_EXIT(EFI_SUCCESS);
 | 
						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.
 | 
					 * 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:
 | 
						case EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER:
 | 
				
			||||||
		if (controller_handle == handle)
 | 
							if (controller_handle == handle)
 | 
				
			||||||
			goto out;
 | 
								goto out;
 | 
				
			||||||
 | 
							/* fall-through */
 | 
				
			||||||
	case EFI_OPEN_PROTOCOL_BY_DRIVER:
 | 
						case EFI_OPEN_PROTOCOL_BY_DRIVER:
 | 
				
			||||||
	case EFI_OPEN_PROTOCOL_BY_DRIVER | EFI_OPEN_PROTOCOL_EXCLUSIVE:
 | 
						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;
 | 
								goto out;
 | 
				
			||||||
 | 
							/* fall-through */
 | 
				
			||||||
	case EFI_OPEN_PROTOCOL_EXCLUSIVE:
 | 
						case EFI_OPEN_PROTOCOL_EXCLUSIVE:
 | 
				
			||||||
		if (agent_handle == NULL)
 | 
							/* Check that the agent handle is valid */
 | 
				
			||||||
 | 
							if (!efi_search_obj(agent_handle))
 | 
				
			||||||
			goto out;
 | 
								goto out;
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
| 
						 | 
					@ -2177,8 +2276,8 @@ static efi_status_t EFIAPI efi_open_protocol(
 | 
				
			||||||
	if (r != EFI_SUCCESS)
 | 
						if (r != EFI_SUCCESS)
 | 
				
			||||||
		goto out;
 | 
							goto out;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (attributes != EFI_OPEN_PROTOCOL_TEST_PROTOCOL)
 | 
						r = efi_protocol_open(handler, protocol_interface, agent_handle,
 | 
				
			||||||
		*protocol_interface = handler->protocol_interface;
 | 
								      controller_handle, attributes);
 | 
				
			||||||
out:
 | 
					out:
 | 
				
			||||||
	return EFI_EXIT(r);
 | 
						return EFI_EXIT(r);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue