18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (c) 2015, Linaro Limited 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci#include <linux/device.h> 68c2ecf20Sopenharmony_ci#include <linux/slab.h> 78c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 88c2ecf20Sopenharmony_ci#include "optee_private.h" 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_cistruct optee_supp_req { 118c2ecf20Sopenharmony_ci struct list_head link; 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci bool in_queue; 148c2ecf20Sopenharmony_ci u32 func; 158c2ecf20Sopenharmony_ci u32 ret; 168c2ecf20Sopenharmony_ci size_t num_params; 178c2ecf20Sopenharmony_ci struct tee_param *param; 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci struct completion c; 208c2ecf20Sopenharmony_ci}; 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_civoid optee_supp_init(struct optee_supp *supp) 238c2ecf20Sopenharmony_ci{ 248c2ecf20Sopenharmony_ci memset(supp, 0, sizeof(*supp)); 258c2ecf20Sopenharmony_ci mutex_init(&supp->mutex); 268c2ecf20Sopenharmony_ci init_completion(&supp->reqs_c); 278c2ecf20Sopenharmony_ci idr_init(&supp->idr); 288c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&supp->reqs); 298c2ecf20Sopenharmony_ci supp->req_id = -1; 308c2ecf20Sopenharmony_ci} 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_civoid optee_supp_uninit(struct optee_supp *supp) 338c2ecf20Sopenharmony_ci{ 348c2ecf20Sopenharmony_ci mutex_destroy(&supp->mutex); 358c2ecf20Sopenharmony_ci idr_destroy(&supp->idr); 368c2ecf20Sopenharmony_ci} 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_civoid optee_supp_release(struct optee_supp *supp) 398c2ecf20Sopenharmony_ci{ 408c2ecf20Sopenharmony_ci int id; 418c2ecf20Sopenharmony_ci struct optee_supp_req *req; 428c2ecf20Sopenharmony_ci struct optee_supp_req *req_tmp; 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci mutex_lock(&supp->mutex); 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci /* Abort all request retrieved by supplicant */ 478c2ecf20Sopenharmony_ci idr_for_each_entry(&supp->idr, req, id) { 488c2ecf20Sopenharmony_ci idr_remove(&supp->idr, id); 498c2ecf20Sopenharmony_ci req->ret = TEEC_ERROR_COMMUNICATION; 508c2ecf20Sopenharmony_ci complete(&req->c); 518c2ecf20Sopenharmony_ci } 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci /* Abort all queued requests */ 548c2ecf20Sopenharmony_ci list_for_each_entry_safe(req, req_tmp, &supp->reqs, link) { 558c2ecf20Sopenharmony_ci list_del(&req->link); 568c2ecf20Sopenharmony_ci req->in_queue = false; 578c2ecf20Sopenharmony_ci req->ret = TEEC_ERROR_COMMUNICATION; 588c2ecf20Sopenharmony_ci complete(&req->c); 598c2ecf20Sopenharmony_ci } 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci supp->ctx = NULL; 628c2ecf20Sopenharmony_ci supp->req_id = -1; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci mutex_unlock(&supp->mutex); 658c2ecf20Sopenharmony_ci} 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci/** 688c2ecf20Sopenharmony_ci * optee_supp_thrd_req() - request service from supplicant 698c2ecf20Sopenharmony_ci * @ctx: context doing the request 708c2ecf20Sopenharmony_ci * @func: function requested 718c2ecf20Sopenharmony_ci * @num_params: number of elements in @param array 728c2ecf20Sopenharmony_ci * @param: parameters for function 738c2ecf20Sopenharmony_ci * 748c2ecf20Sopenharmony_ci * Returns result of operation to be passed to secure world 758c2ecf20Sopenharmony_ci */ 768c2ecf20Sopenharmony_ciu32 optee_supp_thrd_req(struct tee_context *ctx, u32 func, size_t num_params, 778c2ecf20Sopenharmony_ci struct tee_param *param) 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci{ 808c2ecf20Sopenharmony_ci struct optee *optee = tee_get_drvdata(ctx->teedev); 818c2ecf20Sopenharmony_ci struct optee_supp *supp = &optee->supp; 828c2ecf20Sopenharmony_ci struct optee_supp_req *req; 838c2ecf20Sopenharmony_ci bool interruptable; 848c2ecf20Sopenharmony_ci u32 ret; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci /* 878c2ecf20Sopenharmony_ci * Return in case there is no supplicant available and 888c2ecf20Sopenharmony_ci * non-blocking request. 898c2ecf20Sopenharmony_ci */ 908c2ecf20Sopenharmony_ci if (!supp->ctx && ctx->supp_nowait) 918c2ecf20Sopenharmony_ci return TEEC_ERROR_COMMUNICATION; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci req = kzalloc(sizeof(*req), GFP_KERNEL); 948c2ecf20Sopenharmony_ci if (!req) 958c2ecf20Sopenharmony_ci return TEEC_ERROR_OUT_OF_MEMORY; 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci init_completion(&req->c); 988c2ecf20Sopenharmony_ci req->func = func; 998c2ecf20Sopenharmony_ci req->num_params = num_params; 1008c2ecf20Sopenharmony_ci req->param = param; 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci /* Insert the request in the request list */ 1038c2ecf20Sopenharmony_ci mutex_lock(&supp->mutex); 1048c2ecf20Sopenharmony_ci list_add_tail(&req->link, &supp->reqs); 1058c2ecf20Sopenharmony_ci req->in_queue = true; 1068c2ecf20Sopenharmony_ci mutex_unlock(&supp->mutex); 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci /* Tell an eventual waiter there's a new request */ 1098c2ecf20Sopenharmony_ci complete(&supp->reqs_c); 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci /* 1128c2ecf20Sopenharmony_ci * Wait for supplicant to process and return result, once we've 1138c2ecf20Sopenharmony_ci * returned from wait_for_completion(&req->c) successfully we have 1148c2ecf20Sopenharmony_ci * exclusive access again. 1158c2ecf20Sopenharmony_ci */ 1168c2ecf20Sopenharmony_ci while (wait_for_completion_interruptible(&req->c)) { 1178c2ecf20Sopenharmony_ci mutex_lock(&supp->mutex); 1188c2ecf20Sopenharmony_ci interruptable = !supp->ctx; 1198c2ecf20Sopenharmony_ci if (interruptable) { 1208c2ecf20Sopenharmony_ci /* 1218c2ecf20Sopenharmony_ci * There's no supplicant available and since the 1228c2ecf20Sopenharmony_ci * supp->mutex currently is held none can 1238c2ecf20Sopenharmony_ci * become available until the mutex released 1248c2ecf20Sopenharmony_ci * again. 1258c2ecf20Sopenharmony_ci * 1268c2ecf20Sopenharmony_ci * Interrupting an RPC to supplicant is only 1278c2ecf20Sopenharmony_ci * allowed as a way of slightly improving the user 1288c2ecf20Sopenharmony_ci * experience in case the supplicant hasn't been 1298c2ecf20Sopenharmony_ci * started yet. During normal operation the supplicant 1308c2ecf20Sopenharmony_ci * will serve all requests in a timely manner and 1318c2ecf20Sopenharmony_ci * interrupting then wouldn't make sense. 1328c2ecf20Sopenharmony_ci */ 1338c2ecf20Sopenharmony_ci if (req->in_queue) { 1348c2ecf20Sopenharmony_ci list_del(&req->link); 1358c2ecf20Sopenharmony_ci req->in_queue = false; 1368c2ecf20Sopenharmony_ci } 1378c2ecf20Sopenharmony_ci } 1388c2ecf20Sopenharmony_ci mutex_unlock(&supp->mutex); 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci if (interruptable) { 1418c2ecf20Sopenharmony_ci req->ret = TEEC_ERROR_COMMUNICATION; 1428c2ecf20Sopenharmony_ci break; 1438c2ecf20Sopenharmony_ci } 1448c2ecf20Sopenharmony_ci } 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci ret = req->ret; 1478c2ecf20Sopenharmony_ci kfree(req); 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci return ret; 1508c2ecf20Sopenharmony_ci} 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_cistatic struct optee_supp_req *supp_pop_entry(struct optee_supp *supp, 1538c2ecf20Sopenharmony_ci int num_params, int *id) 1548c2ecf20Sopenharmony_ci{ 1558c2ecf20Sopenharmony_ci struct optee_supp_req *req; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci if (supp->req_id != -1) { 1588c2ecf20Sopenharmony_ci /* 1598c2ecf20Sopenharmony_ci * Supplicant should not mix synchronous and asnynchronous 1608c2ecf20Sopenharmony_ci * requests. 1618c2ecf20Sopenharmony_ci */ 1628c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 1638c2ecf20Sopenharmony_ci } 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci if (list_empty(&supp->reqs)) 1668c2ecf20Sopenharmony_ci return NULL; 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci req = list_first_entry(&supp->reqs, struct optee_supp_req, link); 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci if (num_params < req->num_params) { 1718c2ecf20Sopenharmony_ci /* Not enough room for parameters */ 1728c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 1738c2ecf20Sopenharmony_ci } 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci *id = idr_alloc(&supp->idr, req, 1, 0, GFP_KERNEL); 1768c2ecf20Sopenharmony_ci if (*id < 0) 1778c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci list_del(&req->link); 1808c2ecf20Sopenharmony_ci req->in_queue = false; 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci return req; 1838c2ecf20Sopenharmony_ci} 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_cistatic int supp_check_recv_params(size_t num_params, struct tee_param *params, 1868c2ecf20Sopenharmony_ci size_t *num_meta) 1878c2ecf20Sopenharmony_ci{ 1888c2ecf20Sopenharmony_ci size_t n; 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci if (!num_params) 1918c2ecf20Sopenharmony_ci return -EINVAL; 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci /* 1948c2ecf20Sopenharmony_ci * If there's memrefs we need to decrease those as they where 1958c2ecf20Sopenharmony_ci * increased earlier and we'll even refuse to accept any below. 1968c2ecf20Sopenharmony_ci */ 1978c2ecf20Sopenharmony_ci for (n = 0; n < num_params; n++) 1988c2ecf20Sopenharmony_ci if (tee_param_is_memref(params + n) && params[n].u.memref.shm) 1998c2ecf20Sopenharmony_ci tee_shm_put(params[n].u.memref.shm); 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci /* 2028c2ecf20Sopenharmony_ci * We only expect parameters as TEE_IOCTL_PARAM_ATTR_TYPE_NONE with 2038c2ecf20Sopenharmony_ci * or without the TEE_IOCTL_PARAM_ATTR_META bit set. 2048c2ecf20Sopenharmony_ci */ 2058c2ecf20Sopenharmony_ci for (n = 0; n < num_params; n++) 2068c2ecf20Sopenharmony_ci if (params[n].attr && 2078c2ecf20Sopenharmony_ci params[n].attr != TEE_IOCTL_PARAM_ATTR_META) 2088c2ecf20Sopenharmony_ci return -EINVAL; 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci /* At most we'll need one meta parameter so no need to check for more */ 2118c2ecf20Sopenharmony_ci if (params->attr == TEE_IOCTL_PARAM_ATTR_META) 2128c2ecf20Sopenharmony_ci *num_meta = 1; 2138c2ecf20Sopenharmony_ci else 2148c2ecf20Sopenharmony_ci *num_meta = 0; 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci return 0; 2178c2ecf20Sopenharmony_ci} 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci/** 2208c2ecf20Sopenharmony_ci * optee_supp_recv() - receive request for supplicant 2218c2ecf20Sopenharmony_ci * @ctx: context receiving the request 2228c2ecf20Sopenharmony_ci * @func: requested function in supplicant 2238c2ecf20Sopenharmony_ci * @num_params: number of elements allocated in @param, updated with number 2248c2ecf20Sopenharmony_ci * used elements 2258c2ecf20Sopenharmony_ci * @param: space for parameters for @func 2268c2ecf20Sopenharmony_ci * 2278c2ecf20Sopenharmony_ci * Returns 0 on success or <0 on failure 2288c2ecf20Sopenharmony_ci */ 2298c2ecf20Sopenharmony_ciint optee_supp_recv(struct tee_context *ctx, u32 *func, u32 *num_params, 2308c2ecf20Sopenharmony_ci struct tee_param *param) 2318c2ecf20Sopenharmony_ci{ 2328c2ecf20Sopenharmony_ci struct tee_device *teedev = ctx->teedev; 2338c2ecf20Sopenharmony_ci struct optee *optee = tee_get_drvdata(teedev); 2348c2ecf20Sopenharmony_ci struct optee_supp *supp = &optee->supp; 2358c2ecf20Sopenharmony_ci struct optee_supp_req *req = NULL; 2368c2ecf20Sopenharmony_ci int id; 2378c2ecf20Sopenharmony_ci size_t num_meta; 2388c2ecf20Sopenharmony_ci int rc; 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci rc = supp_check_recv_params(*num_params, param, &num_meta); 2418c2ecf20Sopenharmony_ci if (rc) 2428c2ecf20Sopenharmony_ci return rc; 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci while (true) { 2458c2ecf20Sopenharmony_ci mutex_lock(&supp->mutex); 2468c2ecf20Sopenharmony_ci req = supp_pop_entry(supp, *num_params - num_meta, &id); 2478c2ecf20Sopenharmony_ci mutex_unlock(&supp->mutex); 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci if (req) { 2508c2ecf20Sopenharmony_ci if (IS_ERR(req)) 2518c2ecf20Sopenharmony_ci return PTR_ERR(req); 2528c2ecf20Sopenharmony_ci break; 2538c2ecf20Sopenharmony_ci } 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci /* 2568c2ecf20Sopenharmony_ci * If we didn't get a request we'll block in 2578c2ecf20Sopenharmony_ci * wait_for_completion() to avoid needless spinning. 2588c2ecf20Sopenharmony_ci * 2598c2ecf20Sopenharmony_ci * This is where supplicant will be hanging most of 2608c2ecf20Sopenharmony_ci * the time, let's make this interruptable so we 2618c2ecf20Sopenharmony_ci * can easily restart supplicant if needed. 2628c2ecf20Sopenharmony_ci */ 2638c2ecf20Sopenharmony_ci if (wait_for_completion_interruptible(&supp->reqs_c)) 2648c2ecf20Sopenharmony_ci return -ERESTARTSYS; 2658c2ecf20Sopenharmony_ci } 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci if (num_meta) { 2688c2ecf20Sopenharmony_ci /* 2698c2ecf20Sopenharmony_ci * tee-supplicant support meta parameters -> requsts can be 2708c2ecf20Sopenharmony_ci * processed asynchronously. 2718c2ecf20Sopenharmony_ci */ 2728c2ecf20Sopenharmony_ci param->attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT | 2738c2ecf20Sopenharmony_ci TEE_IOCTL_PARAM_ATTR_META; 2748c2ecf20Sopenharmony_ci param->u.value.a = id; 2758c2ecf20Sopenharmony_ci param->u.value.b = 0; 2768c2ecf20Sopenharmony_ci param->u.value.c = 0; 2778c2ecf20Sopenharmony_ci } else { 2788c2ecf20Sopenharmony_ci mutex_lock(&supp->mutex); 2798c2ecf20Sopenharmony_ci supp->req_id = id; 2808c2ecf20Sopenharmony_ci mutex_unlock(&supp->mutex); 2818c2ecf20Sopenharmony_ci } 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci *func = req->func; 2848c2ecf20Sopenharmony_ci *num_params = req->num_params + num_meta; 2858c2ecf20Sopenharmony_ci memcpy(param + num_meta, req->param, 2868c2ecf20Sopenharmony_ci sizeof(struct tee_param) * req->num_params); 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci return 0; 2898c2ecf20Sopenharmony_ci} 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_cistatic struct optee_supp_req *supp_pop_req(struct optee_supp *supp, 2928c2ecf20Sopenharmony_ci size_t num_params, 2938c2ecf20Sopenharmony_ci struct tee_param *param, 2948c2ecf20Sopenharmony_ci size_t *num_meta) 2958c2ecf20Sopenharmony_ci{ 2968c2ecf20Sopenharmony_ci struct optee_supp_req *req; 2978c2ecf20Sopenharmony_ci int id; 2988c2ecf20Sopenharmony_ci size_t nm; 2998c2ecf20Sopenharmony_ci const u32 attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT | 3008c2ecf20Sopenharmony_ci TEE_IOCTL_PARAM_ATTR_META; 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci if (!num_params) 3038c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci if (supp->req_id == -1) { 3068c2ecf20Sopenharmony_ci if (param->attr != attr) 3078c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 3088c2ecf20Sopenharmony_ci id = param->u.value.a; 3098c2ecf20Sopenharmony_ci nm = 1; 3108c2ecf20Sopenharmony_ci } else { 3118c2ecf20Sopenharmony_ci id = supp->req_id; 3128c2ecf20Sopenharmony_ci nm = 0; 3138c2ecf20Sopenharmony_ci } 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci req = idr_find(&supp->idr, id); 3168c2ecf20Sopenharmony_ci if (!req) 3178c2ecf20Sopenharmony_ci return ERR_PTR(-ENOENT); 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci if ((num_params - nm) != req->num_params) 3208c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci idr_remove(&supp->idr, id); 3238c2ecf20Sopenharmony_ci supp->req_id = -1; 3248c2ecf20Sopenharmony_ci *num_meta = nm; 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci return req; 3278c2ecf20Sopenharmony_ci} 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci/** 3308c2ecf20Sopenharmony_ci * optee_supp_send() - send result of request from supplicant 3318c2ecf20Sopenharmony_ci * @ctx: context sending result 3328c2ecf20Sopenharmony_ci * @ret: return value of request 3338c2ecf20Sopenharmony_ci * @num_params: number of parameters returned 3348c2ecf20Sopenharmony_ci * @param: returned parameters 3358c2ecf20Sopenharmony_ci * 3368c2ecf20Sopenharmony_ci * Returns 0 on success or <0 on failure. 3378c2ecf20Sopenharmony_ci */ 3388c2ecf20Sopenharmony_ciint optee_supp_send(struct tee_context *ctx, u32 ret, u32 num_params, 3398c2ecf20Sopenharmony_ci struct tee_param *param) 3408c2ecf20Sopenharmony_ci{ 3418c2ecf20Sopenharmony_ci struct tee_device *teedev = ctx->teedev; 3428c2ecf20Sopenharmony_ci struct optee *optee = tee_get_drvdata(teedev); 3438c2ecf20Sopenharmony_ci struct optee_supp *supp = &optee->supp; 3448c2ecf20Sopenharmony_ci struct optee_supp_req *req; 3458c2ecf20Sopenharmony_ci size_t n; 3468c2ecf20Sopenharmony_ci size_t num_meta; 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci mutex_lock(&supp->mutex); 3498c2ecf20Sopenharmony_ci req = supp_pop_req(supp, num_params, param, &num_meta); 3508c2ecf20Sopenharmony_ci mutex_unlock(&supp->mutex); 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci if (IS_ERR(req)) { 3538c2ecf20Sopenharmony_ci /* Something is wrong, let supplicant restart. */ 3548c2ecf20Sopenharmony_ci return PTR_ERR(req); 3558c2ecf20Sopenharmony_ci } 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci /* Update out and in/out parameters */ 3588c2ecf20Sopenharmony_ci for (n = 0; n < req->num_params; n++) { 3598c2ecf20Sopenharmony_ci struct tee_param *p = req->param + n; 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci switch (p->attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) { 3628c2ecf20Sopenharmony_ci case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT: 3638c2ecf20Sopenharmony_ci case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT: 3648c2ecf20Sopenharmony_ci p->u.value.a = param[n + num_meta].u.value.a; 3658c2ecf20Sopenharmony_ci p->u.value.b = param[n + num_meta].u.value.b; 3668c2ecf20Sopenharmony_ci p->u.value.c = param[n + num_meta].u.value.c; 3678c2ecf20Sopenharmony_ci break; 3688c2ecf20Sopenharmony_ci case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT: 3698c2ecf20Sopenharmony_ci case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT: 3708c2ecf20Sopenharmony_ci p->u.memref.size = param[n + num_meta].u.memref.size; 3718c2ecf20Sopenharmony_ci break; 3728c2ecf20Sopenharmony_ci default: 3738c2ecf20Sopenharmony_ci break; 3748c2ecf20Sopenharmony_ci } 3758c2ecf20Sopenharmony_ci } 3768c2ecf20Sopenharmony_ci req->ret = ret; 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci /* Let the requesting thread continue */ 3798c2ecf20Sopenharmony_ci complete(&req->c); 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci return 0; 3828c2ecf20Sopenharmony_ci} 383