示例#1
0
/*
 * tee_invoke_command - invoke TEE to invoke a GP TEE command
 */
static int tz_invoke(struct tee_session *sess, struct tee_cmd *cmd)
{
	struct tee *tee;
	struct tee_tz *ptee;
	int ret = 0;

	struct teesmc32_arg *arg32;
	uintptr_t parg32;
	struct teesmc32_param *params32;

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

	dev_dbg(DEV, "> sessid %x cmd %x type %x\n",
		sess->sessid, cmd->cmd, cmd->param.type);

	if (!CAPABLE(tee)) {
		dev_dbg(tee->dev, "< not capable\n");
		return -EBUSY;
	}

	arg32 = (typeof(arg32))alloc_tee_arg(ptee, &parg32,
			TEESMC32_GET_ARG_SIZE(TEEC_CONFIG_PAYLOAD_REF_COUNT));
	if (!arg32) {
		free_tee_arg(ptee, parg32);
		return TEEC_ERROR_OUT_OF_MEMORY;
	}

	memset(arg32, 0, sizeof(*arg32));
	arg32->num_params = TEEC_CONFIG_PAYLOAD_REF_COUNT;
	params32 = TEESMC32_GET_PARAMS(arg32);

	arg32->cmd = TEESMC_CMD_INVOKE_COMMAND;
	arg32->session = sess->sessid;
	arg32->ta_func = cmd->cmd;

	set_params(ptee, params32, cmd->param.type, &cmd->param);

	call_tee(ptee, parg32, arg32);

	get_params(&cmd->param, params32);

	if (arg32->ret != TEEC_ERROR_COMMUNICATION) {
		cmd->err = arg32->ret;
		cmd->origin = arg32->ret_origin;
	} else
		ret = -EBUSY;

	free_tee_arg(ptee, parg32);

	dev_dbg(DEV, "< %x:%d\n", arg32->ret, ret);
	return ret;
}
示例#2
0
/*
 * tee_invoke_command - invoke TEE to invoke a GP TEE command
 */
static TEEC_Result tee_invoke_command(struct tee_session *ts,
	enum t_cmd_service_id sec_cmd,
	uint32_t ta_cmd,
	uint32_t param_type,
	TEEC_Value params[TEEC_CONFIG_PAYLOAD_REF_COUNT],
	uint32_t *origin)
{
	TEEC_Result ret_tee;
	struct teesmc32_arg *arg32;
	uintptr_t parg32;
	struct teesmc32_param *params32;

	dev_dbg(DEV, "> [%p] [%d]\n", (void *)ts->id, ta_cmd);

	arg32 = (typeof(arg32))alloc_tee_arg(&parg32,
			TEESMC32_GET_ARG_SIZE(TEEC_CONFIG_PAYLOAD_REF_COUNT));
	if (!arg32) {
		free_tee_arg(parg32);
		return TEEC_ERROR_OUT_OF_MEMORY;
	}

	memset(arg32, 0, sizeof(*arg32));
	arg32->num_params = TEEC_CONFIG_PAYLOAD_REF_COUNT;
	params32 = TEESMC32_GET_PARAMS(arg32);

	arg32->cmd = TEESMC_CMD_INVOKE_COMMAND;
	arg32->session = ts->id;
	arg32->ta_func = ta_cmd;

	set_params(params32, param_type, params);

	mutex_lock(&e_mutex_teez);
	call_tee(parg32, arg32);
	mutex_unlock(&e_mutex_teez);

	ret_tee = arg32->ret;

	get_params(params, params32);

	if (origin)
		*origin = arg32->ret_origin;

	free_tee_arg(parg32);
	dev_dbg(DEV, "< [%p]\n", (void *)ret_tee);
	return ret_tee;
}
示例#3
0
static void handle_rpc_func_cmd_mutex_wait(struct tee_tz *ptee,
						struct teesmc32_arg *arg32)
{
	struct teesmc32_param *params;

	if (arg32->num_params != 2)
		goto bad;

	params = TEESMC32_GET_PARAMS(arg32);

	if ((params[0].attr & TEESMC_ATTR_TYPE_MASK) !=
			TEESMC_ATTR_TYPE_VALUE_INPUT)
		goto bad;
	if ((params[1].attr & TEESMC_ATTR_TYPE_MASK) !=
			TEESMC_ATTR_TYPE_VALUE_INPUT)
		goto bad;

	switch (params[0].u.value.a) {
	case TEE_MUTEX_WAIT_SLEEP:
		tee_mutex_wait_sleep(DEV, &ptee->mutex_wait,
				     params[1].u.value.a,
				     params[1].u.value.b);
		break;
	case TEE_MUTEX_WAIT_WAKEUP:
		tee_mutex_wait_wakeup(DEV, &ptee->mutex_wait,
				      params[1].u.value.a,
				      params[1].u.value.b);
		break;
	case TEE_MUTEX_WAIT_DELETE:
		tee_mutex_wait_delete(DEV, &ptee->mutex_wait,
				      params[1].u.value.a);
		break;
	default:
		goto bad;
	}

	arg32->ret = TEEC_SUCCESS;
	return;
bad:
	arg32->ret = TEEC_ERROR_BAD_PARAMETERS;
}
示例#4
0
static void handle_rpc_func_cmd_wait(struct teesmc32_arg *arg32)
{
	struct teesmc32_param *params;
	u32 msec_to_wait;

	if (arg32->num_params != 1)
		goto bad;

	params = TEESMC32_GET_PARAMS(arg32);
	msec_to_wait = params[0].u.value.a;

	/* set task's state to interruptible sleep */
	set_current_state(TASK_INTERRUPTIBLE);

	/* take a nap */
	schedule_timeout(msecs_to_jiffies(msec_to_wait));

	arg32->ret = TEEC_SUCCESS;
	return;
bad:
	arg32->ret = TEEC_ERROR_BAD_PARAMETERS;
}
示例#5
0
/*
 * tee_open_session - invoke TEE to open a GP TEE session
 */
static int tz_open(struct tee_session *sess, struct tee_cmd *cmd)
{
	struct tee *tee;
	struct tee_tz *ptee;
	int ret = 0;

	struct teesmc32_arg *arg32;
	struct teesmc32_param *params32;
	struct teesmc_meta_open_session *meta;
	uintptr_t parg32;
	uintptr_t pmeta;
	size_t num_meta = 1;
	uint8_t *ta;
	TEEC_UUID *uuid;

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

	if (cmd->uuid)
		uuid = cmd->uuid->kaddr;
	else
		uuid = NULL;

	dev_dbg(tee->dev, "> ta kaddr %p, uuid=%08x-%04x-%04x\n",
		(cmd->ta) ? cmd->ta->kaddr : NULL,
		((uuid) ? uuid->timeLow : 0xDEAD),
		((uuid) ? uuid->timeMid : 0xDEAD),
		((uuid) ? uuid->timeHiAndVersion : 0xDEAD));

	if (!CAPABLE(ptee->tee)) {
		dev_dbg(tee->dev, "< not capable\n");
		return -EBUSY;
	}

	/* case ta binary is inside the open request */
	ta = NULL;
	if (cmd->ta)
		ta = cmd->ta->kaddr;
	if (ta)
		num_meta++;

	arg32 = alloc_tee_arg(ptee, &parg32, TEESMC32_GET_ARG_SIZE(
				TEEC_CONFIG_PAYLOAD_REF_COUNT + num_meta));
	meta = alloc_tee_arg(ptee, &pmeta, sizeof(*meta));

	if ((arg32 == NULL) || (meta == NULL)) {
		free_tee_arg(ptee, parg32);
		free_tee_arg(ptee, pmeta);
		return TEEC_ERROR_OUT_OF_MEMORY;
	}

	memset(arg32, 0, sizeof(*arg32));
	memset(meta, 0, sizeof(*meta));
	arg32->num_params = TEEC_CONFIG_PAYLOAD_REF_COUNT + num_meta;
	params32 = TEESMC32_GET_PARAMS(arg32);

	arg32->cmd = TEESMC_CMD_OPEN_SESSION;

	params32[0].u.memref.buf_ptr = pmeta;
	params32[0].u.memref.size = sizeof(*meta);
	params32[0].attr = TEESMC_ATTR_TYPE_MEMREF_INPUT |
			 TEESMC_ATTR_META | get_cache_attrs(ptee);

	if (ta) {
		params32[1].u.memref.buf_ptr =
			tee_shm_pool_v2p(DEV, ptee->shm_pool, cmd->ta->kaddr);
		params32[1].u.memref.size = cmd->ta->size_req;
		params32[1].attr = TEESMC_ATTR_TYPE_MEMREF_INPUT |
				 TEESMC_ATTR_META | get_cache_attrs(ptee);
	}

	if (uuid != NULL)
		memcpy(meta->uuid, uuid, TEESMC_UUID_LEN);
	meta->clnt_login = 0; /* FIXME: is this reliable ? used ? */

	params32 += num_meta;
	set_params(ptee, params32, cmd->param.type, &cmd->param);

	call_tee(ptee, parg32, arg32);

	get_params(&cmd->param, params32);

	if (arg32->ret != TEEC_ERROR_COMMUNICATION) {
		sess->sessid = arg32->session;
		cmd->err = arg32->ret;
		cmd->origin = arg32->ret_origin;
	} else
		ret = -EBUSY;

	free_tee_arg(ptee, parg32);
	free_tee_arg(ptee, pmeta);

	dev_dbg(DEV, "< %x:%d\n", arg32->ret, ret);
	return ret;
}
示例#6
0
static void handle_rpc_func_cmd_to_supplicant(struct tee_tz *ptee,
						struct teesmc32_arg *arg32)
{
	struct teesmc32_param *params;
	struct tee_rpc_invoke inv;
	size_t n;
	uint32_t ret;

	if (arg32->num_params > TEE_RPC_BUFFER_NUMBER) {
		arg32->ret = TEEC_ERROR_GENERIC;
		return;
	}

	params = TEESMC32_GET_PARAMS(arg32);

	memset(&inv, 0, sizeof(inv));
	inv.cmd = arg32->cmd;
	/*
	 * Set a suitable error code in case tee-supplicant
	 * ignores the request.
	 */
	inv.res = TEEC_ERROR_NOT_IMPLEMENTED;
	inv.nbr_bf = arg32->num_params;
	for (n = 0; n < arg32->num_params; n++) {
		inv.cmds[n].buffer =
			(void *)(uintptr_t)params[n].u.memref.buf_ptr;
		inv.cmds[n].size = params[n].u.memref.size;
		switch (params[n].attr & TEESMC_ATTR_TYPE_MASK) {
		case TEESMC_ATTR_TYPE_VALUE_INPUT:
		case TEESMC_ATTR_TYPE_VALUE_OUTPUT:
		case TEESMC_ATTR_TYPE_VALUE_INOUT:
			inv.cmds[n].type = TEE_RPC_VALUE;
			break;
		case TEESMC_ATTR_TYPE_MEMREF_INPUT:
		case TEESMC_ATTR_TYPE_MEMREF_OUTPUT:
		case TEESMC_ATTR_TYPE_MEMREF_INOUT:
			inv.cmds[n].type = TEE_RPC_BUFFER;
			break;
		default:
			arg32->ret = TEEC_ERROR_GENERIC;
			return;
		}
	}

	ret = tee_supp_cmd(ptee->tee, TEE_RPC_ICMD_INVOKE,
				  &inv, sizeof(inv));
	if (ret == TEEC_RPC_OK)
		arg32->ret = inv.res;

	for (n = 0; n < arg32->num_params; n++) {
		switch (params[n].attr & TEESMC_ATTR_TYPE_MASK) {
		case TEESMC_ATTR_TYPE_VALUE_INPUT:
		case TEESMC_ATTR_TYPE_VALUE_OUTPUT:
		case TEESMC_ATTR_TYPE_VALUE_INOUT:
		case TEESMC_ATTR_TYPE_MEMREF_OUTPUT:
		case TEESMC_ATTR_TYPE_MEMREF_INOUT:
			/*
			 * Allow supplicant to assign a new pointer
			 * to an out-buffer. Needed when the
			 * supplicant allocates a new buffer, for
			 * instance when loading a TA.
			 */
			params[n].u.memref.buf_ptr =
					(uint32_t)(uintptr_t)inv.cmds[n].buffer;
			params[n].u.memref.size = inv.cmds[n].size;
			break;
		default:
			break;
		}
	}
}
示例#7
0
static u32 handle_rpc(struct smc_param *param)
{
	switch (TEESMC_RETURN_GET_RPC_FUNC(param->a0)) {
	case TEESMC_RPC_FUNC_ALLOC_ARG:
		param->a1 = tee_shm_pool_alloc(DEV, TZop.Allocator,
					param->a1, 4);
	case TEESMC_RPC_FUNC_ALLOC_PAYLOAD:
		/* Can't support payload shared memory with this interface */
		param->a2 = 0;
		break;
	case TEESMC_RPC_FUNC_FREE_ARG:
		tee_shm_pool_free(DEV, TZop.Allocator, param->a1, 0);
		break;
	case TEESMC_RPC_FUNC_FREE_PAYLOAD:
		/* Can't support payload shared memory with this interface */
		break;
	case TEESMC_ST_RPC_FUNC_ALLOC_PAYLOAD:
	{
		struct tee_shm *shm;

		shm = tee_shm_allocate(&TZop, 0, param->a1, 0);
		if (!shm) {
			param->a1 = 0;
			break;
		}
		param->a1 = shm->paddr;
		param->a2 = (uint32_t)shm;
		break;
	}
	case TEESMC_ST_RPC_FUNC_FREE_PAYLOAD:
		if (param->a1)
			tee_shm_unallocate((struct tee_shm *)param->a1);
		break;
	case TEESMC_RPC_FUNC_IRQ:
		break;
	case TEESMC_RPC_FUNC_CMD:
	{
		struct teesmc32_arg *arg32;
		struct teesmc32_param *params;
		struct tee_rpc_invoke inv;
		size_t n;
		uint32_t ret;

		arg32 = tee_shm_pool_p2v(DEV, TZop.Allocator, param->a1);

		if (arg32->num_params > TEE_RPC_BUFFER_NUMBER) {
			arg32->ret = TEEC_ERROR_GENERIC;
			goto out;
		}

		params = TEESMC32_GET_PARAMS(arg32);

		memset(&inv, 0, sizeof(inv));
		inv.cmd = arg32->cmd;
		/*
		 * Set a suitable error code in case tee-supplicant
		 * ignores the request.
		 */
		inv.res = TEEC_ERROR_NOT_IMPLEMENTED;
		inv.nbr_bf = arg32->num_params;
		for (n = 0; n < arg32->num_params; n++) {
			inv.cmds[n].buffer = (void *)params[n].u.memref.buf_ptr;
			inv.cmds[n].size = params[n].u.memref.size;
			switch (params[n].attr & TEESMC_ATTR_TYPE_MASK) {
			case TEESMC_ATTR_TYPE_VALUE_INPUT:
			case TEESMC_ATTR_TYPE_VALUE_OUTPUT:
			case TEESMC_ATTR_TYPE_VALUE_INOUT:
				inv.cmds[n].type = TEE_RPC_VALUE;
				break;
			case TEESMC_ATTR_TYPE_MEMREF_INPUT:
			case TEESMC_ATTR_TYPE_MEMREF_OUTPUT:
			case TEESMC_ATTR_TYPE_MEMREF_INOUT:
				inv.cmds[n].type = TEE_RPC_BUFFER;
				break;
			default:
				arg32->ret = TEEC_ERROR_GENERIC;
				goto out;
			}
		}

		ret = tee_supp_cmd(&TZop, TEE_RPC_ICMD_INVOKE,
					  &inv, sizeof(inv));
		if (ret == TEEC_RPC_OK)
			arg32->ret = inv.res;

		for (n = 0; n < arg32->num_params; n++) {
			switch (params[n].attr & TEESMC_ATTR_TYPE_MASK) {
			case TEESMC_ATTR_TYPE_VALUE_INPUT:
			case TEESMC_ATTR_TYPE_VALUE_OUTPUT:
			case TEESMC_ATTR_TYPE_VALUE_INOUT:
			case TEESMC_ATTR_TYPE_MEMREF_OUTPUT:
			case TEESMC_ATTR_TYPE_MEMREF_INOUT:
				/*
				 * Allow supplicant to assign a new pointer
				 * to an out-buffer. Needed when the
				 * supplicant allocates a new buffer, for
				 * instance when loading a TA.
				 */
				params[n].u.memref.buf_ptr =
						(uint32_t)inv.cmds[n].buffer;
				params[n].u.memref.size = inv.cmds[n].size;
				break;
			default:
				break;
			}
		}

		break;
	}
	default:
		dev_warn(DEV, "Unknown RPC func 0x%x\n",
			 TEESMC_RETURN_GET_RPC_FUNC(param->a0));
		break;
	}

out:
	if (irqs_disabled())
		return TEESMC32_FASTCALL_RETURN_FROM_RPC;
	else
		return TEESMC32_CALL_RETURN_FROM_RPC;
}
示例#8
0
/*
 * tee_open_session - invoke TEE to open a GP TEE session
 */
static TEEC_Result tee_open_session(struct tee_session *ts,
	enum t_cmd_service_id sec_cmd,
	uint32_t ta_cmd,
	uint32_t param_type,
	TEEC_Value params[TEEC_CONFIG_PAYLOAD_REF_COUNT],
	uint32_t *origin)
{
	TEEC_Result ret_tee;
	struct teesmc32_arg *arg32;
	uintptr_t parg32;
	struct teesmc32_param *params32;
	struct teesmc_meta_open_session *meta;
	uintptr_t pmeta;
	size_t num_meta = 1;


	dev_dbg(DEV, "> uuid=%08x-%04x-%04x\n",
		((ts->uuid) ? ts->uuid->timeLow : 0xDEAD),
		((ts->uuid) ? ts->uuid->timeMid : 0xDEAD),
		((ts->uuid) ? ts->uuid->
		 timeHiAndVersion : 0xDEAD));

	if (tee_tz_ready == false)
		return TEEC_ERROR_BUSY;

	if (ts->ta)
		num_meta++;

	arg32 = (typeof(arg32))alloc_tee_arg(&parg32, TEESMC32_GET_ARG_SIZE(
				TEEC_CONFIG_PAYLOAD_REF_COUNT + num_meta));
	meta = (typeof(meta))alloc_tee_arg(&pmeta, sizeof(*meta));

	if ((arg32 == NULL) || (meta == NULL)) {
		free_tee_arg(parg32);
		free_tee_arg(pmeta);
		return TEEC_ERROR_OUT_OF_MEMORY;
	}

	memset(arg32, 0, sizeof(*arg32));
	memset(meta, 0, sizeof(*meta));
	arg32->num_params = TEEC_CONFIG_PAYLOAD_REF_COUNT + num_meta;
	params32 = TEESMC32_GET_PARAMS(arg32);

	arg32->cmd = TEESMC_CMD_OPEN_SESSION;

	params32[0].u.memref.buf_ptr = pmeta;
	params32[0].u.memref.size = sizeof(*meta);
	params32[0].attr = TEESMC_ATTR_TYPE_MEMREF_INPUT |
			 TEESMC_ATTR_META | get_cache_attrs();

	if (ts->ta != NULL) {
		params32[1].u.memref.buf_ptr =
			tee_shm_pool_v2p(DEV, TZop.Allocator, ts->ta);
		params32[1].u.memref.size = ts->tasize;
		params32[1].attr = TEESMC_ATTR_TYPE_MEMREF_INPUT |
				 TEESMC_ATTR_META | get_cache_attrs();
	}

	if (ts->uuid != NULL)
		memcpy(meta->uuid, ts->uuid, TEESMC_UUID_LEN);
	meta->clnt_login = ts->login;

	set_params(params32 + num_meta, param_type, params);

	mutex_lock(&e_mutex_teez);
	call_tee(parg32, arg32);
	mutex_unlock(&e_mutex_teez);

	ts->id = arg32->session;
	ret_tee = arg32->ret;
	if (origin)
		*origin = arg32->ret_origin;

	get_params(params, params32 + num_meta);

	free_tee_arg(parg32);
	free_tee_arg(pmeta);
	dev_dbg(DEV, "< [%d]\n", ret_tee);
	return ret_tee;
}