Ejemplo n.º 1
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;

}
Ejemplo n.º 2
0
/*
 * Clean up a list of shared memory descriptors.
 */
static void tf_shared_memory_cleanup_list(
		struct tf_connection *connection,
		struct list_head *shmem_desc_list)
{
	while (!list_empty(shmem_desc_list)) {
		struct tf_shmem_desc *shmem_desc;

		shmem_desc = list_first_entry(shmem_desc_list,
			struct tf_shmem_desc, list);

		tf_unmap_shmem(connection, shmem_desc, 1);
	}
}
Ejemplo n.º 3
0
static long tf_ctrl_device_ioctl(struct file *file, unsigned int ioctl_num,
	unsigned long ioctl_param)
{
	int result = S_SUCCESS;
	struct tf_pa_ctrl pa_ctrl;
	struct tf_device *dev = tf_get_device();

	dpr_info("%s(%p, %u, %p)\n",
		__func__, file, ioctl_num, (void *) ioctl_param);

	mutex_lock(&dev->dev_mutex);

	if (ioctl_num != IOCTL_TF_PA_CTRL) {
		dpr_err("%s(%p): ioctl number is invalid (%p)\n",
			__func__, file, (void *)ioctl_num);

		result = -EFAULT;
		goto exit;
	}

	if ((ioctl_param & 0x3) != 0) {
		dpr_err("%s(%p): ioctl command message pointer is not word "
			"aligned (%p)\n",
			__func__, file, (void *)ioctl_param);

		result = -EFAULT;
		goto exit;
	}

	if (copy_from_user(&pa_ctrl, (struct tf_pa_ctrl *)ioctl_param,
			sizeof(struct tf_pa_ctrl))) {
		dpr_err("%s(%p): cannot access ioctl parameter (%p)\n",
			__func__, file, (void *)ioctl_param);

		result = -EFAULT;
		goto exit;
	}

	switch (pa_ctrl.nPACommand) {
	case TF_PA_CTRL_START: {
		struct tf_shmem_desc *shmem_desc = NULL;
		u32 shared_mem_descriptors[TF_MAX_COARSE_PAGES];
		u32 descriptor_count;
		u32 offset;
		struct tf_connection *connection;

		dpr_info("%s(%p): Start the SMC PA (%d bytes) with conf "
			"(%d bytes)\n",
			__func__, file, pa_ctrl.pa_size, pa_ctrl.conf_size);

		connection = tf_conn_from_file(file);

		if (dev->workspace_addr == 0) {
			result = -ENOMEM;
			goto start_exit;
		}

		result = tf_validate_shmem_and_flags(
				(u32)pa_ctrl.conf_buffer,
				pa_ctrl.conf_size,
				TF_SHMEM_TYPE_READ);
		if (result != 0)
			goto start_exit;

		offset = 0;
		result = tf_map_shmem(
				connection,
				(u32)pa_ctrl.conf_buffer,
				TF_SHMEM_TYPE_READ,
				true, /* in user space */
				shared_mem_descriptors,
				&offset,
				pa_ctrl.conf_size,
				&shmem_desc,
				&descriptor_count);
		if (result != 0)
			goto start_exit;

		if (descriptor_count > 1) {
			dpr_err("%s(%p): configuration file is too long (%d)\n",
				__func__, file, descriptor_count);
			result = -ENOMEM;
			goto start_exit;
		}

		result = tf_start(&dev->sm,
			dev->workspace_addr,
			dev->workspace_size,
			pa_ctrl.pa_buffer,
			pa_ctrl.pa_size,
			shared_mem_descriptors[0],
			offset,
			pa_ctrl.conf_size);
		if (result)
			dpr_err("SMC: start failed\n");
		else
			dpr_info("SMC: started\n");

start_exit:
		tf_unmap_shmem(connection, shmem_desc, true); /* full cleanup */
		break;
	}

	case TF_PA_CTRL_STOP:
		dpr_info("%s(%p): Stop the SMC PA\n", __func__, file);

		result = tf_power_management(&dev->sm,
			TF_POWER_OPERATION_SHUTDOWN);
		if (result)
			dpr_err("SMC: stop failed [0x%x]\n", result);
		else
			dpr_info("SMC: stopped\n");
		break;

	default:
		result = -EOPNOTSUPP;
		break;
	}

exit:
	mutex_unlock(&dev->dev_mutex);
	return result;
}
Ejemplo n.º 4
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;
}
Ejemplo n.º 5
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;
}
Ejemplo n.º 6
0
/**
 * Find the first available slot for a new block of shared memory
 * and map the user buffer.
 * Update the descriptors to L1 descriptors
 * Update the buffer_start_offset and buffer_size fields
 * shmem_desc is updated to the mapped shared memory descriptor
 **/
int tf_map_shmem(
		struct tf_connection *connection,
		u32 buffer,
		/* flags for read-write access rights on the memory */
		u32 flags,
		bool in_user_space,
		u32 descriptors[TF_MAX_COARSE_PAGES],
		u32 *buffer_start_offset,
		u32 buffer_size,
		struct tf_shmem_desc **shmem_desc,
		u32 *descriptor_count)
{
	struct tf_shmem_desc *desc = NULL;
	int error;

	dprintk(KERN_INFO "tf_map_shmem(%p, %p, flags = 0x%08x)\n",
					connection,
					(void *) buffer,
					flags);

	mutex_lock(&(connection->shmem_mutex));

	/*
	 * Check the list of free shared memory
	 * is not empty
	 */
	if (list_empty(&(connection->free_shmem_list))) {
		if (atomic_read(&(connection->shmem_count)) ==
				TF_SHMEM_MAX_COUNT) {
			printk(KERN_ERR "tf_map_shmem(%p):"
				" maximum shared memories already registered\n",
				connection);
			error = -ENOMEM;
			goto error;
		}

		/* no descriptor available, allocate a new one */

		desc = (struct tf_shmem_desc *) internal_kmalloc(
			sizeof(*desc), GFP_KERNEL);
		if (desc == NULL) {
			printk(KERN_ERR "tf_map_shmem(%p):"
				" failed to allocate descriptor\n",
				connection);
			error = -ENOMEM;
			goto error;
		}

		/* Initialize the structure */
		desc->type = TF_SHMEM_TYPE_REGISTERED_SHMEM;
		atomic_set(&desc->ref_count, 1);
		INIT_LIST_HEAD(&(desc->list));

		atomic_inc(&(connection->shmem_count));
	} else {
		/* take the first free shared memory descriptor */
		desc = list_first_entry(&(connection->free_shmem_list),
			struct tf_shmem_desc, list);
		list_del(&(desc->list));
	}

	/* Add the descriptor to the used list */
	list_add(&(desc->list), &(connection->used_shmem_list));

	error = tf_fill_descriptor_table(
			&(connection->cpt_alloc_context),
			desc,
			buffer,
			connection->vmas,
			descriptors,
			buffer_size,
			buffer_start_offset,
			in_user_space,
			flags,
			descriptor_count);

	if (error != 0) {
		dprintk(KERN_ERR "tf_map_shmem(%p):"
			" tf_fill_descriptor_table failed with error "
			"code %d!\n",
			connection,
			error);
		goto error;
	}
	desc->client_buffer = (u8 *) buffer;

	/*
	 * Successful completion.
	 */
	*shmem_desc = desc;
	mutex_unlock(&(connection->shmem_mutex));
	dprintk(KERN_DEBUG "tf_map_shmem: success\n");
	return 0;


	/*
	 * Error handling.
	 */
error:
	mutex_unlock(&(connection->shmem_mutex));
	dprintk(KERN_ERR "tf_map_shmem: failure with error code %d\n",
		error);

	tf_unmap_shmem(
			connection,
			desc,
			0);

	return error;
}
Ejemplo n.º 7
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;
}