static u32 handle_rpc(struct tee_tz *ptee, struct smc_param *param) { struct tee_shm *shm; int cookie; switch (TEESMC_RETURN_GET_RPC_FUNC(param->a0)) { case TEESMC_RPC_FUNC_ALLOC_ARG: param->a1 = tee_shm_pool_alloc(DEV, ptee->shm_pool, param->a1, 4); break; 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, ptee->shm_pool, 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: shm = tee_shm_alloc_from_rpc(ptee->tee, param->a1, TEE_SHM_TEMP | TEE_SHM_FROM_RPC); if (!shm) { param->a1 = 0; break; } cookie = handle_get(&shm_handle_db, shm); if (cookie < 0) { tee_shm_free_from_rpc(shm); param->a1 = 0; break; } param->a1 = shm->paddr; param->a2 = cookie; break; case TEESMC_ST_RPC_FUNC_FREE_PAYLOAD: if (true || param->a1) { shm = handle_put(&shm_handle_db, param->a1); if (shm) tee_shm_free_from_rpc(shm); } break; case TEESMC_RPC_FUNC_IRQ: break; case TEESMC_RPC_FUNC_CMD: handle_rpc_func_cmd(ptee, param->a1); break; default: dev_warn(DEV, "Unknown RPC func 0x%x\n", (u32)TEESMC_RETURN_GET_RPC_FUNC(param->a0)); break; } if (irqs_disabled()) return TEESMC32_FASTCALL_RETURN_FROM_RPC; else return TEESMC32_CALL_RETURN_FROM_RPC; }
static struct tee_shm *tz_alloc(struct tee *tee, size_t size, uint32_t flags) { struct tee_shm *shm = NULL; struct tee_tz *ptee; size_t size_aligned; BUG_ON(!tee->priv); ptee = tee->priv; dev_dbg(DEV, "%s: s=%d,flags=0x%08x\n", __func__, (int)size, flags); /* comment due to #6357 * if ( (flags & ~(tee->shm_flags | TEE_SHM_MAPPED * | TEE_SHM_TEMP | TEE_SHM_FROM_RPC)) != 0 ) { dev_err(tee->dev, "%s: flag parameter is invalid\n", __func__); return ERR_PTR(-EINVAL); }*/ size_aligned = ((size / SZ_4K) + 1) * SZ_4K; if (unlikely(size_aligned == 0)) { dev_err(DEV, "[%s] requested size too big\n", __func__); return NULL; } shm = devm_kzalloc(tee->dev, sizeof(struct tee_shm), GFP_KERNEL); if (!shm) { dev_err(tee->dev, "%s: kzalloc failed\n", __func__); return ERR_PTR(-ENOMEM); } shm->size_alloc = ((size / SZ_4K) + 1) * SZ_4K; shm->size_req = size; shm->paddr = tee_shm_pool_alloc(tee->dev, ptee->shm_pool, shm->size_alloc, ALLOC_ALIGN); if (!shm->paddr) { dev_err(tee->dev, "%s: cannot alloc memory, size 0x%lx\n", __func__, (unsigned long)shm->size_alloc); devm_kfree(tee->dev, shm); return ERR_PTR(-ENOMEM); } shm->kaddr = tee_shm_pool_p2v(tee->dev, ptee->shm_pool, shm->paddr); if (!shm->kaddr) { dev_err(tee->dev, "%s: p2v(%p)=0\n", __func__, (void *)shm->paddr); tee_shm_pool_free(tee->dev, ptee->shm_pool, shm->paddr, NULL); devm_kfree(tee->dev, shm); return ERR_PTR(-EFAULT); } shm->flags = flags; if (ptee->shm_cached) shm->flags |= TEE_SHM_CACHED; dev_dbg(tee->dev, "%s: kaddr=%p, paddr=%p, shm=%p, size %x:%x\n", __func__, shm->kaddr, (void *)shm->paddr, shm, (unsigned int)shm->size_req, (unsigned int)shm->size_alloc); return shm; }
/* allocate tee service argument buffer and return virtual address */ static void *alloc_tee_arg(unsigned long *p, size_t l) { if ((p == NULL) || (l == 0)) return NULL; /* assume a 4 bytes aligned is sufficient */ *p = tee_shm_pool_alloc(DEV, TZop.Allocator, l, 4); if (*p == 0) return NULL; return tee_shm_pool_p2v(DEV, TZop.Allocator, *p); }
/* allocate tee service argument buffer and return virtual address */ static void *alloc_tee_arg(struct tee_tz *ptee, unsigned long *p, size_t l) { void *vaddr; dev_dbg(DEV, ">\n"); BUG_ON(!CAPABLE(ptee->tee)); if ((p == NULL) || (l == 0)) return NULL; /* assume a 4 bytes aligned is sufficient */ *p = tee_shm_pool_alloc(DEV, ptee->shm_pool, l, ALLOC_ALIGN); if (*p == 0) return NULL; vaddr = tee_shm_pool_p2v(DEV, ptee->shm_pool, *p); dev_dbg(DEV, "< %p\n", vaddr); return vaddr; }
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; }