Example #1
0
/* configure_shm - Negotiate Shared Memory configuration with teetz. */
static int configure_shm(void)
{
	struct smc_param param = { 0 };
	int ret = 0;

	if (shm_paddr)
		return -EINVAL;

	mutex_lock(&e_mutex_teez);
	param.a0 = TEESMC32_ST_FASTCALL_GET_SHM_CONFIG;
	tee_smc_call(&param);
	mutex_unlock(&e_mutex_teez);

	if (param.a0 != TEESMC_RETURN_OK) {
		dev_err(DEV, "shm service not available: %X", (uint)param.a0);
		ret = -EINVAL;
		goto out;
	}

	shm_paddr = param.a1;
	shm_size = param.a2;
	shm_cached = (bool)param.a3;

	if (shm_cached)
		shm_vaddr = ioremap_cached(shm_paddr, shm_size);
	else
		shm_vaddr = ioremap_nocache(shm_paddr, shm_size);

	if (shm_vaddr == NULL) {
		dev_err(DEV, "shm ioremap failed\n");
		ret = -ENOMEM;
		goto out;
	}

	TZop.Allocator = tee_shm_pool_create(
			DEV, shm_size, shm_vaddr, shm_paddr);

	if (!TZop.Allocator) {
		dev_err(DEV, "shm pool creation failed (%d)", shm_size);
		ret = -EINVAL;
		goto out;
	}

	if (shm_cached)
		tee_shm_pool_set_cached(TZop.Allocator);
out:
	if (ret)
		shm_paddr = 0;

	dev_dbg(DEV, "teetz shm: ret=%d pa=0x%lX va=0x%p size=%d, %scached",
		ret, shm_paddr, shm_vaddr, shm_size,
			shm_cached == 1 ? "" : "un");
	return ret;
}
/* configure_shm - Negotiate Shared Memory configuration with teetz. */
static int configure_shm(struct tee_tz *ptee)
{
	struct smc_param param = { 0 };
	size_t shm_size = -1;
	int ret = 0;

	dev_dbg(DEV, ">\n");
	BUG_ON(!CAPABLE(ptee->tee));

	mutex_lock(&ptee->mutex);
	param.a0 = TEESMC32_ST_FASTCALL_GET_SHM_CONFIG;
	tee_smc_call(&param);
	mutex_unlock(&ptee->mutex);

	if (param.a0 != TEESMC_RETURN_OK) {
		dev_err(DEV, "shm service not available: %X", (uint)param.a0);
		ret = -EINVAL;
		goto out;
	}

	ptee->shm_paddr = param.a1;
	shm_size = param.a2;
	ptee->shm_cached = (bool)param.a3;

	if (ptee->shm_cached)
		ptee->shm_vaddr = ioremap_cache(ptee->shm_paddr, shm_size);
	else
		ptee->shm_vaddr = ioremap_nocache(ptee->shm_paddr, shm_size);

	if (ptee->shm_vaddr == NULL) {
		dev_err(DEV, "shm ioremap failed\n");
		ret = -ENOMEM;
		goto out;
	}

	ptee->shm_pool = tee_shm_pool_create(DEV, shm_size,
					     ptee->shm_vaddr, ptee->shm_paddr);

	if (!ptee->shm_pool) {
		dev_err(DEV, "shm pool creation failed (%zu)", shm_size);
		ret = -EINVAL;
		goto out;
	}

	if (ptee->shm_cached)
		tee_shm_pool_set_cached(ptee->shm_pool);
out:
	dev_dbg(DEV, "< ret=%d pa=0x%lX va=0x%p size=%zu, %scached",
		ret, ptee->shm_paddr, ptee->shm_vaddr, shm_size,
		(ptee->shm_cached == 1) ? "" : "un");
	return ret;
}
Example #3
0
static bool teesmc_api_uid_is_st(void)
{
	struct smc_param param = { .a0 = TEESMC32_CALLS_UID };

	mutex_lock(&e_mutex_teez);
	tee_smc_call(&param);
	mutex_unlock(&e_mutex_teez);

	if (param.a0 == TEESMC_ST_UID_R0 && param.a1 == TEESMC_ST_UID_R1 &&
	    param.a2 == TEESMC_ST_UID_R2 && (param.a3 == TEESMC_ST_UID32_R3 ||
					     param.a3 == TEESMC_ST_UID64_R3))
		return true;

	return false;
}
Example #4
0
static bool teesmc_os_uuid_is_optee(void)
{
	struct smc_param param = { .a0 = TEESMC32_CALL_GET_OS_UUID };

	mutex_lock(&e_mutex_teez);
	tee_smc_call(&param);
	mutex_unlock(&e_mutex_teez);

	if (param.a0 == TEESMC_OS_OPTEE_UUID_R0 &&
	    param.a1 == TEESMC_OS_OPTEE_UUID_R1 &&
	    param.a2 == TEESMC_OS_OPTEE_UUID_R2 &&
	    param.a3 == TEESMC_OS_OPTEE_UUID_R3)
		return true;

	return false;
}
Example #5
0
static void call_tee(uintptr_t parg32, struct teesmc32_arg *arg32)
{
	u32 ret;
	u32 funcid;
	struct smc_param param = { 0 };

	if (irqs_disabled())
		funcid = TEESMC32_FASTCALL_WITH_ARG;
	else
		funcid = TEESMC32_CALL_WITH_ARG;

	param.a1 = parg32;
	while (true) {
		param.a0 = funcid;

		tee_smc_call(&param);
		ret = param.a0;

		if (ret == TEESMC_RETURN_EBUSY) {
			/* "Can't happen" */
			BUG_ON(1);
		} else if (TEESMC_RETURN_IS_RPC(ret)) {
			/* Process the RPC. */
			funcid = handle_rpc(&param);
		} else {
			break;
		}
	}

	switch (ret) {
	case TEESMC_RETURN_UNKNOWN_FUNCTION:
		arg32->ret = TEEC_ERROR_NOT_IMPLEMENTED;
		arg32->ret_origin = TEEC_ORIGIN_COMMS;
		break;
	case TEESMC_RETURN_OK:
		/* arg32->ret set by secure world */
		break;
	default:
		/* Should not happen */
		arg32->ret = TEEC_ERROR_COMMUNICATION;
		arg32->ret_origin = TEEC_ORIGIN_COMMS;
		break;
	}
}
/* register_outercache_mutex - Negotiate/Disable outer cache shared mutex */
static int register_outercache_mutex(struct tee_tz *ptee, bool reg)
{
	unsigned long *vaddr = NULL;
	int ret = 0;
	struct smc_param param;
	uintptr_t paddr = 0;

	dev_dbg(ptee->tee->dev, ">\n");
	BUG_ON(!CAPABLE(ptee->tee));

	if ((reg == true) && (ptee->tz_outer_cache_mutex != NULL)) {
		dev_err(DEV, "outer cache shared mutex already registered\n");
		return -EINVAL;
	}
	if ((reg == false) && (ptee->tz_outer_cache_mutex == NULL))
		return 0;

	mutex_lock(&ptee->mutex);

	if (reg == false) {
		vaddr = ptee->tz_outer_cache_mutex;
		ptee->tz_outer_cache_mutex = NULL;
		goto out;
	}

	memset(&param, 0, sizeof(param));
	param.a0 = TEESMC32_ST_FASTCALL_L2CC_MUTEX;
	param.a1 = TEESMC_ST_L2CC_MUTEX_GET_ADDR;
	tee_smc_call(&param);

	if (param.a0 != TEESMC_RETURN_OK) {
		dev_warn(DEV, "no TZ l2cc mutex service supported\n");
		goto out;
	}
	paddr = param.a2;
	dev_dbg(DEV, "outer cache shared mutex paddr 0x%lx\n", paddr);

	vaddr = ioremap_cache(paddr, sizeof(u32));
	if (vaddr == NULL) {
		dev_warn(DEV, "TZ l2cc mutex disabled: ioremap failed\n");
		ret = -ENOMEM;
		goto out;
	}

	dev_dbg(DEV, "outer cache shared mutex vaddr %p\n", vaddr);
	if (outer_tz_mutex(vaddr) == false) {
		dev_warn(DEV, "TZ l2cc mutex disabled: outer cache refused\n");
		goto out;
	}

	memset(&param, 0, sizeof(param));
	param.a0 = TEESMC32_ST_FASTCALL_L2CC_MUTEX;
	param.a1 = TEESMC_ST_L2CC_MUTEX_ENABLE;
	tee_smc_call(&param);

	if (param.a0 != TEESMC_RETURN_OK) {

		dev_warn(DEV, "TZ l2cc mutex disabled: TZ enable failed\n");
		goto out;
	}
	ptee->tz_outer_cache_mutex = vaddr;

out:
	if (ptee->tz_outer_cache_mutex == NULL) {
		memset(&param, 0, sizeof(param));
		param.a0 = TEESMC32_ST_FASTCALL_L2CC_MUTEX;
		param.a1 = TEESMC_ST_L2CC_MUTEX_DISABLE;
		tee_smc_call(&param);
		outer_tz_mutex(NULL);
		if (vaddr)
			iounmap(vaddr);
		dev_dbg(DEV, "outer cache shared mutex disabled\n");
	}

	mutex_unlock(&ptee->mutex);
	dev_dbg(DEV, "< teetz outer mutex: ret=%d pa=0x%lX va=0x%p %sabled\n",
		ret, paddr, vaddr, ptee->tz_outer_cache_mutex ? "en" : "dis");
	return ret;
}
static void call_tee(struct tee_tz *ptee,
			uintptr_t parg32, struct teesmc32_arg *arg32)
{
	u32 ret;
	u32 funcid;
	struct smc_param param = { 0 };

	if (irqs_disabled())
		funcid = TEESMC32_FASTCALL_WITH_ARG;
	else
		funcid = TEESMC32_CALL_WITH_ARG;

	/*
	 * Commented out elements used to visualize the layout dynamic part
	 * of the struct. Note that these fields are not available at all
	 * if num_params == 0.
	 *
	 * params is accessed through the macro TEESMC32_GET_PARAMS
	 */

	/* struct teesmc32_param params[num_params]; */


	param.a1 = parg32;
	e_lock_teez(ptee);
	while (true) {
		param.a0 = funcid;

		tee_smc_call(&param);
		ret = param.a0;

		if (ret == TEESMC_RETURN_EBUSY) {
			/*
			 * Since secure world returned busy, release the
			 * lock we had when entering this function and wait
			 * for "something to happen" (something else to
			 * exit from secure world and needed resources may
			 * have become available).
			 */
			e_lock_wait_completion_teez(ptee);
		} else if (TEESMC_RETURN_IS_RPC(ret)) {
			/* Process the RPC. */
			e_unlock_teez(ptee);
			funcid = handle_rpc(ptee, &param);
			e_lock_teez(ptee);
		} else {
			break;
		}
	}
	e_unlock_teez(ptee);

	switch (ret) {
	case TEESMC_RETURN_UNKNOWN_FUNCTION:
		break;
	case TEESMC_RETURN_OK:
		/* arg32->ret set by secure world */
		break;
	default:
		/* Should not happen */
		arg32->ret = TEEC_ERROR_COMMUNICATION;
		arg32->ret_origin = TEEC_ORIGIN_COMMS;
		break;
	}
}