/* 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(¶m); 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(¶m); 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; }
static bool teesmc_api_uid_is_st(void) { struct smc_param param = { .a0 = TEESMC32_CALLS_UID }; mutex_lock(&e_mutex_teez); tee_smc_call(¶m); 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; }
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(¶m); 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; }
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(¶m); 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(¶m); } 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(¶m, 0, sizeof(param)); param.a0 = TEESMC32_ST_FASTCALL_L2CC_MUTEX; param.a1 = TEESMC_ST_L2CC_MUTEX_GET_ADDR; tee_smc_call(¶m); 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(¶m, 0, sizeof(param)); param.a0 = TEESMC32_ST_FASTCALL_L2CC_MUTEX; param.a1 = TEESMC_ST_L2CC_MUTEX_ENABLE; tee_smc_call(¶m); 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(¶m, 0, sizeof(param)); param.a0 = TEESMC32_ST_FASTCALL_L2CC_MUTEX; param.a1 = TEESMC_ST_L2CC_MUTEX_DISABLE; tee_smc_call(¶m); 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(¶m); 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, ¶m); 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; } }