int tee_session_close_and_destroy(struct tee_session *sess) { int ret; struct tee *tee; struct tee_context *ctx; if (!sess || !sess->ctx || !sess->ctx->tee) return -EINVAL; ctx = sess->ctx; tee = ctx->tee; dev_dbg(_DEV(tee), "%s: > sess=%p\n", __func__, sess); if (!tee_session_is_opened(sess)) return -EINVAL; ret = tee_session_close_be(sess); mutex_lock(&tee->lock); tee_dec_stats(&tee->stats[TEE_STATS_SESSION_IDX]); list_del(&sess->entry); devm_kfree(_DEV(tee), sess); tee_context_put(ctx); tee_put(tee); mutex_unlock(&tee->lock); dev_dbg(_DEV(tee), "%s: <\n", __func__); return ret; }
static int tee_session_cancel_be(struct tee_session *sess, struct tee_cmd_io *cmd_io) { int ret = -EINVAL; struct tee *tee; struct tee_cmd cmd; BUG_ON(!sess || !sess->ctx || !sess->ctx->tee); tee = sess->ctx->tee; dev_dbg(_DEV(tee), "%s: > sessid=%08x, cmd=0x%08x\n", __func__, sess->sessid, cmd_io->cmd); ret = _init_tee_cmd(sess, cmd_io, &cmd); if (ret) goto out; ret = tee->ops->cancel(sess, &cmd); out: _release_tee_cmd(sess, &cmd); dev_dbg(_DEV(tee), "%s: < ret=%d", __func__, ret); return ret; }
static long tee_session_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { struct tee *tee; struct tee_session *sess = filp->private_data; int ret; BUG_ON(!sess || !sess->ctx || !sess->ctx->tee); tee = sess->ctx->tee; dev_dbg(_DEV(tee), "%s: > cmd nr=%d\n", __func__, _IOC_NR(cmd)); switch (cmd) { case TEE_INVOKE_COMMAND_IOC: ret = tee_do_invoke_command(sess, (struct tee_cmd_io __user *)arg); break; case TEE_REQUEST_CANCELLATION_IOC: ret = tee_do_cancel_cmd(sess, (struct tee_cmd_io __user *)arg); break; default: ret = -ENOSYS; break; } dev_dbg(_DEV(tee), "%s: < ret=%d\n", __func__, ret); return ret; }
int tee_session_invoke_be(struct tee_session *sess, struct tee_cmd_io *cmd_io) { int ret = -EINVAL; struct tee *tee; struct tee_cmd cmd; BUG_ON(!sess || !sess->ctx || !sess->ctx->tee); tee = sess->ctx->tee; dev_dbg(_DEV(tee), "%s: > sessid=%08x, cmd=0x%08x\n", __func__, sess->sessid, cmd_io->cmd); ret = _init_tee_cmd(sess, cmd_io, &cmd); if (ret) goto out; ret = tee->ops->invoke(sess, &cmd); if (!ret) _update_client_tee_cmd(sess, cmd_io, &cmd); else { /* propagate the reason of the error */ cmd_io->origin = cmd.origin; cmd_io->err = cmd.err; } out: _release_tee_cmd(sess, &cmd); dev_dbg(_DEV(tee), "%s: < ret=%d", __func__, ret); return ret; }
static struct sg_table *_tee_shm_dma_buf_map_dma_buf( struct dma_buf_attachment *attach, enum dma_data_direction dir) { struct tee_shm_attach *tee_shm_attach = attach->priv; struct tee_shm *tee_shm = attach->dmabuf->priv; struct sg_table *sgt = NULL; struct scatterlist *rd, *wr; unsigned int i; int nents, ret; struct tee *tee; tee = tee_shm->tee; INMSG(); /* just return current sgt if already requested. */ if (tee_shm_attach->dir == dir && tee_shm_attach->is_mapped) { OUTMSGX(&tee_shm_attach->sgt); return &tee_shm_attach->sgt; } sgt = &tee_shm_attach->sgt; ret = sg_alloc_table(sgt, tee_shm->sgt.orig_nents, GFP_KERNEL); if (ret) { dev_err(_DEV(tee), "failed to alloc sgt.\n"); return ERR_PTR(-ENOMEM); } rd = tee_shm->sgt.sgl; wr = sgt->sgl; for (i = 0; i < sgt->orig_nents; ++i) { sg_set_page(wr, sg_page(rd), rd->length, rd->offset); rd = sg_next(rd); wr = sg_next(wr); } if (dir != DMA_NONE) { nents = dma_map_sg(attach->dev, sgt->sgl, sgt->orig_nents, dir); if (!nents) { dev_err(_DEV(tee), "failed to map sgl with iommu.\n"); sg_free_table(sgt); sgt = ERR_PTR(-EIO); goto err_unlock; } } tee_shm_attach->is_mapped = true; tee_shm_attach->dir = dir; attach->priv = tee_shm_attach; err_unlock: OUTMSGX(sgt); return sgt; }
struct tee_shm *tee_shm_alloc(struct tee *tee, size_t size, uint32_t flags) { struct tee_shm *shm; unsigned long pfn; unsigned int nr_pages; struct page *page; int ret; INMSG(); shm = tee->ops->alloc(tee, size, flags); if (IS_ERR_OR_NULL(shm)) { dev_err(_DEV(tee), "%s: allocation failed (s=%d,flags=0x%08x) err=%ld\n", __func__, (int)size, flags, PTR_ERR(shm)); goto exit; } shm->tee = tee; dev_dbg(_DEV(tee), "%s: shm=%p, paddr=%p,s=%d/%d app=\"%s\" pid=%d\n", __func__, shm, (void *)shm->paddr, (int)shm->size_req, (int)shm->size_alloc, current->comm, current->pid); pfn = shm->paddr >> PAGE_SHIFT; page = pfn_to_page(pfn); if (IS_ERR_OR_NULL(page)) { dev_err(_DEV(tee), "%s: pfn_to_page(%lx) failed\n", __func__, pfn); tee->ops->free(shm); return (struct tee_shm *)page; } /* Only one page of contiguous physical memory */ nr_pages = 1; ret = sg_alloc_table_from_pages(&shm->sgt, &page, nr_pages, 0, nr_pages * PAGE_SIZE, GFP_KERNEL); if (IS_ERR_VALUE(ret)) { dev_err(_DEV(tee), "%s: sg_alloc_table_from_pages() failed\n", __func__); tee->ops->free(shm); shm = ERR_PTR(ret); } exit: OUTMSGX(shm); return shm; }
static void _tee_shm_detach_dma_buf(struct dma_buf *dmabuf, struct dma_buf_attachment *attach) { struct tee_shm_attach *tee_shm_attach = attach->priv; struct sg_table *sgt; struct tee_shm *shm; struct tee *tee; shm = dmabuf->priv; tee = shm->tee; INMSG(); if (!tee_shm_attach) { OUTMSG(0); return; } sgt = &tee_shm_attach->sgt; if (tee_shm_attach->dir != DMA_NONE) dma_unmap_sg(attach->dev, sgt->sgl, sgt->nents, tee_shm_attach->dir); sg_free_table(sgt); devm_kfree(_DEV(tee), tee_shm_attach); attach->priv = NULL; OUTMSG(0); }
static int _tee_shm_dma_buf_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma) { struct tee_shm *shm = dmabuf->priv; size_t size = vma->vm_end - vma->vm_start; struct tee *tee; int ret; pgprot_t prot; unsigned long pfn; tee = shm->ctx->tee; pfn = shm->paddr >> PAGE_SHIFT; INMSG(); if (shm->flags & TEE_SHM_CACHED) prot = vma->vm_page_prot; else prot = pgprot_noncached(vma->vm_page_prot); ret = remap_pfn_range(vma, vma->vm_start, pfn, size, prot); if (!ret) vma->vm_private_data = (void *)shm; dev_dbg(_DEV(shm->ctx->tee), "%s: map the shm (p@=%p,s=%dKiB) => %x\n", __func__, (void *)shm->paddr, (int)size / 1024, (unsigned int)vma->vm_start); OUTMSG(ret); return ret; }
static int _tee_shm_attach_dma_buf(struct dma_buf *dmabuf, struct device *dev, struct dma_buf_attachment *attach) { struct tee_shm_attach *tee_shm_attach; struct tee_shm *shm; struct tee *tee; shm = dmabuf->priv; tee = shm->tee; INMSG(); tee_shm_attach = devm_kzalloc(_DEV(tee), sizeof(*tee_shm_attach), GFP_KERNEL); if (!tee_shm_attach) { OUTMSG(-ENOMEM); return -ENOMEM; } tee_shm_attach->dir = DMA_NONE; attach->priv = tee_shm_attach; OUTMSG(0); return 0; }
static int tee_session_close_be(struct tee_session *sess) { int ret = -EINVAL; struct tee *tee; BUG_ON(!sess || !sess->ctx || !sess->ctx->tee); tee = sess->ctx->tee; dev_dbg(_DEV(tee), "%s: > sessid=%08x", __func__, sess->sessid); ret = tee->ops->close(sess); sess->sessid = 0; dev_dbg(_DEV(tee), "%s: < ret=%d", __func__, ret); return ret; }
static int tee_do_cancel_cmd(struct tee_session *sess, struct tee_cmd_io __user *u_cmd) { int ret = -EINVAL; struct tee *tee; struct tee_cmd_io k_cmd; struct tee_context *ctx; BUG_ON(!sess->ctx); BUG_ON(!sess->ctx->tee); ctx = sess->ctx; tee = sess->ctx->tee; dev_dbg(sess->ctx->tee->dev, "%s: > sessid=%08x\n", __func__, sess->sessid); BUG_ON(!sess->sessid); if (tee_copy_from_user (ctx, &k_cmd, (void *)u_cmd, sizeof(struct tee_cmd_io))) { dev_err(_DEV(tee), "%s: tee_copy_from_user failed\n", __func__); goto exit; } if ((k_cmd.op == NULL) || (k_cmd.uuid != NULL) || (k_cmd.data != NULL) || (k_cmd.data_size != 0)) { dev_err(_DEV(tee), "%s: op or/and data parameters are not valid\n", __func__); goto exit; } ret = tee_session_cancel_be(sess, &k_cmd); if (ret) dev_err(_DEV(tee), "%s: tee_invoke_command failed\n", __func__); tee_put_user(ctx, k_cmd.err, &u_cmd->err); tee_put_user(ctx, k_cmd.origin, &u_cmd->origin); exit: dev_dbg(_DEV(tee), "%s: < ret=%d", __func__, ret); return ret; }
static void *_tee_shm_dma_buf_kmap(struct dma_buf *db, unsigned long pgnum) { struct tee_shm *shm = db->priv; dev_dbg(_DEV(shm->ctx->tee), "%s: kmap the shm (p@=%p, v@=%p, s=%zdKiB)\n", __func__, (void *)shm->paddr, (void *)shm->kaddr, shm->size_alloc / 1024); /* * A this stage, a shm allocated by the tee * must be have a kernel address */ return shm->kaddr; }
static int tee_session_open_be(struct tee_session *sess, struct tee_cmd_io *cmd_io) { int ret = -EINVAL; struct tee *tee; struct tee_cmd cmd; BUG_ON(!sess || !sess->ctx || !sess->ctx->tee); tee = sess->ctx->tee; dev_dbg(_DEV(tee), "%s: > open a new session", __func__); sess->sessid = 0; ret = _init_tee_cmd(sess, cmd_io, &cmd); if (ret) goto out; if (cmd.uuid) { dev_dbg(_DEV(tee), "%s: UUID=%s\n", __func__, _uuid_to_str((TEEC_UUID *) cmd.uuid->kaddr)); } ret = tee->ops->open(sess, &cmd); if (ret == 0) _update_client_tee_cmd(sess, cmd_io, &cmd); else { /* propagate the reason of the error */ cmd_io->origin = cmd.origin; cmd_io->err = cmd.err; } out: _release_tee_cmd(sess, &cmd); dev_dbg(_DEV(tee), "%s: < ret=%d, sessid=%08x", __func__, ret, sess->sessid); return ret; }
int tee_session_create_fd(struct tee_context *ctx, struct tee_cmd_io *cmd_io) { int ret; struct tee_session *sess; struct tee *tee = ctx->tee; BUG_ON(cmd_io->fd_sess > 0); dev_dbg(_DEV(tee), "%s: >\n", __func__); sess = tee_session_create_and_open(ctx, cmd_io); if (IS_ERR_OR_NULL(sess)) { ret = PTR_ERR(sess); dev_dbg(_DEV(tee), "%s: ERROR can't create the session (ret=%d, err=0x%08x, org=%d)\n", __func__, ret, cmd_io->err, cmd_io->origin); cmd_io->fd_sess = -1; goto out; } /* Retrieve a fd */ cmd_io->fd_sess = -1; ret = anon_inode_getfd("tee_session", &tee_session_fops, sess, O_CLOEXEC); if (ret < 0) { dev_err(_DEV(tee), "%s: ERROR can't get a fd (ret=%d)\n", __func__, ret); tee_session_close_and_destroy(sess); goto out; } cmd_io->fd_sess = ret; ret = 0; out: dev_dbg(_DEV(tee), "%s: < ret=%d, sess=%p, fd=%d\n", __func__, ret, sess, cmd_io->fd_sess); return ret; }
void tee_shm_free(struct tee_shm *shm) { struct tee *tee; if (IS_ERR_OR_NULL(shm)) return; tee = shm->tee; if (tee == NULL) pr_warn("invalid call to tee_shm_free(%p): NULL tee\n", shm); else if (shm->tee == NULL) dev_warn(_DEV(tee), "tee_shm_free(%p): NULL tee\n", shm); else { sg_free_table(&shm->sgt); shm->tee->ops->free(shm); } }
static void _tee_shm_dma_buf_release(struct dma_buf *dmabuf) { struct tee_shm *shm = dmabuf->priv; struct tee_context *ctx; struct tee *tee; tee = shm->ctx->tee; INMSG(); ctx = shm->ctx; dev_dbg(_DEV(ctx->tee), "%s: shm=%p, paddr=%p,s=%d/%d app=\"%s\" pid=%d\n", __func__, shm, (void *)shm->paddr, (int)shm->size_req, (int)shm->size_alloc, current->comm, current->pid); tee_shm_free_io(shm); OUTMSG(0); }
struct tee_session *tee_session_create_and_open(struct tee_context *ctx, struct tee_cmd_io *cmd_io) { int ret = 0; struct tee_session *sess; struct tee *tee; BUG_ON(!ctx->tee); tee = ctx->tee; dev_dbg(_DEV(tee), "%s: >\n", __func__); ret = tee_get(tee); if (ret) return ERR_PTR(-EBUSY); sess = devm_kzalloc(_DEV(tee), sizeof(struct tee_session), GFP_KERNEL); if (!sess) { dev_err(_DEV(tee), "%s: tee_session allocation() failed\n", __func__); tee_put(tee); return ERR_PTR(-ENOMEM); } tee_context_get(ctx); sess->ctx = ctx; ret = tee_session_open_be(sess, cmd_io); mutex_lock(&tee->lock); if (ret || !sess->sessid || cmd_io->err) { dev_err(_DEV(tee), "%s: ERROR ret=%d (err=0x%08x, org=%d, sessid=0x%08x)\n", __func__, ret, cmd_io->err, cmd_io->origin, sess->sessid); tee_put(tee); tee_context_put(ctx); devm_kfree(_DEV(tee), sess); mutex_unlock(&tee->lock); if (ret) return ERR_PTR(ret); else return NULL; } tee_inc_stats(&tee->stats[TEE_STATS_SESSION_IDX]); list_add_tail(&sess->entry, &ctx->list_sess); mutex_unlock(&tee->lock); dev_dbg(_DEV(tee), "%s: < sess=%p\n", __func__, sess); return sess; }
struct tee_shm *tee_shm_alloc_from_rpc(struct tee *tee, size_t size) { struct tee_shm *shm; INMSG(); shm = tee_shm_alloc(tee, size, TEE_SHM_TEMP | TEE_SHM_FROM_RPC); if (IS_ERR_OR_NULL(shm)) { dev_err(_DEV(tee), "%s: buffer allocation failed (%ld)\n", __func__, PTR_ERR(shm)); goto out; } mutex_lock(&tee->lock); tee_inc_stats(&tee->stats[TEE_STATS_SHM_IDX]); list_add_tail(&shm->entry, &tee->list_rpc_shm); mutex_unlock(&tee->lock); shm->ctx = NULL; out: OUTMSGX(shm); return shm; }
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; }
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; }