From patchwork Tue Dec 3 04:19:19 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Amirreza Zarrabi X-Patchwork-Id: 847029 Received: from mx0a-0031df01.pphosted.com (mx0a-0031df01.pphosted.com [205.220.168.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 9C286166F29; Tue, 3 Dec 2024 04:20:24 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=205.220.168.131 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1733199626; cv=none; b=J1kJ/2dweyYbUJoV27DpSfSLHx3L1lGSi6MaanCLzDYplsha3uEcm9Tpb7MSGD4YfT+V0/ITFiriCFnrp5/t6eFS9vvnjH3jb6A5vVrky6rhxZZrH2giNOUcGEfKgBkmMn7sPhOIfCdd6mugsVjVfUXH2+ckMiEmuHoi1KsZC2Q= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1733199626; c=relaxed/simple; bh=OLZ1v2QzrSrSkIZI04gALvSBD1D2VCLpxJp0bOz2UMA=; h=From:Date:Subject:MIME-Version:Content-Type:Message-ID:References: In-Reply-To:To:CC; b=dwFvFhatLp4v27iglxBCMFGhaNR2wu6EpXvVYwvoCoMyXD4QV1CtAaKydZg6PoUb27hlPU8HAbFq4aZtHmoV4nCoARCYEJCg1BNfqxF/gwgJjhLyp44hFPJCUsHepbaaNgReDBmFQ78FY7fdsT+/xUTIjMuRGIBI+xYQkdFL3/M= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=quicinc.com; spf=pass smtp.mailfrom=quicinc.com; dkim=pass (2048-bit key) header.d=quicinc.com header.i=@quicinc.com header.b=PIW7d5y3; arc=none smtp.client-ip=205.220.168.131 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=quicinc.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=quicinc.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=quicinc.com header.i=@quicinc.com header.b="PIW7d5y3" Received: from pps.filterd (m0279866.ppops.net [127.0.0.1]) by mx0a-0031df01.pphosted.com (8.18.1.2/8.18.1.2) with ESMTP id 4B34BYKD031795; Tue, 3 Dec 2024 04:20:07 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=quicinc.com; h= cc:content-transfer-encoding:content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to; s=qcppdkim1; bh= DzDawwrp1oDEx6fSIHvQDRbS0UQEe6+wD+e+JOken8I=; b=PIW7d5y3UI8Mq9ff aAJ9PKRUvUarWS4XBhtMp94UliIsgJtx2+m7o238DgSFAxBTmo1IdDb7SaC6eFG0 ddeVm0HIfHBUaKh9btmqcHrSV+ADI26mg8uOhMCekQ4OqB0P7zM9Mb7kvchRSaVy tI+CQMCq8zizi+Ho9/r/LWTxvah/4xXUUDdqSUTuCHnwbDtb/BfgmbWwD4l/N8vf oTdQR4OAY49Z4f2QYgxLc/2X7Cf/RIYlzVN0eBu2Mw+USKS3XYR2+sQkgyMEcRTD EcCE806C7r64M58SO6cpNIn7IVlAX4kIQe69G8RxdKXYN0H2U171eIKZXB74jFK3 9uAtxg== Received: from nasanppmta02.qualcomm.com (i-global254.qualcomm.com [199.106.103.254]) by mx0a-0031df01.pphosted.com (PPS) with ESMTPS id 439trbg0j5-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 03 Dec 2024 04:20:06 +0000 (GMT) Received: from nasanex01b.na.qualcomm.com (nasanex01b.na.qualcomm.com [10.46.141.250]) by NASANPPMTA02.qualcomm.com (8.18.1.2/8.18.1.2) with ESMTPS id 4B34K6HG016645 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 3 Dec 2024 04:20:06 GMT Received: from hu-azarrabi-lv.qualcomm.com (10.49.16.6) by nasanex01b.na.qualcomm.com (10.46.141.250) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1544.9; Mon, 2 Dec 2024 20:20:05 -0800 From: Amirreza Zarrabi Date: Mon, 2 Dec 2024 20:19:19 -0800 Subject: [PATCH 03/10] tee: add TEE_IOCTL_PARAM_ATTR_TYPE_OBJREF Precedence: bulk X-Mailing-List: linux-arm-msm@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-ID: <20241202-qcom-tee-using-tee-ss-without-mem-obj-v1-3-f502ef01e016@quicinc.com> References: <20241202-qcom-tee-using-tee-ss-without-mem-obj-v1-0-f502ef01e016@quicinc.com> In-Reply-To: <20241202-qcom-tee-using-tee-ss-without-mem-obj-v1-0-f502ef01e016@quicinc.com> To: Jens Wiklander , Sumit Garg , Bjorn Andersson , "Konrad Dybcio" , Rob Herring , "Krzysztof Kozlowski" , Conor Dooley , "Bartosz Golaszewski" , Srinivas Kandagatla CC: , , , , , Amirreza Zarrabi X-Mailer: b4 0.13.0 X-ClientProxiedBy: nalasex01c.na.qualcomm.com (10.47.97.35) To nasanex01b.na.qualcomm.com (10.46.141.250) X-QCInternal: smtphost X-Proofpoint-Virus-Version: vendor=nai engine=6200 definitions=5800 signatures=585085 X-Proofpoint-GUID: Fc7wX2G3Y5JT37CwiZHAyyPe7hIxauVQ X-Proofpoint-ORIG-GUID: Fc7wX2G3Y5JT37CwiZHAyyPe7hIxauVQ X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1039,Hydra:6.0.680,FMLib:17.12.60.29 definitions=2024-09-06_09,2024-09-06_01,2024-09-02_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 mlxlogscore=999 mlxscore=0 suspectscore=0 spamscore=0 malwarescore=0 adultscore=0 priorityscore=1501 clxscore=1015 phishscore=0 lowpriorityscore=0 impostorscore=0 bulkscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.19.0-2411120000 definitions=main-2412030034 The TEE subsystem allows session-based access to trusted services, requiring a session to be established to receive a service. This is not suitable for an environment that represents services as objects. An object supports various operations that a client can invoke, potentially generating a result or a new object that can be invoked independently of the original object. Add TEE_IOCTL_PARAM_ATTR_TYPE_OBJREF_INPUT/OUTPUT/INOUT to represent an object. Objects may reside in either TEE or userspace. To invoke an object in TEE, introduce a new ioctl. Use the existing SUPPL_RECV and SUPPL_SEND to invoke an object in userspace. Signed-off-by: Amirreza Zarrabi --- drivers/tee/tee_core.c | 85 ++++++++++++++++++++++++++++++++++++++++++++++++ include/linux/tee_core.h | 4 +++ include/linux/tee_drv.h | 6 ++++ include/uapi/linux/tee.h | 41 +++++++++++++++++++---- 4 files changed, 130 insertions(+), 6 deletions(-) diff --git a/drivers/tee/tee_core.c b/drivers/tee/tee_core.c index 942ff5b359b2..037bd17159e2 100644 --- a/drivers/tee/tee_core.c +++ b/drivers/tee/tee_core.c @@ -374,6 +374,7 @@ static int params_from_user(struct tee_context *ctx, struct tee_param *params, switch (ip.attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) { case TEE_IOCTL_PARAM_ATTR_TYPE_NONE: case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT: + case TEE_IOCTL_PARAM_ATTR_TYPE_OBJREF_OUTPUT: break; case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT: case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT: @@ -391,6 +392,11 @@ static int params_from_user(struct tee_context *ctx, struct tee_param *params, return -EFAULT; break; + case TEE_IOCTL_PARAM_ATTR_TYPE_OBJREF_INPUT: + case TEE_IOCTL_PARAM_ATTR_TYPE_OBJREF_INOUT: + params[n].u.objref.id = ip.a; + params[n].u.objref.flags = ip.b; + break; case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT: case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT: case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT: @@ -464,6 +470,12 @@ static int params_to_user(struct tee_ioctl_param __user *uparams, if (put_user((u64)p->u.membuf.size, &up->b)) return -EFAULT; break; + case TEE_IOCTL_PARAM_ATTR_TYPE_OBJREF_OUTPUT: + case TEE_IOCTL_PARAM_ATTR_TYPE_OBJREF_INOUT: + if (put_user(p->u.objref.id, &up->a) || + put_user(p->u.objref.flags, &up->b)) + return -EFAULT; + break; case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT: case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT: if (put_user((u64)p->u.memref.size, &up->b)) @@ -616,6 +628,66 @@ static int tee_ioctl_invoke(struct tee_context *ctx, return rc; } +static int tee_ioctl_object_invoke(struct tee_context *ctx, + struct tee_ioctl_buf_data __user *ubuf) +{ + int rc; + size_t n; + struct tee_ioctl_buf_data buf; + struct tee_ioctl_object_invoke_arg __user *uarg; + struct tee_ioctl_object_invoke_arg arg; + struct tee_ioctl_param __user *uparams = NULL; + struct tee_param *params = NULL; + + if (!ctx->teedev->desc->ops->object_invoke_func) + return -EINVAL; + + if (copy_from_user(&buf, ubuf, sizeof(buf))) + return -EFAULT; + + if (buf.buf_len > TEE_MAX_ARG_SIZE || + buf.buf_len < sizeof(struct tee_ioctl_object_invoke_arg)) + return -EINVAL; + + uarg = u64_to_user_ptr(buf.buf_ptr); + if (copy_from_user(&arg, uarg, sizeof(arg))) + return -EFAULT; + + if (sizeof(arg) + TEE_IOCTL_PARAM_SIZE(arg.num_params) != buf.buf_len) + return -EINVAL; + + if (arg.num_params) { + params = kcalloc(arg.num_params, sizeof(struct tee_param), + GFP_KERNEL); + if (!params) + return -ENOMEM; + uparams = uarg->params; + rc = params_from_user(ctx, params, arg.num_params, uparams); + if (rc) + goto out; + } + + rc = ctx->teedev->desc->ops->object_invoke_func(ctx, &arg, params); + if (rc) + goto out; + + if (put_user(arg.ret, &uarg->ret)) { + rc = -EFAULT; + goto out; + } + rc = params_to_user(uparams, arg.num_params, params); +out: + if (params) { + /* Decrease ref count for all valid shared memory pointers */ + for (n = 0; n < arg.num_params; n++) + if (tee_param_is_memref(params + n) && + params[n].u.memref.shm) + tee_shm_put(params[n].u.memref.shm); + kfree(params); + } + return rc; +} + static int tee_ioctl_cancel(struct tee_context *ctx, struct tee_ioctl_cancel_arg __user *uarg) { @@ -670,6 +742,12 @@ static int params_to_supp(struct tee_context *ctx, ip.b = p->u.membuf.size; ip.c = 0; break; + case TEE_IOCTL_PARAM_ATTR_TYPE_OBJREF_INPUT: + case TEE_IOCTL_PARAM_ATTR_TYPE_OBJREF_INOUT: + ip.a = p->u.objref.id; + ip.b = p->u.objref.flags; + ip.c = 0; + break; case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT: case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT: case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT: @@ -777,6 +855,11 @@ static int params_from_supp(struct tee_param *params, size_t num_params, p->u.membuf.uaddr = u64_to_user_ptr(ip.a); p->u.membuf.size = ip.b; break; + case TEE_IOCTL_PARAM_ATTR_TYPE_OBJREF_OUTPUT: + case TEE_IOCTL_PARAM_ATTR_TYPE_OBJREF_INOUT: + p->u.objref.id = ip.a; + p->u.objref.flags = ip.b; + break; case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT: case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT: /* @@ -857,6 +940,8 @@ static long tee_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) return tee_ioctl_open_session(ctx, uarg); case TEE_IOC_INVOKE: return tee_ioctl_invoke(ctx, uarg); + case TEE_IOC_OBJECT_INVOKE: + return tee_ioctl_object_invoke(ctx, uarg); case TEE_IOC_CANCEL: return tee_ioctl_cancel(ctx, uarg); case TEE_IOC_CLOSE_SESSION: diff --git a/include/linux/tee_core.h b/include/linux/tee_core.h index a38494d6b5f4..6311dedd2b83 100644 --- a/include/linux/tee_core.h +++ b/include/linux/tee_core.h @@ -71,6 +71,7 @@ struct tee_device { * @close_session: close a session * @system_session: declare session as a system session * @invoke_func: invoke a trusted function + * @object_invoke_func: invoke an object * @cancel_req: request cancel of an ongoing invoke or open * @supp_recv: called for supplicant to get a command * @supp_send: called for supplicant to send a response @@ -90,6 +91,9 @@ struct tee_driver_ops { int (*invoke_func)(struct tee_context *ctx, struct tee_ioctl_invoke_arg *arg, struct tee_param *param); + int (*object_invoke_func)(struct tee_context *ctx, + struct tee_ioctl_object_invoke_arg *arg, + struct tee_param *param); int (*cancel_req)(struct tee_context *ctx, u32 cancel_id, u32 session); int (*supp_recv)(struct tee_context *ctx, u32 *func, u32 *num_params, struct tee_param *param); diff --git a/include/linux/tee_drv.h b/include/linux/tee_drv.h index b66e611fece4..a556e6bc0c53 100644 --- a/include/linux/tee_drv.h +++ b/include/linux/tee_drv.h @@ -87,6 +87,11 @@ struct tee_param_membuf { size_t size; }; +struct tee_param_objref { + u64 id; + u64 flags; +}; + struct tee_param_value { u64 a; u64 b; @@ -97,6 +102,7 @@ struct tee_param { u64 attr; union { struct tee_param_memref memref; + struct tee_param_objref objref; struct tee_param_membuf membuf; struct tee_param_value value; } u; diff --git a/include/uapi/linux/tee.h b/include/uapi/linux/tee.h index fae68386968a..5d33a8009efb 100644 --- a/include/uapi/linux/tee.h +++ b/include/uapi/linux/tee.h @@ -48,8 +48,10 @@ #define TEE_GEN_CAP_PRIVILEGED (1 << 1)/* Privileged device (for supplicant) */ #define TEE_GEN_CAP_REG_MEM (1 << 2)/* Supports registering shared memory */ #define TEE_GEN_CAP_MEMREF_NULL (1 << 3)/* NULL MemRef support */ +#define TEE_GEN_CAP_OBJREF (1 << 4)/* Supports generic object reference */ -#define TEE_MEMREF_NULL (__u64)(-1) /* NULL MemRef Buffer */ +#define TEE_MEMREF_NULL ((__u64)(-1)) /* NULL MemRef Buffer */ +#define TEE_OBJREF_NULL ((__u64)(-1)) /* NULL ObjRef Object */ /* * TEE Implementation ID @@ -158,6 +160,13 @@ struct tee_ioctl_buf_data { #define TEE_IOCTL_PARAM_ATTR_TYPE_MEMBUF_OUTPUT 9 #define TEE_IOCTL_PARAM_ATTR_TYPE_MEMBUF_INOUT 10 /* input and output */ +/* + * These defines object reference parameters. + */ +#define TEE_IOCTL_PARAM_ATTR_TYPE_OBJREF_INPUT 11 +#define TEE_IOCTL_PARAM_ATTR_TYPE_OBJREF_OUTPUT 12 +#define TEE_IOCTL_PARAM_ATTR_TYPE_OBJREF_INOUT 13 + /* * Mask for the type part of the attribute, leaves room for more types */ @@ -195,15 +204,16 @@ struct tee_ioctl_buf_data { * @attr: attributes * @a: if a memref, offset into the shared memory object, * else if a membuf, address into the user buffer, - * else a value parameter - * @b: if a memref or membuf, size of the buffer, else a value parameter + * else if an objref, object identifier, else a value parameter + * @b: if a memref or membuf, size of the buffer, + * else if objref, a flag for object, else a value parameter * @c: if a memref, shared memory identifier, else a value parameter * * @attr & TEE_PARAM_ATTR_TYPE_MASK indicates if memref, membuf, or value is * used in the union. TEE_PARAM_ATTR_TYPE_VALUE_* indicates value, - * TEE_PARAM_ATTR_TYPE_MEMREF_* indicates memref, and TEE_PARAM_ATTR_TYPE_MEMBUF_* - * indicates membuf. TEE_PARAM_ATTR_TYPE_NONE indicates that none of the members - * are used. + * TEE_PARAM_ATTR_TYPE_MEMREF_* indicates memref, TEE_PARAM_ATTR_TYPE_MEMBUF_* + * indicates membuf, and TEE_PARAM_ATTR_TYPE_OBJREF_* indicates objref. + * TEE_PARAM_ATTR_TYPE_NONE indicates that none of the members are used. * * Shared memory is allocated with TEE_IOC_SHM_ALLOC which returns an * identifier representing the shared memory object. A memref can reference @@ -411,4 +421,23 @@ struct tee_ioctl_shm_register_data { * munmap(): unmaps previously shared memory */ +/** + * struct tee_ioctl_invoke_func_arg - Invokes an object in a Trusted Application. + * @object: [in] Object id + * @op: [in] Object operation, specific to the object + * @ret: [out] return value + * @num_params [in] number of parameters following this struct + */ +struct tee_ioctl_object_invoke_arg { + __u64 object; + __u32 op; + __u32 ret; + __u32 num_params; + /* num_params tells the actual number of element in params */ + struct tee_ioctl_param params[]; +}; + +#define TEE_IOC_OBJECT_INVOKE _IOR(TEE_IOC_MAGIC, TEE_IOC_BASE + 10, \ + struct tee_ioctl_buf_data) + #endif /*__TEE_H*/ From patchwork Tue Dec 3 04:19:21 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Amirreza Zarrabi X-Patchwork-Id: 847027 Received: from mx0a-0031df01.pphosted.com (mx0a-0031df01.pphosted.com [205.220.168.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A7CD818FC80; Tue, 3 Dec 2024 04:20:27 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=205.220.168.131 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1733199631; cv=none; b=XwX5d4klxATG+c3tBwnYExLLPONYXwMTv7yG8o/S+AzFYN093qYL8xscQyYZ9VHSSdM6EXdLmhrvFKSs+FnzHv2iVeBiAK2WbW7t/039PpYfdQT/YsVSSJrv19ZI8QRj9K/zQg3HSJfZ2IX4wzMn//A85t0fHuCfXYNAMPDiBY8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1733199631; c=relaxed/simple; bh=8Jh/aSX0JJL0rIc/IRSdMgo0eHFG8jKGrP5w5BL14gI=; h=From:Date:Subject:MIME-Version:Content-Type:Message-ID:References: In-Reply-To:To:CC; b=Hw2S05AsISjBCYhnKyijnJHtXJHBl6kCEIsIswvJBCnre6nQTB7Z8k5Ez9v8Ds4/COuIS4XMJtwkif5AGsrUZRF6vMt8+rLjC4iezd8YhqfjZOXjJNZyZD9OtK2nI/N2EEvlmKW9WaU/GOPn+u7ZjeIhtzTX06JrXc7t01JhJIg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=quicinc.com; spf=pass smtp.mailfrom=quicinc.com; dkim=pass (2048-bit key) header.d=quicinc.com header.i=@quicinc.com header.b=BfO/PHFI; arc=none smtp.client-ip=205.220.168.131 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=quicinc.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=quicinc.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=quicinc.com header.i=@quicinc.com header.b="BfO/PHFI" Received: from pps.filterd (m0279864.ppops.net [127.0.0.1]) by mx0a-0031df01.pphosted.com (8.18.1.2/8.18.1.2) with ESMTP id 4B2JkpZ1020570; Tue, 3 Dec 2024 04:20:08 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=quicinc.com; h= cc:content-transfer-encoding:content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to; s=qcppdkim1; bh= LoAge/Z1b8cRAGZHXk69+Y73mAmVDaNtF/gHLP4ydGk=; b=BfO/PHFIPYvA40xS AzzzMerxdXCmV6+i31lUI5j5VaJKvjPQRIWMeUrYvAob60VWzD4Ou+Vdv/i7ZCNc Gl8oMCISVD4yAsEIL9vO7TbsLqXW+vCkTEeagGo6X9pGiYbsg4W+Sl1iNaHfB73W NiVVP1pfYvRR1Ebv4tkF3f2yc7LG1daWKRh4TtP2DLE4qc/ZX0hdB468U6V8EPms lz5CDXdiujpsLJgBwKoXXM3NO7f7boja5MMZhp+RUlcXG4Q2oLMy/HH2oyMLrraK DT5c9pOVrcbwyZ6XjNKCsSz214Tuz0ND2VTDn0d8FUYl3V1Ur2+ZoJYu9ZLJB6eP oVhM/A== Received: from nasanppmta01.qualcomm.com (i-global254.qualcomm.com [199.106.103.254]) by mx0a-0031df01.pphosted.com (PPS) with ESMTPS id 437uvjxmq6-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 03 Dec 2024 04:20:07 +0000 (GMT) Received: from nasanex01b.na.qualcomm.com (nasanex01b.na.qualcomm.com [10.46.141.250]) by NASANPPMTA01.qualcomm.com (8.18.1.2/8.18.1.2) with ESMTPS id 4B34K67b031210 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 3 Dec 2024 04:20:07 GMT Received: from hu-azarrabi-lv.qualcomm.com (10.49.16.6) by nasanex01b.na.qualcomm.com (10.46.141.250) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1544.9; Mon, 2 Dec 2024 20:20:06 -0800 From: Amirreza Zarrabi Date: Mon, 2 Dec 2024 20:19:21 -0800 Subject: [PATCH 05/10] qcomtee: implement object invoke support Precedence: bulk X-Mailing-List: linux-arm-msm@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-ID: <20241202-qcom-tee-using-tee-ss-without-mem-obj-v1-5-f502ef01e016@quicinc.com> References: <20241202-qcom-tee-using-tee-ss-without-mem-obj-v1-0-f502ef01e016@quicinc.com> In-Reply-To: <20241202-qcom-tee-using-tee-ss-without-mem-obj-v1-0-f502ef01e016@quicinc.com> To: Jens Wiklander , Sumit Garg , Bjorn Andersson , "Konrad Dybcio" , Rob Herring , "Krzysztof Kozlowski" , Conor Dooley , "Bartosz Golaszewski" , Srinivas Kandagatla CC: , , , , , Amirreza Zarrabi X-Mailer: b4 0.13.0 X-ClientProxiedBy: nalasex01c.na.qualcomm.com (10.47.97.35) To nasanex01b.na.qualcomm.com (10.46.141.250) X-QCInternal: smtphost X-Proofpoint-Virus-Version: vendor=nai engine=6200 definitions=5800 signatures=585085 X-Proofpoint-GUID: h7Zz9DlfSQnRnHUTrqwNvazoXYwXy5hv X-Proofpoint-ORIG-GUID: h7Zz9DlfSQnRnHUTrqwNvazoXYwXy5hv X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1039,Hydra:6.0.680,FMLib:17.12.60.29 definitions=2024-09-06_09,2024-09-06_01,2024-09-02_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 mlxscore=0 malwarescore=0 suspectscore=0 mlxlogscore=999 impostorscore=0 adultscore=0 phishscore=0 bulkscore=0 priorityscore=1501 clxscore=1011 spamscore=0 lowpriorityscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.19.0-2411120000 definitions=main-2412030034 Introduce qcom_tee_object, which represents an object in both QTEE and the kernel. QTEE clients can invoke an instance of qcom_tee_object to access QTEE services. If this invocation produces a new object in QTEE, an instance of qcom_tee_object will be returned. Similarly, QTEE can request services from the kernel by issuing a callback request, which invokes an instance of qcom_tee_object in the kernel. Any subsystem that exposes a service to QTEE should allocate and initialize an instance of qcom_tee_object with a dispatcher callback that is called when the object is invoked. Signed-off-by: Amirreza Zarrabi --- drivers/tee/Kconfig | 1 + drivers/tee/Makefile | 1 + drivers/tee/qcomtee/Kconfig | 10 + drivers/tee/qcomtee/Makefile | 6 + drivers/tee/qcomtee/async.c | 153 ++++++ drivers/tee/qcomtee/core.c | 928 +++++++++++++++++++++++++++++++++ drivers/tee/qcomtee/qcom_scm.c | 36 ++ drivers/tee/qcomtee/qcomtee_msg.h | 217 ++++++++ drivers/tee/qcomtee/qcomtee_private.h | 47 ++ drivers/tee/qcomtee/release.c | 66 +++ include/linux/firmware/qcom/qcom_tee.h | 284 ++++++++++ 11 files changed, 1749 insertions(+) diff --git a/drivers/tee/Kconfig b/drivers/tee/Kconfig index 61b507c18780..3a995d7f0d74 100644 --- a/drivers/tee/Kconfig +++ b/drivers/tee/Kconfig @@ -16,5 +16,6 @@ if TEE source "drivers/tee/optee/Kconfig" source "drivers/tee/amdtee/Kconfig" source "drivers/tee/tstee/Kconfig" +source "drivers/tee/qcomtee/Kconfig" endif diff --git a/drivers/tee/Makefile b/drivers/tee/Makefile index 5488cba30bd2..74e987f8f7ea 100644 --- a/drivers/tee/Makefile +++ b/drivers/tee/Makefile @@ -6,3 +6,4 @@ tee-objs += tee_shm_pool.o obj-$(CONFIG_OPTEE) += optee/ obj-$(CONFIG_AMDTEE) += amdtee/ obj-$(CONFIG_ARM_TSTEE) += tstee/ +obj-$(CONFIG_QCOMTEE) += qcomtee/ diff --git a/drivers/tee/qcomtee/Kconfig b/drivers/tee/qcomtee/Kconfig new file mode 100644 index 000000000000..d180a6d07d33 --- /dev/null +++ b/drivers/tee/qcomtee/Kconfig @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: GPL-2.0-only +# Qualcomm Trusted Execution Environment Configuration +config QCOMTEE + tristate "Qualcomm TEE Support" + select QCOM_SCM + help + This option enables the Qualcomm Trusted Execution Environment (QTEE) + driver. It provides an API to access services offered by QTEE and any + loaded Trusted Applications (TAs), as well as exporting kernel + services to QTEE. diff --git a/drivers/tee/qcomtee/Makefile b/drivers/tee/qcomtee/Makefile new file mode 100644 index 000000000000..7dc5e6373042 --- /dev/null +++ b/drivers/tee/qcomtee/Makefile @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0-only +obj-$(CONFIG_QCOMTEE) += qcomtee.o +qcomtee-objs += async.o +qcomtee-objs += core.o +qcomtee-objs += qcom_scm.o +qcomtee-objs += release.o diff --git a/drivers/tee/qcomtee/async.c b/drivers/tee/qcomtee/async.c new file mode 100644 index 000000000000..218ec0209722 --- /dev/null +++ b/drivers/tee/qcomtee/async.c @@ -0,0 +1,153 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include +#include + +#include "qcomtee_private.h" +#include "qcomtee_msg.h" + +#define QCOM_TEE_ASYNC_VERSION_1_0 0x00010000U /* Major: 0x0001, Minor: 0x0000. */ +#define QCOM_TEE_ASYNC_VERSION_1_1 0x00010001U /* Major: 0x0001, Minor: 0x0001. */ +#define QCOM_TEE_ASYNC_VERSION_1_2 0x00010002U /* Major: 0x0001, Minor: 0x0002. */ +#define QCOM_TEE_ASYNC_VERSION QCOM_TEE_ASYNC_VERSION_1_2 /* Current Version. */ + +#define QCOM_TEE_ASYNC_VERSION_MAJOR(n) upper_16_bits(n) +#define QCOM_TEE_ASYNC_VERSION_MINOR(n) lower_16_bits(n) + +/** + * struct qcom_tee_async_msg_hdr - Asynchronous message header format. + * @version: current async protocol version of remote endpoint + * @op: async operation + * + * @version specifies the endpoints (QTEE or driver) supported async protocol, e.g. + * if QTEE set @version to %QCOM_TEE_ASYNC_VERSION_1_1, QTEE handles operations + * supported in %QCOM_TEE_ASYNC_VERSION_1_1 or %QCOM_TEE_ASYNC_VERSION_1_0. + * @op determins the message format. + */ +struct qcom_tee_async_msg_hdr { + u32 version; + u32 op; +}; + +/** + * struct qcom_tee_async_release_msg - Release asynchronous message. + * @hdr: message header as &struct qcom_tee_async_msg_hdr + * @counts: number of objects in @object_ids + * @object_ids: array of object ids should be released + * + * Available in Major = 0x0001, Minor >= 0x0000. + */ +struct qcom_tee_async_release_msg { + struct qcom_tee_async_msg_hdr hdr; + u32 counts; + u32 object_ids[] __counted_by(counts); +}; + +/** + * qcom_tee_get_async_buffer() - Get start of the asynchronous message in outbound buffer. + * @oic: context used for current invocation + * @async_buffer: return buffer to extract from or fill in async messages + * + * If @oic is used for direct object invocation, whole outbound buffer is available for + * async message. If @oic is used for callback request, the tail of outbound buffer (after + * the callback request message) is available for async message. + */ +static void qcom_tee_get_async_buffer(struct qcom_tee_object_invoke_ctx *oic, + struct qcom_tee_buffer *async_buffer) +{ + struct qcom_tee_msg_callback *msg; + unsigned int offset; + int i; + + if (!(oic->flags & QCOM_TEE_OIC_FLAG_BUSY)) { + /* The outbound buffer is empty. Using the whole buffer. */ + offset = 0; + } else { + msg = (struct qcom_tee_msg_callback *)oic->out_msg.addr; + + /* Start offset in a message for buffer arguments. */ + offset = qcom_tee_msg_buffer_args(struct qcom_tee_msg_callback, + qcom_tee_msg_args(msg)); + + /* Add size of IB arguments. */ + qcom_tee_msg_for_each_input_buffer(i, msg) + offset += qcom_tee_msg_offset_align(msg->args[i].b.size); + + /* Add size of OB arguments. */ + qcom_tee_msg_for_each_output_buffer(i, msg) + offset += qcom_tee_msg_offset_align(msg->args[i].b.size); + } + + async_buffer->addr = oic->out_msg.addr + offset; + async_buffer->size = oic->out_msg.size - offset; +} + +/** + * qcom_tee_async_release_handler() - Process QTEE async requests for releasing objects. + * @oic: context used for current invocation + * @msg: async message for object release + * @size: size of the async buffer available + * + * Return: Size of outbound buffer used when processing @msg. + */ +static size_t qcom_tee_async_release_handler(struct qcom_tee_object_invoke_ctx *oic, + struct qcom_tee_async_msg_hdr *async_msg, size_t size) +{ + struct qcom_tee_async_release_msg *msg = (struct qcom_tee_async_release_msg *)async_msg; + struct qcom_tee_object *object; + int i; + + for (i = 0; i < msg->counts; i++) { + object = qcom_tee_idx_erase(msg->object_ids[i]); + qcom_tee_object_put(object); + } + + return struct_size_t(struct qcom_tee_async_release_msg, object_ids, i); +} + +/** + * qcom_tee_fetch_async_reqs() - Fetch and process asynchronous messages. + * @oic: context used for current invocation + * + * It looks for handler to process the requested operations in the async message. + * Currently, only support async release requests. + */ +void qcom_tee_fetch_async_reqs(struct qcom_tee_object_invoke_ctx *oic) +{ + struct qcom_tee_async_msg_hdr *async_msg; + struct qcom_tee_buffer async_buffer; + size_t consumed, used = 0; + + qcom_tee_get_async_buffer(oic, &async_buffer); + + while (async_buffer.size - used > sizeof(struct qcom_tee_async_msg_hdr)) { + async_msg = (struct qcom_tee_async_msg_hdr *)(async_buffer.addr + used); + + if (QCOM_TEE_ASYNC_VERSION_MAJOR(async_msg->version) != + QCOM_TEE_ASYNC_VERSION_MAJOR(QCOM_TEE_ASYNC_VERSION)) + goto out; + + switch (async_msg->op) { + case QCOM_TEE_MSG_OBJECT_OP_RELEASE: + consumed = qcom_tee_async_release_handler(oic, async_msg, + async_buffer.size - used); + break; + default: + /* Unsupported operations. */ + goto out; + } + + /* Supported operation but unable to parse the message. */ + if (!consumed) + goto out; + + used += qcom_tee_msg_offset_align(consumed); + } + + out: + /* Reset the async messages buffer so async requests do not loopback to QTEE. */ + memzero_explicit(async_buffer.addr, async_buffer.size); +} diff --git a/drivers/tee/qcomtee/core.c b/drivers/tee/qcomtee/core.c new file mode 100644 index 000000000000..a949ef4cceee --- /dev/null +++ b/drivers/tee/qcomtee/core.c @@ -0,0 +1,928 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "qcomtee_msg.h" +#include "qcomtee_private.h" + +/* Static instance of object represents QTEE root object. */ +struct qcom_tee_object qcom_tee_object_root = { + .name = "root", + .object_type = QCOM_TEE_OBJECT_TYPE_ROOT, + .info.qtee_id = QCOM_TEE_MSG_OBJECT_ROOT, +}; +EXPORT_SYMBOL_GPL(qcom_tee_object_root); + +/* Next argument of type @type after index @i. */ +int qcom_tee_next_arg_type(struct qcom_tee_arg *u, int i, enum qcom_tee_arg_type type) +{ + while (u[i].type != QCOM_TEE_ARG_TYPE_INV && u[i].type != type) + i++; + return i; +} + +/* QTEE expects IDs with QCOM_TEE_MSG_OBJECT_NS_BIT set for object of + * QCOM_TEE_OBJECT_TYPE_CB_OBJECT type. + */ +#define QCOM_TEE_OBJECT_ID_START (QCOM_TEE_MSG_OBJECT_NS_BIT + 1) +#define QCOM_TEE_OBJECT_ID_END (UINT_MAX) + +#define QCOM_TEE_OBJECT_SET(p, type, ...) __QCOM_TEE_OBJECT_SET(p, type, ##__VA_ARGS__, 0UL) +#define __QCOM_TEE_OBJECT_SET(p, type, optr, ...) do { \ + (p)->object_type = (type); \ + (p)->info.qtee_id = (unsigned long)(optr); \ + } while (0) + +static struct qcom_tee_object *qcom_tee_object_alloc(void) +{ + struct qcom_tee_object *object; + + object = kzalloc(sizeof(*object), GFP_KERNEL); + if (object) { + QCOM_TEE_OBJECT_SET(object, QCOM_TEE_OBJECT_TYPE_NULL); + kref_init(&object->refcount); + } + + return object; +} + +void qcom_tee_object_free(struct qcom_tee_object *object) +{ + kfree(object->name); + kfree(object); +} + +static void qcom_tee_object_release(struct kref *refcount) +{ + struct qcom_tee_object *object; + struct module *owner; + const char *name; + + object = container_of(refcount, struct qcom_tee_object, refcount); + + synchronize_rcu(); + + switch (typeof_qcom_tee_object(object)) { + case QCOM_TEE_OBJECT_TYPE_TEE: + qcom_tee_release_tee_object(object); + + break; + case QCOM_TEE_OBJECT_TYPE_CB_OBJECT: + /* Copy, as after release we should not access object. */ + name = object->name; + owner = object->owner; + + if (object->ops->release) + object->ops->release(object); + + module_put(owner); + kfree_const(name); + + break; + case QCOM_TEE_OBJECT_TYPE_ROOT: + case QCOM_TEE_OBJECT_TYPE_NULL: + default: + break; + } +} + +/** + * qcom_tee_object_get() - Increase object's refcount. + * @object: object to increase the refcount + */ +int qcom_tee_object_get(struct qcom_tee_object *object) +{ + if (object != NULL_QCOM_TEE_OBJECT && + object != ROOT_QCOM_TEE_OBJECT) + return kref_get_unless_zero(&object->refcount); + + return 0; +} +EXPORT_SYMBOL_GPL(qcom_tee_object_get); + +/** + * qcom_tee_object_put() - Decrease object's refcount + * @object: object to decrease the refcount + */ +void qcom_tee_object_put(struct qcom_tee_object *object) +{ + if (object != NULL_QCOM_TEE_OBJECT && + object != ROOT_QCOM_TEE_OBJECT) + kref_put(&object->refcount, qcom_tee_object_release); +} +EXPORT_SYMBOL_GPL(qcom_tee_object_put); + +/* ''Local Object Table''. */ +/* Object from kernel that are exported to QTEE are assigned an id and stored in + * xa_qcom_local_objects (kernel object table). QTEE uses this id to reference the + * object using qcom_tee_local_object_get. + */ +static DEFINE_XARRAY_ALLOC(xa_qcom_local_objects); + +static int qcom_tee_idx_alloc(u32 *idx, struct qcom_tee_object *object) +{ + static u32 xa_last_id = QCOM_TEE_OBJECT_ID_START; + + /* Every id allocated here, has QCOM_TEE_MSG_OBJECT_NS_BIT set. */ + return xa_alloc_cyclic(&xa_qcom_local_objects, idx, object, + XA_LIMIT(QCOM_TEE_OBJECT_ID_START, QCOM_TEE_OBJECT_ID_END), + &xa_last_id, GFP_KERNEL); +} + +struct qcom_tee_object *qcom_tee_idx_erase(u32 idx) +{ + if (idx < QCOM_TEE_OBJECT_ID_START || idx > QCOM_TEE_OBJECT_ID_END) + return NULL_QCOM_TEE_OBJECT; + + return xa_erase(&xa_qcom_local_objects, idx); +} + +/** + * qcom_tee_object_id_get() - Get an id for an object to sent to QTEE. + * @object: object to get its id. + * @object_id: object id. + * + * For object hosted in REE, they are added to object table, and the idx in the + * object table is used as id. For object hosted in QTEE, use the QTEE id stored in + * @object. This is called on a path to QTEE to construct a message, see + * qcom_tee_prepare_msg() and qcom_tee_update_msg(). + * + * Return: On success return 0 or <0 on failure. + */ +static int qcom_tee_object_id_get(struct qcom_tee_object *object, unsigned int *object_id) +{ + u32 idx; + + switch (typeof_qcom_tee_object(object)) { + case QCOM_TEE_OBJECT_TYPE_CB_OBJECT: + if (qcom_tee_idx_alloc(&idx, object) < 0) + return -ENOSPC; + + *object_id = idx; + + break; + case QCOM_TEE_OBJECT_TYPE_ROOT: + case QCOM_TEE_OBJECT_TYPE_TEE: + *object_id = object->info.qtee_id; + + break; + case QCOM_TEE_OBJECT_TYPE_NULL: + *object_id = QCOM_TEE_MSG_OBJECT_NULL; + + break; + } + + return 0; +} + +/* Release object id assigned in qcom_tee_object_id_get. */ +static void qcom_tee_object_id_put(unsigned int object_id) +{ + qcom_tee_idx_erase(object_id); +} + +/** + * qcom_tee_local_object_get() - Get an object in REE referenced by the id. + * @object_id: object id. + * + * It is called on behalf of QTEE to obtain instance of object for an id. It is + * called on a path from QTEE to construct an argument of &struct qcom_tee_arg, + * see qcom_tee_update_args() and qcom_tee_prepare_args(). + * + * It increases the object's refcount on success. + * + * Return: On error returns %NULL_QCOM_TEE_OBJECT. On success, the object. + */ +static struct qcom_tee_object *qcom_tee_local_object_get(unsigned int object_id) +{ + struct qcom_tee_object *object; + + /* We trust QTEE does not mess the refcounts. + * It does not issue RELEASE request and qcom_tee_object_get(), simultaneously. + */ + + object = xa_load(&xa_qcom_local_objects, object_id); + + qcom_tee_object_get(object); + + return object; +} + +/** + * __qcom_tee_object_user_init() - Initialize an object for user. + * @object: object to initialize. + * @ot: type of object as &enum qcom_tee_object_type. + * @ops: instance of callbacks. + * @fmt: name assigned to the object. + * + * Return: On success return 0 or <0 on failure. + */ +int __qcom_tee_object_user_init(struct qcom_tee_object *object, enum qcom_tee_object_type ot, + struct qcom_tee_object_operations *ops, struct module *owner, + const char *fmt, ...) +{ + va_list ap; + int ret; + + kref_init(&object->refcount); + QCOM_TEE_OBJECT_SET(object, QCOM_TEE_OBJECT_TYPE_NULL); + + va_start(ap, fmt); + switch (ot) { + case QCOM_TEE_OBJECT_TYPE_NULL: + ret = 0; + + break; + case QCOM_TEE_OBJECT_TYPE_CB_OBJECT: + object->ops = ops; + if (!object->ops->dispatch) + return -EINVAL; + + object->owner = owner; + if (!try_module_get(object->owner)) + return -EINVAL; + + /* If failed, "no-name"; it is not really a reason to fail here. */ + object->name = kvasprintf_const(GFP_KERNEL, fmt, ap); + QCOM_TEE_OBJECT_SET(object, QCOM_TEE_OBJECT_TYPE_CB_OBJECT); + + ret = 0; + break; + case QCOM_TEE_OBJECT_TYPE_ROOT: + case QCOM_TEE_OBJECT_TYPE_TEE: + default: + ret = -EINVAL; + } + va_end(ap); + + return ret; +} +EXPORT_SYMBOL_GPL(__qcom_tee_object_user_init); + +/** + * qcom_tee_object_type() - Returns type of object represented by an object id. + * @object_id: object id for the object. + * + * This is similar to typeof_qcom_tee_object() but instead of receiving object + * as argument it receives object id. It is used internally on return path + * from QTEE. + * + * Return: Returns type of object referenced by @object_id. + */ +static enum qcom_tee_object_type qcom_tee_object_type(unsigned int object_id) +{ + if (object_id == QCOM_TEE_MSG_OBJECT_NULL) + return QCOM_TEE_OBJECT_TYPE_NULL; + + if (object_id & QCOM_TEE_MSG_OBJECT_NS_BIT) + return QCOM_TEE_OBJECT_TYPE_CB_OBJECT; + + return QCOM_TEE_OBJECT_TYPE_TEE; +} + +/** + * qcom_tee_object_init() - Initialize an object for QTEE. + * @object: return object + * @object_id: object id received form QTEE + * + * Return: On success return 0 or <0 on failure. + */ +static int qcom_tee_object_init(struct qcom_tee_object **object, unsigned int object_id) +{ + struct qcom_tee_object *qto; + int ret = 0; + + switch (qcom_tee_object_type(object_id)) { + case QCOM_TEE_OBJECT_TYPE_NULL: + *object = NULL_QCOM_TEE_OBJECT; + + break; + case QCOM_TEE_OBJECT_TYPE_CB_OBJECT: + qto = qcom_tee_local_object_get(object_id); + if (qto != NULL_QCOM_TEE_OBJECT) + *object = qto; + else + ret = -EINVAL; + + break; + case QCOM_TEE_OBJECT_TYPE_TEE: + qto = qcom_tee_object_alloc(); + if (qto) { + /* If failed, "no-name"; it is not really a reason to fail here. */ + qto->name = kasprintf(GFP_KERNEL, "qcom_tee-%u", object_id); + QCOM_TEE_OBJECT_SET(qto, QCOM_TEE_OBJECT_TYPE_TEE, object_id); + + *object = qto; + } else { + ret = -ENOMEM; + } + + break; + default: + + break; + } + + if (ret) + *object = NULL_QCOM_TEE_OBJECT; + + return ret; +} + +/* Marshaling API. */ +/* qcom_tee_prepare_msg - Prepares inbound buffer for sending to QTEE + * qcom_tee_update_args - Parses QTEE response in inbound buffer + * qcom_tee_prepare_args - Parses QTEE request from outbound buffer + * qcom_tee_update_msg - Updates outbound buffer with response for QTEE request + */ + +static int qcom_tee_prepare_msg(struct qcom_tee_object_invoke_ctx *oic, + struct qcom_tee_object *object, u32 op, struct qcom_tee_arg *u) +{ + struct qcom_tee_msg_object_invoke *msg; + unsigned int object_id; + int ib, ob, io, oo; + size_t off; + int i; + + /* Use input message buffer in 'oic'. */ + msg = (struct qcom_tee_msg_object_invoke *)oic->in_msg.addr; + + /* Start offset in a message for buffer arguments. */ + off = qcom_tee_msg_buffer_args(struct qcom_tee_msg_object_invoke, qcom_tee_args_len(u)); + + /* Get id of object being invoked. */ + if (qcom_tee_object_id_get(object, &object_id)) + return -ENOSPC; + + ib = 0; + qcom_tee_arg_for_each_input_buffer(i, u) { + void *ptr; + + /* qcom_tee_msg_buffers_alloc() already checked overflow in message! */ + msg->args[ib].b.offset = off; + msg->args[ib].b.size = u[i].b.size; + + ptr = qcom_tee_msg_offset_to_ptr(msg, off); + if (!(u[i].flags & QCOM_TEE_ARG_FLAGS_UADDR)) + memcpy(ptr, u[i].b.addr, u[i].b.size); + else if (copy_from_user(ptr, u[i].b.uaddr, u[i].b.size)) + return -EINVAL; + + off += qcom_tee_msg_offset_align(u[i].b.size); + ib++; + } + + ob = ib; + qcom_tee_arg_for_each_output_buffer(i, u) { + /* qcom_tee_msg_buffers_alloc() already checked overflow in message! */ + msg->args[ob].b.offset = off; + msg->args[ob].b.size = u[i].b.size; + + off += qcom_tee_msg_offset_align(u[i].b.size); + ob++; + } + + io = ob; + qcom_tee_arg_for_each_input_object(i, u) { + if (qcom_tee_object_id_get(u[i].o, &msg->args[io].o)) { + /* Unable to qcom_tee_object_id_get; put whatever we got. */ + qcom_tee_object_id_put(object_id); + for (--io; io >= ob; io--) + qcom_tee_object_id_put(msg->args[io].o); + + return -ENOSPC; + } + + io++; + } + + oo = io; + qcom_tee_arg_for_each_output_object(i, u) + oo++; + + /* Set object, operation, and argument counts. */ + qcom_tee_msg_init(msg, object_id, op, ib, ob, io, oo); + + return 0; +} + +static int qcom_tee_update_args(struct qcom_tee_arg *u, struct qcom_tee_object_invoke_ctx *oic) +{ + struct qcom_tee_msg_object_invoke *msg; + int ib, ob, io, oo; + int i, ret = 0; + + /* Use input message buffer in 'oic'. */ + msg = (struct qcom_tee_msg_object_invoke *)oic->in_msg.addr; + + ib = 0; + qcom_tee_arg_for_each_input_buffer(i, u) + ib++; + + ob = ib; + qcom_tee_arg_for_each_output_buffer(i, u) { + void *ptr = qcom_tee_msg_offset_to_ptr(msg, msg->args[ob].b.offset); + + if (!(u[i].flags & QCOM_TEE_ARG_FLAGS_UADDR)) { + memcpy(u[i].b.addr, ptr, msg->args[ob].b.size); + } else if (copy_to_user(u[i].b.uaddr, ptr, msg->args[ob].b.size)) { + /* On ERROR, continue to process arguments to get to output object. */ + ret = -EINVAL; + } + + u[i].b.size = msg->args[ob].b.size; + ob++; + } + + io = ob; + qcom_tee_arg_for_each_input_object(i, u) + io++; + + oo = io; + qcom_tee_arg_for_each_output_object(i, u) { + int err; + + /* On ERROR, continue to process arguments so that we can issue the RELEASE. */ + err = qcom_tee_object_init(&u[i].o, msg->args[oo].o); + if (err) + ret = err; + + oo++; + } + + return ret; +} + +static int qcom_tee_prepare_args(struct qcom_tee_object_invoke_ctx *oic) +{ + int i, ret = 0; + + /* Use output message buffer in 'oic'. */ + struct qcom_tee_msg_callback *msg = (struct qcom_tee_msg_callback *)oic->out_msg.addr; + + qcom_tee_msg_for_each_input_buffer(i, msg) { + oic->u[i].b.addr = qcom_tee_msg_offset_to_ptr(msg, msg->args[i].b.offset); + oic->u[i].b.size = msg->args[i].b.size; + oic->u[i].type = QCOM_TEE_ARG_TYPE_IB; + } + + qcom_tee_msg_for_each_output_buffer(i, msg) { + oic->u[i].b.addr = qcom_tee_msg_offset_to_ptr(msg, msg->args[i].b.offset); + oic->u[i].b.size = msg->args[i].b.size; + oic->u[i].type = QCOM_TEE_ARG_TYPE_OB; + } + + qcom_tee_msg_for_each_input_object(i, msg) { + int err; + + /* On ERROR, continue to process arguments so that we can issue the RELEASE. */ + err = qcom_tee_object_init(&oic->u[i].o, msg->args[i].o); + if (err) + ret = err; + + oic->u[i].type = QCOM_TEE_ARG_TYPE_IO; + } + + qcom_tee_msg_for_each_output_object(i, msg) + oic->u[i].type = QCOM_TEE_ARG_TYPE_OO; + + /* End of Arguments. */ + oic->u[i].type = QCOM_TEE_ARG_TYPE_INV; + + return ret; +} + +static int qcom_tee_update_msg(struct qcom_tee_object_invoke_ctx *oic) +{ + int ib, ob, io, oo; + int i; + + /* Use output message buffer in 'oic'. */ + struct qcom_tee_msg_callback *msg = (struct qcom_tee_msg_callback *)oic->out_msg.addr; + + ib = 0; + qcom_tee_arg_for_each_input_buffer(i, oic->u) + ib++; + + ob = ib; + qcom_tee_arg_for_each_output_buffer(i, oic->u) { + /* Only reduce size; never increase it. */ + if (msg->args[ob].b.size < oic->u[i].b.size) + return -EINVAL; + + msg->args[ob].b.size = oic->u[i].b.size; + ob++; + } + + io = ob; + qcom_tee_arg_for_each_input_object(i, oic->u) + io++; + + oo = io; + qcom_tee_arg_for_each_output_object(i, oic->u) { + if (qcom_tee_object_id_get(oic->u[i].o, &msg->args[oo].o)) { + /* Unable to qcom_tee_object_id_get; put whatever we got. */ + for (--oo; oo >= io; --oo) + qcom_tee_object_id_put(msg->args[oo].o); + + return -ENOSPC; + } + + oo++; + } + + return 0; +} + +/** + * define MAX_BUFFER_SIZE - Maximum size of inbound and outbound buffers. + * + * QTEE transport does not impose any restriction on these buffers. However, if size of + * buffers are larger then %MAX_BUFFER_SIZE, user should probably use some other + * form of shared memory with QTEE. + */ +#define MAX_BUFFER_SIZE SZ_8K + +/* Pool to allocate inbound and outbound buffers. */ +static struct qcom_tzmem_pool *tzmem_msg_pool; + +static int qcom_tee_msg_buffers_alloc(struct qcom_tee_object_invoke_ctx *oic, + struct qcom_tee_arg *u) +{ + size_t size; + int i; + + /* Start offset in a message for buffer arguments. */ + size = qcom_tee_msg_buffer_args(struct qcom_tee_msg_object_invoke, qcom_tee_args_len(u)); + if (size > MAX_BUFFER_SIZE) + return -EINVAL; + + /* Add size of IB arguments. */ + qcom_tee_arg_for_each_input_buffer(i, u) { + size = size_add(size, qcom_tee_msg_offset_align(u[i].b.size)); + if (size > MAX_BUFFER_SIZE) + return -EINVAL; + } + + /* Add size of OB arguments. */ + qcom_tee_arg_for_each_output_buffer(i, u) { + size = size_add(size, qcom_tee_msg_offset_align(u[i].b.size)); + if (size > MAX_BUFFER_SIZE) + return -EINVAL; + } + + /* QTEE requires inbound buffer size to be page aligned. */ + size = PAGE_ALIGN(size); + + /* Do allocations. */ + oic->in_msg.size = size; + oic->in_msg.addr = qcom_tzmem_alloc(tzmem_msg_pool, size, GFP_KERNEL); + if (!oic->in_msg.addr) + return -EINVAL; + + oic->out_msg.size = MAX_BUFFER_SIZE; + oic->out_msg.addr = qcom_tzmem_alloc(tzmem_msg_pool, MAX_BUFFER_SIZE, GFP_KERNEL); + if (!oic->out_msg.addr) { + qcom_tzmem_free(oic->in_msg.addr); + + return -EINVAL; + } + + oic->in_msg_paddr = qcom_tzmem_to_phys(oic->in_msg.addr); + oic->out_msg_paddr = qcom_tzmem_to_phys(oic->out_msg.addr); + + /* QTEE assume unused buffers are zeroed; Do it now! */ + memzero_explicit(oic->in_msg.addr, oic->in_msg.size); + memzero_explicit(oic->out_msg.addr, oic->out_msg.size); + + return 0; +} + +static void qcom_tee_msg_buffers_free(struct qcom_tee_object_invoke_ctx *oic) +{ + qcom_tzmem_free(oic->in_msg.addr); + qcom_tzmem_free(oic->out_msg.addr); +} + +static int qcom_tee_msg_buffers_init(void) +{ + struct qcom_tzmem_pool_config config = { + .policy = QCOM_TZMEM_POLICY_ON_DEMAND, + /* 4M seems enough, it is used for QTEE meg header and qcom_tee_msg_arg array. */ + .max_size = SZ_4M + }; + + tzmem_msg_pool = qcom_tzmem_pool_new(&config); + if (IS_ERR(tzmem_msg_pool)) + return PTR_ERR(tzmem_msg_pool); + + return 0; +} + +static void qcom_tee_msg_buffers_destroy(void) +{ + qcom_tzmem_pool_free(tzmem_msg_pool); +} + +/* Invoke a REE object. */ +static void qcom_tee_object_invoke(struct qcom_tee_object_invoke_ctx *oic, + struct qcom_tee_msg_callback *msg) +{ + int i, errno; + u32 op; + + /* Get object being invoked. */ + unsigned int object_id = msg->cxt; + struct qcom_tee_object *object; + + /* QTEE can not invoke NULL object or objects it hosts. */ + if (qcom_tee_object_type(object_id) == QCOM_TEE_OBJECT_TYPE_NULL || + qcom_tee_object_type(object_id) == QCOM_TEE_OBJECT_TYPE_TEE) { + errno = -EINVAL; + goto out; + } + + object = qcom_tee_local_object_get(object_id); + if (object == NULL_QCOM_TEE_OBJECT) { + errno = -EINVAL; + goto out; + } + + oic->object = object; + + /* Filter bits used by transport. */ + op = msg->op & QCOM_TEE_MSG_OBJECT_OP_MASK; + + switch (op) { + case QCOM_TEE_MSG_OBJECT_OP_RELEASE: + qcom_tee_object_id_put(object_id); + qcom_tee_object_put(object); + errno = 0; + + break; + case QCOM_TEE_MSG_OBJECT_OP_RETAIN: + qcom_tee_object_get(object); + errno = 0; + + break; + default: + errno = qcom_tee_prepare_args(oic); + if (errno) { + /* Unable to parse the message. Release any object arrived as input. */ + qcom_tee_arg_for_each_input_buffer(i, oic->u) + qcom_tee_object_put(oic->u[i].o); + + break; + } + + errno = object->ops->dispatch(oic, object, op, oic->u); + if (!errno) { + /* On SUCCESS, notify object at appropriate time. */ + oic->flags |= QCOM_TEE_OIC_FLAG_NOTIFY; + } + } + +out: + + oic->errno = errno; +} + +/** + * __qcom_tee_object_do_invoke() - Submit an invocation for an object. + * @oic: context to use for current invocation. + * @object: object being invoked. + * @op: requested operation on object. + * @u: array of argument for the current invocation. + * @result: result returned from QTEE. + * + * The caller is responsible to keep track of the refcount for each object, + * including @object. On return, the caller loses the ownership of all input + * object of type %QCOM_TEE_OBJECT_TYPE_CB_OBJECT. + * + * Return: On success return 0. On error returns -EINVAL and -ENOSPC if unable to initiate + * the invocation, -EAGAIN if invocation failed and user may retry the invocation. + * Otherwise, -ENODEV on fatal failure. + */ +int __qcom_tee_object_do_invoke(struct qcom_tee_object_invoke_ctx *oic, + struct qcom_tee_object *object, u32 op, struct qcom_tee_arg *u, + int *result) +{ + struct qcom_tee_msg_callback *cb_msg; + u64 response_type; + int i, ret, errno; + + ret = qcom_tee_msg_buffers_alloc(oic, u); + if (ret) + return ret; + + ret = qcom_tee_prepare_msg(oic, object, op, u); + if (ret) + goto out; + + cb_msg = (struct qcom_tee_msg_callback *)oic->out_msg.addr; + + while (1) { + if (oic->flags & QCOM_TEE_OIC_FLAG_BUSY) { + errno = oic->errno; + /* Update output buffer only if result is SUCCESS. */ + if (!errno) + errno = qcom_tee_update_msg(oic); + + qcom_tee_msg_translate_err(cb_msg, errno); + } + + /* Invoke remote object. */ + ret = qcom_tee_object_invoke_ctx_invoke(oic, result, &response_type); + + if (oic->flags & QCOM_TEE_OIC_FLAG_BUSY) { + struct qcom_tee_object *qto = oic->object; + + if (qto) { + if (oic->flags & QCOM_TEE_OIC_FLAG_NOTIFY) { + if (qto->ops->notify) + qto->ops->notify(oic, qto, errno || ret); + } + + /* Matching get is in qcom_tee_object_invoke. */ + qcom_tee_object_put(qto); + } + + oic->object = NULL_QCOM_TEE_OBJECT; + oic->flags &= ~(QCOM_TEE_OIC_FLAG_BUSY | QCOM_TEE_OIC_FLAG_NOTIFY); + } + + if (ret) { + if (!(oic->flags & QCOM_TEE_OIC_FLAG_SHARED)) { + /* Release QCOM_TEE_OBJECT_TYPE_CB_OBJECT input objects. */ + qcom_tee_arg_for_each_input_object(i, u) + if (typeof_qcom_tee_object(u[i].o) == + QCOM_TEE_OBJECT_TYPE_CB_OBJECT) + qcom_tee_object_put(u[i].o); + + ret = -EAGAIN; + } else { + /* On error, there is no clean way to exit. */ + /* For some reason we can not communicate with QTEE, so we can not + * notify QTEE about the failure and do further cleanup. + */ + ret = -ENODEV; + } + + goto out; + + } else { + /* QTEE obtained the ownership of QCOM_TEE_OBJECT_TYPE_CB_OBJECT + * input objects in 'u'. On further failure, QTEE is responsible + * to release them. + */ + oic->flags |= QCOM_TEE_OIC_FLAG_SHARED; + } + + /* Is it a callback request? */ +#define QCOM_TEE_RESULT_INBOUND_REQ_NEEDED 3 + if (response_type != QCOM_TEE_RESULT_INBOUND_REQ_NEEDED) { + if (!*result) { + ret = qcom_tee_update_args(u, oic); + if (ret) { + qcom_tee_arg_for_each_output_object(i, u) + qcom_tee_object_put(u[i].o); + + ret = -EAGAIN; + } + } + + break; + + } else { + oic->flags |= QCOM_TEE_OIC_FLAG_BUSY; + /* Before dispatching the request, handle any pending async requests. */ + qcom_tee_fetch_async_reqs(oic); + qcom_tee_object_invoke(oic, cb_msg); + } + } + + qcom_tee_fetch_async_reqs(oic); + +out: + qcom_tee_msg_buffers_free(oic); + + return ret; +} + +int qcom_tee_object_do_invoke(struct qcom_tee_object_invoke_ctx *oic, + struct qcom_tee_object *object, u32 op, struct qcom_tee_arg *u, + int *result) +{ + /* User can not set bits used by transport. */ + if (op & ~QCOM_TEE_MSG_OBJECT_OP_MASK) + return -EINVAL; + + /* User can only invoke QTEE hosted objects. */ + if (typeof_qcom_tee_object(object) != QCOM_TEE_OBJECT_TYPE_TEE && + typeof_qcom_tee_object(object) != QCOM_TEE_OBJECT_TYPE_ROOT) + return -EINVAL; + + /* User can not issue reserved operations to QTEE. */ + if (op == QCOM_TEE_MSG_OBJECT_OP_RELEASE || op == QCOM_TEE_MSG_OBJECT_OP_RETAIN) + return -EINVAL; + + return __qcom_tee_object_do_invoke(oic, object, op, u, result); +} +EXPORT_SYMBOL_GPL(qcom_tee_object_do_invoke); + +/* Dump object table. */ +static ssize_t qcom_tee_object_table_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + struct qcom_tee_object *object; + unsigned long idx; + size_t len = 0; + + xa_for_each_start(&xa_qcom_local_objects, idx, object, QCOM_TEE_OBJECT_ID_START) { + len += sysfs_emit_at(buf, len, "%4lx %4d %s\n", idx, + kref_read(&object->refcount), + qcom_tee_object_name(object)); + } + + return len; +} + +static struct kobj_attribute object_table = __ATTR_RO(qcom_tee_object_table); +static struct kobj_attribute release = __ATTR_RO(qcom_tee_release_wq); +static struct attribute *attrs[] = { + &object_table.attr, + &release.attr, + NULL +}; + +static struct attribute_group attr_group = { + .attrs = attrs, +}; + +static struct kobject *qcom_tee_object_invoke_kobj; +static int __init qcom_tee_object_invoke_init(void) +{ + int ret; + + ret = qcom_tee_release_init(); + if (ret) + return ret; + + ret = qcom_tee_msg_buffers_init(); + if (ret) + goto err_release_destroy; + + /* Create '/sys/firmware/qcom_tee'. */ + qcom_tee_object_invoke_kobj = kobject_create_and_add("qcom_tee", firmware_kobj); + if (!qcom_tee_object_invoke_kobj) { + ret = -ENOMEM; + + goto err_msg_buffers_destroy; + } + + /* Create 'qcom_tee_object_table' and 'qcom_tee_release_wq'. */ + ret = sysfs_create_group(qcom_tee_object_invoke_kobj, &attr_group); + if (ret) + goto err_kobject_put; + + return 0; + +err_kobject_put: + /* Remove '/sys/firmware/qcom_tee'. */ + kobject_put(qcom_tee_object_invoke_kobj); +err_msg_buffers_destroy: + qcom_tee_msg_buffers_destroy(); +err_release_destroy: + qcom_tee_release_destroy(); + + return ret; +} +module_init(qcom_tee_object_invoke_init); + +static void __exit qcom_tee_object_invoke_deinit(void) +{ + /* Wait for RELEASE operations for QTEE objects. */ + qcom_tee_release_destroy(); + qcom_tee_msg_buffers_destroy(); + sysfs_remove_group(qcom_tee_object_invoke_kobj, &attr_group); + kobject_put(qcom_tee_object_invoke_kobj); +} +module_exit(qcom_tee_object_invoke_deinit); + +MODULE_AUTHOR("Qualcomm"); +MODULE_DESCRIPTION("QTEE driver"); +MODULE_VERSION("1.0"); +MODULE_LICENSE("GPL"); diff --git a/drivers/tee/qcomtee/qcom_scm.c b/drivers/tee/qcomtee/qcom_scm.c new file mode 100644 index 000000000000..230faf249095 --- /dev/null +++ b/drivers/tee/qcomtee/qcom_scm.c @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include + +#include "qcomtee_private.h" + +int qcom_tee_object_invoke_ctx_invoke(struct qcom_tee_object_invoke_ctx *oic, + int *result, u64 *response_type) +{ + int ret; + u64 res; + + if (!(oic->flags & QCOM_TEE_OIC_FLAG_BUSY)) { + /* Direct QTEE object invocation. */ + ret = qcom_scm_qtee_invoke_smc(oic->in_msg_paddr, + oic->in_msg.size, + oic->out_msg_paddr, + oic->out_msg.size, + &res, response_type, NULL); + } else { + /* Submit callback response. */ + ret = qcom_scm_qtee_callback_response(oic->out_msg_paddr, + oic->out_msg.size, + &res, response_type, NULL); + } + + if (ret) + pr_err("QTEE returned with %d.\n", ret); + else + *result = (int)res; + + return ret; +} diff --git a/drivers/tee/qcomtee/qcomtee_msg.h b/drivers/tee/qcomtee/qcomtee_msg.h new file mode 100644 index 000000000000..7c968834ec9d --- /dev/null +++ b/drivers/tee/qcomtee/qcomtee_msg.h @@ -0,0 +1,217 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef QCOMTEE_MSG_H +#define QCOMTEE_MSG_H + +#include + +/** + * DOC: ''Qualcomm TEE'' (QTEE) Transport Message + * + * There are two buffers shared with QTEE, inbound and outbound buffers. + * The inbound buffer is used for direct object invocation and the outbound buffer is + * used to make a request from QTEE to kernel, i.e. callback request. + * + * The unused tail of the outbound buffer is also used for sending and receiving + * asynchronous messages. An asynchronous message is independent from the current + * object invocation (i.e. contents of the inbound buffer) or callback request + * (i.e. the head of the outbound buffer), see qcom_tee_get_async_buffer(). It is + * used by endpoints (QTEE or kernel) as an optimization to reduce number of context + * switches between secure and non-secure world. + * + * For instance, QTEE never sends an explicit callback request to release an object in + * kernel. Instead, it sends asynchronous release messages in outbound buffer when QTEE + * returns from previous direct object invocation, or append asynchronous release + * messages after the current callback request. + * + * QTEE supports two types of arguments in a message: buffer and object arguments. + * Depending on the direction of data flow, they could be input buffer (IO) to QTEE, + * output buffer (OB) from QTEE, input object (IO) to QTEE, or output object (OO) from + * QTEE. Object arguments hold object ids. Buffer arguments hold (offset, size) pairs + * into the inbound or outbound buffers. + * + * QTEE holds an object table for objects, it hosts and exposes to kernel. An object id + * is an index to the object table in QTEE. + * + * For direct object invocation message format in inbound buffer see + * &struct qcom_tee_msg_object_invoke. For callback request message format in outbound + * buffer see &struct qcom_tee_msg_callback. For the message format for asynchronous message + * in outbound buffer see &struct qcom_tee_async_msg_hdr. + */ + +/** + * define QCOM_TEE_MSG_OBJECT_NS_BIT - Non-secure bit + * + * Object id is a globally unique 32-bit number. Ids referencing objects in kernel should + * have %QCOM_TEE_MSG_OBJECT_NS_BIT set. + */ +#define QCOM_TEE_MSG_OBJECT_NS_BIT BIT(31) + +/* Static object ids recognized by QTEE. */ +#define QCOM_TEE_MSG_OBJECT_NULL (0U) +#define QCOM_TEE_MSG_OBJECT_ROOT (1U) + +/* Definitions from QTEE as part of the transport protocol. */ + +/* qcom_tee_msg_arg is argument as recognized by QTEE. */ +union qcom_tee_msg_arg { + struct { + u32 offset; + u32 size; + } b; + u32 o; +}; + +/* BI and BO payloads in a QTEE messages should be at 64-bit boundaries. */ +#define qcom_tee_msg_offset_align(o) ALIGN((o), sizeof(u64)) + +/* Operation for objects is 32-bit. Transport uses upper 16-bits internally. */ +#define QCOM_TEE_MSG_OBJECT_OP_MASK 0x0000FFFFU + +/* Reserved Operation IDs sent to QTEE: */ +/* QCOM_TEE_MSG_OBJECT_OP_RELEASE - Reduces the refcount and releases the object. + * QCOM_TEE_MSG_OBJECT_OP_RETAIN - Increases the refcount. + * + * These operation id are valid for all objects. They are not available outside of this + * driver. Developers should use qcom_tee_object_get() and qcom_tee_object_put(), to + * achieve the same. + */ + +#define QCOM_TEE_MSG_OBJECT_OP_RELEASE (QCOM_TEE_MSG_OBJECT_OP_MASK - 0) +#define QCOM_TEE_MSG_OBJECT_OP_RETAIN (QCOM_TEE_MSG_OBJECT_OP_MASK - 1) + +/** + * struct qcom_tee_msg_object_invoke - Direct object invocation message + * @ctx: object id hosted in QTEE + * @op: operation for the object + * @counts: number of different type of arguments in @args + * @args: array of arguments + * + * @counts consists of 4 * 4-bits felids. Bits 0 - 3, is number of input buffers, + * bits 4 - 7, is number of output buffers, bits 8 - 11, is number of input objects, + * and bits 12 - 15, is number of output objects. Remaining bits should be zero. + * + * Maximum number of arguments of each type is defined by %QCOM_TEE_ARGS_PER_TYPE. + */ +struct qcom_tee_msg_object_invoke { + u32 cxt; + u32 op; + u32 counts; + union qcom_tee_msg_arg args[]; +}; + +/** + * struct qcom_tee_msg_callback - Callback request message + * @result: result of operation @op on object referenced by @cxt + * @cxt: object id hosted in kernel + * @op: operation for the object + * @counts: number of different type of arguments in @args + * @args: array of arguments + * + * For details of @counts, see &qcom_tee_msg_object_invoke.counts. + */ +struct qcom_tee_msg_callback { + u32 result; + u32 cxt; + u32 op; + u32 counts; + union qcom_tee_msg_arg args[]; +}; + +/* Offset in the message for the beginning of buffer argument's contents. */ +#define qcom_tee_msg_buffer_args(t, n) \ + qcom_tee_msg_offset_align(struct_size_t(t, args, n)) +/* Pointer to the beginning of a buffer argument's content at an offset in a message. */ +#define qcom_tee_msg_offset_to_ptr(m, off) ((void *)&((char *)(m))[(off)]) + +/* Some helpers to manage msg.counts. */ + +#define QCOM_TEE_MSG_NUM_IB(x) ((x) & 0xfU) +#define QCOM_TEE_MSG_NUM_OB(x) (((x) >> 4) & 0xfU) +#define QCOM_TEE_MSG_NUM_IO(x) (((x) >> 8) & 0xfU) +#define QCOM_TEE_MSG_NUM_OO(x) (((x) >> 12) & 0xfU) + +#define QCOM_TEE_MSG_IDX_IB(x) (0U) +#define QCOM_TEE_MSG_IDX_OB(x) (QCOM_TEE_MSG_IDX_IB(x) + QCOM_TEE_MSG_NUM_IB(x)) +#define QCOM_TEE_MSG_IDX_IO(x) (QCOM_TEE_MSG_IDX_OB(x) + QCOM_TEE_MSG_NUM_OB(x)) +#define QCOM_TEE_MSG_IDX_OO(x) (QCOM_TEE_MSG_IDX_IO(x) + QCOM_TEE_MSG_NUM_IO(x)) + +#define qcom_tee_msg_for_each(i, c, type) \ + for (i = QCOM_TEE_MSG_IDX_##type(c); \ + i < (QCOM_TEE_MSG_IDX_##type(c) + QCOM_TEE_MSG_NUM_##type(c)); \ + i++) + +#define qcom_tee_msg_for_each_input_buffer(i, m) qcom_tee_msg_for_each(i, (m)->counts, IB) +#define qcom_tee_msg_for_each_output_buffer(i, m) qcom_tee_msg_for_each(i, (m)->counts, OB) +#define qcom_tee_msg_for_each_input_object(i, m) qcom_tee_msg_for_each(i, (m)->counts, IO) +#define qcom_tee_msg_for_each_output_object(i, m) qcom_tee_msg_for_each(i, (m)->counts, OO) + +/* Sum of arguments in a message. */ +#define qcom_tee_msg_args(m) (QCOM_TEE_MSG_IDX_OO((m)->counts) + QCOM_TEE_MSG_NUM_OO((m)->counts)) + +static inline void qcom_tee_msg_init(struct qcom_tee_msg_object_invoke *msg, u32 cxt, u32 op, + int in_buffer, int out_buffer, int in_object, int out_object) +{ + msg->counts |= (in_buffer & 0xfU); + msg->counts |= ((out_buffer - in_buffer) & 0xfU) << 4; + msg->counts |= ((in_object - out_buffer) & 0xfU) << 8; + msg->counts |= ((out_object - in_object) & 0xfU) << 12; + msg->cxt = cxt; + msg->op = op; +} + +/* Generic error codes. */ +#define QCOM_TEE_MSG_OK 0 /* non-specific success code. */ +#define QCOM_TEE_MSG_ERROR 1 /* non-specific error. */ +#define QCOM_TEE_MSG_ERROR_INVALID 2 /* unsupported/unrecognized request. */ +#define QCOM_TEE_MSG_ERROR_SIZE_IN 3 /* supplied buffer/string too large. */ +#define QCOM_TEE_MSG_ERROR_SIZE_OUT 4 /* supplied output buffer too small. */ +#define QCOM_TEE_MSG_ERROR_USERBASE 10 /* start of user-defined error range. */ + +/* Transport layer error codes. */ +#define QCOM_TEE_MSG_ERROR_DEFUNCT -90 /* object no longer exists. */ +#define QCOM_TEE_MSG_ERROR_ABORT -91 /* calling thread must exit. */ +#define QCOM_TEE_MSG_ERROR_BADOBJ -92 /* invalid object context. */ +#define QCOM_TEE_MSG_ERROR_NOSLOTS -93 /* caller's object table full. */ +#define QCOM_TEE_MSG_ERROR_MAXARGS -94 /* too many args. */ +#define QCOM_TEE_MSG_ERROR_MAXDATA -95 /* buffers too large. */ +#define QCOM_TEE_MSG_ERROR_UNAVAIL -96 /* the request could not be processed. */ +#define QCOM_TEE_MSG_ERROR_KMEM -97 /* kernel out of memory. */ +#define QCOM_TEE_MSG_ERROR_REMOTE -98 /* local method sent to remote object. */ +#define QCOM_TEE_MSG_ERROR_BUSY -99 /* Object is busy. */ +#define QCOM_TEE_MSG_ERROR_TIMEOUT -103 /* Call Back Object invocation timed out. */ + +static inline void qcom_tee_msg_translate_err(struct qcom_tee_msg_callback *cb_msg, int err) +{ + if (!err) { + cb_msg->result = QCOM_TEE_MSG_OK; + } else if (err < 0) { + /* If err < 0, then it is a transport error. */ + switch (err) { + case -ENOMEM: + cb_msg->result = QCOM_TEE_MSG_ERROR_KMEM; + break; + case -ENODEV: + cb_msg->result = QCOM_TEE_MSG_ERROR_DEFUNCT; + break; + case -ENOSPC: + case -EBUSY: + cb_msg->result = QCOM_TEE_MSG_ERROR_BUSY; + break; + case -EBADF: + case -EINVAL: + cb_msg->result = QCOM_TEE_MSG_ERROR_UNAVAIL; + break; + default: + cb_msg->result = QCOM_TEE_MSG_ERROR; + } + } else { + /* If err > 0, then it is user defined error, pass it as is. */ + cb_msg->result = err; + } +} + +#endif /* QCOMTEE_MSG_H */ diff --git a/drivers/tee/qcomtee/qcomtee_private.h b/drivers/tee/qcomtee/qcomtee_private.h new file mode 100644 index 000000000000..e3e4ef51c0b2 --- /dev/null +++ b/drivers/tee/qcomtee/qcomtee_private.h @@ -0,0 +1,47 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef QCOM_TEE_PRIVATE_H +#define QCOM_TEE_PRIVATE_H + +#include +#include +#include + +struct qcom_tee_object *qcom_tee_idx_erase(u32 idx); +void qcom_tee_object_free(struct qcom_tee_object *object); + +/* Process async messages form QTEE. */ +void qcom_tee_fetch_async_reqs(struct qcom_tee_object_invoke_ctx *oic); + +int qcom_tee_release_init(void); +void qcom_tee_release_destroy(void); +void qcom_tee_release_tee_object(struct qcom_tee_object *object); +ssize_t qcom_tee_release_wq_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf); + +/* SCM call. */ +int qcom_tee_object_invoke_ctx_invoke(struct qcom_tee_object_invoke_ctx *oic, + int *result, u64 *response_type); + +/** + * __qcom_tee_object_do_invoke() - Submit an invocation for an object. + * @oic: context to use for current invocation. + * @object: object being invoked. + * @op: requested operation on object. + * @u: array of argument for the current invocation. + * @result: result returned from QTEE. + * + * Same as qcom_tee_object_do_invoke() without @object and @op is 32-bit, + * upper 16-bits are for internal use. + * + * Return: On success return 0. On error returns -EINVAL and -ENOSPC if unable to initiate + * the invocation, -EAGAIN if invocation failed and user can retry the invocation. + * Otherwise, -ENODEV on fatal failure. + */ +int __qcom_tee_object_do_invoke(struct qcom_tee_object_invoke_ctx *oic, + struct qcom_tee_object *object, u32 op, struct qcom_tee_arg *u, + int *result); + +#endif /* QCOM_TEE_PRIVATE_H */ diff --git a/drivers/tee/qcomtee/release.c b/drivers/tee/qcomtee/release.c new file mode 100644 index 000000000000..f2e048418e23 --- /dev/null +++ b/drivers/tee/qcomtee/release.c @@ -0,0 +1,66 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include "qcomtee_private.h" +#include "qcomtee_msg.h" + +static struct workqueue_struct *qcom_tee_release_wq; + +/* Number of all release requests pending for processing. */ +static atomic_t qcom_tee_pending_releases = ATOMIC_INIT(0); + +/* qcom_tee_object_do_release makes direct object invocation to release an object. */ +static void qcom_tee_destroy_user_object(struct work_struct *work) +{ + static struct qcom_tee_object_invoke_ctx oic; + static struct qcom_tee_arg args[1] = { 0 }; + struct qcom_tee_object *object; + int ret, result; + + object = container_of(work, struct qcom_tee_object, work); + + ret = __qcom_tee_object_do_invoke(&oic, object, QCOM_TEE_MSG_OBJECT_OP_RELEASE, args, + &result); + + /* Is it safe to retry the release? */ + if (ret == -EAGAIN) { + queue_work(qcom_tee_release_wq, &object->work); + } else { + if (ret || result) + pr_err("%s: %s release failed, ret = %d (%x).\n", + __func__, qcom_tee_object_name(object), ret, result); + + atomic_dec(&qcom_tee_pending_releases); + qcom_tee_object_free(object); + } +} + +/* qcom_tee_release_tee_object puts object in release work queue. */ +void qcom_tee_release_tee_object(struct qcom_tee_object *object) +{ + INIT_WORK(&object->work, qcom_tee_destroy_user_object); + atomic_inc(&qcom_tee_pending_releases); + queue_work(qcom_tee_release_wq, &object->work); +} + +ssize_t qcom_tee_release_wq_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) +{ + return sysfs_emit(buf, "%d\n", atomic_read(&qcom_tee_pending_releases)); +} + +int qcom_tee_release_init(void) +{ + qcom_tee_release_wq = alloc_ordered_workqueue("qcom_tee_release_wq", 0); + if (!qcom_tee_release_wq) + return -ENOMEM; + + return 0; +} + +void qcom_tee_release_destroy(void) +{ + /* It drains the wq. */ + destroy_workqueue(qcom_tee_release_wq); +} diff --git a/include/linux/firmware/qcom/qcom_tee.h b/include/linux/firmware/qcom/qcom_tee.h new file mode 100644 index 000000000000..90e5e10a0e62 --- /dev/null +++ b/include/linux/firmware/qcom/qcom_tee.h @@ -0,0 +1,284 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef __QCOM_TEE_H +#define __QCOM_TEE_H + +#include +#include +#include + +struct qcom_tee_object; + +/** + * DOC: Overview + * + * qcom_tee_object provides object ref-counting, id allocation for objects hosted in + * REE, and necessary message marshaling for Qualcomm TEE (QTEE). + * + * To invoke an object in QTEE, user calls qcom_tee_object_do_invoke() while passing + * an instance of &struct qcom_tee_object and the requested operation + arguments. + * + * After the boot, QTEE provides a static object %ROOT_QCOM_TEE_OBJECT (type of + * %QCOM_TEE_OBJECT_TYPE_ROOT). The root object is invoked to pass user's credentials and + * obtain other instances of &struct qcom_tee_object (type of %QCOM_TEE_OBJECT_TYPE_TEE) + * that represents services and TAs in QTEE, see &enum qcom_tee_object_type. + * + * The object received from QTEE are refcounted. So the owner of these objects can + * issue qcom_tee_object_get(), to increase the refcount, and pass objects to other + * clients, or issue qcom_tee_object_put() to decrease the refcount, and releasing + * the resources in QTEE. + * + * REE can host services accessible to QTEE. A driver should embed an instance of + * &struct qcom_tee_object in the struct it wants to export to QTEE (it is called + * callback object). It issues qcom_tee_object_user_init() to set the dispatch() + * operation for the callback object and set its type to %QCOM_TEE_OBJECT_TYPE_CB_OBJECT. + * + * core.c holds an object table for callback objects. An object id is assigned + * to each callback object which is an index to the object table. QTEE uses these ids + * to reference or invoke callback objects. + * + * If QTEE invoke a callback object in REE, the dispatch() operation is called in the + * context of thread that called qcom_tee_object_do_invoke(), originally. + */ + +/** + * enum qcom_tee_object_typ - Object types. + * @QCOM_TEE_OBJECT_TYPE_TEE: object hosted on QTEE. + * @QCOM_TEE_OBJECT_TYPE_CB_OBJECT: object hosted on REE. + * @QCOM_TEE_OBJECT_TYPE_ROOT: 'primordial' object. + * @QCOM_TEE_OBJECT_TYPE_NULL: NULL object. + * + * Primordial object is used for bootstrapping the IPC connection between a REE + * and QTEE. It is invoked by REE when it wants to get a 'client env'. + */ +enum qcom_tee_object_type { + QCOM_TEE_OBJECT_TYPE_TEE, + QCOM_TEE_OBJECT_TYPE_CB_OBJECT, + QCOM_TEE_OBJECT_TYPE_ROOT, + QCOM_TEE_OBJECT_TYPE_NULL, +}; + +/** + * enum qcom_tee_arg_type - Type of QTEE argument. + * @QCOM_TEE_ARG_TYPE_INV: invalid type. + * @QCOM_TEE_ARG_TYPE_IB: input buffer (IO). + * @QCOM_TEE_ARG_TYPE_OO: output object (OO). + * @QCOM_TEE_ARG_TYPE_OB: output buffer (OB). + * @QCOM_TEE_ARG_TYPE_IO: input object (IO). + * + * Use invalid type to specify end of argument array. + */ +enum qcom_tee_arg_type { + QCOM_TEE_ARG_TYPE_INV = 0, + QCOM_TEE_ARG_TYPE_OB, + QCOM_TEE_ARG_TYPE_OO, + QCOM_TEE_ARG_TYPE_IB, + QCOM_TEE_ARG_TYPE_IO, + QCOM_TEE_ARG_TYPE_NR, +}; + +/** + * define QCOM_TEE_ARGS_PER_TYPE - Maximum arguments of specific type. + * + * QTEE transport protocol limits maximum number of argument of specific type + * (i.e. IB, OB, IO, and OO). + */ +#define QCOM_TEE_ARGS_PER_TYPE 16 + +/* Maximum arguments that can fit in a QTEE message, ignoring the type. */ +#define QCOM_TEE_ARGS_MAX (QCOM_TEE_ARGS_PER_TYPE * (QCOM_TEE_ARG_TYPE_NR - 1)) + +struct qcom_tee_buffer { + union { + void *addr; + void __user *uaddr; + }; + size_t size; +}; + +/** + * struct qcom_tee_arg - Argument for QTEE object invocation. + * @type: type of argument as &enum qcom_tee_arg_type. + * @flags: extra flags. + * @b: address and size if type of argument is buffer. + * @o: object instance if type of argument is object. + * + * &qcom_tee_arg.flags only accept %QCOM_TEE_ARG_FLAGS_UADDR for now which states + * that &qcom_tee_arg.b contains userspace address in uaddr. + */ +struct qcom_tee_arg { + enum qcom_tee_arg_type type; +/* 'b.uaddr' holds a __user address. */ +#define QCOM_TEE_ARG_FLAGS_UADDR 1 + unsigned int flags; + union { + struct qcom_tee_buffer b; + struct qcom_tee_object *o; + }; +}; + +static inline int qcom_tee_args_len(struct qcom_tee_arg *args) +{ + int i = 0; + + while (args[i].type != QCOM_TEE_ARG_TYPE_INV) + i++; + return i; +} + +#define QCOM_TEE_OIC_FLAG_BUSY BIT(1) /* Context is busy (callback is in progress). */ +#define QCOM_TEE_OIC_FLAG_NOTIFY BIT(2) /* Context needs to notify the current object. */ +#define QCOM_TEE_OIC_FLAG_SHARED BIT(3) /* Context has shared state with QTEE. */ + +struct qcom_tee_object_invoke_ctx { + unsigned long flags; + int errno; + + /* Current object invoked in this callback context. */ + struct qcom_tee_object *object; + + /* Arguments passed to dispatch callback (+1 for ending QCOM_TEE_ARG_TYPE_INV). */ + struct qcom_tee_arg u[QCOM_TEE_ARGS_MAX + 1]; + + /* Inbound and Outbound buffers shared with QTEE. */ + struct qcom_tee_buffer in_msg; /* Inbound Buffer. */ + phys_addr_t in_msg_paddr; /* Physical address of inbound buffer. */ + struct qcom_tee_buffer out_msg; /* Outbound Buffer. */ + phys_addr_t out_msg_paddr; /* Physical address of outbound buffer. */ + + /* Extra data attached to this context. */ + void *data; +}; + +/** + * qcom_tee_object_do_invoke() - Submit an invocation for an object. + * @oic: context to use for current invocation. + * @object: object being invoked. + * @op: requested operation on object. + * @u: array of argument for the current invocation. + * @result: result returned from QTEE. + * + * The caller is responsible to keep track of the refcount for each object, + * including @object. On return, the caller loses the ownership of all input object of + * type %QCOM_TEE_OBJECT_TYPE_CB_OBJECT. + * + * @object can be of %QCOM_TEE_OBJECT_TYPE_ROOT or %QCOM_TEE_OBJECT_TYPE_TEE types. + * + * Return: On success return 0. On error returns -EINVAL and -ENOSPC if unable to initiate + * the invocation, -EAGAIN if invocation failed and user may retry the invocation. + * Otherwise, -ENODEV on fatal failure. + */ +int qcom_tee_object_do_invoke(struct qcom_tee_object_invoke_ctx *oic, + struct qcom_tee_object *object, u32 op, struct qcom_tee_arg *u, + int *result); + +/** + * struct qcom_tee_object_operations - Callback object operations. + * @release: release object if QTEE is not using it. + * @dispatch: dispatch the operation requested by QTEE. + * @notify: report status of any pending response submitted by @dispatch. + * + * Transport may fail (e.g. object table is full) even after @dispatch successfully submitted + * the response. @notify is called to do the necessary cleanup. + */ +struct qcom_tee_object_operations { + void (*release)(struct qcom_tee_object *object); + int (*dispatch)(struct qcom_tee_object_invoke_ctx *oic, + struct qcom_tee_object *object, u32 op, struct qcom_tee_arg *args); + void (*notify)(struct qcom_tee_object_invoke_ctx *oic, + struct qcom_tee_object *object, int err); +}; + +/** + * struct qcom_tee_object - QTEE or REE object. + * @name: object name. + * @refcount: reference counter. + * @object_type: object type as &enum qcom_tee_object_type. + * @info: extra information for object. + * @owner: owning module/driver. + * @ops: callback operations for object of type %QCOM_TEE_OBJECT_TYPE_CB_OBJECT. + * @work: work for async operation on object. + * + * @work is currently only used for release object of %QCOM_TEE_OBJECT_TYPE_TEE type. + */ +struct qcom_tee_object { + const char *name; + struct kref refcount; + + enum qcom_tee_object_type object_type; + union object_info { + /* QTEE object id if object_type is %QCOM_TEE_OBJECT_TYPE_TEE. */ + unsigned long qtee_id; + } info; + + struct module *owner; + struct qcom_tee_object_operations *ops; + struct work_struct work; +}; + +/* Static instances of qcom_tee_object objects. */ +#define NULL_QCOM_TEE_OBJECT ((struct qcom_tee_object *)(0)) +extern struct qcom_tee_object qcom_tee_object_root; +#define ROOT_QCOM_TEE_OBJECT (&qcom_tee_object_root) + +static inline enum qcom_tee_object_type typeof_qcom_tee_object(struct qcom_tee_object *object) +{ + if (object == NULL_QCOM_TEE_OBJECT) + return QCOM_TEE_OBJECT_TYPE_NULL; + return object->object_type; +} + +static inline const char *qcom_tee_object_name(struct qcom_tee_object *object) +{ + if (object == NULL_QCOM_TEE_OBJECT) + return "null"; + + if (!object->name) + return "no-name"; + return object->name; +} + +/** + * __qcom_tee_object_user_init() - Initialize an object for user. + * @object: object to initialize. + * @object_type: type of object as &enum qcom_tee_object_type. + * @ops: instance of callbacks. + * @owner: owning module/driver. + * @fmt: name assigned to the object. + * + * Return: On success return 0 or <0 on failure. + */ +int __qcom_tee_object_user_init(struct qcom_tee_object *object, enum qcom_tee_object_type ot, + struct qcom_tee_object_operations *ops, struct module *owner, + const char *fmt, ...); +#define qcom_tee_object_user_init(obj, ot, ops, fmt, ...) \ + __qcom_tee_object_user_init((obj), (ot), (ops), THIS_MODULE, (fmt), __VA_ARGS__) + +/* Object release is RCU protected. */ +int qcom_tee_object_get(struct qcom_tee_object *object); +void qcom_tee_object_put(struct qcom_tee_object *object); + +#define qcom_tee_arg_for_each(i, args) \ + for (i = 0; args[i].type != QCOM_TEE_ARG_TYPE_INV; i++) + +/* Next argument of type @type after index @i. */ +int qcom_tee_next_arg_type(struct qcom_tee_arg *u, int i, enum qcom_tee_arg_type type); + +/* Iterate over argument of given type. */ +#define qcom_tee_arg_for_each_type(i, args, at) \ + for (i = 0, i = qcom_tee_next_arg_type(args, i, at); \ + args[i].type != QCOM_TEE_ARG_TYPE_INV; \ + i++, i = qcom_tee_next_arg_type(args, i, at)) + +#define qcom_tee_arg_for_each_input_buffer(i, args) \ + qcom_tee_arg_for_each_type(i, args, QCOM_TEE_ARG_TYPE_IB) +#define qcom_tee_arg_for_each_output_buffer(i, args) \ + qcom_tee_arg_for_each_type(i, args, QCOM_TEE_ARG_TYPE_OB) +#define qcom_tee_arg_for_each_input_object(i, args) \ + qcom_tee_arg_for_each_type(i, args, QCOM_TEE_ARG_TYPE_IO) +#define qcom_tee_arg_for_each_output_object(i, args) \ + qcom_tee_arg_for_each_type(i, args, QCOM_TEE_ARG_TYPE_OO) + +#endif /* __QCOM_TEE_H */ From patchwork Tue Dec 3 04:19:22 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Amirreza Zarrabi X-Patchwork-Id: 847030 Received: from mx0a-0031df01.pphosted.com (mx0a-0031df01.pphosted.com [205.220.168.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 9C1F315FD01; Tue, 3 Dec 2024 04:20:24 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=205.220.168.131 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1733199626; cv=none; b=cs0y/i5zxvuIQ9eG0NhVqFlC7i9jsTjaMVxQQPqybZjjAj+m2gfe8VbYKoRcOhKM2FVUa0Ah/6/Djtd/VRSGmGgA+5mJvhH1YD6msolkDbzklPXsiPG6QVDKkj1xtu5MP1t+M6+d0Lvv2Gg9D7d9xlCFylQVH6Pn15BigzCem1s= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1733199626; c=relaxed/simple; bh=4Ip/eYMJTKWmEjDinKD9UL0HIK6h/JR0O4OY7QZiKM0=; h=From:Date:Subject:MIME-Version:Content-Type:Message-ID:References: In-Reply-To:To:CC; b=E2ofD8P9nuJav769KrWBhUZ5ZnJsdSaHqkJPtYiQ8HodlnooU3FPMiLENIyb4Rt2DlLFiaOvy04a+LJRq2cAyeoPoDBwC8wydmBH7zOq43jbqmzkBzgRTdWapDC5IM2rtOipZzkmrVmnk0eKl4DR2FCWoC8ZmCu9JAMMSvGxU0s= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=quicinc.com; spf=pass smtp.mailfrom=quicinc.com; dkim=pass (2048-bit key) header.d=quicinc.com header.i=@quicinc.com header.b=mX9ReGUt; arc=none smtp.client-ip=205.220.168.131 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=quicinc.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=quicinc.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=quicinc.com header.i=@quicinc.com header.b="mX9ReGUt" Received: from pps.filterd (m0279863.ppops.net [127.0.0.1]) by mx0a-0031df01.pphosted.com (8.18.1.2/8.18.1.2) with ESMTP id 4B2KfxWX011526; Tue, 3 Dec 2024 04:20:08 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=quicinc.com; h= cc:content-transfer-encoding:content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to; s=qcppdkim1; bh= 4pW94t0mQwR/YAdL0hlJgtjMU3iWcKHn55GbIYlcqUM=; b=mX9ReGUt+pO77iN5 ouFA0Sdwe1RgQoC2CtHk8hoHo9v7rdB7Aa1x0KG2OZxJ8iknn/2Y8W3vnzQu6ROp mD5ZjS/eBWiNzlR37WKRbOHnowwAfdYorHNJ3vvt0NxCXQhcrUAiALFe0FSFaDNA Zs0s6RHtgQIwKVECB3/jZsTQVTXojn79b9af9bqYnnwUZdf24D6b9H3xqZQt54KW kXITdZL2sAgRJpZy3f0B8Vn4dgp07wyTFLQALyFJLjkBw7Nt5XTc9K6ZZ2vRI926 Q2tBDLfNwErcULQqMkeRvmIaJdbth41n7TFl0slBNqtWNCRZxAoTa42iwrpk2xGQ lwiTKw== Received: from nasanppmta05.qualcomm.com (i-global254.qualcomm.com [199.106.103.254]) by mx0a-0031df01.pphosted.com (PPS) with ESMTPS id 4393mpbqre-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 03 Dec 2024 04:20:07 +0000 (GMT) Received: from nasanex01b.na.qualcomm.com (nasanex01b.na.qualcomm.com [10.46.141.250]) by NASANPPMTA05.qualcomm.com (8.18.1.2/8.18.1.2) with ESMTPS id 4B34K7vE024250 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 3 Dec 2024 04:20:07 GMT Received: from hu-azarrabi-lv.qualcomm.com (10.49.16.6) by nasanex01b.na.qualcomm.com (10.46.141.250) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1544.9; Mon, 2 Dec 2024 20:20:06 -0800 From: Amirreza Zarrabi Date: Mon, 2 Dec 2024 20:19:22 -0800 Subject: [PATCH 06/10] qcomtee: add primordial object Precedence: bulk X-Mailing-List: linux-arm-msm@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-ID: <20241202-qcom-tee-using-tee-ss-without-mem-obj-v1-6-f502ef01e016@quicinc.com> References: <20241202-qcom-tee-using-tee-ss-without-mem-obj-v1-0-f502ef01e016@quicinc.com> In-Reply-To: <20241202-qcom-tee-using-tee-ss-without-mem-obj-v1-0-f502ef01e016@quicinc.com> To: Jens Wiklander , Sumit Garg , Bjorn Andersson , "Konrad Dybcio" , Rob Herring , "Krzysztof Kozlowski" , Conor Dooley , "Bartosz Golaszewski" , Srinivas Kandagatla CC: , , , , , Amirreza Zarrabi X-Mailer: b4 0.13.0 X-ClientProxiedBy: nalasex01c.na.qualcomm.com (10.47.97.35) To nasanex01b.na.qualcomm.com (10.46.141.250) X-QCInternal: smtphost X-Proofpoint-Virus-Version: vendor=nai engine=6200 definitions=5800 signatures=585085 X-Proofpoint-ORIG-GUID: wQdIXnWhvwQwx4MFC-ExCuKmECqWa2Vg X-Proofpoint-GUID: wQdIXnWhvwQwx4MFC-ExCuKmECqWa2Vg X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1039,Hydra:6.0.680,FMLib:17.12.60.29 definitions=2024-09-06_09,2024-09-06_01,2024-09-02_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 phishscore=0 mlxlogscore=999 impostorscore=0 mlxscore=0 malwarescore=0 suspectscore=0 lowpriorityscore=0 adultscore=0 spamscore=0 priorityscore=1501 clxscore=1011 bulkscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.19.0-2411120000 definitions=main-2412030034 After booting, the kernel provides a static object known as the primordial object. This object is utilized by QTEE for native kernel services such as yield or privileged operations. Signed-off-by: Amirreza Zarrabi --- drivers/tee/qcomtee/Makefile | 1 + drivers/tee/qcomtee/core.c | 12 +++++-- drivers/tee/qcomtee/primordial_obj.c | 63 +++++++++++++++++++++++++++++++++++ drivers/tee/qcomtee/qcomtee_private.h | 5 +++ 4 files changed, 78 insertions(+), 3 deletions(-) diff --git a/drivers/tee/qcomtee/Makefile b/drivers/tee/qcomtee/Makefile index 7dc5e6373042..108bc7fdabcb 100644 --- a/drivers/tee/qcomtee/Makefile +++ b/drivers/tee/qcomtee/Makefile @@ -2,5 +2,6 @@ obj-$(CONFIG_QCOMTEE) += qcomtee.o qcomtee-objs += async.o qcomtee-objs += core.o +qcomtee-objs += primordial_obj.o qcomtee-objs += qcom_scm.o qcomtee-objs += release.o diff --git a/drivers/tee/qcomtee/core.c b/drivers/tee/qcomtee/core.c index a949ef4cceee..79f1181cf676 100644 --- a/drivers/tee/qcomtee/core.c +++ b/drivers/tee/qcomtee/core.c @@ -34,9 +34,11 @@ int qcom_tee_next_arg_type(struct qcom_tee_arg *u, int i, enum qcom_tee_arg_type } /* QTEE expects IDs with QCOM_TEE_MSG_OBJECT_NS_BIT set for object of - * QCOM_TEE_OBJECT_TYPE_CB_OBJECT type. + * QCOM_TEE_OBJECT_TYPE_CB_OBJECT type. The first ID with QCOM_TEE_MSG_OBJECT_NS_BIT set is + * reserved for primordial object. */ -#define QCOM_TEE_OBJECT_ID_START (QCOM_TEE_MSG_OBJECT_NS_BIT + 1) +#define QCOM_TEE_OBJECT_PRIMORDIAL (QCOM_TEE_MSG_OBJECT_NS_BIT) +#define QCOM_TEE_OBJECT_ID_START (QCOM_TEE_OBJECT_PRIMORDIAL + 1) #define QCOM_TEE_OBJECT_ID_END (UINT_MAX) #define QCOM_TEE_OBJECT_SET(p, type, ...) __QCOM_TEE_OBJECT_SET(p, type, ##__VA_ARGS__, 0UL) @@ -118,7 +120,8 @@ EXPORT_SYMBOL_GPL(qcom_tee_object_get); */ void qcom_tee_object_put(struct qcom_tee_object *object) { - if (object != NULL_QCOM_TEE_OBJECT && + if (object != &qcom_tee_primordial_object && + object != NULL_QCOM_TEE_OBJECT && object != ROOT_QCOM_TEE_OBJECT) kref_put(&object->refcount, qcom_tee_object_release); } @@ -209,6 +212,9 @@ static struct qcom_tee_object *qcom_tee_local_object_get(unsigned int object_id) { struct qcom_tee_object *object; + if (object_id == QCOM_TEE_OBJECT_PRIMORDIAL) + return &qcom_tee_primordial_object; + /* We trust QTEE does not mess the refcounts. * It does not issue RELEASE request and qcom_tee_object_get(), simultaneously. */ diff --git a/drivers/tee/qcomtee/primordial_obj.c b/drivers/tee/qcomtee/primordial_obj.c new file mode 100644 index 000000000000..9065074b02e6 --- /dev/null +++ b/drivers/tee/qcomtee/primordial_obj.c @@ -0,0 +1,63 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include "qcomtee_private.h" + +/** + * DOC: Primordial Object + * + * After the boot, REE provides a static object of type %QCOM_TEE_OBJECT_TYPE_CB_OBJECT + * called primordial object. This object is used for native REE services or privileged operations. + * + * We support + * - %QCOM_TEE_OBJECT_OP_YIELD to yield by the thread running in QTEE. + * - %QCOM_TEE_OBJECT_OP_SLEEP to wait for period of time. + */ + +#define QCOM_TEE_OBJECT_OP_YIELD 1 +#define QCOM_TEE_OBJECT_OP_SLEEP 2 + +static int qcom_tee_primordial_object_dispatch(struct qcom_tee_object_invoke_ctx *oic, + struct qcom_tee_object *primordial_object_unused, + u32 op, struct qcom_tee_arg *args) +{ + int err = 0; + + switch (op) { + case QCOM_TEE_OBJECT_OP_YIELD: + cond_resched(); + /* No output object. */ + oic->data = NULL; + break; + case QCOM_TEE_OBJECT_OP_SLEEP: + /* Check message format matched QCOM_TEE_OBJECT_OP_SLEEP op. */ + if (qcom_tee_args_len(args) != 1 || /* Expect 1 argument. */ + args[0].type != QCOM_TEE_ARG_TYPE_IB || /* Time to sleep in ms. */ + args[0].b.size < sizeof(u32)) /* Buffer should hold a u32. */ + return -EINVAL; + + msleep(*(u32 *)(args[0].b.addr)); + /* No output object. */ + oic->data = NULL; + break; + default: + err = -EINVAL; + } + + return err; +} + +static struct qcom_tee_object_operations qcom_tee_primordial_object_ops = { + .dispatch = qcom_tee_primordial_object_dispatch, +}; + +struct qcom_tee_object qcom_tee_primordial_object = { + .name = "primordial", + .object_type = QCOM_TEE_OBJECT_TYPE_CB_OBJECT, + .ops = &qcom_tee_primordial_object_ops +}; diff --git a/drivers/tee/qcomtee/qcomtee_private.h b/drivers/tee/qcomtee/qcomtee_private.h index e3e4ef51c0b2..c718cd2d8463 100644 --- a/drivers/tee/qcomtee/qcomtee_private.h +++ b/drivers/tee/qcomtee/qcomtee_private.h @@ -44,4 +44,9 @@ int __qcom_tee_object_do_invoke(struct qcom_tee_object_invoke_ctx *oic, struct qcom_tee_object *object, u32 op, struct qcom_tee_arg *u, int *result); +/* OBJECTS: */ + +/* (1) Primordial Object. */ +extern struct qcom_tee_object qcom_tee_primordial_object; + #endif /* QCOM_TEE_PRIVATE_H */ From patchwork Tue Dec 3 04:19:23 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Amirreza Zarrabi X-Patchwork-Id: 847032 Received: from mx0b-0031df01.pphosted.com (mx0b-0031df01.pphosted.com [205.220.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C0427A32; Tue, 3 Dec 2024 04:20:13 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=205.220.180.131 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1733199615; cv=none; b=i2sU56XfXDa1YHyjmW+5qO05oHoZLWFwkRqpnZU9Z2L6H8mJFGiW56becCV/gx1G7H2lgMzPiHhrdboTmXXVWKIsrXkzEev65Ollh6J2i0t3j5eogHVCqMs7DgGu+PKlkj+RRjDb1B3i+4zk9X1fH9Sp2qrsieQsC2bgNGaELmw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1733199615; c=relaxed/simple; bh=1k74yh5rMWor9nCD5PeVEFmS/qSH1qXubMdHAr4kg4g=; h=From:Date:Subject:MIME-Version:Content-Type:Message-ID:References: In-Reply-To:To:CC; b=fFdhrdqsOHXxbCwq8iLXxbGWRfdBz1gyiyOUi9KizhWRQ1WfBNOvGTOG1eNOL61KthBeQzELnfPWoISXIZE14LRb9ZrRhowDxycOVBxSMD3p8uPXI+K7fdRMmCc5em90FzDZ+BJO8pj+mvCHR0nQy5kJtvkIM0Q0xuKIkzi/QjI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=quicinc.com; spf=pass smtp.mailfrom=quicinc.com; dkim=pass (2048-bit key) header.d=quicinc.com header.i=@quicinc.com header.b=pfE3mqjV; arc=none smtp.client-ip=205.220.180.131 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=quicinc.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=quicinc.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=quicinc.com header.i=@quicinc.com header.b="pfE3mqjV" Received: from pps.filterd (m0279870.ppops.net [127.0.0.1]) by mx0a-0031df01.pphosted.com (8.18.1.2/8.18.1.2) with ESMTP id 4B2K0u0D028930; Tue, 3 Dec 2024 04:20:08 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=quicinc.com; h= cc:content-transfer-encoding:content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to; s=qcppdkim1; bh= owDSHhy8Sr3+CM51CcotyNAWcQJ8/9cPHNsDP/LdFTQ=; b=pfE3mqjVKdhkq0AE bsm9/pd4+k8Q3P6Li3/cqBioGbaoiP0MSaRT+Is4WchaIRKVIgQF5acA7bgFnLBV 4tV7xqPgNyShxoD8/K/3+JScB5jg0bLsjkVFiOv5S94pc+WD36IwS+Y3EzYceNLf 0ZWXhiolPSOH5nAffUWaHBspvKhNxcdaO8jp7YVVmvOWNuFLFVyiAHm80EHvmRdu MvwOomyTqNNMgnyBLtSSAaJShvE9UPBCm4L3L8/iqd73jJA/4ofF5DlLXQO6TxDB kaASJ+jGEst4MAsD0+w2QeOn0OlrAFL2tZZpOKOtGT2rF6I04o0rgZt2iwXtEZQ0 ct7T4Q== Received: from nasanppmta03.qualcomm.com (i-global254.qualcomm.com [199.106.103.254]) by mx0a-0031df01.pphosted.com (PPS) with ESMTPS id 437tstesja-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 03 Dec 2024 04:20:08 +0000 (GMT) Received: from nasanex01b.na.qualcomm.com (nasanex01b.na.qualcomm.com [10.46.141.250]) by NASANPPMTA03.qualcomm.com (8.18.1.2/8.18.1.2) with ESMTPS id 4B34K70c029965 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 3 Dec 2024 04:20:07 GMT Received: from hu-azarrabi-lv.qualcomm.com (10.49.16.6) by nasanex01b.na.qualcomm.com (10.46.141.250) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1544.9; Mon, 2 Dec 2024 20:20:06 -0800 From: Amirreza Zarrabi Date: Mon, 2 Dec 2024 20:19:23 -0800 Subject: [PATCH 07/10] dt-bindings: arm: qcomtee: add QTEE driver devicetree binding for TEE subsystem Precedence: bulk X-Mailing-List: linux-arm-msm@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-ID: <20241202-qcom-tee-using-tee-ss-without-mem-obj-v1-7-f502ef01e016@quicinc.com> References: <20241202-qcom-tee-using-tee-ss-without-mem-obj-v1-0-f502ef01e016@quicinc.com> In-Reply-To: <20241202-qcom-tee-using-tee-ss-without-mem-obj-v1-0-f502ef01e016@quicinc.com> To: Jens Wiklander , Sumit Garg , Bjorn Andersson , "Konrad Dybcio" , Rob Herring , "Krzysztof Kozlowski" , Conor Dooley , "Bartosz Golaszewski" , Srinivas Kandagatla CC: , , , , , Amirreza Zarrabi X-Mailer: b4 0.13.0 X-ClientProxiedBy: nalasex01c.na.qualcomm.com (10.47.97.35) To nasanex01b.na.qualcomm.com (10.46.141.250) X-QCInternal: smtphost X-Proofpoint-Virus-Version: vendor=nai engine=6200 definitions=5800 signatures=585085 X-Proofpoint-ORIG-GUID: 8lovn5mFuGbrdZsva5UXpvSHwQRofjvf X-Proofpoint-GUID: 8lovn5mFuGbrdZsva5UXpvSHwQRofjvf X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1039,Hydra:6.0.680,FMLib:17.12.60.29 definitions=2024-09-06_09,2024-09-06_01,2024-09-02_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 lowpriorityscore=0 malwarescore=0 spamscore=0 impostorscore=0 mlxlogscore=999 mlxscore=0 priorityscore=1501 suspectscore=0 phishscore=0 adultscore=0 clxscore=1015 bulkscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.19.0-2411120000 definitions=main-2412030033 Introduce qcom,tee compatible string. Signed-off-by: Amirreza Zarrabi --- .../devicetree/bindings/arm/firmware/qcom,tee.yaml | 34 ++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/Documentation/devicetree/bindings/arm/firmware/qcom,tee.yaml b/Documentation/devicetree/bindings/arm/firmware/qcom,tee.yaml new file mode 100644 index 000000000000..43b7e8ac944e --- /dev/null +++ b/Documentation/devicetree/bindings/arm/firmware/qcom,tee.yaml @@ -0,0 +1,34 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/arm/firmware/qcom,tee.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm TEE + +maintainers: + - Amirreza Zarrabi + +description: | + QTEE is a piece of software provide a Trusted Execution Environment using ARM + TrustZone for Qualcomm SoC. + +properties: + $nodename: + const: qcom_tee + + compatible: + const: qcom,tee + +required: + - compatible + +additionalProperties: false + +examples: + - | + firmware { + qcom_tee { + compatible = "qcom,tee"; + }; + }; From patchwork Tue Dec 3 04:19:25 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Amirreza Zarrabi X-Patchwork-Id: 847031 Received: from mx0a-0031df01.pphosted.com (mx0a-0031df01.pphosted.com [205.220.168.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 9C247166F25; Tue, 3 Dec 2024 04:20:24 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=205.220.168.131 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1733199626; cv=none; b=fkq5iB974wZa8CetvPGpYlvvxU/ImPUw347T3qVd/we2EwU7D//wfz7k6Pmu3a0BUoGtUz+LC2qIGkLBb5o44kt7Mkz6/2DJtys8SoFTV2yb8NXpsCXUpDR8I3Smi8I42ORIq0GO29jEdzzDob/1HEu5Wdu8oKTTa7QjN+bPnWg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1733199626; c=relaxed/simple; bh=DfsTpQhuDVPTpBwxnbE96woq0PpXEf79V1MdViROPLM=; h=From:Date:Subject:MIME-Version:Content-Type:Message-ID:References: In-Reply-To:To:CC; b=JZkzBC+XRF4xMXi7M7cHOg5ITBoe+sxalrRbc8W26wYBOnFplqv32prHRiATzmp5M0hOxW87WK35RDB0zGBJCQDMnQ/hxtl8W25r9ZbplhHXLpB+/vUK0TKcy4R/P48otNWFHqZVKw824SOPqCJSK2NJMDqZmFv7RFVLM3LQ7cU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=quicinc.com; spf=pass smtp.mailfrom=quicinc.com; dkim=pass (2048-bit key) header.d=quicinc.com header.i=@quicinc.com header.b=YVW+/Xvp; arc=none smtp.client-ip=205.220.168.131 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=quicinc.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=quicinc.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=quicinc.com header.i=@quicinc.com header.b="YVW+/Xvp" Received: from pps.filterd (m0279865.ppops.net [127.0.0.1]) by mx0a-0031df01.pphosted.com (8.18.1.2/8.18.1.2) with ESMTP id 4B2Jn2e0003080; Tue, 3 Dec 2024 04:20:08 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=quicinc.com; h= cc:content-transfer-encoding:content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to; s=qcppdkim1; bh= O4bWYQjlUTtsncfGn51zMsyUq6OeHDQHavuJcZ+eD3A=; b=YVW+/XvpNRduslLv 5rbM+jGmoIJyU8shvcToFXbyWaGRnOQV4bcPiZpiG3rGun+RcEdorbWGMwDMMbvD KhiXSSFySEunczvA7Ln7BgOUwe8+GDVkckfZ5lYHwAbNadCoYpyxGCfreYK10+sr DjQZGsWL/kRbhyHdEdySYi9Z1SsBa23rKP0ESYN9AxPjF/ojDPDmpqxrZusJTeeK G4mNx/Qmkw/mODYOhrohEf/VectW2aQuSY6yDbRm7rbyp4uoG+lRAa1jis4FUhNC +aw40cHStsAtkvNFb7934fBLEJXOQlwDANozHJpVlJI9umWTYVY1JiRhSkGb/kTP dEDXng== Received: from nasanppmta05.qualcomm.com (i-global254.qualcomm.com [199.106.103.254]) by mx0a-0031df01.pphosted.com (PPS) with ESMTPS id 437snqxv5e-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 03 Dec 2024 04:20:08 +0000 (GMT) Received: from nasanex01b.na.qualcomm.com (nasanex01b.na.qualcomm.com [10.46.141.250]) by NASANPPMTA05.qualcomm.com (8.18.1.2/8.18.1.2) with ESMTPS id 4B34K8wn024268 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 3 Dec 2024 04:20:08 GMT Received: from hu-azarrabi-lv.qualcomm.com (10.49.16.6) by nasanex01b.na.qualcomm.com (10.46.141.250) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1544.9; Mon, 2 Dec 2024 20:20:07 -0800 From: Amirreza Zarrabi Date: Mon, 2 Dec 2024 20:19:25 -0800 Subject: [PATCH 09/10] arm64: dts: qcom: sm8650: add support for QTEE Precedence: bulk X-Mailing-List: linux-arm-msm@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-ID: <20241202-qcom-tee-using-tee-ss-without-mem-obj-v1-9-f502ef01e016@quicinc.com> References: <20241202-qcom-tee-using-tee-ss-without-mem-obj-v1-0-f502ef01e016@quicinc.com> In-Reply-To: <20241202-qcom-tee-using-tee-ss-without-mem-obj-v1-0-f502ef01e016@quicinc.com> To: Jens Wiklander , Sumit Garg , Bjorn Andersson , "Konrad Dybcio" , Rob Herring , "Krzysztof Kozlowski" , Conor Dooley , "Bartosz Golaszewski" , Srinivas Kandagatla CC: , , , , , Amirreza Zarrabi X-Mailer: b4 0.13.0 X-ClientProxiedBy: nalasex01c.na.qualcomm.com (10.47.97.35) To nasanex01b.na.qualcomm.com (10.46.141.250) X-QCInternal: smtphost X-Proofpoint-Virus-Version: vendor=nai engine=6200 definitions=5800 signatures=585085 X-Proofpoint-ORIG-GUID: _8JIZmuVEHs8ZWhLHMzQa9YHubpc-4US X-Proofpoint-GUID: _8JIZmuVEHs8ZWhLHMzQa9YHubpc-4US X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1039,Hydra:6.0.680,FMLib:17.12.60.29 definitions=2024-09-06_09,2024-09-06_01,2024-09-02_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 spamscore=0 bulkscore=0 phishscore=0 adultscore=0 impostorscore=0 malwarescore=0 lowpriorityscore=0 suspectscore=0 priorityscore=1501 mlxscore=0 mlxlogscore=923 clxscore=1015 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.19.0-2411120000 definitions=main-2412030034 Add qcom_tee node. Signed-off-by: Amirreza Zarrabi --- arch/arm64/boot/dts/qcom/sm8650.dtsi | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sm8650.dtsi b/arch/arm64/boot/dts/qcom/sm8650.dtsi index 25e47505adcb..41505b032e3a 100644 --- a/arch/arm64/boot/dts/qcom/sm8650.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8650.dtsi @@ -372,6 +372,10 @@ scm: scm { interconnects = <&aggre2_noc MASTER_CRYPTO QCOM_ICC_TAG_ALWAYS &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; }; + + qcom_tee { + compatible = "qcom,tee"; + }; }; clk_virt: interconnect-0 { From patchwork Tue Dec 3 04:19:26 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Amirreza Zarrabi X-Patchwork-Id: 847028 Received: from mx0a-0031df01.pphosted.com (mx0a-0031df01.pphosted.com [205.220.168.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 6E301186616; Tue, 3 Dec 2024 04:20:25 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=205.220.168.131 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1733199627; cv=none; b=UBCQR0j1Q7atybXBwJF2Nw0rWqS1GfC5dhn+T/TaUYaZSpLoszjlPZc7TqcmzRqsnx6SJ/9xYV19i9DoCgCVMNGpftKSPWztFuY+zNxtLTq4EcVWJnSTV5+b4FKLpBa0dV1SfGotXekTCWdCeu0EGtspRfda/nsjvXwBiMK1YUo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1733199627; c=relaxed/simple; bh=6ooM/9AY9xoHRBcOk7ycakkouxWVLDV98VBpDCj+F2k=; h=From:Date:Subject:MIME-Version:Content-Type:Message-ID:References: In-Reply-To:To:CC; b=tIoqcBR8KOa2tozQNopX4Ld2JVYlDTwVvo/XI00KPpV2kwRv9JTgG8HM6gHw9I4bxYmZKqdtpbsK5dbTxltEIjKs8pa/dy+Sinkhgnezx3q4ePv7aYKwhRgBSpGNQYT/TtlbP+30OhNEm9q9sYHexDOpxivhBuhAgNvhPy/VFRY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=quicinc.com; spf=pass smtp.mailfrom=quicinc.com; dkim=pass (2048-bit key) header.d=quicinc.com header.i=@quicinc.com header.b=kK2GnW7t; arc=none smtp.client-ip=205.220.168.131 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=quicinc.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=quicinc.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=quicinc.com header.i=@quicinc.com header.b="kK2GnW7t" Received: from pps.filterd (m0279867.ppops.net [127.0.0.1]) by mx0a-0031df01.pphosted.com (8.18.1.2/8.18.1.2) with ESMTP id 4B2JjaPl009592; Tue, 3 Dec 2024 04:20:09 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=quicinc.com; h= cc:content-transfer-encoding:content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to; s=qcppdkim1; bh= nJ8oUk0DjJmQHwnQTgTBlinyuDwrdPECWWpX6XK+l/Q=; b=kK2GnW7t/OUg+a79 iQtwfyd1lHO7fGjal+vJ+xGK13rMRVgy3MhP+dqFgwAsEBNkW7v4w4d3EwhrQNyw Njd6j3/0UjFij7sA6jy6k28//criU/LZxvDy+ru/lUjZVgOQN36gLxRH3DHJnkc9 p4yfRFsUA5nnZqZd4fzjY1ebeO+Wt6caEKnTQZslIC3F9cUQBhPeIfejeyNydOO1 B1yH0mCBhtqbwoOdZbYgDC91/Fhxf1qSTpcGMyPkhZ0nXy+1RPfi/EgOsffDC7Xf mhSQ6coRPE8BvE6d0Di/uOR2BoIM0kCHf/J5YeG7fBaTgpUUptV/zGkkUyiXe0zy B295tg== Received: from nasanppmta05.qualcomm.com (i-global254.qualcomm.com [199.106.103.254]) by mx0a-0031df01.pphosted.com (PPS) with ESMTPS id 437rdeeycg-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 03 Dec 2024 04:20:09 +0000 (GMT) Received: from nasanex01b.na.qualcomm.com (nasanex01b.na.qualcomm.com [10.46.141.250]) by NASANPPMTA05.qualcomm.com (8.18.1.2/8.18.1.2) with ESMTPS id 4B34K8xw024278 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 3 Dec 2024 04:20:08 GMT Received: from hu-azarrabi-lv.qualcomm.com (10.49.16.6) by nasanex01b.na.qualcomm.com (10.46.141.250) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1544.9; Mon, 2 Dec 2024 20:20:07 -0800 From: Amirreza Zarrabi Date: Mon, 2 Dec 2024 20:19:26 -0800 Subject: [PATCH 10/10] Documentation: tee: Add Qualcomm TEE driver Precedence: bulk X-Mailing-List: linux-arm-msm@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-ID: <20241202-qcom-tee-using-tee-ss-without-mem-obj-v1-10-f502ef01e016@quicinc.com> References: <20241202-qcom-tee-using-tee-ss-without-mem-obj-v1-0-f502ef01e016@quicinc.com> In-Reply-To: <20241202-qcom-tee-using-tee-ss-without-mem-obj-v1-0-f502ef01e016@quicinc.com> To: Jens Wiklander , Sumit Garg , Bjorn Andersson , "Konrad Dybcio" , Rob Herring , "Krzysztof Kozlowski" , Conor Dooley , "Bartosz Golaszewski" , Srinivas Kandagatla CC: , , , , , Amirreza Zarrabi X-Mailer: b4 0.13.0 X-ClientProxiedBy: nalasex01c.na.qualcomm.com (10.47.97.35) To nasanex01b.na.qualcomm.com (10.46.141.250) X-QCInternal: smtphost X-Proofpoint-Virus-Version: vendor=nai engine=6200 definitions=5800 signatures=585085 X-Proofpoint-ORIG-GUID: iM7jLcEG1YVF7CY-ICZHAjpc1FI2Vv0o X-Proofpoint-GUID: iM7jLcEG1YVF7CY-ICZHAjpc1FI2Vv0o X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1039,Hydra:6.0.680,FMLib:17.12.60.29 definitions=2024-09-06_09,2024-09-06_01,2024-09-02_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 spamscore=0 mlxscore=0 adultscore=0 malwarescore=0 mlxlogscore=999 phishscore=0 suspectscore=0 impostorscore=0 clxscore=1011 lowpriorityscore=0 bulkscore=0 priorityscore=1501 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.19.0-2411120000 definitions=main-2412030034 Add documentation for the Qualcomm TEE driver. Signed-off-by: Amirreza Zarrabi --- Documentation/tee/index.rst | 1 + Documentation/tee/qtee.rst | 143 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 144 insertions(+) diff --git a/Documentation/tee/index.rst b/Documentation/tee/index.rst index 4be6e69d7837..62afb7ee9b52 100644 --- a/Documentation/tee/index.rst +++ b/Documentation/tee/index.rst @@ -11,6 +11,7 @@ TEE Subsystem op-tee amd-tee ts-tee + qtee .. only:: subproject and html diff --git a/Documentation/tee/qtee.rst b/Documentation/tee/qtee.rst new file mode 100644 index 000000000000..3185af2c2b2b --- /dev/null +++ b/Documentation/tee/qtee.rst @@ -0,0 +1,143 @@ +.. SPDX-License-Identifier: GPL-2.0 + +============================================= +QTEE (Qualcomm Trusted Execution Environment) +============================================= + +The QTEE driver handle communication with Qualcomm TEE [1]. + +Lowest level of communication with QTEE builds on ARM SMC Calling Convention +(SMCCC) [2], which is the foundation for QTEE's Secure Channel Manager (SCM) [3] +used internally by the driver [4]. + +In a QTEE-based system, services are represented as objects with series of +operations that can be called to produce results, including other objects. When +an object is hosted within QTEE, executing its operations is referred to as direct +invocation. QTEE can invoke objects hosted in the kernel or userspace using a +method known as callback requests. + +The SCM provides two functions for object invocation and callback request: + +- QCOM_SCM_SMCINVOKE_INVOKE for direct invocation. It can return either a result or a callback request. +- QCOM_SCM_SMCINVOKE_CB_RSP submits a response for a previous callback request. + +The QTEE Transport Message [5] is stacked on top of SCM driver functions. + +A message consists of two buffers shared with QTEE, inbound and outbound buffers. +The inbound buffer is used for direct invocation and the outbound buffer is used +to make callback request. This picture shows the contents of a QTEE transport message:: + + +---------------------+ + | v + +-----------------+-------+-------+------+--------------------------+ + | qcom_tee_msg_ |object | buffer | | + | object_invoke | id | offset, size | | (inbound buffer) + +-----------------+-------+--------------+--------------------------+ + <---- header -----><---- arguments ------><- in/out buffer payload -> + + +-----------+ + | v + +-----------------+-------+-------+------+----------------------+ + | qcom_tee_msg_ |object | buffer | | + | callback | id | offset, size | | (outbound buffer) + +-----------------+-------+--------------+----------------------+ + +Each buffer is started with a header and array of arguments. + +QTEE Transport Message supports four types of arguments: + +- Input object is an object parameter to the current invocation or callback request +- Output object is an object parameter from the current invocation or callback request +- Input buffer is (offset, size) pair to the inbound or outbound region to store parameter to the current invocation or callback request +- Output buffer is (offset, size) pair to the inbound or outbound region to store parameter from the current invocation or callback request + +The QTEE driver offers the qcom_tee_object, which represents an object within both +QTEE and the kernel. To access any service in QTEE, client needs to invoke an +instance of this object. Any structure intended to represent a service for export +to QTEE should include an instance of qcom_tee_object:: + + struct driver_service { + struct qcom_tee_object object; + ... + }; + + #define to_driver_service_object(o) container_of((o), struct driver_service, object) + + static int driver_service_dispatch(struct qcom_tee_object *object, u32 op, + struct qcom_tee_arg *args) + { + struct driver_service *so = to_driver_service_object(object); + + switch(op) { + case OBJECT_OP1: + ... + break; + default: + return -EINVAL; + } + } + + static void driver_service_object_release(struct si_object *object) + { + struct driver_service *so = to_driver_service_object(object); + kfree(so); + } + + struct si_object_operations driver_service_ops = { + .release = driver_service_object_release; + .dispatch = driver_service_dispatch; + }; + + void service_init(void) + { + struct driver_service *so = kzalloc(sizeof(*so), GFP_KERNEL); + + /* Initialize so->object as a callback object. */ + qcom_tee_object_user_init(&so->object, QCOM_TEE_OBJECT_TYPE_CB_OBJECT, + &driver_service_ops, "driver_service_object"); + + /* Invoke a QTEE object and pass/register 'so->object' with QTEE. */ + ... + } + module_init(service_init); + +The QTEE driver utilizes qcom_tee_object to encapsulate userspace objects. When a +callback request is made, it translates into calling the dispatch callback. For +userspace objects, this is converted into requests accessible to callback servers +and available through generic TEE API IOCTLs. + +Picture of the relationship between the different components in the QTEE +architecture:: + + User space Kernel Secure world + ~~~~~~~~~~ ~~~~~~ ~~~~~~~~~~~~ + +--------+ +----------+ +--------------+ + | Client | |callback | | Trusted | + +--------+ |server | | Application | + /\ +----------+ +--------------+ + || +----------+ /\ /\ + || |callback | || || + || |server | || \/ + || +----------+ || +--------------+ + \/ /\ || | TEE Internal | + +-------+ || || | API | + | TEE | || || +--------+--------+ +--------------+ + | Client| || || | TEE | QTEE | | QTEE | + | API | \/ \/ | subsys | driver | | Trusted OS | + +-------+----------------+----+-------+----+-------------+--------------+ + | Generic TEE API | | QTEE MSG | + | IOCTL (TEE_IOC_*) | | SMCCC (QCOM_SCM_SMCINVOKE_*) | + +-----------------------------+ +---------------------------------+ + +References +========== + +[1] https://docs.qualcomm.com/bundle/publicresource/topics/80-70015-11/qualcomm-trusted-execution-environment.html + +[2] http://infocenter.arm.com/help/topic/com.arm.doc.den0028a/index.html + +[3] drivers/firmware/qcom/qcom_scm.c + +[4] /local/mnt/workspace/Linux/drivers/tee/qcomtee/qcom_scm.c + +[5] drivers/tee/qcomtee/qcomtee_msg.h \ No newline at end of file