/* ********************* * 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; }
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; } }
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__); }
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; } }
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); } } }
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, ¶m->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, ¶m->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; }
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); } } }
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, ¶m->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 *)¶m->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 *)¶m-> 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, ¶m->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 *)¶m->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 *) ¶m->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; }