Example #1
0
/*
 * Closes a client session from the Secure World
 */
int tf_close_client_session(
	struct tf_connection *connection,
	union tf_command *command,
	union tf_answer *answer)
{
	int error = 0;

	dprintk(KERN_DEBUG "tf_close_client_session(%p)\n", connection);

	command->close_client_session.message_size =
		(sizeof(struct tf_command_close_client_session) -
			sizeof(struct tf_command_header)) / 4;
	command->close_client_session.device_context =
		connection->device_context;

	error = tf_send_receive(
		&connection->dev->sm,
		command,
		answer,
		connection,
		true);

	if (error != 0)
		dprintk(KERN_ERR "tf_close_client_session returns %d\n",
			error);
	else
		dprintk(KERN_ERR "tf_close_client_session returns "
			"error 0x%08X\n",
			answer->close_client_session.error_code);

	return error;
}
Example #2
0
/*
 * Releases a shared memory from the Secure World
 */
int tf_release_shared_memory(
	struct tf_connection *connection,
	union tf_command *command,
	union tf_answer *answer)
{
	int error = 0;

	dprintk(KERN_DEBUG "tf_release_shared_memory(%p)\n", connection);

	command->release_shared_memory.message_size =
		(sizeof(struct tf_command_release_shared_memory) -
			sizeof(struct tf_command_header)) / 4;
	command->release_shared_memory.device_context =
		connection->device_context;

	error = tf_send_receive(
		&connection->dev->sm,
		command,
		answer,
		connection,
		true);

	if ((error != 0) ||
		(answer->release_shared_memory.error_code != S_SUCCESS))
		goto error;

	/* Use block_id to get back the pointer to shmem_desc */
	tf_unmap_shmem(
		connection,
		(struct tf_shmem_desc *)
			answer->release_shared_memory.block_id,
		0);

	/* successful completion */
	dprintk(KERN_INFO "tf_release_shared_memory(%p):"
		" block_id=0x%08x block=0x%08x\n",
		connection, answer->release_shared_memory.block_id,
		command->release_shared_memory.block);
	return 0;


error:
	if (error != 0)
		dprintk(KERN_ERR "tf_release_shared_memory returns %d\n",
			error);
	else
		dprintk(KERN_ERR "tf_release_shared_memory returns "
			"nChannelStatus 0x%08X\n",
			answer->release_shared_memory.error_code);

	return error;

}
Example #3
0
 /*
 * Perform a Secure World shutdown operation.
 * The routine does not return if the operation succeeds.
 * the routine returns an appropriate error code if
 * the operation fails.
 */
int tf_pm_shutdown(struct tf_comm *comm)
{

	int error;
	union tf_command command;
	union tf_answer answer;

	dprintk(KERN_INFO "tf_pm_shutdown()\n");

	memset(&command, 0, sizeof(command));

	command.header.message_type = TF_MESSAGE_TYPE_MANAGEMENT;
	command.header.message_size =
			(sizeof(struct tf_command_management) -
				sizeof(struct tf_command_header))/sizeof(u32);

	command.management.command = TF_MANAGEMENT_SHUTDOWN;

	error = tf_send_receive(
		comm,
		&command,
		&answer,
		NULL,
		false);

	if (error != 0) {
		dprintk(KERN_ERR "tf_pm_shutdown(): "
			"tf_send_receive failed (error %d)!\n",
			error);
		return error;
	}

#ifdef CONFIG_TF_DRIVER_DEBUG_SUPPORT
	if (answer.header.error_code != 0)
		dprintk(KERN_ERR "tf_driver: shutdown failed.\n");
	else
		dprintk(KERN_INFO "tf_driver: shutdown succeeded.\n");
#endif

	return answer.header.error_code;
}
Example #4
0
/*
 * Cancels a client command from the Secure World
 */
int tf_cancel_client_command(
	struct tf_connection *connection,
	union tf_command *command,
	union tf_answer *answer)
{
	int error = 0;

	dprintk(KERN_DEBUG "tf_cancel_client_command(%p)\n", connection);

	command->cancel_client_operation.device_context =
		connection->device_context;
	command->cancel_client_operation.message_size =
		(sizeof(struct tf_command_cancel_client_operation) -
			sizeof(struct tf_command_header)) / 4;

	error = tf_send_receive(
		&connection->dev->sm,
		command,
		answer,
		connection,
		true);

	if ((error != 0) ||
		(answer->cancel_client_operation.error_code != S_SUCCESS))
		goto error;


	/* successful completion */
	return 0;

error:
	if (error != 0)
		dprintk(KERN_ERR "tf_cancel_client_command returns %d\n",
			error);
	else
		dprintk(KERN_ERR "tf_cancel_client_command returns "
			"nChannelStatus 0x%08X\n",
			answer->cancel_client_operation.error_code);

	return error;
}
Example #5
0
int tf_delayed_secure_resume(void)
{
	int ret;
	union tf_command message;
	union tf_answer answer;
	struct tf_device *dev = tf_get_device();

	spin_lock(&tf_delayed_resume_lock);
	if (likely(tf_need_delayed_resume == DELAYED_RESUME_NONE)) {
		spin_unlock(&tf_delayed_resume_lock);
		return 0;
	}

	if (unlikely(tf_need_delayed_resume == DELAYED_RESUME_ONGOING)) {
		spin_unlock(&tf_delayed_resume_lock);

		/*
		 * Wait for the other caller to actually finish the delayed
		 * resume operation
		 */
		while (tf_need_delayed_resume != DELAYED_RESUME_NONE)
			cpu_relax();

		return 0;
	}

	tf_need_delayed_resume = DELAYED_RESUME_ONGOING;
	spin_unlock(&tf_delayed_resume_lock);

	/*
	 * When the system leaves CORE OFF, HWA are configured as secure.  We
	 * need them as public for the Linux Crypto API.
	 */
	memset(&message, 0, sizeof(message));

	message.header.message_type = TF_MESSAGE_TYPE_MANAGEMENT;
	message.header.message_size =
		(sizeof(struct tf_command_management) -
			sizeof(struct tf_command_header))/sizeof(u32);
	message.management.command =
		TF_MANAGEMENT_RESUME_FROM_CORE_OFF;

	ret = tf_send_receive(&dev->sm, &message, &answer, NULL, false);
	if (ret) {
		printk(KERN_ERR "tf_pm_resume(%p): "
			"tf_send_receive failed (error %d)!\n",
			&dev->sm, ret);

		unregister_smc_public_crypto_digest();
		unregister_smc_public_crypto_aes();
		return ret;
	}

	if (answer.header.error_code) {
		unregister_smc_public_crypto_digest();
		unregister_smc_public_crypto_aes();
	}

	spin_lock(&tf_delayed_resume_lock);
	tf_need_delayed_resume = DELAYED_RESUME_NONE;
	spin_unlock(&tf_delayed_resume_lock);

	return answer.header.error_code;
}
Example #6
0
/*
 * Opens a client session to the Secure World
 */
int tf_open_client_session(
	struct tf_connection *connection,
	union tf_command *command,
	union tf_answer *answer)
{
	int error = 0;
	struct tf_shmem_desc *shmem_desc[4] = {NULL};
	u32 i;

	dprintk(KERN_INFO "tf_open_client_session(%p)\n", connection);

	/*
	 * Initialize the message size with no login data. This will be later
	 * adjusted the the cases below
	 */
	command->open_client_session.message_size =
		(sizeof(struct tf_command_open_client_session) - 20
			- sizeof(struct tf_command_header))/4;

	switch (command->open_client_session.login_type) {
	case TF_LOGIN_PUBLIC:
		 /* Nothing to do */
		 break;

	case TF_LOGIN_USER:
		/*
		 * Send the EUID of the calling application in the login data.
		 * Update message size.
		 */
		*(u32 *) &command->open_client_session.login_data =
			current_euid();
#ifndef CONFIG_ANDROID
		command->open_client_session.login_type =
			(u32) TF_LOGIN_USER_LINUX_EUID;
#else
		command->open_client_session.login_type =
			(u32) TF_LOGIN_USER_ANDROID_EUID;
#endif

		/* Added one word */
		command->open_client_session.message_size += 1;
		break;

	case TF_LOGIN_GROUP: {
		/* Check requested GID */
		gid_t  requested_gid =
			*(u32 *) command->open_client_session.login_data;

		if (!tf_check_gid(requested_gid)) {
			dprintk(KERN_ERR "tf_open_client_session(%p) "
				"TF_LOGIN_GROUP: requested GID (0x%x) does "
				"not match real eGID (0x%x)"
				"or any of the supplementary GIDs\n",
				connection, requested_gid, current_egid());
			error = -EACCES;
			goto error;
		}
#ifndef CONFIG_ANDROID
		command->open_client_session.login_type =
			TF_LOGIN_GROUP_LINUX_GID;
#else
		command->open_client_session.login_type =
			TF_LOGIN_GROUP_ANDROID_GID;
#endif

		command->open_client_session.message_size += 1; /* GID */
		break;
	}

#ifndef CONFIG_ANDROID
	case TF_LOGIN_APPLICATION: {
		/*
		 * Compute SHA-1 hash of the application fully-qualified path
		 * name.  Truncate the hash to 16 bytes and send it as login
		 * data.  Update message size.
		 */
		u8 pSHA1Hash[SHA1_DIGEST_SIZE];

		error = tf_hash_application_path_and_data(pSHA1Hash,
			NULL, 0);
		if (error != 0) {
			dprintk(KERN_ERR "tf_open_client_session: "
				"error in tf_hash_application_path_and_data\n");
			goto error;
		}
		memcpy(&command->open_client_session.login_data,
			pSHA1Hash, 16);
		command->open_client_session.login_type =
			TF_LOGIN_APPLICATION_LINUX_PATH_SHA1_HASH;
		/* 16 bytes */
		command->open_client_session.message_size += 4;
		break;
	}
#else
	case TF_LOGIN_APPLICATION:
		/*
		 * Send the real UID of the calling application in the login
		 * data. Update message size.
		 */
		*(u32 *) &command->open_client_session.login_data =
			current_uid();

		command->open_client_session.login_type =
			(u32) TF_LOGIN_APPLICATION_ANDROID_UID;

		/* Added one word */
		command->open_client_session.message_size += 1;
		break;
#endif

#ifndef CONFIG_ANDROID
	case TF_LOGIN_APPLICATION_USER: {
		/*
		 * Compute SHA-1 hash of the concatenation of the application
		 * fully-qualified path name and the EUID of the calling
		 * application.  Truncate the hash to 16 bytes and send it as
		 * login data.  Update message size.
		 */
		u8 pSHA1Hash[SHA1_DIGEST_SIZE];

		error = tf_hash_application_path_and_data(pSHA1Hash,
			(u8 *) &(current_euid()), sizeof(current_euid()));
		if (error != 0) {
			dprintk(KERN_ERR "tf_open_client_session: "
				"error in tf_hash_application_path_and_data\n");
			goto error;
		}
		memcpy(&command->open_client_session.login_data,
			pSHA1Hash, 16);
		command->open_client_session.login_type =
			TF_LOGIN_APPLICATION_USER_LINUX_PATH_EUID_SHA1_HASH;

		/* 16 bytes */
		command->open_client_session.message_size += 4;

		break;
	}
#else
	case TF_LOGIN_APPLICATION_USER:
		/*
		 * Send the real UID and the EUID of the calling application in
		 * the login data. Update message size.
		 */
		*(u32 *) &command->open_client_session.login_data =
			current_uid();
		*(u32 *) &command->open_client_session.login_data[4] =
			current_euid();

		command->open_client_session.login_type =
			TF_LOGIN_APPLICATION_USER_ANDROID_UID_EUID;

		/* Added two words */
		command->open_client_session.message_size += 2;
		break;
#endif

#ifndef CONFIG_ANDROID
	case TF_LOGIN_APPLICATION_GROUP: {
		/*
		 * Check requested GID.  Compute SHA-1 hash of the concatenation
		 * of the application fully-qualified path name and the
		 * requested GID.  Update message size
		 */
		gid_t  requested_gid;
		u8     pSHA1Hash[SHA1_DIGEST_SIZE];

		requested_gid =	*(u32 *) &command->open_client_session.
			login_data;

		if (!tf_check_gid(requested_gid)) {
			dprintk(KERN_ERR "tf_open_client_session(%p) "
			"TF_LOGIN_APPLICATION_GROUP: requested GID (0x%x) "
			"does not match real eGID (0x%x)"
			"or any of the supplementary GIDs\n",
			connection, requested_gid, current_egid());
			error = -EACCES;
			goto error;
		}

		error = tf_hash_application_path_and_data(pSHA1Hash,
			&requested_gid, sizeof(u32));
		if (error != 0) {
			dprintk(KERN_ERR "tf_open_client_session: "
				"error in tf_hash_application_path_and_data\n");
			goto error;
		}

		memcpy(&command->open_client_session.login_data,
			pSHA1Hash, 16);
		command->open_client_session.login_type =
			TF_LOGIN_APPLICATION_GROUP_LINUX_PATH_GID_SHA1_HASH;

		/* 16 bytes */
		command->open_client_session.message_size += 4;
		break;
	}
#else
	case TF_LOGIN_APPLICATION_GROUP: {
		/*
		 * Check requested GID. Send the real UID and the requested GID
		 * in the login data. Update message size.
		 */
		gid_t requested_gid;

		requested_gid =	*(u32 *) &command->open_client_session.
			login_data;

		if (!tf_check_gid(requested_gid)) {
			dprintk(KERN_ERR "tf_open_client_session(%p) "
			"TF_LOGIN_APPLICATION_GROUP: requested GID (0x%x) "
			"does not match real eGID (0x%x)"
			"or any of the supplementary GIDs\n",
			connection, requested_gid, current_egid());
			error = -EACCES;
			goto error;
		}

		*(u32 *) &command->open_client_session.login_data =
			current_uid();
		*(u32 *) &command->open_client_session.login_data[4] =
			requested_gid;

		command->open_client_session.login_type =
			TF_LOGIN_APPLICATION_GROUP_ANDROID_UID_GID;

		/* Added two words */
		command->open_client_session.message_size += 2;

		break;
	}
#endif

	case TF_LOGIN_PRIVILEGED:
		/* A privileged login may be performed only on behalf of the
		   kernel itself or on behalf of a process with euid=0 or
		   egid=0 or euid=system or egid=system. */
		if (connection->owner == TF_CONNECTION_OWNER_KERNEL) {
			dprintk(KERN_DEBUG "tf_open_client_session: "
				"TF_LOGIN_PRIVILEGED for kernel API\n");
		} else if ((current_euid() != TF_PRIVILEGED_UID_GID) &&
			   (current_egid() != TF_PRIVILEGED_UID_GID) &&
			   (current_euid() != 0) && (current_egid() != 0)) {
			dprintk(KERN_ERR "tf_open_client_session: "
				" user %d, group %d not allowed to open "
				"session with TF_LOGIN_PRIVILEGED\n",
				current_euid(), current_egid());
			error = -EACCES;
			goto error;
		} else {
			dprintk(KERN_DEBUG "tf_open_client_session: "
				"TF_LOGIN_PRIVILEGED for %u:%u\n",
				current_euid(), current_egid());
		}
		command->open_client_session.login_type =
			TF_LOGIN_PRIVILEGED;
		break;

	case TF_LOGIN_AUTHENTICATION: {
		/*
		 * Compute SHA-1 hash of the application binary
		 * Send this hash as the login data (20 bytes)
		 */

		u8 *hash;
		hash = &(command->open_client_session.login_data[0]);

		error = tf_get_current_process_hash(hash);
		if (error != 0) {
			dprintk(KERN_ERR "tf_open_client_session: "
				"error in tf_get_current_process_hash\n");
			goto error;
		}
		command->open_client_session.login_type =
			TF_LOGIN_AUTHENTICATION_BINARY_SHA1_HASH;

		/* 20 bytes */
		command->open_client_session.message_size += 5;
		break;
	}

	case TF_LOGIN_PRIVILEGED_KERNEL:
		/* A kernel login may be performed only on behalf of the
		   kernel itself. */
		if (connection->owner == TF_CONNECTION_OWNER_KERNEL) {
			dprintk(KERN_DEBUG "tf_open_client_session: "
				"TF_LOGIN_PRIVILEGED_KERNEL for kernel API\n");
			command->open_client_session.login_type =
				TF_LOGIN_PRIVILEGED_KERNEL;
		} else {
			dprintk(KERN_ERR "tf_open_client_session: "
				" user %d, group %d not allowed to open "
				"session with TF_LOGIN_PRIVILEGED_KERNEL\n",
				current_euid(), current_egid());
			error = -EACCES;
			goto error;
		}
		command->open_client_session.login_type =
			TF_LOGIN_PRIVILEGED_KERNEL;
		break;

	default:
		 dprintk(KERN_ERR "tf_open_client_session: "
			"unknown login_type(%08X)\n",
			command->open_client_session.login_type);
		 error = -EOPNOTSUPP;
		 goto error;
	}

	/* Map the temporary memory references */
	for (i = 0; i < 4; i++) {
		int param_type;
		param_type = TF_GET_PARAM_TYPE(
			command->open_client_session.param_types, i);
		if ((param_type & (TF_PARAM_TYPE_MEMREF_FLAG |
				   TF_PARAM_TYPE_REGISTERED_MEMREF_FLAG))
				== TF_PARAM_TYPE_MEMREF_FLAG) {
			/* Map temp mem ref */
			error = tf_map_temp_shmem(connection,
				&command->open_client_session.
					params[i].temp_memref,
				param_type,
				&shmem_desc[i]);
			if (error != 0) {
				dprintk(KERN_ERR "tf_open_client_session: "
					"unable to map temporary memory block "
					"(%08X)\n", error);
				goto error;
			}
		}
	}

	/* Fill the handle of the Device Context */
	command->open_client_session.device_context =
		connection->device_context;

	error = tf_send_receive(
		&connection->dev->sm,
		command,
		answer,
		connection,
		true);

error:
	/* Unmap the temporary memory references */
	for (i = 0; i < 4; i++)
		if (shmem_desc[i] != NULL)
			tf_unmap_shmem(connection, shmem_desc[i], 0);

	if (error != 0)
		dprintk(KERN_ERR "tf_open_client_session returns %d\n",
			error);
	else
		dprintk(KERN_ERR "tf_open_client_session returns "
			"error_code 0x%08X\n",
			answer->open_client_session.error_code);

	return error;
}
Example #7
0
int tf_create_device_context(
	struct tf_connection *connection)
{
	union tf_command command;
	union tf_answer  answer;
	int error = 0;

	dprintk(KERN_INFO "tf_create_device_context(%p)\n",
			connection);

	command.create_device_context.message_type =
		TF_MESSAGE_TYPE_CREATE_DEVICE_CONTEXT;
	command.create_device_context.message_size =
		(sizeof(struct tf_command_create_device_context)
			- sizeof(struct tf_command_header))/sizeof(u32);
	command.create_device_context.operation_id = (u32) &answer;
	command.create_device_context.device_context_id = (u32) connection;

	error = tf_send_receive(
		&connection->dev->sm,
		&command,
		&answer,
		connection,
		true);

	if ((error != 0) ||
		(answer.create_device_context.error_code != S_SUCCESS))
		goto error;

	/*
	 * CREATE_DEVICE_CONTEXT succeeded,
	 * store device context handler and update connection status
	 */
	connection->device_context =
		answer.create_device_context.device_context;
	spin_lock(&(connection->state_lock));
	connection->state = TF_CONN_STATE_VALID_DEVICE_CONTEXT;
	spin_unlock(&(connection->state_lock));

	/* successful completion */
	dprintk(KERN_INFO "tf_create_device_context(%p):"
		" device_context=0x%08x\n",
		connection,
		answer.create_device_context.device_context);
	return 0;

error:
	if (error != 0) {
		dprintk(KERN_ERR "tf_create_device_context failed with "
			"error %d\n", error);
	} else {
		/*
		 * We sent a DeviceCreateContext. The state is now
		 * TF_CONN_STATE_CREATE_DEVICE_CONTEXT_SENT It has to be
		 * reset if we ever want to send a DeviceCreateContext again
		 */
		spin_lock(&(connection->state_lock));
		connection->state = TF_CONN_STATE_NO_DEVICE_CONTEXT;
		spin_unlock(&(connection->state_lock));
		dprintk(KERN_ERR "tf_create_device_context failed with "
			"error_code 0x%08X\n",
			answer.create_device_context.error_code);
		if (answer.create_device_context.error_code ==
			S_ERROR_OUT_OF_MEMORY)
			error = -ENOMEM;
		else
			error = -EFAULT;
	}

	return error;
}
Example #8
0
/*
 * Destroys a device context from the Secure World
 */
int tf_destroy_device_context(
	struct tf_connection *connection)
{
	int error;
	/*
	 * AFY: better use the specialized tf_command_destroy_device_context
	 * structure: this will save stack
	 */
	union tf_command command;
	union tf_answer answer;

	dprintk(KERN_INFO "tf_destroy_device_context(%p)\n", connection);

	BUG_ON(connection == NULL);

	command.header.message_type = TF_MESSAGE_TYPE_DESTROY_DEVICE_CONTEXT;
	command.header.message_size =
		(sizeof(struct tf_command_destroy_device_context) -
			sizeof(struct tf_command_header))/sizeof(u32);

	/*
	 * fill in the device context handler
	 * it is guarantied that the first shared memory descriptor describes
	 * the device context
	 */
	command.destroy_device_context.device_context =
		connection->device_context;

	error = tf_send_receive(
		&connection->dev->sm,
		&command,
		&answer,
		connection,
		false);

	if ((error != 0) ||
		(answer.destroy_device_context.error_code != S_SUCCESS))
		goto error;

	spin_lock(&(connection->state_lock));
	connection->state = TF_CONN_STATE_NO_DEVICE_CONTEXT;
	spin_unlock(&(connection->state_lock));

	/* successful completion */
	dprintk(KERN_INFO "tf_destroy_device_context(%p)\n",
		connection);
	return 0;

error:
	if (error != 0) {
		dprintk(KERN_ERR "tf_destroy_device_context failed with "
			"error %d\n", error);
	} else {
		dprintk(KERN_ERR "tf_destroy_device_context failed with "
			"error_code 0x%08X\n",
			answer.destroy_device_context.error_code);
		if (answer.destroy_device_context.error_code ==
			S_ERROR_OUT_OF_MEMORY)
			error = -ENOMEM;
		else
			error = -EFAULT;
	}

	return error;
}
Example #9
0
/*
 * Invokes a client command to the Secure World
 */
int tf_invoke_client_command(
	struct tf_connection *connection,
	union tf_command *command,
	union tf_answer *answer)
{
	int error = 0;
	struct tf_shmem_desc *shmem_desc[4] = {NULL};
	int i;
#ifdef CONFIG_TF_ION
	struct ion_handle *new_handle = NULL;
#endif /* CONFIG_TF_ION */

	dprintk(KERN_INFO "tf_invoke_client_command(%p)\n", connection);

	command->release_shared_memory.message_size =
		(sizeof(struct tf_command_invoke_client_command) -
			sizeof(struct tf_command_header)) / 4;

#ifdef CONFIG_TF_ZEBRA
	error = tf_crypto_try_shortcuted_update(connection,
		(struct tf_command_invoke_client_command *) command,
		(struct tf_answer_invoke_client_command *) answer);
	if (error == 0)
		return error;
#endif

	/* Map the tmprefs */
	for (i = 0; i < 4; i++) {
		int param_type = TF_GET_PARAM_TYPE(
			command->invoke_client_command.param_types, i);

		if ((param_type & (TF_PARAM_TYPE_MEMREF_FLAG |
					TF_PARAM_TYPE_REGISTERED_MEMREF_FLAG))
				== TF_PARAM_TYPE_MEMREF_FLAG) {
			/* A temporary memref: map it */
			error = tf_map_temp_shmem(connection,
					&command->invoke_client_command.
						params[i].temp_memref,
					param_type, &shmem_desc[i]);
			if (error != 0) {
				dprintk(KERN_ERR
					"tf_invoke_client_command: "
					"unable to map temporary memory "
					"block\n (%08X)", error);
				goto error;
			}
		}
#ifdef CONFIG_TF_ION
		else if (param_type == TF_PARAM_TYPE_MEMREF_ION_HANDLE) {
			struct tf_command_invoke_client_command *invoke;
			ion_phys_addr_t ion_addr;
			size_t ion_len;
			struct ion_buffer *buffer;

			if (connection->ion_client == NULL) {
				connection->ion_client = ion_client_create(
					zebra_ion_device,
					(1 << ION_HEAP_TYPE_CARVEOUT),
					"tf");
			}
			if (connection->ion_client == NULL) {
				dprintk(KERN_ERR "%s(%p): "
					"unable to create ion client\n",
					__func__, connection);
				error = -EFAULT;
				goto error;
			}

			invoke = &command->invoke_client_command;

			dprintk(KERN_INFO "ion_handle %x",
				invoke->params[i].value.a);
			buffer = ion_share(connection->ion_client,
				(struct ion_handle *)invoke->params[i].value.a);
			if (buffer == NULL) {
				dprintk(KERN_ERR "%s(%p): "
					"unable to share ion handle\n",
					__func__, connection);
				error = -EFAULT;
				goto error;
			}

			dprintk(KERN_INFO "ion_buffer %p", buffer);
			new_handle = ion_import(connection->ion_client, buffer);
			if (new_handle == NULL) {
				dprintk(KERN_ERR "%s(%p): "
					"unable to import ion buffer\n",
					__func__, connection);
				error = -EFAULT;
				goto error;
			}

			dprintk(KERN_INFO "new_handle %x", new_handle);
			error = ion_phys(connection->ion_client,
					new_handle,
					&ion_addr,
					&ion_len);
			if (error) {
				dprintk(KERN_ERR
				"%s: unable to convert ion handle "
				"0x%08X (error code 0x%08X)\n",
				__func__,
				new_handle,
				error);
				error = -EINVAL;
				goto error;
			}
			dprintk(KERN_INFO
			"%s: handle=0x%08x phys_add=0x%08x length=0x%08x\n",
			__func__, invoke->params[i].value.a, ion_addr, ion_len);

			invoke->params[i].value.a = (u32) ion_addr;
			invoke->params[i].value.b = (u32) ion_len;

			invoke->param_types &= ~((0xF) << (4*i));
			invoke->param_types |=
				TF_PARAM_TYPE_VALUE_INPUT << (4*i);
		}
#endif /* CONFIG_TF_ION */
	}

	command->invoke_client_command.device_context =
		connection->device_context;

	error = tf_send_receive(&connection->dev->sm, command,
		answer, connection, true);

error:
#ifdef CONFIG_TF_ION
	if (new_handle != NULL)
		ion_free(connection->ion_client, new_handle);
#endif /* CONFIG_TF_ION */
	/* Unmap de temp mem refs */
	for (i = 0; i < 4; i++) {
		if (shmem_desc[i] != NULL) {
			dprintk(KERN_INFO "tf_invoke_client_command: "
				"UnMatemp_memref %d\n ", i);

			tf_unmap_shmem(connection, shmem_desc[i], 0);
		}
	}

	if (error != 0)
		dprintk(KERN_ERR "tf_invoke_client_command returns %d\n",
			error);
	else
		dprintk(KERN_ERR "tf_invoke_client_command returns "
			"error_code 0x%08X\n",
			answer->invoke_client_command.error_code);

	return error;
}
Example #10
0
/*
 * Registers a shared memory to the Secure World
 */
int tf_register_shared_memory(
	struct tf_connection *connection,
	union tf_command *command,
	union tf_answer *answer)
{
	int error = 0;
	struct tf_shmem_desc *shmem_desc = NULL;
	bool in_user_space = connection->owner != TF_CONNECTION_OWNER_KERNEL;
	struct tf_command_register_shared_memory *msg =
		&command->register_shared_memory;

	dprintk(KERN_INFO "tf_register_shared_memory(%p) "
		"%p[0x%08X][0x%08x]\n",
		connection,
		(void *)msg->shared_mem_descriptors[0],
		msg->shared_mem_size,
		(u32)msg->memory_flags);

	if (in_user_space) {
		error = tf_validate_shmem_and_flags(
			msg->shared_mem_descriptors[0],
			msg->shared_mem_size,
			(u32)msg->memory_flags);
		if (error != 0)
			goto error;
	}

	/* Initialize message_size with no descriptors */
	msg->message_size
		= (offsetof(struct tf_command_register_shared_memory,
						shared_mem_descriptors) -
			sizeof(struct tf_command_header)) / 4;

	/* Map the shmem block and update the message */
	if (msg->shared_mem_size == 0) {
		/* Empty shared mem */
		msg->shared_mem_start_offset = msg->shared_mem_descriptors[0];
	} else {
		u32 descriptor_count;
		error = tf_map_shmem(
			connection,
			msg->shared_mem_descriptors[0],
			msg->memory_flags,
			in_user_space,
			msg->shared_mem_descriptors,
			&(msg->shared_mem_start_offset),
			msg->shared_mem_size,
			&shmem_desc,
			&descriptor_count);
		if (error != 0) {
			dprintk(KERN_ERR "tf_register_shared_memory: "
				"unable to map shared memory block\n");
			goto error;
		}
		msg->message_size += descriptor_count;
	}

	/*
	 * write the correct device context handle and the address of the shared
	 * memory descriptor in the message
	 */
	msg->device_context = connection->device_context;
	msg->block_id = (u32)shmem_desc;

	/* Send the updated message */
	error = tf_send_receive(
		&connection->dev->sm,
		command,
		answer,
		connection,
		true);

	if ((error != 0) ||
		(answer->register_shared_memory.error_code
			!= S_SUCCESS)) {
		dprintk(KERN_ERR "tf_register_shared_memory: "
			"operation failed. Unmap block\n");
		goto error;
	}

	/* Saves the block handle returned by the secure world */
	if (shmem_desc != NULL)
		shmem_desc->block_identifier =
			answer->register_shared_memory.block;

	/* successful completion */
	dprintk(KERN_INFO "tf_register_shared_memory(%p):"
		" block_id=0x%08x block=0x%08x\n",
		connection, msg->block_id,
		answer->register_shared_memory.block);
	return 0;

	/* error completion */
error:
	tf_unmap_shmem(
		connection,
		shmem_desc,
		0);

	if (error != 0)
		dprintk(KERN_ERR "tf_register_shared_memory returns %d\n",
			error);
	else
		dprintk(KERN_ERR "tf_register_shared_memory returns "
			"error_code 0x%08X\n",
			answer->register_shared_memory.error_code);

	return error;
}