/* *********************
 * set params in ntw
 * *********************/
tee_stat_t tee_msgm_set_params(tee_msgm_t msgm, tee_msg_op_info_t *params)
{
	tee_msgm_ntw_struct *ntw_handle = NULL;
	tee_stat_t set_params_stat = TEEC_SUCCESS;
	uint32_t times = PARAM_NUMBERS, idx = 0, type = TEEC_NONE;

	OSA_ASSERT((msgm && params));
	ntw_handle = (tee_msgm_ntw_struct *) msgm;
	OSA_ASSERT(IS_MAGIC_VALID(ntw_handle->magic));
	while (times--) {
		type = TEEC_PARAM_TYPE_GET(params->paramTypes, idx);
		if (!IS_PARAMTYPES_TYPE_VALID(type)) {
			TZDD_DBG("tee_msgm_set_params: bad paramsTypes\n");
			return TEEC_ERROR_BAD_PARAMETERS;
		}
		if (IS_TYPE_MEMREF(type)) {
			if (!IS_NTW_MEM_FLAG_VALID(params->params[idx].memref.parent->flags)) {
				TZDD_DBG("tee_msgm_set_params: un-compatible arg\n");
				return TEEC_ERROR_BAD_PARAMETERS;
			}
		}
		idx++;
	}
	set_params_stat = set_params(msgm, params);
	return set_params_stat;
}
Esempio n. 2
0
static void set_params(struct tee_tz *ptee,
		struct teesmc32_param params32[TEEC_CONFIG_PAYLOAD_REF_COUNT],
		uint32_t param_types,
		struct tee_data *data)
{
	size_t n;
	struct tee_shm **shm;
	TEEC_Value *value;

	for (n = 0; n < TEEC_CONFIG_PAYLOAD_REF_COUNT; n++) {
		uint32_t type = TEEC_PARAM_TYPE_GET(param_types, n);

		params32[n].attr = param_type_teec2teesmc(type);
		if (params32[n].attr == TEESMC_ATTR_TYPE_NONE)
			continue;
		if (params32[n].attr < TEESMC_ATTR_TYPE_MEMREF_INPUT) {
			value = (TEEC_Value *)&data->params[n];
			params32[n].u.value.a = value->a;
			params32[n].u.value.b = value->b;
			continue;
		}
		shm = (struct tee_shm **)&data->params[n];
		params32[n].attr |= get_cache_attrs(ptee);
		params32[n].u.memref.buf_ptr = (*shm)->paddr;
		params32[n].u.memref.size = (*shm)->size_req;
	}
}
Esempio n. 3
0
static void _release_tee_cmd(struct tee_session *sess, struct tee_cmd *cmd)
{
	int idx;
	struct tee_context *ctx;

	BUG_ON(!cmd);
	BUG_ON(!sess);
	BUG_ON(!sess->ctx);
	BUG_ON(!sess->ctx->tee);

	ctx = sess->ctx;

	dev_dbg(_DEV_TEE, "%s: > free the temporary objects...\n", __func__);

	tee_shm_free(cmd->uuid);

	if (cmd->param.type_original == TEEC_PARAM_TYPES(TEEC_NONE,
			TEEC_NONE, TEEC_NONE, TEEC_NONE))
		goto out;

	for (idx = 0; idx < TEEC_CONFIG_PAYLOAD_REF_COUNT; ++idx) {
		int type = TEEC_PARAM_TYPE_GET(cmd->param.type_original, idx);
		struct tee_shm *shm;
		switch (type) {
		case TEEC_NONE:
		case TEEC_VALUE_INPUT:
		case TEEC_VALUE_OUTPUT:
		case TEEC_VALUE_INOUT:
			break;
		case TEEC_MEMREF_TEMP_INPUT:
		case TEEC_MEMREF_TEMP_OUTPUT:
		case TEEC_MEMREF_TEMP_INOUT:
		case TEEC_MEMREF_WHOLE:
		case TEEC_MEMREF_PARTIAL_INPUT:
		case TEEC_MEMREF_PARTIAL_OUTPUT:
		case TEEC_MEMREF_PARTIAL_INOUT:
			if (IS_ERR_OR_NULL(cmd->param.params[idx].shm))
				break;

			shm = cmd->param.params[idx].shm;

			if (is_mapped_temp(shm->flags))
				tee_shm_free(shm);
			else
				tee_shm_put(ctx, shm);
			break;
		default:
			BUG_ON(1);
		}
	}

out:
	memset(cmd, 0, sizeof(struct tee_cmd));
	dev_dbg(_DEV_TEE, "%s: <\n", __func__);
}
Esempio n. 4
0
static void set_params(
		struct teesmc32_param params32[TEEC_CONFIG_PAYLOAD_REF_COUNT],
		uint32_t param_types,
		TEEC_Value params[TEEC_CONFIG_PAYLOAD_REF_COUNT])
{
	size_t n;

	for (n = 0; n < TEEC_CONFIG_PAYLOAD_REF_COUNT; n++) {
		uint8_t a = TEEC_PARAM_TYPE_GET(param_types, n);

		if (a == TEEC_MEMREF_TEMP_INPUT ||
		    a == TEEC_MEMREF_TEMP_OUTPUT ||
		    a == TEEC_MEMREF_TEMP_INOUT)
			a |= get_cache_attrs();

		params32[n].attr = a;
		params32[n].u.value.a = params[n].a;
		params32[n].u.value.b = params[n].b;
	}
}
Esempio n. 5
0
static void _update_client_tee_cmd(struct tee_session *sess,
				   struct tee_cmd_io *cmd_io,
				   struct tee_cmd *cmd)
{
	int idx;
	struct tee_context *ctx;

	BUG_ON(!cmd_io);
	BUG_ON(!cmd_io->op);
	BUG_ON(!cmd_io->op->params);
	BUG_ON(!cmd);
	BUG_ON(!sess->ctx);
	ctx = sess->ctx;

	dev_dbg(_DEV_TEE, "%s: returned err=0x%08x (origin=%d)\n", __func__,
		cmd->err, cmd->origin);

	cmd_io->origin = cmd->origin;
	cmd_io->err = cmd->err;

	if (cmd->param.type_original == TEEC_PARAM_TYPES(TEEC_NONE,
			TEEC_NONE, TEEC_NONE, TEEC_NONE))
		return;

	for (idx = 0; idx < TEEC_CONFIG_PAYLOAD_REF_COUNT; ++idx) {
		int type = TEEC_PARAM_TYPE_GET(cmd->param.type_original, idx);
		int offset = 0;
		size_t size;
		size_t size_new;
		TEEC_SharedMemory *parent;

		dev_dbg(_DEV_TEE, "%s: id %d type %d\n", __func__, idx, type);
		BUG_ON(!tee_session_is_supported_type(sess, type));
		switch (type) {
		case TEEC_NONE:
		case TEEC_VALUE_INPUT:
		case TEEC_MEMREF_TEMP_INPUT:
		case TEEC_MEMREF_PARTIAL_INPUT:
			break;
		case TEEC_VALUE_OUTPUT:
		case TEEC_VALUE_INOUT:
			dev_dbg(_DEV_TEE, "%s: a=%08x, b=%08x\n",
				__func__,
				cmd->param.params[idx].value.a,
				cmd->param.params[idx].value.b);
			if (tee_copy_to_user
			    (ctx, &cmd_io->op->params[idx].value,
			     &cmd->param.params[idx].value,
			     sizeof(cmd_io->op->params[idx].value)))
				dev_err(_DEV_TEE,
					"%s:%d: can't update %d result to user\n",
					__func__, __LINE__, idx);
			break;
		case TEEC_MEMREF_TEMP_OUTPUT:
		case TEEC_MEMREF_TEMP_INOUT:
			/* Returned updated size */
			size_new = cmd->param.params[idx].shm->size_req;
			if (size_new !=
				cmd_io->op->params[idx].tmpref.size) {
				dev_dbg(_DEV_TEE,
					"Size has been updated by the TA %zd != %zd\n",
					size_new,
					cmd_io->op->params[idx].tmpref.size);
				tee_put_user(ctx, size_new,
				     &cmd_io->op->params[idx].tmpref.size);
			}

			dev_dbg(_DEV_TEE, "%s: tmpref %p\n", __func__,
				cmd->param.params[idx].shm->kaddr);

			/* ensure we do not exceed the shared buffer length */
			if (size_new > cmd_io->op->params[idx].tmpref.size)
				dev_err(_DEV_TEE,
					"  *** Wrong returned size from %d:%zd > %zd\n",
					idx, size_new,
					cmd_io->op->params[idx].tmpref.size);

			else if (tee_copy_to_user
				 (ctx,
				  cmd_io->op->params[idx].tmpref.buffer,
				  cmd->param.params[idx].shm->kaddr,
				  size_new))
				dev_err(_DEV_TEE,
					"%s:%d: can't update %d result to user\n",
					__func__, __LINE__, idx);
			break;

		case TEEC_MEMREF_PARTIAL_OUTPUT:
		case TEEC_MEMREF_PARTIAL_INOUT:
		case TEEC_MEMREF_WHOLE:
			parent = &cmd->param.c_shm[idx];
			if (type == TEEC_MEMREF_WHOLE) {
				offset = 0;
				size = parent->size;
			} else {
				offset = cmd_io->op->params[idx].memref.offset;
				size = cmd_io->op->params[idx].memref.size;
			}

			/* Returned updated size */
			size_new = cmd->param.params[idx].shm->size_req;
			tee_put_user(ctx, size_new,
					&cmd_io->op->params[idx].memref.size);

			/*
			 * If we allocated a tmpref buffer,
			 * copy back data to the user buffer
			 */
			if (is_mapped_temp(cmd->param.params[idx].shm->flags)) {
				if (parent->buffer &&
					offset + size_new <= parent->size) {
					if (tee_copy_to_user(ctx,
					   parent->buffer + offset,
					   cmd->param.params[idx].shm->kaddr,
					   size_new))
							dev_err(_DEV_TEE,
								"%s: can't update %d data to user\n",
								__func__, idx);
				}
			}
			break;
		default:
			BUG_ON(1);
		}
	}

}
Esempio n. 6
0
static int _init_tee_cmd(struct tee_session *sess, struct tee_cmd_io *cmd_io,
			 struct tee_cmd *cmd)
{
	int ret = -EINVAL;
	int idx;
	TEEC_Operation op;
	struct tee_data *param = &cmd->param;
	struct tee *tee;
	struct tee_context *ctx;

	BUG_ON(!sess->ctx);
	BUG_ON(!sess->ctx->tee);
	ctx = sess->ctx;
	tee = sess->ctx->tee;

	dev_dbg(_DEV(tee), "%s: > sessid=%08x\n", __func__, sess->sessid);

	memset(cmd, 0, sizeof(struct tee_cmd));

	cmd->cmd = cmd_io->cmd;
	cmd->origin = TEEC_ORIGIN_TEE;
	cmd->err = TEEC_ERROR_BAD_PARAMETERS;
	cmd_io->origin = cmd->origin;
	cmd_io->err = cmd->err;

	if (tee_context_copy_from_client(ctx, &op, cmd_io->op, sizeof(op)))
		goto out;

	cmd->param.type_original = op.paramTypes;

	for (idx = 0; idx < TEEC_CONFIG_PAYLOAD_REF_COUNT; ++idx) {
		uint32_t offset = 0;
		uint32_t size = 0;
		int type = TEEC_PARAM_TYPE_GET(op.paramTypes, idx);

		switch (type) {
		case TEEC_NONE:
			break;

		case TEEC_VALUE_INPUT:
		case TEEC_VALUE_OUTPUT:
		case TEEC_VALUE_INOUT:
			param->params[idx].value = op.params[idx].value;
			dev_dbg(_DEV_TEE,
				"%s: param[%d]:type=%d,a=%08x,b=%08x (VALUE)\n",
				__func__, idx, type, param->params[idx].value.a,
				param->params[idx].value.b);
			break;

		case TEEC_MEMREF_TEMP_INPUT:
		case TEEC_MEMREF_TEMP_OUTPUT:
		case TEEC_MEMREF_TEMP_INOUT:
			dev_dbg(_DEV_TEE,
				"> param[%d]:type=%d,buffer=%p,s=%zu (TMPREF)\n",
				idx, type, op.params[idx].tmpref.buffer,
				op.params[idx].tmpref.size);

			param->params[idx].shm =
			    tee_context_create_tmpref_buffer(ctx,
					     op.params[idx].tmpref.size,
					     op.params[idx].tmpref.buffer,
					     type);
			if (IS_ERR_OR_NULL(param->params[idx].shm))
				goto out;

			dev_dbg(_DEV_TEE, "< %d %p:%zd\n", idx,
					(void *)param->params[idx].shm->paddr,
					param->params[idx].shm->size_alloc);
			break;

		case TEEC_MEMREF_PARTIAL_INPUT:
		case TEEC_MEMREF_PARTIAL_OUTPUT:
		case TEEC_MEMREF_PARTIAL_INOUT:
		case TEEC_MEMREF_WHOLE:
			if (tee_copy_from_user(ctx, &param->c_shm[idx],
						op.params[idx].memref.parent,
						sizeof(param->c_shm[idx]))) {
				goto out;
			}

			if (type == TEEC_MEMREF_WHOLE) {
				offset = 0;
				size = param->c_shm[idx].size;
			} else { /* for PARTIAL, check the size */
				offset = op.params[idx].memref.offset;
				size = op.params[idx].memref.size;
				if (param->c_shm[idx].size < size + offset) {
					dev_err(_DEV(tee), "A PARTIAL parameter is bigger than the parent %zd < %d + %d\n",
						param->c_shm[idx].size, size,
						offset);
					goto out;
				}
			}

			dev_dbg(_DEV_TEE, "> param[%d]:type=%d,buffer=%p, offset=%d size=%d\n",
					idx, type, param->c_shm[idx].buffer,
					offset, size);

			type = to_memref_type(param->c_shm[idx].flags);
			if (type == 0)
				goto out;

			param->params[idx].shm = tee_shm_get(ctx,
					&param->c_shm[idx], size, offset);

			if (IS_ERR_OR_NULL(param->params[idx].shm)) {
				param->params[idx].shm =
				    tee_context_create_tmpref_buffer(ctx, size,
				       param->c_shm[idx].buffer + offset, type);

				if (IS_ERR_OR_NULL(param->params[idx].shm))
					goto out;
			}

			dev_dbg(_DEV_TEE, "< %d %p:%zd\n", idx,
				(void *)param->params[idx].shm->paddr,
				param->params[idx].shm->size_req);
			break;

		default:
			BUG_ON(1);
		}

		param->type |= (type << (idx * 4));
	}

	if (cmd_io->uuid != NULL) {
		dev_dbg(_DEV_TEE, "%s: copy UUID value...\n", __func__);
		cmd->uuid = tee_context_alloc_shm_tmp(sess->ctx,
			sizeof(*cmd_io->uuid), cmd_io->uuid, TEEC_MEM_INPUT);
		if (IS_ERR_OR_NULL(cmd->uuid)) {
			ret = -EINVAL;
			goto out;
		}
	}

	ret = 0;

out:
	if (ret)
		_release_tee_cmd(sess, cmd);

	dev_dbg(_DEV_TEE, "%s: < ret=%d\n", __func__, ret);
	return ret;
}
/*
 * the buffer does NOT include the command header.
 * the header is maintained by callers.
 * the typical behavior of callers is to alloc
 * sizeof(tee_msg_head_t) + buf-size.
 * then set "mem + sizeof(tee_msg_head_t)" as the arg, buf.
 *
 * send Msg: tee_msgm_set_msg_buf(msgm, mi, NULL, &size); STAT_SET
 *           tee_msgm_set_msg_buf(msgm, NULL, buf, NULL); STAT_CLEAR
 * receive Msg: tee_msgm_set_msg_buf(msgm, NULL, buf, NULL);
 * **************************************************************************
 */
tee_stat_t tee_msgm_set_msg_buf(tee_msgm_t msgm, tee_msgm_msg_info_t *mi,
				uint8_t *buf, uint32_t *size)
{
	tee_msgm_ntw_struct *ntw_handle = NULL;
	uint32_t buf_size = 0, pages = 0, types = 0, idx = 0, value = 0;
	tee_stat_t shm_stat = TEEC_SUCCESS;
	TEEC_Operation *ntw_op = NULL;

	/* either mi && size or buf non-NULL; */
	OSA_ASSERT(((mi && size) || buf));
	OSA_ASSERT(msgm);
	ntw_handle = (tee_msgm_ntw_struct *) msgm;
	OSA_ASSERT(IS_MAGIC_VALID(ntw_handle->magic));

	if (NULL != buf) {
		/* set handle-item according to buf-ptr */
		ntw_handle->ntw_cmd = (cmd_struct *) buf;
		ntw_handle->body = buf + sizeof(cmd_struct);
		if (TEE_NTW_CMD_STAT_SET == ntw_handle->cmd_record.stat) {
			/* send msg: empty buffer for set cmd and params */
			osa_memset(buf, 0, ntw_handle->cmd_record.msg_sz);
			INIT_CMD_MAGIC(ntw_handle->ntw_cmd->magic);
			ntw_handle->ntw_params =
			    (params_struct *) (ntw_handle->body +
					       ntw_handle->cmd_record.cmd_sz);
			ntw_handle->ntw_cmd->cmd_sz =
			    ntw_handle->cmd_record.cmd_sz;
			ntw_handle->op =
			    _g_op_array[ntw_handle->cmd_record.cmd];
			ntw_handle->cmd_record.stat = TEE_NTW_CMD_STAT_CLEAR;
		} else {
			/* receive msg: msg for get cmd or params */
			OSA_ASSERT(IS_CMD_MAGIC_VALID
				   (ntw_handle->ntw_cmd->magic));
			ntw_handle->ntw_params =
			    (params_struct *) (ntw_handle->body +
					       ntw_handle->ntw_cmd->cmd_sz);
			ntw_handle->op = _g_op_array[ntw_handle->ntw_cmd->cmd];
		}
	} else if (mi && size) {
		/* send msg: calculate the size of msg-buf
		 * according info provided by mi
		*/
		OSA_ASSERT(TEE_NTW_CMD_STAT_CLEAR ==
			   ntw_handle->cmd_record.stat);
		/* handle tmp_mem_ref */
		if (mi->msg_op_info) {
			ntw_op = mi->msg_op_info;
			types = ntw_op->paramTypes;
			for (idx = 0; idx < 4; idx++) {
				value = TEEC_PARAM_TYPE_GET(types, idx);
				if (IS_TYPE_TMPREF(value)) {
					buf_size +=
					    ntw_op->params[idx].tmpref.size;
				}
			}
		}
		/* calculate the size of cmd_body */
		if (TEE_CMD_INVALID <= mi->cmd && TEE_CMD_CAN_OP >= mi->cmd) {
			if (TEE_CMD_MAP_SHM == mi->cmd
			    && NULL != mi->msg_map_shm_info) {
				shm_stat =
				    _calc_map_shm_len(mi->msg_map_shm_info,
						      &pages);
				if (TEEC_SUCCESS != shm_stat)
					return shm_stat;

				ntw_handle->cmd_record.cmd_sz =
				    _g_body_size_array[mi->cmd] +
				    pages * sizeof(tee_msgm_phys_memblock_t);
			} else
				ntw_handle->cmd_record.cmd_sz =
				    _g_body_size_array[mi->cmd];
		} else {
			TZDD_DBG("ERROR: cmd not exist\n");
			OSA_ASSERT(0);
		}
		/* saved rec to cmd_record */
		ntw_handle->cmd_record.param_size = buf_size;
		ntw_handle->cmd_record.cmd = mi->cmd;
		ntw_handle->cmd_record.stat = TEE_NTW_CMD_STAT_SET;
		*size = sizeof(cmd_struct) + ntw_handle->cmd_record.cmd_sz +
		    sizeof(params_struct) + ntw_handle->cmd_record.param_size;
		ntw_handle->cmd_record.msg_sz = *size;
	} else {
		TZDD_DBG("ERROR: both mi&&size and buf are NULL pointer\n");
		OSA_ASSERT(0);
	}
	return TEEC_SUCCESS;
}
Esempio n. 8
0
static void _update_client_tee_cmd(struct tee_session *sess,
				   struct tee_cmd_io *cmd_io,
				   struct tee_cmd *cmd)
{
	int idx;
	struct tee_context *ctx;
	BUG_ON(!cmd_io);
	BUG_ON(!cmd_io->op);
	BUG_ON(!cmd_io->op->params);
	BUG_ON(!cmd);
	BUG_ON(!sess->ctx);
	ctx = sess->ctx;

	dev_dbg(_DEV_TEE, "%s: returned err=0x%08x (origin=%d)\n", __func__,
		cmd->err, cmd->origin);

	cmd_io->origin = cmd->origin;
	cmd_io->err = cmd->err;

	if (cmd->param.type_original == TEEC_PARAM_TYPES(TEEC_NONE,
			TEEC_NONE, TEEC_NONE, TEEC_NONE))
		return;

	for (idx = 0; idx < TEEC_CONFIG_PAYLOAD_REF_COUNT; ++idx) {
		int type = TEEC_PARAM_TYPE_GET(cmd->param.type_original, idx);
		dev_dbg(_DEV_TEE, "%s: id %d type %d\n", __func__, idx, type);
		BUG_ON(!tee_session_is_supported_type(sess, type));
		switch (type) {
		case TEEC_NONE:
		case TEEC_VALUE_INPUT:
		case TEEC_MEMREF_TEMP_INPUT:
		case TEEC_MEMREF_PARTIAL_INPUT:
			break;
		case TEEC_VALUE_OUTPUT:
		case TEEC_VALUE_INOUT:{
				dev_dbg(_DEV_TEE, "%s: a=%08x, b=%08x\n",
					__func__,
					cmd->param.params[idx].value.a,
					cmd->param.params[idx].value.b);
				if (tee_copy_to_user
				    (ctx, &cmd_io->op->params[idx].value,
				     &cmd->param.params[idx].value,
				     sizeof(cmd_io->op->params[idx].value)))
					dev_err(_DEV_TEE,
						"%s:%d: can't update %d result to user\n",
						__func__, __LINE__, idx);
				break;
			}
		case TEEC_MEMREF_TEMP_OUTPUT:
		case TEEC_MEMREF_TEMP_INOUT:{
				/* Returned updated size */
				size_t size =
					cmd->param.params[idx].shm->size_req;
				if (size !=
					cmd_io->op->params[idx].tmpref.size) {
					dev_dbg(_DEV_TEE,
						"Size has been updated by the TA %zu != %zu\n",
						size,
						cmd_io->op->params[idx].tmpref.
						size);
					tee_put_user(ctx, size,
						     &cmd_io->op->params[idx].
						     tmpref.size);
				}

				BUG_ON(!cmd->param.params[idx].shm);
				BUG_ON(!
				       (cmd->param.params[idx].shm->
					flags & TEE_SHM_TEMP));
				dev_dbg(_DEV_TEE, "%s: tmpref %p\n", __func__,
					cmd->param.params[idx].shm->kaddr);

				/* ensure we do not exceed
				 * the shared buffer length */
				if (size > cmd_io->op->params[idx].tmpref.size)
					dev_err(_DEV_TEE,
						"  *** Wrong returned size from %d:%zu > %zu\n",
						idx, size,
						cmd_io->op->params[idx].tmpref.
						size);

				else if (tee_copy_to_user
					 (ctx,
					  cmd_io->op->params[idx].tmpref.buffer,
					  cmd->param.params[idx].shm->kaddr,
					  size))
					dev_err(_DEV_TEE,
						"%s:%d: can't update %d result to user\n",
						__func__, __LINE__, idx);
				break;
			}
		case TEEC_MEMREF_WHOLE:{
				/* Returned updated size */
				size_t size =
					cmd->param.params[idx].shm->size_req;
				if (size !=
					cmd_io->op->params[idx].memref.size) {
					dev_dbg(_DEV_TEE,
						"Size has been updated by the TA %zu != %zu\n",
						size,
						cmd_io->op->params[idx].memref.
						size);
					tee_put_user(ctx, size,
						     &cmd_io->op->params[idx].
						     memref.size);
				}

				/* ensure we do not exceed
				 * the shared buffer length */
				if (size > cmd->param.c_shm[idx].size)
					dev_err(_DEV_TEE,
						"  *** Wrong returned size from %d:%zu > %zu\n",
						idx, size,
						cmd->param.c_shm[idx].size);

				else if ((cmd->param.params[idx].shm->flags &
					(TEE_SHM_MAPPED | TEE_SHM_TEMP)) ==
					(TEE_SHM_MAPPED | TEE_SHM_TEMP)) {
					BUG_ON(!cmd->param.c_shm[idx].buffer);
					BUG_ON(!cmd->param.c_shm[idx].size > 0);
					dev_dbg(_DEV_TEE, "%s: whole %p\n",
						__func__,
						cmd->param.params[idx].shm->
						kaddr);
					if (tee_copy_to_user
					    (ctx, cmd->param.c_shm[idx].buffer,
					     cmd->param.params[idx].shm->kaddr,
					     size))
						dev_err(_DEV_TEE,
							"%s: can't update %d result to user\n",
							__func__, idx);
				}
				break;
			}
		case TEEC_MEMREF_PARTIAL_OUTPUT:
		case TEEC_MEMREF_PARTIAL_INOUT:{
				int offset =
				    cmd_io->op->params[idx].memref.offset;
				/* Returned updated size */
				size_t size =
					cmd->param.params[idx].shm->size_req;

				if (size !=
					cmd_io->op->params[idx].memref.size) {
					dev_dbg(_DEV_TEE,
						"Size has been updated by the TA %zu != %zu\n",
						size,
						cmd_io->op->params[idx].memref.
						size);
					tee_put_user(ctx, size,
						     &cmd_io->op->params[idx].
						     memref.size);
				}

				/* ensure we do not exceed
				 * the shared buffer length */
				if ((offset + size) >
				    cmd->param.c_shm[idx].size)
					dev_err(_DEV_TEE,
						"  *** Wrong returned size from %d:%d +%zu > %zu\n",
						idx, offset, size,
						cmd->param.c_shm[idx].size);

				/* If we allocated a tmpref buffer,
				 * copy back data to the user buffer */
				else if ((cmd->param.params[idx].shm->flags &
					(TEE_SHM_MAPPED | TEE_SHM_TEMP)) ==
					(TEE_SHM_MAPPED | TEE_SHM_TEMP)) {
					BUG_ON(!cmd->param.c_shm[idx].buffer);
					BUG_ON(!cmd->param.c_shm[idx].size > 0);
					if (tee_copy_to_user
					    (ctx,
					     cmd->param.c_shm[idx].buffer +
					     offset,
					     cmd->param.params[idx].shm->kaddr,
					     size))
						dev_err(_DEV_TEE,
							"%s: can't update %d result to user\n",
							__func__, idx);
				}
				break;
			}
		default:
			BUG_ON(1);
		}
	}

}
Esempio n. 9
0
static int _copy_op(struct tee_session *sess, struct tee_cmd_io *cmd_io,
		    struct tee_cmd *cmd)
{
	int res = -EINVAL;
	int idx;
	TEEC_Operation op;
	struct tee_data *param = &cmd->param;
	struct tee *tee;
	struct tee_context *ctx;

	BUG_ON(!sess->ctx);
	BUG_ON(!sess->ctx->tee);
	ctx = sess->ctx;
	tee = sess->ctx->tee;

	dev_dbg(_DEV(tee), "%s: > sessid=%08x\n", __func__, sess->sessid);

	if (tee_context_copy_from_client
	    (sess->ctx, &op, cmd_io->op, sizeof(TEEC_Operation)))
		goto out;

	cmd->param.type_original = op.paramTypes;

	if (cmd->param.type_original == TEEC_PARAM_TYPES(TEEC_NONE,
			TEEC_NONE, TEEC_NONE, TEEC_NONE)) {
		param->type = cmd->param.type_original;
		res = 0;
		goto out;
	}

	for (idx = 0; idx < TEEC_CONFIG_PAYLOAD_REF_COUNT; ++idx) {
		int type = TEEC_PARAM_TYPE_GET(op.paramTypes, idx);
		switch (type) {
		case TEEC_NONE:
			break;
		case TEEC_VALUE_INPUT:
		case TEEC_VALUE_OUTPUT:
		case TEEC_VALUE_INOUT:
			param->params[idx].value = op.params[idx].value;
			dev_dbg(_DEV_TEE,
				"%s: param[%d]:type=%d,a=%08x,b=%08x (VALUE)\n",
				__func__, idx, type, param->params[idx].value.a,
				param->params[idx].value.b);
			break;

		case TEEC_MEMREF_TEMP_INPUT:
		case TEEC_MEMREF_TEMP_OUTPUT:
		case TEEC_MEMREF_TEMP_INOUT:
			dev_dbg(_DEV_TEE,
				"> param[%d]:type=%d,buffer=%p,s=%zu (TMPREF)\n",
				idx, type, op.params[idx].tmpref.buffer,
				op.params[idx].tmpref.size);
			param->params[idx].shm =
			    tee_context_create_tmpref_buffer(sess->ctx,
							     op.params[idx].
							     tmpref.size,
							     op.params[idx].
							     tmpref.buffer,
							     type);
			if (IS_ERR_OR_NULL(param->params[idx].shm))
				return -ENOMEM;
			dev_dbg(_DEV_TEE, "< %d %p:%zu (TMPREF)\n",
				idx, (void *)param->params[idx].shm->paddr,
				param->params[idx].shm->size_req);
			break;

		case TEEC_MEMREF_WHOLE:
			if (sess->ctx->usr_client) {
				if (tee_copy_from_user(ctx, &param->c_shm[idx],
						       op.params[idx].memref.
						       parent,
						       sizeof
						       (TEEC_SharedMemory))) {
					res = TEEC_ERROR_BAD_PARAMETERS;
					goto out;
				}
			} else
				param->c_shm[idx] =
				    *op.params[idx].memref.parent;

			BUG_ON(!param->c_shm[idx].buffer);
			BUG_ON(!param->c_shm[idx].size);

			if (param->c_shm[idx].flags == TEEC_MEM_INPUT)
				type = TEEC_MEMREF_TEMP_INPUT;
			else if (param->c_shm[idx].flags == TEEC_MEM_OUTPUT)
				type = TEEC_MEMREF_TEMP_OUTPUT;
			else if (param->c_shm[idx].flags ==
				 (TEEC_MEM_INPUT | TEEC_MEM_OUTPUT))
				type = TEEC_MEMREF_TEMP_INOUT;

			if (check_shm
			    (tee, (struct tee_shm_io *)&param->c_shm[idx])) {
				dev_dbg(_DEV_TEE,
					"> param[%d]:type=%d,buffer=%p, s=%zu (WHOLE)\n",
					idx, type, op.params[idx].tmpref.buffer,
					param->c_shm[idx].size);

				param->params[idx].shm =
				    tee_context_create_tmpref_buffer(sess->ctx,
						param->c_shm[idx].size,
						param->c_shm[idx].buffer,
						type);
				if (IS_ERR_OR_NULL(param->params[idx].shm))
					return -ENOMEM;

				dev_dbg(_DEV_TEE, "< %d %p:%zu (WHOLE)\n",
					idx,
					(void *)param->params[idx].shm->paddr,
					param->params[idx].shm->size_req);
			} else {
				struct tee_shm *shm;
				/* The buffer is already allocated by the tee
				 * get a reference on it
				 */
				shm =
				    tee_shm_get(sess->ctx,
						(struct tee_shm_io *)&param->
						c_shm[idx]);
				if (!shm)
					/* not allocated by us,
					 * is it a use case ? */
					BUG_ON(1);

				param->params[idx].shm =
				    devm_kzalloc(tee->dev,
						 sizeof(struct tee_shm),
						 GFP_KERNEL);
				if (!param->params[idx].shm)
					return -ENOMEM;

				param->params[idx].shm->parent = shm;
				param->params[idx].shm->ctx = sess->ctx;
				param->params[idx].shm->tee = tee;
				param->params[idx].shm->dev = tee->dev;
				param->params[idx].shm->size_req =
				    param->c_shm[idx].size;
				param->params[idx].shm->size_alloc = 0;
				param->params[idx].shm->kaddr = shm->kaddr;
				param->params[idx].shm->paddr = shm->paddr;
				param->params[idx].shm->flags =
				    shm->flags | TEE_SHM_PARENT;
			}
			break;

		case TEEC_MEMREF_PARTIAL_INPUT:
		case TEEC_MEMREF_PARTIAL_OUTPUT:
		case TEEC_MEMREF_PARTIAL_INOUT:{
				uint32_t offset = op.params[idx].memref.offset;
				uint32_t size = op.params[idx].memref.size;

				if (sess->ctx->usr_client) {
					if (tee_copy_from_user
					    (ctx, &param->c_shm[idx],
					     op.params[idx].memref.parent,
					     sizeof(TEEC_SharedMemory))) {
						res = TEEC_ERROR_BAD_PARAMETERS;
						goto out;
					}
				} else
					param->c_shm[idx] =
					    *op.params[idx].memref.parent;

				dev_dbg(_DEV_TEE,
					"> param[%d]:type=%d,buffer=%p, offset=%x s=%d (PARTIAL)\n",
					idx, type, param->c_shm[idx].buffer,
					offset, size);

				if (type == TEEC_MEMREF_PARTIAL_INPUT)
					type = TEEC_MEMREF_TEMP_INPUT;
				else if (type == TEEC_MEMREF_PARTIAL_OUTPUT)
					type = TEEC_MEMREF_TEMP_OUTPUT;
				else if (type == TEEC_MEMREF_PARTIAL_INOUT)
					type = TEEC_MEMREF_TEMP_INOUT;


				if (check_shm
				    (tee,
				     (struct tee_shm_io *)&param->c_shm[idx])) {

					param->params[idx].shm =
					    tee_context_create_tmpref_buffer
					    (sess->ctx, size,
					     param->c_shm[idx].buffer + offset,
					     type);
					if (IS_ERR_OR_NULL(
							param->params[idx].shm))
						return -ENOMEM;

				} else {
					struct tee_shm *shm;
					/* The buffer is already allocated by
					 * the tee
					 * get a reference on it
					 */

					shm =
					    tee_shm_get(sess->ctx,
							(struct tee_shm_io *)
							&param->c_shm[idx]);
					if (!shm)
						/* not allocated by us,
						 * is it a use case ? */
						BUG_ON(1);

					param->params[idx].shm =
					    devm_kzalloc(tee->dev,
							 sizeof(struct tee_shm),
							 GFP_KERNEL);
					if (!param->params[idx].shm)
						return -ENOMEM;

					param->params[idx].shm->parent = shm;
					param->params[idx].shm->ctx = sess->ctx;
					param->params[idx].shm->tee = tee;
					param->params[idx].shm->dev = tee->dev;
					param->params[idx].shm->size_req = size;
					param->params[idx].shm->size_alloc = 0;
					param->params[idx].shm->kaddr =
					    shm->kaddr + offset;
					param->params[idx].shm->paddr =
					    shm->paddr + offset;
					param->params[idx].shm->flags =
					    shm->flags | TEE_SHM_PARENT;


				}
				dev_dbg(_DEV_TEE, "< %d %p:%zu (PARTIAL)\n",
					idx,
					(void *)param->params[idx].shm->paddr,
					param->params[idx].shm->size_req);
				break;
			}
		default:
			BUG_ON(1);
		}

		param->type |= (type << (idx * 4));
	}
	res = 0;

out:
	dev_dbg(_DEV(tee), "%s: < fd=%d\n", __func__, res);
	return res;
}