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;
		}
	}
}
Example #2
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;
}