From nobody Thu Oct 2 20:38:43 2025 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 A43E42367A8 for ; Thu, 11 Sep 2025 03:41:28 +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=1757562090; cv=none; b=E1V/pvBto8hiT8aTZh8tuzPvrO5oD/pEz4FmTGkcgD6fuFHAa36Whgz84OI03Q/MiDRLGOwk7OgOq1w/s6D07U+gr+zm63f5JM8Vb44DSzCC4hpj4FKMA3oDZaf1WF7N/TmXg+1ycmRXlRSII7vBPSxnigVSmECYdHldds+9j6g= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757562090; c=relaxed/simple; bh=lgp1LOhLLp/W5q+GFi1cI9hy6O6fqjuRWo/O+rRQgWY=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=si9UcxlAWtSbJwZvUmNJaC8RtENF7jYQmkPWgK6fR8+ydXuDQk/s+qQxip335yJt/r5jGx0g7u2PuIKZUS+3hXyxpd6CqYUmScHFtkkWPqU2B+JfyaUfyx9ubp6IKX7h1Mbk/pBF0+Q2qpg80tsk+/NvNYEgYy4sFmiiEQIZaU4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=oss.qualcomm.com; spf=pass smtp.mailfrom=oss.qualcomm.com; dkim=pass (2048-bit key) header.d=qualcomm.com header.i=@qualcomm.com header.b=EIs45YAr; arc=none smtp.client-ip=205.220.180.131 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=oss.qualcomm.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=oss.qualcomm.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=qualcomm.com header.i=@qualcomm.com header.b="EIs45YAr" Received: from pps.filterd (m0279873.ppops.net [127.0.0.1]) by mx0a-0031df01.pphosted.com (8.18.1.2/8.18.1.2) with ESMTP id 58B2IuRi008865 for ; Thu, 11 Sep 2025 03:41:27 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=qualcomm.com; h= cc:content-transfer-encoding:content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to; s=qcppdkim1; bh= 30MVqau9h2AN1WxS7vqJoVCbxWXWCZTilNucOIr42c8=; b=EIs45YAro3qEwEC3 a49S8A5D3EncjdPj4pIvqAWDdUSLOmHG2HDZGjZuHSARbL6L6rSQhLJ91KRJLPg0 vVLgDbfsziahyewB62mUcRNrkrKWFPciihRSbL10ktDRqQlC1mnzL+gPOwHVtB12 dAiGsS/ItG3P2pXKFK2oRk1R6Qm2uA2ERieOcO3a0Nr4HvyWnDb9ba5XhHm6oNM3 bfgpkEOMoOK0nuYdpgPdOUSvSCmq/pdWgRjWz7ZU+FxpFXomJEQZQBjObtHys6AR uignD4nLgz5sXiwtNIAnyVDI+7DP3Goxu/MCFYLDCAPt64nDzzU2C7LkOgdIONfO zCfOww== Received: from mail-pj1-f72.google.com (mail-pj1-f72.google.com [209.85.216.72]) by mx0a-0031df01.pphosted.com (PPS) with ESMTPS id 490aappd9n-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128 verify=NOT) for ; Thu, 11 Sep 2025 03:41:27 +0000 (GMT) Received: by mail-pj1-f72.google.com with SMTP id 98e67ed59e1d1-329e55e686dso426519a91.3 for ; Wed, 10 Sep 2025 20:41:27 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1757562086; x=1758166886; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=30MVqau9h2AN1WxS7vqJoVCbxWXWCZTilNucOIr42c8=; b=kYRmDwBgYIiEHzRXcUIkXgaQxkF6cvJ6UhVN1Dub3Y5VWtuwxVAojSjdkQvlq/9tvn XH+uxA3mhCABCMZDB0hUSnmjhOO9Hs9N3JbQ/FYQfrb1hpdnRhfMEQ/OpYDw6fLOT2SG XFSOnxyKYCA6C8vLrfKPPlep2RTTTUU3SSyygYECxHnR7j33WYbYdViAJ5HUPwW449gb CXGt7HqKywTjVVToO5jXCJ5v2FDNsITb0SVwP660O5EMfdFD5R6CjnxioCnc6XkLuhxL w30RF7Gr6OoGEdcLvVC8V1pfgy7hY4be95nPLxnjZoOsInHP5Kzmsvf1vh5+bhh7/P24 /IiA== X-Forwarded-Encrypted: i=1; AJvYcCUdX5CbpFwuTVJ/wcQ8l5ZnrnJ02jV34dHVyyG6u1E3ScoIM19WhF0mxGojq9iwsKpbBJ0cA/OIK3//Ibg=@vger.kernel.org X-Gm-Message-State: AOJu0YwZgXXgHjT+MRcCmYi+yECT2gaifs/rCQ8uvvUB+UAgZYLK1F5i spEkHl7uClJhl/39ZzHSA/Fr0MKhcnGq8ZB5yRjzcAVMw5tDgj0mU6Avg3/O3dblNN+kO9EcI8u RWAHyUFEbsBbf6JKHvbpZz64BCGlJU+UsbER68f5N/SqmNEelqhGnlbzzRuyupUxHcg== X-Gm-Gg: ASbGncuy5KCX046H0E1xYF+7sarmsjQpTxO7EuwCFbb3MweJljIi7CSCTmQDXic+tPV olC0JRiEPM0HtSDf3b3UNtGPFehRzChOMwRitugP7O8xsvz7iDpMnUk008uOjJjcD/XC974omTC 5d0tc+SSON2g3tylnHeOSytTnpwJaIY0SpDfmPQHauMpIbTw01q47T965teIB6E1I8H1bp7dgqU lNpTOPSie5B3iIbPZTYpHQp3ioCTr9A+/Ngn9OR28npWNlPCJR05y1MUuq/J70DWhHlEXKy/3VI +TpRiRZmUSLaL4XF8lT5zF5UIgrt4S7nRufb79NBrFaGW3SqvkfCEeqBBTcb89wymavBtjwwENS JT0tyejZDpZgKazMNutzV6R8= X-Received: by 2002:a17:902:d2d1:b0:250:411d:fa83 with SMTP id d9443c01a7336-2516dfcccbemr289529855ad.15.1757562085895; Wed, 10 Sep 2025 20:41:25 -0700 (PDT) X-Google-Smtp-Source: AGHT+IHNK+dvhXEwjPbidgExO5vSVEoN4mnn7hiDWFYTbts3RbLRlhWqysKV/H87BRXyKuni3VCG8w== X-Received: by 2002:a17:902:d2d1:b0:250:411d:fa83 with SMTP id d9443c01a7336-2516dfcccbemr289529355ad.15.1757562085362; Wed, 10 Sep 2025 20:41:25 -0700 (PDT) Received: from hu-azarrabi-lv.qualcomm.com (Global_NAT1.qualcomm.com. [129.46.96.20]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-25c3b304f76sm2962275ad.130.2025.09.10.20.41.23 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 10 Sep 2025 20:41:24 -0700 (PDT) From: Amirreza Zarrabi Date: Wed, 10 Sep 2025 20:41:14 -0700 Subject: [PATCH v11 01/11] firmware: qcom: tzmem: export shm_bridge create/delete Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20250910-qcom-tee-using-tee-ss-without-mem-obj-v11-1-520e867b3d74@oss.qualcomm.com> References: <20250910-qcom-tee-using-tee-ss-without-mem-obj-v11-0-520e867b3d74@oss.qualcomm.com> In-Reply-To: <20250910-qcom-tee-using-tee-ss-without-mem-obj-v11-0-520e867b3d74@oss.qualcomm.com> To: Jens Wiklander , Sumit Garg , Bjorn Andersson , Konrad Dybcio , Bartosz Golaszewski , Apurupa Pattapu , Kees Cook , "Gustavo A. R. Silva" , Sumit Semwal , =?utf-8?q?Christian_K=C3=B6nig?= Cc: Harshal Dev , linux-arm-msm@vger.kernel.org, op-tee@lists.trustedfirmware.org, linux-kernel@vger.kernel.org, linux-hardening@vger.kernel.org, dri-devel@lists.freedesktop.org, linaro-mm-sig@lists.linaro.org, linux-doc@vger.kernel.org, Amirreza Zarrabi , Neil Armstrong , Kuldeep Singh X-Mailer: b4 0.13.0 X-Authority-Analysis: v=2.4 cv=eMETjGp1 c=1 sm=1 tr=0 ts=68c244e7 cx=c_pps a=RP+M6JBNLl+fLTcSJhASfg==:117 a=ouPCqIW2jiPt+lZRy3xVPw==:17 a=IkcTkHD0fZMA:10 a=yJojWOMRYYMA:10 a=sWKEhP36mHoA:10 a=KKAkSRfTAAAA:8 a=COk6AnOGAAAA:8 a=EUspDBNiAAAA:8 a=5numxkeOl0lsm_bA3l4A:9 a=QEXdDO2ut3YA:10 a=iS9zxrgQBfv6-_F4QbHw:22 a=cvBusfyB2V15izCimMoJ:22 a=TjNXssC_j7lpFel5tvFf:22 X-Proofpoint-GUID: IWSb531uGe6dA92gSiG-PI6GSDaI1o-N X-Proofpoint-ORIG-GUID: IWSb531uGe6dA92gSiG-PI6GSDaI1o-N X-Proofpoint-Spam-Details-Enc: AW1haW4tMjUwOTA2MDAwMCBTYWx0ZWRfX7jxkyjxXl2TE oOqTsLaq7VKodwfMJ32JeUfC7RlcXvWg96SuERjQu62lHUadHhBCrpM5FEG48B2L2QsQNgTomnU PPKnPKt0RSj4BPp1thDsx8Q+It8l+I5VtR8hBrylMbMANse5cfreqpiBK4RlZwo6HnbmGMzcbkG 2iUzNkhfVYGGXjfIVCaJh0+0R2uzAkiYeIiUw2Bracu6rHv8AaPyiI7GPadElxg1gQKZQx5YUPs XXaK7zZvfb9TeSCITUj+ZXA3y9aPiTuqnE0reVRsZD9f//Ckz3Qvxr5+gxywidGu3AaM2T7dqi+ 7WQIgaMWtvRdp8zizwJLVL8JNEczbSDoE0QYlCOsWR01Ngp6EHEqlIMvfjYj2sBAPrP98nU226g RX/RqH/0 X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1117,Hydra:6.1.9,FMLib:17.12.80.40 definitions=2025-09-10_04,2025-09-10_01,2025-03-28_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 impostorscore=0 priorityscore=1501 malwarescore=0 clxscore=1015 adultscore=0 bulkscore=0 phishscore=0 spamscore=0 suspectscore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.19.0-2507300000 definitions=main-2509060000 Anyone with access to contiguous physical memory should be able to share memory with QTEE using shm_bridge. Tested-by: Neil Armstrong Tested-by: Harshal Dev Reviewed-by: Kuldeep Singh Signed-off-by: Amirreza Zarrabi --- drivers/firmware/qcom/qcom_tzmem.c | 63 ++++++++++++++++++++++++++--= ---- include/linux/firmware/qcom/qcom_tzmem.h | 15 ++++++++ 2 files changed, 67 insertions(+), 11 deletions(-) diff --git a/drivers/firmware/qcom/qcom_tzmem.c b/drivers/firmware/qcom/qco= m_tzmem.c index ea0a35355657..186511ced924 100644 --- a/drivers/firmware/qcom/qcom_tzmem.c +++ b/drivers/firmware/qcom/qcom_tzmem.c @@ -109,7 +109,19 @@ static int qcom_tzmem_init(void) return 0; } =20 -static int qcom_tzmem_init_area(struct qcom_tzmem_area *area) +/** + * qcom_tzmem_shm_bridge_create() - Create a SHM bridge. + * @paddr: Physical address of the memory to share. + * @size: Size of the memory to share. + * @handle: Handle to the SHM bridge. + * + * On platforms that support SHM bridge, this function creates a SHM bridge + * for the given memory region with QTEE. The handle returned by this func= tion + * must be passed to qcom_tzmem_shm_bridge_delete() to free the SHM bridge. + * + * Return: On success, returns 0; on failure, returns < 0. + */ +int qcom_tzmem_shm_bridge_create(phys_addr_t paddr, size_t size, u64 *hand= le) { u64 pfn_and_ns_perm, ipfn_and_s_perm, size_and_flags; int ret; @@ -117,17 +129,49 @@ static int qcom_tzmem_init_area(struct qcom_tzmem_are= a *area) if (!qcom_tzmem_using_shm_bridge) return 0; =20 - pfn_and_ns_perm =3D (u64)area->paddr | QCOM_SCM_PERM_RW; - ipfn_and_s_perm =3D (u64)area->paddr | QCOM_SCM_PERM_RW; - size_and_flags =3D area->size | (1 << QCOM_SHM_BRIDGE_NUM_VM_SHIFT); + pfn_and_ns_perm =3D paddr | QCOM_SCM_PERM_RW; + ipfn_and_s_perm =3D paddr | QCOM_SCM_PERM_RW; + size_and_flags =3D size | (1 << QCOM_SHM_BRIDGE_NUM_VM_SHIFT); + + ret =3D qcom_scm_shm_bridge_create(pfn_and_ns_perm, ipfn_and_s_perm, + size_and_flags, QCOM_SCM_VMID_HLOS, + handle); + if (ret) { + dev_err(qcom_tzmem_dev, + "SHM Bridge failed: ret %d paddr 0x%pa, size %zu\n", + ret, &paddr, size); + + return ret; + } + + return 0; +} +EXPORT_SYMBOL_GPL(qcom_tzmem_shm_bridge_create); + +/** + * qcom_tzmem_shm_bridge_delete() - Delete a SHM bridge. + * @handle: Handle to the SHM bridge. + * + * On platforms that support SHM bridge, this function deletes the SHM bri= dge + * for the given memory region. The handle must be the same as the one + * returned by qcom_tzmem_shm_bridge_create(). + */ +void qcom_tzmem_shm_bridge_delete(u64 handle) +{ + if (qcom_tzmem_using_shm_bridge) + qcom_scm_shm_bridge_delete(handle); +} +EXPORT_SYMBOL_GPL(qcom_tzmem_shm_bridge_delete); + +static int qcom_tzmem_init_area(struct qcom_tzmem_area *area) +{ + int ret; =20 u64 *handle __free(kfree) =3D kzalloc(sizeof(*handle), GFP_KERNEL); if (!handle) return -ENOMEM; =20 - ret =3D qcom_scm_shm_bridge_create(pfn_and_ns_perm, ipfn_and_s_perm, - size_and_flags, QCOM_SCM_VMID_HLOS, - handle); + ret =3D qcom_tzmem_shm_bridge_create(area->paddr, area->size, handle); if (ret) return ret; =20 @@ -140,10 +184,7 @@ static void qcom_tzmem_cleanup_area(struct qcom_tzmem_= area *area) { u64 *handle =3D area->priv; =20 - if (!qcom_tzmem_using_shm_bridge) - return; - - qcom_scm_shm_bridge_delete(*handle); + qcom_tzmem_shm_bridge_delete(*handle); kfree(handle); } =20 diff --git a/include/linux/firmware/qcom/qcom_tzmem.h b/include/linux/firmw= are/qcom/qcom_tzmem.h index b83b63a0c049..48ac0e5454c7 100644 --- a/include/linux/firmware/qcom/qcom_tzmem.h +++ b/include/linux/firmware/qcom/qcom_tzmem.h @@ -53,4 +53,19 @@ DEFINE_FREE(qcom_tzmem, void *, if (_T) qcom_tzmem_free(= _T)) =20 phys_addr_t qcom_tzmem_to_phys(void *ptr); =20 +#if IS_ENABLED(CONFIG_QCOM_TZMEM_MODE_SHMBRIDGE) +int qcom_tzmem_shm_bridge_create(phys_addr_t paddr, size_t size, u64 *hand= le); +void qcom_tzmem_shm_bridge_delete(u64 handle); +#else +static inline int qcom_tzmem_shm_bridge_create(phys_addr_t paddr, + size_t size, u64 *handle) +{ + return 0; +} + +static inline void qcom_tzmem_shm_bridge_delete(u64 handle) +{ +} +#endif + #endif /* __QCOM_TZMEM */ --=20 2.34.1 From nobody Thu Oct 2 20:38:43 2025 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 4B42F23A9AE for ; Thu, 11 Sep 2025 03:41:30 +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=1757562092; cv=none; b=gehz1A4DolbW48QwOobt+5upC8sf+OZePRbCbkykxz5WStvK9tlbgi6Pqz8aiYNY371jtKRG0XquTmLGeTAHNIaM5fH2tb11590UnhL0QtKGfpodv3YCUKLlN9WikebaId/oRFg832rXbvXt5qzvj4w/zqVjKf/VK9XY7yDhpxw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757562092; c=relaxed/simple; bh=YQcEFnOl6kY4qFaLVPv2nJjyrWQl03MYHwKFS3Sg01k=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=NEOyMKUKEaNUPDlNkT4i968ahXoCee9nKuzUt2Z1zLQuvEknpGN4TlJBPNXEqWG75lELFV9U+O6FUZq2tl375E7oYW4Zdbg6HNVdvtQjFcutMhtEaUSlWYDysQtx1qmcyKBf7opG2bBxPUEDvJdVVHvTXF5uTOt+RGztfGpxlHQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=oss.qualcomm.com; spf=pass smtp.mailfrom=oss.qualcomm.com; dkim=pass (2048-bit key) header.d=qualcomm.com header.i=@qualcomm.com header.b=NusHSjON; arc=none smtp.client-ip=205.220.180.131 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=oss.qualcomm.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=oss.qualcomm.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=qualcomm.com header.i=@qualcomm.com header.b="NusHSjON" Received: from pps.filterd (m0279871.ppops.net [127.0.0.1]) by mx0a-0031df01.pphosted.com (8.18.1.2/8.18.1.2) with ESMTP id 58B2IYgS026069 for ; Thu, 11 Sep 2025 03:41:29 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=qualcomm.com; h= cc:content-transfer-encoding:content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to; s=qcppdkim1; bh= NKbqXe7PMoUiJg4m7VYYPBBjDC8LJ5A/UZIjVDLkyUM=; b=NusHSjONBcCZHeO6 NNHtprFSfWfZeWdl6bd7CF6//A2hSDg1yDm2z6KzBrfynLDbcKNLqmeB7kTrwhAg 4v9QCD/rBeVjTh7dbZZIdqTbDyFGbgMVn4/KsH0WTMITAtCtR54omKhMWWvpPdFw twwNg0yzbcjFBNogTU5KNGgbsFLXNxVYPd3I/AGHzvr8gVmq6uVa2yq7XhSGfieP Qok5WUVXNsN5F18iGfhWtawoMBS49tkJmHdA1j8yo55fmXjZM+fgOQyXJz+GszFT 5HDnIHLthlYE0+c+pLRxLtqH+Jt3mSWnWxRhOzxXC3sgh77BJxeNjOE1Yf5WI/ka nJIiiQ== Received: from mail-pl1-f197.google.com (mail-pl1-f197.google.com [209.85.214.197]) by mx0a-0031df01.pphosted.com (PPS) with ESMTPS id 490cj0x2vg-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128 verify=NOT) for ; Thu, 11 Sep 2025 03:41:28 +0000 (GMT) Received: by mail-pl1-f197.google.com with SMTP id d9443c01a7336-25c2a4c20a2so2390315ad.3 for ; Wed, 10 Sep 2025 20:41:28 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1757562087; x=1758166887; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=NKbqXe7PMoUiJg4m7VYYPBBjDC8LJ5A/UZIjVDLkyUM=; b=ONXeClKXr4ojSE6o8UqOCPdlH2UVz3iGn8VrcpWrWc6IvdVBaq3DQzDoetl+u+vCqS y6vTZjF1nyvMwgotqoGbH5gB9WqgpUJTE0cMSxpxuu1o67j4bUa4OZ7cr9l7ZM1ZPNqz IQxn3r7aZgpPjYubr98KUB5Zbf9feCxaTs3dUUXWg+fNVym0RqGXcLGKrjvt8FhsRSku oInpwRGTAKAb03zXxK4RdOaKCnbLIAtDcxfpo3ACq4KwwHaW6Cft0ea6C/Mn1xRIGQI6 aiEbcMPlvbiv7h5UQGXm+bQebX5IApot9Sh9qD4E8kqo/5Sjv6FXpYrgMJYWNrpED/5s qV3Q== X-Forwarded-Encrypted: i=1; AJvYcCW0MEW8vcJWuiTk08rr3VG0Kg0RlUzVRItHcpb1sipOjw6pkZ6+1BUuoUPm3KyHQoI1jH3myJGf8Vjoh3o=@vger.kernel.org X-Gm-Message-State: AOJu0YxGTHTrHjaXKjUmLobmAlUT+u6qr//l8kMNlwolFnwdaBa7WEm/ XHC+8lq+GQP9gqRW9XmTXiBbleTJ7BeXfWm9QkxusGk3KJOcGO1y8k4VmfEdDL7Ratb4ZScwDSA PGZI08chEcmDB1p/LJRfziNjIicL3lNMHvu1piDKxLG2aDB2E556tROpflTyc95gi6A== X-Gm-Gg: ASbGncs5kst0LaxGJncVgmpBXFuhmP3l4qchXZCB6v9CFbsFYfoOboc6NAmtCFyp6Hu 5oDi2Mw9nivk56Xez9LTDZK4u94cwuufYPZkY0FlFy65TT9uMHY6uTwhfFb3JDWmZXMfavjbQrH Uy08qdRAfm53IH5SL2fb0PC+RkW1Y4/NTSRqJM5AnOgzHq0uSnWkFqm8ptJFkBLhNhoh55h41Es hhE+C7lIImCw0CY3yVLlGCz0vnQl1bR4oLJp7n88spW29MF6R/KpRYAaHF4EZhNC3h1ccFJNDrM VNVSmcSBjYd0a5GjRF+m4evbbH2Cy37oqDczGn2c00mcr/xz9yfdAW0HXJTp378omrjWEObqq18 BD/QfDXA3ahbjrW4nLY0/cZ0= X-Received: by 2002:a17:903:38cf:b0:245:f7f3:6760 with SMTP id d9443c01a7336-25175f72ac4mr220641405ad.55.1757562087466; Wed, 10 Sep 2025 20:41:27 -0700 (PDT) X-Google-Smtp-Source: AGHT+IF2kwOIrXlQY9Hp2LbT+Ha1VF4JSti2xLqtCO4iZN0yyVAUste29kkfj5azPlxcC0nrkqPLFA== X-Received: by 2002:a17:903:38cf:b0:245:f7f3:6760 with SMTP id d9443c01a7336-25175f72ac4mr220641085ad.55.1757562086931; Wed, 10 Sep 2025 20:41:26 -0700 (PDT) Received: from hu-azarrabi-lv.qualcomm.com (Global_NAT1.qualcomm.com. [129.46.96.20]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-25c3b304f76sm2962275ad.130.2025.09.10.20.41.25 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 10 Sep 2025 20:41:26 -0700 (PDT) From: Amirreza Zarrabi Date: Wed, 10 Sep 2025 20:41:15 -0700 Subject: [PATCH v11 02/11] firmware: qcom: scm: add support for object invocation Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20250910-qcom-tee-using-tee-ss-without-mem-obj-v11-2-520e867b3d74@oss.qualcomm.com> References: <20250910-qcom-tee-using-tee-ss-without-mem-obj-v11-0-520e867b3d74@oss.qualcomm.com> In-Reply-To: <20250910-qcom-tee-using-tee-ss-without-mem-obj-v11-0-520e867b3d74@oss.qualcomm.com> To: Jens Wiklander , Sumit Garg , Bjorn Andersson , Konrad Dybcio , Bartosz Golaszewski , Apurupa Pattapu , Kees Cook , "Gustavo A. R. Silva" , Sumit Semwal , =?utf-8?q?Christian_K=C3=B6nig?= Cc: Harshal Dev , linux-arm-msm@vger.kernel.org, op-tee@lists.trustedfirmware.org, linux-kernel@vger.kernel.org, linux-hardening@vger.kernel.org, dri-devel@lists.freedesktop.org, linaro-mm-sig@lists.linaro.org, linux-doc@vger.kernel.org, Amirreza Zarrabi , Neil Armstrong X-Mailer: b4 0.13.0 X-Proofpoint-ORIG-GUID: MK8myNe5DEsDcaqA9kdFWhLMtE_xkMK3 X-Proofpoint-GUID: MK8myNe5DEsDcaqA9kdFWhLMtE_xkMK3 X-Proofpoint-Spam-Details-Enc: AW1haW4tMjUwOTA2MDAyNCBTYWx0ZWRfX4C0tYaqmqU8Z yBI+rY8XcML9Glh9A9CBa6a1sWsHloErfBEsNCHRISD0JFxPW1DZYllUgnQ7+PMxvY9Kt+Mmy8x 5ENuFiXI7nfm/M+EdV7lIvNkET0f8iKTkw/WMUiIvDoG0VG3t625l686wW0+Is6/lQvJmX+Ilii TrOPV6l73qcBKE7oePiihnNVEVdy4J6DX52HkaJcSsxdF2IzBPbaTm+Y0OP9U/hss+1IM6LYfW1 ppgLD/gOQYVIchWSpwBIsJOjnXUkYNt+6VPSV4eTPCdVSCT81A6K/cgfhITdacuZhSC+iJzJmMS 0CTUKW0yRN2vVBZJ/dZhl3GxH+YqAFypekFNE7CCm00kxsbYtBBNnwMmuUzDZiZwpAfsZVqPKYN mgpT1nvH X-Authority-Analysis: v=2.4 cv=QeFmvtbv c=1 sm=1 tr=0 ts=68c244e8 cx=c_pps a=cmESyDAEBpBGqyK7t0alAg==:117 a=ouPCqIW2jiPt+lZRy3xVPw==:17 a=IkcTkHD0fZMA:10 a=yJojWOMRYYMA:10 a=KKAkSRfTAAAA:8 a=COk6AnOGAAAA:8 a=EUspDBNiAAAA:8 a=dBYAKgxw8cyf2mnx-aAA:9 a=QEXdDO2ut3YA:10 a=1OuFwYUASf3TG4hYMiVC:22 a=cvBusfyB2V15izCimMoJ:22 a=TjNXssC_j7lpFel5tvFf:22 X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1117,Hydra:6.1.9,FMLib:17.12.80.40 definitions=2025-09-10_04,2025-09-10_01,2025-03-28_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 phishscore=0 priorityscore=1501 clxscore=1015 spamscore=0 impostorscore=0 bulkscore=0 suspectscore=0 adultscore=0 malwarescore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.19.0-2507300000 definitions=main-2509060024 Qualcomm TEE (QTEE) hosts Trusted Applications (TAs) and services in the secure world, accessed via objects. A QTEE client can invoke these objects to request services. Similarly, QTEE can request services from the nonsecure world using objects exported to the secure world. Add low-level primitives to facilitate the invocation of objects hosted in QTEE, as well as those hosted in the nonsecure world. If support for object invocation is available, the qcom_scm allocates a dedicated child platform device. The driver for this device communicates with QTEE using low-level primitives. Tested-by: Neil Armstrong Tested-by: Harshal Dev Signed-off-by: Amirreza Zarrabi --- drivers/firmware/qcom/qcom_scm.c | 119 +++++++++++++++++++++++++++++= ++++ drivers/firmware/qcom/qcom_scm.h | 7 ++ include/linux/firmware/qcom/qcom_scm.h | 6 ++ 3 files changed, 132 insertions(+) diff --git a/drivers/firmware/qcom/qcom_scm.c b/drivers/firmware/qcom/qcom_= scm.c index 26cd0458aacd..9b5a9a0f68cf 100644 --- a/drivers/firmware/qcom/qcom_scm.c +++ b/drivers/firmware/qcom/qcom_scm.c @@ -2093,6 +2093,122 @@ static int qcom_scm_qseecom_init(struct qcom_scm *s= cm) =20 #endif /* CONFIG_QCOM_QSEECOM */ =20 +/** + * qcom_scm_qtee_invoke_smc() - Invoke a QTEE object. + * @inbuf: start address of memory area used for inbound buffer. + * @inbuf_size: size of the memory area used for inbound buffer. + * @outbuf: start address of memory area used for outbound buffer. + * @outbuf_size: size of the memory area used for outbound buffer. + * @result: result of QTEE object invocation. + * @response_type: response type returned by QTEE. + * + * @response_type determines how the contents of @inbuf and @outbuf + * should be processed. + * + * Return: On success, return 0 or <0 on failure. + */ +int qcom_scm_qtee_invoke_smc(phys_addr_t inbuf, size_t inbuf_size, + phys_addr_t outbuf, size_t outbuf_size, + u64 *result, u64 *response_type) +{ + struct qcom_scm_desc desc =3D { + .svc =3D QCOM_SCM_SVC_SMCINVOKE, + .cmd =3D QCOM_SCM_SMCINVOKE_INVOKE, + .owner =3D ARM_SMCCC_OWNER_TRUSTED_OS, + .args[0] =3D inbuf, + .args[1] =3D inbuf_size, + .args[2] =3D outbuf, + .args[3] =3D outbuf_size, + .arginfo =3D QCOM_SCM_ARGS(4, QCOM_SCM_RW, QCOM_SCM_VAL, + QCOM_SCM_RW, QCOM_SCM_VAL), + }; + struct qcom_scm_res res; + int ret; + + ret =3D qcom_scm_call(__scm->dev, &desc, &res); + if (ret) + return ret; + + if (response_type) + *response_type =3D res.result[0]; + + if (result) + *result =3D res.result[1]; + + return 0; +} +EXPORT_SYMBOL(qcom_scm_qtee_invoke_smc); + +/** + * qcom_scm_qtee_callback_response() - Submit response for callback reques= t. + * @buf: start address of memory area used for outbound buffer. + * @buf_size: size of the memory area used for outbound buffer. + * @result: Result of QTEE object invocation. + * @response_type: Response type returned by QTEE. + * + * @response_type determines how the contents of @buf should be processed. + * + * Return: On success, return 0 or <0 on failure. + */ +int qcom_scm_qtee_callback_response(phys_addr_t buf, size_t buf_size, + u64 *result, u64 *response_type) +{ + struct qcom_scm_desc desc =3D { + .svc =3D QCOM_SCM_SVC_SMCINVOKE, + .cmd =3D QCOM_SCM_SMCINVOKE_CB_RSP, + .owner =3D ARM_SMCCC_OWNER_TRUSTED_OS, + .args[0] =3D buf, + .args[1] =3D buf_size, + .arginfo =3D QCOM_SCM_ARGS(2, QCOM_SCM_RW, QCOM_SCM_VAL), + }; + struct qcom_scm_res res; + int ret; + + ret =3D qcom_scm_call(__scm->dev, &desc, &res); + if (ret) + return ret; + + if (response_type) + *response_type =3D res.result[0]; + + if (result) + *result =3D res.result[1]; + + return 0; +} +EXPORT_SYMBOL(qcom_scm_qtee_callback_response); + +static void qcom_scm_qtee_free(void *data) +{ + struct platform_device *qtee_dev =3D data; + + platform_device_unregister(qtee_dev); +} + +static void qcom_scm_qtee_init(struct qcom_scm *scm) +{ + struct platform_device *qtee_dev; + u64 result, response_type; + int ret; + + /* + * Probe for smcinvoke support. This will fail due to invalid buffers, + * but first, it checks whether the call is supported in QTEE syscall + * handler. If it is not supported, -EIO is returned. + */ + ret =3D qcom_scm_qtee_invoke_smc(0, 0, 0, 0, &result, &response_type); + if (ret =3D=3D -EIO) + return; + + /* Setup QTEE interface device. */ + qtee_dev =3D platform_device_register_data(scm->dev, "qcomtee", + PLATFORM_DEVID_NONE, NULL, 0); + if (IS_ERR(qtee_dev)) + return; + + devm_add_action_or_reset(scm->dev, qcom_scm_qtee_free, qtee_dev); +} + /** * qcom_scm_is_available() - Checks if SCM is available */ @@ -2325,6 +2441,9 @@ static int qcom_scm_probe(struct platform_device *pde= v) ret =3D qcom_scm_qseecom_init(scm); WARN(ret < 0, "failed to initialize qseecom: %d\n", ret); =20 + /* Initialize the QTEE object interface. */ + qcom_scm_qtee_init(scm); + return 0; } =20 diff --git a/drivers/firmware/qcom/qcom_scm.h b/drivers/firmware/qcom/qcom_= scm.h index 0e8dd838099e..a56c8212cc0c 100644 --- a/drivers/firmware/qcom/qcom_scm.h +++ b/drivers/firmware/qcom/qcom_scm.h @@ -156,6 +156,13 @@ int qcom_scm_shm_bridge_enable(struct device *scm_dev); #define QCOM_SCM_SVC_GPU 0x28 #define QCOM_SCM_SVC_GPU_INIT_REGS 0x01 =20 +/* ARM_SMCCC_OWNER_TRUSTED_OS calls */ + +#define QCOM_SCM_SVC_SMCINVOKE 0x06 +#define QCOM_SCM_SMCINVOKE_INVOKE_LEGACY 0x00 +#define QCOM_SCM_SMCINVOKE_CB_RSP 0x01 +#define QCOM_SCM_SMCINVOKE_INVOKE 0x02 + /* common error codes */ #define QCOM_SCM_V2_EBUSY -12 #define QCOM_SCM_ENOMEM -5 diff --git a/include/linux/firmware/qcom/qcom_scm.h b/include/linux/firmwar= e/qcom/qcom_scm.h index 0f667bf1d4d9..a55ca771286b 100644 --- a/include/linux/firmware/qcom/qcom_scm.h +++ b/include/linux/firmware/qcom/qcom_scm.h @@ -175,4 +175,10 @@ static inline int qcom_scm_qseecom_app_send(u32 app_id, =20 #endif /* CONFIG_QCOM_QSEECOM */ =20 +int qcom_scm_qtee_invoke_smc(phys_addr_t inbuf, size_t inbuf_size, + phys_addr_t outbuf, size_t outbuf_size, + u64 *result, u64 *response_type); +int qcom_scm_qtee_callback_response(phys_addr_t buf, size_t buf_size, + u64 *result, u64 *response_type); + #endif --=20 2.34.1 From nobody Thu Oct 2 20:38:43 2025 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 906E623BD02 for ; Thu, 11 Sep 2025 03:41:30 +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=1757562092; cv=none; b=j7E5qpcY9/q9gtjQZhEPjmaUA+wAiPUkTSUrJUGekd98JPHtF+yKGrHa05TZWq/2SBt1DRMyBcmtYp1xFj61N1JYwinTP2D59mKTYEhcLYUX4lClQJxj5fQAGf/WHoOTDb7x/P7mFlSK7Gmpeu2ps4h263Ajoe774N2Y24eMWDY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757562092; c=relaxed/simple; bh=PlNtUBn1m92e6j1roGLFXzYvk2/0ghYLEgBgH8NcnDA=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=HCwF6f8PfD6LrmKU9ZMp7SlTFSSr5tnXqOTY7OiONyJT7I27WF1xIsTQWGLPeDek4uLrP5M6t92DT4DyZ3qLWfQO5xollEa99NaWVxz0evg2GMj9kuAgDycC38oA/s/lPgT/lis+OLT3NkUcgBZQ9s9Ore/Jkqoak+bjuMvdELU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=oss.qualcomm.com; spf=pass smtp.mailfrom=oss.qualcomm.com; dkim=pass (2048-bit key) header.d=qualcomm.com header.i=@qualcomm.com header.b=O88QfUT9; arc=none smtp.client-ip=205.220.168.131 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=oss.qualcomm.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=oss.qualcomm.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=qualcomm.com header.i=@qualcomm.com header.b="O88QfUT9" 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 58B2IgR3026922 for ; Thu, 11 Sep 2025 03:41:30 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=qualcomm.com; h= cc:content-transfer-encoding:content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to; s=qcppdkim1; bh= 0cy7zuNmWldsjxlDI+hNSLQe922ofh0kNWkW6uU0Hx8=; b=O88QfUT9GmAis5Ps Rd3Etve6sOMnGsOB1PoKeD8JHjerLUfP2tnBbArzZBPIyEuWUNXDvA90enzHZYIM jMDje6iPstBEmlMOQI0rDe8TGPMgSQ66X/hLrnByK0zob7QCeJHlUHP9PVPKnzPa RcC3Kvr248vdGcBYGqIDecQvOTyole3a9jungNRYUt4VFw+5F8QTQ82+JovIV5pY Q35cY677ctHy0L3+qubkkYTiZmCVZGMj9qJzY3hk0rLj6eOLDtL7r96VEgfcCR7M NMOtOdB5Fw0DLtcxbWyCJXKdIZuppx/BaG4rEIlxKmTIeUcbY8MEURsYwd/HohAH F8hwkg== Received: from mail-pl1-f197.google.com (mail-pl1-f197.google.com [209.85.214.197]) by mx0a-0031df01.pphosted.com (PPS) with ESMTPS id 493f6h14e0-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128 verify=NOT) for ; Thu, 11 Sep 2025 03:41:29 +0000 (GMT) Received: by mail-pl1-f197.google.com with SMTP id d9443c01a7336-24b0e137484so2429225ad.0 for ; Wed, 10 Sep 2025 20:41:29 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1757562089; x=1758166889; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=0cy7zuNmWldsjxlDI+hNSLQe922ofh0kNWkW6uU0Hx8=; b=SX9fYvLAl2GkN7oM6NMdWPMdFGaNK6c6i/iFWJAaLTK9PXV+glfrSOxfugZta9RlVI 2i2WMNt+5QKMMTqyM7LSYHw6cvh67ZbjCPBKvq+d06kzaRWLf6LctjlFPAhtwJa7TxRw QQzGKrtO62wUnVCVfIiQFyuDXuhm7rGHktVWfpXV3OpfGefZzi0CC0r3xdiODwBVRSuW RXvZ5rNGbtGsyZTy/mllyHj7Q5OHe9fVLKvufO+4mq7VDjyk6NSBN/SYrrphmvbTmCYE e84RbbxR3ZqeKQXei+1EZWbfaUkNzznzgUlQ+Twb5E5Nm4mF9Jhr7NwJxhyt5XWxvT2J h0ZA== X-Forwarded-Encrypted: i=1; AJvYcCXXQmhFNh6HBDLl7gHjfiwrwjzcc4AXJzcL4p+8w0/TTF/Tl/xTJ627SbEHmqNouVoJDzRnGmvAVl2GrTI=@vger.kernel.org X-Gm-Message-State: AOJu0YyccxynF4/6pA2w9ohniNb0C3RS2M0vnNW1WuJJ8s5n7bRTa+Tz nkVfezvrbuw5DdVMrucvDalDir8ivZBazV5Jz6Lu9OD7SfvQD7tO6ImPy2nQ6eLFxVdhI3+MciR rXMOnxHDx8xnG8sQRTDYG5tHHOGCFeAWG+s7IccdFToATFt3IeyS9QquxwXIwlgN6tA== X-Gm-Gg: ASbGncs40cHqnD7Ih/UUAf5NEfzjWVviYLSvdcfka15s+eMzA30+2DE/r485KcCiGfZ O9Z8xD8D4KF48YWe27jSJWEMwyqsoIL9tZ8JI/sMpRWNBvVQlotslX0ACtKq4PJmFBUL/xqjzB/ p78h+MMVdOgoxTYmOCr1tP48a/v+8H0fGOQm8gn1mJht2Q7sufguvOYtFeG++AgUSY+RsJIHH66 IIdLIBfoCy0iML84rulXMIA3i9vvDFeThhySY7zNcWEO04yhBPj10ixEY9LbJaKCuZjOJRFqjuA XpeULSjqR0qrEcQi9EEPYqtmAmlLHsuDFaOkma2YT33NC4JKh1JlsXcmKv//mSQ4QJkGvXxw+r6 3zypGlGrrX8/tPj/w+Ysn2HA= X-Received: by 2002:a17:903:2b04:b0:24e:13f6:22d with SMTP id d9443c01a7336-251722929d4mr290434575ad.36.1757562088990; Wed, 10 Sep 2025 20:41:28 -0700 (PDT) X-Google-Smtp-Source: AGHT+IHKhpZZ7QQ2u4bajGkkm1KKWLUYyswJaL/iiPppE3MndRE8NjcBrWi4HRB5LTZP40i4NipFKg== X-Received: by 2002:a17:903:2b04:b0:24e:13f6:22d with SMTP id d9443c01a7336-251722929d4mr290434315ad.36.1757562088589; Wed, 10 Sep 2025 20:41:28 -0700 (PDT) Received: from hu-azarrabi-lv.qualcomm.com (Global_NAT1.qualcomm.com. [129.46.96.20]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-25c3b304f76sm2962275ad.130.2025.09.10.20.41.27 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 10 Sep 2025 20:41:27 -0700 (PDT) From: Amirreza Zarrabi Date: Wed, 10 Sep 2025 20:41:16 -0700 Subject: [PATCH v11 03/11] tee: allow a driver to allocate a tee_device without a pool Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20250910-qcom-tee-using-tee-ss-without-mem-obj-v11-3-520e867b3d74@oss.qualcomm.com> References: <20250910-qcom-tee-using-tee-ss-without-mem-obj-v11-0-520e867b3d74@oss.qualcomm.com> In-Reply-To: <20250910-qcom-tee-using-tee-ss-without-mem-obj-v11-0-520e867b3d74@oss.qualcomm.com> To: Jens Wiklander , Sumit Garg , Bjorn Andersson , Konrad Dybcio , Bartosz Golaszewski , Apurupa Pattapu , Kees Cook , "Gustavo A. R. Silva" , Sumit Semwal , =?utf-8?q?Christian_K=C3=B6nig?= Cc: Harshal Dev , linux-arm-msm@vger.kernel.org, op-tee@lists.trustedfirmware.org, linux-kernel@vger.kernel.org, linux-hardening@vger.kernel.org, dri-devel@lists.freedesktop.org, linaro-mm-sig@lists.linaro.org, linux-doc@vger.kernel.org, Amirreza Zarrabi , Sumit Garg X-Mailer: b4 0.13.0 X-Proofpoint-ORIG-GUID: RVWQWNm_PngR250L30btTq1ytBDTj0Fv X-Proofpoint-Spam-Details-Enc: AW1haW4tMjUwOTEwMDE3NyBTYWx0ZWRfX6DyaB7zmdniM 3rcC360905XtAb9xvtXHAGHl1Fw+vv/kvZqaPND9hV+Phfxp0nuvaBcqXa86k8kqLpd6bOGENkK 3dhDhjCp29C95Q4G+MOV7YBmvwPKurC1nfjVvziOeCYkr1B/oalPA7kuoIyMz6U0Y1StzsvNbb5 w4kWgv8m8lJGjGnZ2dKlmXasLSZ5qpuExqodJCgsaofg2SjdJS6IUH8h8wL3n4x9y4s2SCV+u9K 6xmEpC+MnHir9JS59G+aQ7bevBu2wuh9DgeRbZr8OULwgsBmTplZKZk/Yw2xM9gZ7sD8nT3qK74 spfjX6/fbBjxgKFAaLLzH968aTbVm7OVO7Tqa3vRff4C03ICc0D5R+KVU1Eou/X1loondh6Og3u 2B/zLVPt X-Authority-Analysis: v=2.4 cv=WPB/XmsR c=1 sm=1 tr=0 ts=68c244e9 cx=c_pps a=cmESyDAEBpBGqyK7t0alAg==:117 a=ouPCqIW2jiPt+lZRy3xVPw==:17 a=IkcTkHD0fZMA:10 a=yJojWOMRYYMA:10 a=EUspDBNiAAAA:8 a=1atmPuGhRQHGwWkYLZIA:9 a=QEXdDO2ut3YA:10 a=1OuFwYUASf3TG4hYMiVC:22 X-Proofpoint-GUID: RVWQWNm_PngR250L30btTq1ytBDTj0Fv X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1117,Hydra:6.1.9,FMLib:17.12.80.40 definitions=2025-09-10_04,2025-09-10_01,2025-03-28_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 impostorscore=0 spamscore=0 clxscore=1015 priorityscore=1501 adultscore=0 bulkscore=0 phishscore=0 suspectscore=0 malwarescore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.19.0-2507300000 definitions=main-2509100177 A TEE driver doesn't always need to provide a pool if it doesn't support memory sharing ioctls and can allocate memory for TEE messages in another way. Although this is mentioned in the documentation for tee_device_alloc(), it is not handled correctly. Reviewed-by: Sumit Garg Signed-off-by: Amirreza Zarrabi --- drivers/tee/tee_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tee/tee_core.c b/drivers/tee/tee_core.c index 807317d7b3c5..9fa042d80622 100644 --- a/drivers/tee/tee_core.c +++ b/drivers/tee/tee_core.c @@ -926,7 +926,7 @@ struct tee_device *tee_device_alloc(const struct tee_de= sc *teedesc, =20 if (!teedesc || !teedesc->name || !teedesc->ops || !teedesc->ops->get_version || !teedesc->ops->open || - !teedesc->ops->release || !pool) + !teedesc->ops->release) return ERR_PTR(-EINVAL); =20 teedev =3D kzalloc(sizeof(*teedev), GFP_KERNEL); --=20 2.34.1 From nobody Thu Oct 2 20:38:43 2025 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 C4260239E81 for ; Thu, 11 Sep 2025 03:41:33 +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=1757562095; cv=none; b=GI+BX1l8wxsky0dsl52mbXibEjMbOg/WmMnZPwi2QeU9nCCeILr2yYOXQ2Xr2DJacadualIvk7U8fhiFeQu93KXlFMvK58MPo1w3nRdpWuXllRKu+QkAZXHS9ZKgMAuT/7ZFQIajj2fak7x8QfAiz8di597YPkizyU/35RL8wsk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757562095; c=relaxed/simple; bh=/X/slCEZNUYsN1/1Kb6qKCBb1SuAXT+Ssp2opHduLeg=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=ZI8Kmo9Suq1lAEWv+iLAwkoS2iWK1Fc9FQ/LMmdG/LHfG5YdzSeN5tuR2wRCEXs1e1nybEC4EUh1C4wY6Wqi5+cPHhjiPD95ZK6c3tjBW9D48L6I15ROCq/bS/ByB2NJG2WN8WWOZt4YWfoZStkgbJo5OMK2mWRRgu9wfX4ZITM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=oss.qualcomm.com; spf=pass smtp.mailfrom=oss.qualcomm.com; dkim=pass (2048-bit key) header.d=qualcomm.com header.i=@qualcomm.com header.b=GeVnbJLw; arc=none smtp.client-ip=205.220.180.131 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=oss.qualcomm.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=oss.qualcomm.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=qualcomm.com header.i=@qualcomm.com header.b="GeVnbJLw" Received: from pps.filterd (m0279871.ppops.net [127.0.0.1]) by mx0a-0031df01.pphosted.com (8.18.1.2/8.18.1.2) with ESMTP id 58B2IoKe026350 for ; Thu, 11 Sep 2025 03:41:32 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=qualcomm.com; h= cc:content-transfer-encoding:content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to; s=qcppdkim1; bh= lfnro9xo+EarbMqRFrPWzRQwLLoVHW/MmAqB1i9xt2Q=; b=GeVnbJLw5Qb6NLSF K+I9V5+6UJzRozu1AVPFBHRNBqFo/xlaP1Tun07LFpSzEWQZd+6eTTDHr5cvOZds OcoGnhLN4RRqeI//u/tzlMGRrFuCT/ZAd1PTTCPJJX37+sv2kQEjBzk7FlZxMrik CUNe/UHqQdJu8MWGN6vAQIiEtJI+v2zbsAdxQDunPPvnbdbkg0YXcHxWsX54gb4R HupxtCml0LK7/uaI/QqLMd4kzlFcUL9dKBV+qSwdSNswl3otScZYV1VrhBNnpISv gnBnjERXypPPCL7T6HaWIJ5eHjoM7g5Bx35bpGBN0nCqBtAyAfSJ8Ui0x7t9L+As 9uoJ8g== Received: from mail-pl1-f199.google.com (mail-pl1-f199.google.com [209.85.214.199]) by mx0a-0031df01.pphosted.com (PPS) with ESMTPS id 490cj0x2vq-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128 verify=NOT) for ; Thu, 11 Sep 2025 03:41:32 +0000 (GMT) Received: by mail-pl1-f199.google.com with SMTP id d9443c01a7336-24e04a4f706so2871985ad.2 for ; Wed, 10 Sep 2025 20:41:32 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1757562091; x=1758166891; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=lfnro9xo+EarbMqRFrPWzRQwLLoVHW/MmAqB1i9xt2Q=; b=SPSKI9K5ytpX93iriTFgGOP1x5E3QCoiE+RVp1hy6vWOdXqtAdnLe0B+Pv1ajLqrtf XE6J2c9qJvwS1/iCiZ/yn0sjHSyLjhmnbIKg9ubFFJYPmePXvIyvcntdALXtejsEBQyc hk87BH8b/3kossLeEWLgMQuOylgJhk188vCO4+vxyD6LzRXKRww5Hc8ZMmXqznUfJEto jZwqdEs4goENMW64JWFpOpP6Tz+4R5KJablM0yzwdarCNlh3AGFajrKponI60V8uVp+r +mtFhWihbORUA69Dr0MzYjvZtfrAweXavc3w9b//vW0Dc0Zduvvn+QOaeVD2Y6nx09Qw vaIA== X-Forwarded-Encrypted: i=1; AJvYcCXn2s+6pKCvnTUWXix9U7JV4fFHnmqmUgjLgXSI9k9nnUu6sSmZ0Eo76+ghmP3zhRET+XR0dgNBmhf2GTw=@vger.kernel.org X-Gm-Message-State: AOJu0YyUZMMYmc5c4tz9bXoFl+Zrgp/OtFYxPjOHz3nuXWxias5KOEZ0 Q8PPq6iNjJfPllddJm8ATtV7GET7/sKG27DvnRLatXFv+c6ZXSOR+xT/fc1RLeSPcqkV4kV+YtJ ycrg9gW+TdRW3+pnZ0WVai9m5vdlNwunWdTdaEz4txNW1J3zTZG9Tv9fCd2BVt1+/AA== X-Gm-Gg: ASbGnct3yc1NVvTRfxBkFU3LNf03+6/eUpZi/sGBcb16fRV0NY/BT8Z9kc2AfgG8myd 2EPIk7Wsp+IzMbG0BzrwNhQhvRFW0ef2C/ZFSeILS7r8aKURtzBTnOMBHWQslcAjLz32yUteZdJ +cn8/tx+lzGheW61NYBgouM3cwUhZyZZIfbXBpXaZtIpM6heJe5BS4CzlExBkdzBMqYYFKjKwLg HQdPOnMzMVEbXe6uzVCFfxDCY3Ymk8ixgquTBmg6we4fIHzoXu02Ri/3R3aU/Ict9ebDQCeVTUU /WbvcNRfsKKTa/TwZxgnL9JZ+0RPMHfCYqxOBLuBLHAjX5XCQcPPpXhyM122UiMTB3F3YQgCU7r TmarZsSb2b7knQ+NnJAq+ftY= X-Received: by 2002:a17:902:f681:b0:250:74b2:a840 with SMTP id d9443c01a7336-25172483a34mr238752935ad.44.1757562090723; Wed, 10 Sep 2025 20:41:30 -0700 (PDT) X-Google-Smtp-Source: AGHT+IH2b0ipDRDvZkbzduHPtXWYapgLH3UaQWL1xsBCUzaccisMS56SSp8yl7NyLyuUuiRKSMRPXg== X-Received: by 2002:a17:902:f681:b0:250:74b2:a840 with SMTP id d9443c01a7336-25172483a34mr238752765ad.44.1757562090085; Wed, 10 Sep 2025 20:41:30 -0700 (PDT) Received: from hu-azarrabi-lv.qualcomm.com (Global_NAT1.qualcomm.com. [129.46.96.20]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-25c3b304f76sm2962275ad.130.2025.09.10.20.41.28 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 10 Sep 2025 20:41:29 -0700 (PDT) From: Amirreza Zarrabi Date: Wed, 10 Sep 2025 20:41:17 -0700 Subject: [PATCH v11 04/11] tee: add close_context to TEE driver operation Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20250910-qcom-tee-using-tee-ss-without-mem-obj-v11-4-520e867b3d74@oss.qualcomm.com> References: <20250910-qcom-tee-using-tee-ss-without-mem-obj-v11-0-520e867b3d74@oss.qualcomm.com> In-Reply-To: <20250910-qcom-tee-using-tee-ss-without-mem-obj-v11-0-520e867b3d74@oss.qualcomm.com> To: Jens Wiklander , Sumit Garg , Bjorn Andersson , Konrad Dybcio , Bartosz Golaszewski , Apurupa Pattapu , Kees Cook , "Gustavo A. R. Silva" , Sumit Semwal , =?utf-8?q?Christian_K=C3=B6nig?= Cc: Harshal Dev , linux-arm-msm@vger.kernel.org, op-tee@lists.trustedfirmware.org, linux-kernel@vger.kernel.org, linux-hardening@vger.kernel.org, dri-devel@lists.freedesktop.org, linaro-mm-sig@lists.linaro.org, linux-doc@vger.kernel.org, Amirreza Zarrabi , Sumit Garg , Neil Armstrong X-Mailer: b4 0.13.0 X-Proofpoint-ORIG-GUID: aEjSVoY2Me5yjPQWK5q8uWCelg7ql0GY X-Proofpoint-GUID: aEjSVoY2Me5yjPQWK5q8uWCelg7ql0GY X-Proofpoint-Spam-Details-Enc: AW1haW4tMjUwOTA2MDAyNCBTYWx0ZWRfX/ybCRPWMz7mX ATEQv0XOwjJTcYmvIsHa1WzvJtpi566sCuhWRAlZu64xYv2iBuq+7kshKRYdZYTP4GkjAiKpvoe pXWAGJl57Q3DHwHkz5Gdqh9yA9PDr/Bf/hVL8+MZ4aEWgDhdq4JqC2IiQWi9t+NhZjBhHZCNiMJ CiRIUmvbiMeVqdEzXlTgafNzw8p+tG6ULC6SjdvXaPds1STykDFwA+udfvh2tJ+Gu0SGNNV+cTK BHu7DU7nfXdbMqdmPxlxZ20cYXaOeuettFDIaXV/XjXlum1/nqNcLqJnoV0DYLlVZ/1Dcf+E/Wr TxGf0ROaeSK9jT8LD/nlfmAwJpwtjIbDr3smgcZqZoquWuGPsWtgK080fBAzv0+WbsqpSgKIeof ju3L4TfH X-Authority-Analysis: v=2.4 cv=QeFmvtbv c=1 sm=1 tr=0 ts=68c244ec cx=c_pps a=JL+w9abYAAE89/QcEU+0QA==:117 a=ouPCqIW2jiPt+lZRy3xVPw==:17 a=IkcTkHD0fZMA:10 a=yJojWOMRYYMA:10 a=EUspDBNiAAAA:8 a=KKAkSRfTAAAA:8 a=COk6AnOGAAAA:8 a=0l_YNDiMcOfTHwIteTYA:9 a=QEXdDO2ut3YA:10 a=324X-CrmTo6CU4MGRt3R:22 a=cvBusfyB2V15izCimMoJ:22 a=TjNXssC_j7lpFel5tvFf:22 X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1117,Hydra:6.1.9,FMLib:17.12.80.40 definitions=2025-09-10_04,2025-09-10_01,2025-03-28_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 phishscore=0 priorityscore=1501 clxscore=1015 spamscore=0 impostorscore=0 bulkscore=0 suspectscore=0 adultscore=0 malwarescore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.19.0-2507300000 definitions=main-2509060024 The tee_context can be used to manage TEE user resources, including those allocated by the driver for the TEE on behalf of the user. The release() callback is invoked only when all resources, such as tee_shm, are released and there are no references to the tee_context. When a user closes the device file, the driver should notify the TEE to release any resources it may hold and drop the context references. To achieve this, a close_context() callback is introduced to initiate resource release in the TEE driver when the device file is closed. Relocate teedev_ctx_get, teedev_ctx_put, tee_device_get, and tee_device_get functions to tee_core.h to make them accessible outside the TEE subsystem. Reviewed-by: Sumit Garg Tested-by: Neil Armstrong Tested-by: Harshal Dev Signed-off-by: Amirreza Zarrabi --- drivers/tee/tee_core.c | 7 +++++++ drivers/tee/tee_private.h | 6 ------ include/linux/tee_core.h | 50 +++++++++++++++++++++++++++++++++++++++++++= ++-- 3 files changed, 55 insertions(+), 8 deletions(-) diff --git a/drivers/tee/tee_core.c b/drivers/tee/tee_core.c index 9fa042d80622..f8534a00c56c 100644 --- a/drivers/tee/tee_core.c +++ b/drivers/tee/tee_core.c @@ -79,6 +79,7 @@ void teedev_ctx_get(struct tee_context *ctx) =20 kref_get(&ctx->refcount); } +EXPORT_SYMBOL_GPL(teedev_ctx_get); =20 static void teedev_ctx_release(struct kref *ref) { @@ -96,11 +97,15 @@ void teedev_ctx_put(struct tee_context *ctx) =20 kref_put(&ctx->refcount, teedev_ctx_release); } +EXPORT_SYMBOL_GPL(teedev_ctx_put); =20 void teedev_close_context(struct tee_context *ctx) { struct tee_device *teedev =3D ctx->teedev; =20 + if (teedev->desc->ops->close_context) + teedev->desc->ops->close_context(ctx); + teedev_ctx_put(ctx); tee_device_put(teedev); } @@ -1075,6 +1080,7 @@ void tee_device_put(struct tee_device *teedev) } mutex_unlock(&teedev->mutex); } +EXPORT_SYMBOL_GPL(tee_device_put); =20 bool tee_device_get(struct tee_device *teedev) { @@ -1087,6 +1093,7 @@ bool tee_device_get(struct tee_device *teedev) mutex_unlock(&teedev->mutex); return true; } +EXPORT_SYMBOL_GPL(tee_device_get); =20 /** * tee_device_unregister() - Removes a TEE device diff --git a/drivers/tee/tee_private.h b/drivers/tee/tee_private.h index a9b5e4a6a8f7..6bde688bfcb1 100644 --- a/drivers/tee/tee_private.h +++ b/drivers/tee/tee_private.h @@ -23,12 +23,6 @@ struct tee_shm_dmabuf_ref { =20 int tee_shm_get_fd(struct tee_shm *shm); =20 -bool tee_device_get(struct tee_device *teedev); -void tee_device_put(struct tee_device *teedev); - -void teedev_ctx_get(struct tee_context *ctx); -void teedev_ctx_put(struct tee_context *ctx); - struct tee_shm *tee_shm_alloc_user_buf(struct tee_context *ctx, size_t siz= e); struct tee_shm *tee_shm_register_user_buf(struct tee_context *ctx, unsigned long addr, size_t length); diff --git a/include/linux/tee_core.h b/include/linux/tee_core.h index 7b0c1da2ca6c..456a940d4710 100644 --- a/include/linux/tee_core.h +++ b/include/linux/tee_core.h @@ -76,8 +76,9 @@ struct tee_device { /** * struct tee_driver_ops - driver operations vtable * @get_version: returns version of driver - * @open: called when the device file is opened - * @release: release this open file + * @open: called for a context when the device file is opened + * @close_context: called when the device file is closed + * @release: called to release the context * @open_session: open a new session * @close_session: close a session * @system_session: declare session as a system session @@ -87,11 +88,17 @@ struct tee_device { * @supp_send: called for supplicant to send a response * @shm_register: register shared memory buffer in TEE * @shm_unregister: unregister shared memory buffer in TEE + * + * The context given to @open might last longer than the device file if it= is + * tied to other resources in the TEE driver. @close_context is called whe= n the + * client closes the device file, even if there are existing references to= the + * context. The TEE driver can use @close_context to start cleaning up. */ struct tee_driver_ops { void (*get_version)(struct tee_device *teedev, struct tee_ioctl_version_data *vers); int (*open)(struct tee_context *ctx); + void (*close_context)(struct tee_context *ctx); void (*release)(struct tee_context *ctx); int (*open_session)(struct tee_context *ctx, struct tee_ioctl_open_session_arg *arg, @@ -200,6 +207,24 @@ int tee_device_register_dma_heap(struct tee_device *te= edev, struct tee_protmem_pool *pool); void tee_device_put_all_dma_heaps(struct tee_device *teedev); =20 +/** + * tee_device_get() - Increment the user count for a tee_device + * @teedev: Pointer to the tee_device + * + * If tee_device_unregister() has been called and the final user of @teedev + * has already released the device, this function will fail to prevent new= users + * from accessing the device during the unregistration process. + * + * Returns: true if @teedev remains valid, otherwise false + */ +bool tee_device_get(struct tee_device *teedev); + +/** + * tee_device_put() - Decrease the user count for a tee_device + * @teedev: pointer to the tee_device + */ +void tee_device_put(struct tee_device *teedev); + /** * tee_device_set_dev_groups() - Set device attribute groups * @teedev: Device to register @@ -374,4 +399,25 @@ struct tee_context *teedev_open(struct tee_device *tee= dev); */ void teedev_close_context(struct tee_context *ctx); =20 +/** + * teedev_ctx_get() - Increment the reference count of a context + * @ctx: Pointer to the context + * + * This function increases the refcount of the context, which is tied to + * resources shared by the same tee_device. During the unregistration proc= ess, + * the context may remain valid even after tee_device_unregister() has ret= urned. + * + * Users should ensure that the context's refcount is properly decreased b= efore + * calling tee_device_put(), typically within the context's release() func= tion. + * Alternatively, users can call tee_device_get() and teedev_ctx_get() tog= ether + * and release them simultaneously (see shm_alloc_helper()). + */ +void teedev_ctx_get(struct tee_context *ctx); + +/** + * teedev_ctx_put() - Decrease reference count on a context + * @ctx: pointer to the context + */ +void teedev_ctx_put(struct tee_context *ctx); + #endif /*__TEE_CORE_H*/ --=20 2.34.1 From nobody Thu Oct 2 20:38:43 2025 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 3FA7925782D for ; Thu, 11 Sep 2025 03:41:34 +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=1757562096; cv=none; b=EptvqRcArKptGERWpokCDxlM3SyYXtMi1dOiiCWLNeFKA5Kra0hD2XmBf+Bt8sJbYku/lstAfZ7RYTJqe5G/BrDcdN8qooCR0UdvpvNRwN+qn1JwCd6nwPDfGgXmL0Rx8AcUxEXv4vHMMu8+E2IV60hlGB/Jkd7CjScIiUYuMRg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757562096; c=relaxed/simple; bh=J6gPADf+14CBKS8ZXGs+hL1MfQTHtOtZsIKENSZL1/U=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=QgY9PivQSCXt+UjCPKHomilqvouCeAtdc0TpE73Feyk2cnEj92lEaomcew+NWd7wrGK0I+f7U2zaY1302HkLTKtlHyxx7OCXbRyjChN+yJ9dS5h2vS2ew1B4htcepw9eYlPFrLbAiy9w5cH1rWNF7LCP0kbkebOJ0kjbx/3TscY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=oss.qualcomm.com; spf=pass smtp.mailfrom=oss.qualcomm.com; dkim=pass (2048-bit key) header.d=qualcomm.com header.i=@qualcomm.com header.b=b+DvGnqv; arc=none smtp.client-ip=205.220.168.131 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=oss.qualcomm.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=oss.qualcomm.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=qualcomm.com header.i=@qualcomm.com header.b="b+DvGnqv" 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 58B2IWHA015064 for ; Thu, 11 Sep 2025 03:41:33 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=qualcomm.com; h= cc:content-transfer-encoding:content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to; s=qcppdkim1; bh= OMgYiwriuoaEgjuQdAgHOp5QH1z5K2+Oz1UIvw1UFeo=; b=b+DvGnqvnCv/bKgq grwBl8YCaRiLBk+eMJIJbaXRVS+ip7RQxm3mj2enZN7H5TikYWIbu3XXgRvbdQ1v gEMUeIUZvx9LM7i0HyckrOJ2otRTfPMaVWn2FeOqGHq16+00f+IAS9vyIVbpLiFe Jh24NsLSpXu6xTvAUhOu8usDgS8hHJKAUHoSpH+UnaAhoDBth2ONDo58S/AJRld3 WiR4UE9g0L+4rMAxxblRGDTbpSWILA8VCdcr/sziaNlA4rhhpjDJWwF4QssBsN7Y NYtPmgLmAmG9BT0Xuf7CyVhkUipCnmJZoL1kaDrK1Te71UbyDWZH/Z+UYL8aR9ez aaE+fQ== Received: from mail-pl1-f198.google.com (mail-pl1-f198.google.com [209.85.214.198]) by mx0a-0031df01.pphosted.com (PPS) with ESMTPS id 490e4m61h2-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128 verify=NOT) for ; Thu, 11 Sep 2025 03:41:33 +0000 (GMT) Received: by mail-pl1-f198.google.com with SMTP id d9443c01a7336-24ced7cfa07so3043835ad.1 for ; Wed, 10 Sep 2025 20:41:33 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1757562093; x=1758166893; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=OMgYiwriuoaEgjuQdAgHOp5QH1z5K2+Oz1UIvw1UFeo=; b=voQMBvhdDS/w6ajtfgNa59LYRMQF0I3O6bP8YuHI5yaal5gSTl40T684EsEbMCb2SI XV0FtTA/fedhZ/2KBx4X/0I+1SHFMfTPJhXxvSPzgvQ93LEhfLr1NL/zUtuZoTA6g4Uv nD8oOULANJ4wPs6lr9RTHgLGZazWL2XDeU9eHrdD/77PaRBwkPMF1fQYnhnGkqD62MXF lJugtwONnNHNdXEy7UusU+gMMni1MiowhCs64vgwykbfsh+YeShFXtDyyCDH512TK5Kv lwH+jJvWFMl+E0e1uCoTFtvhkJjwON6MLDMMkm1nrMxOUT9iDGe3tPsMZSAg0D7Z/kuW l3Mg== X-Forwarded-Encrypted: i=1; AJvYcCVoKD9xzxXU/UQrcNh/LjVeDW5UD1bCG7Pu6i1j0MwbBbNwlIvLHOL8c7hwjol+ZfHCyLZJvPhPb9TfRYQ=@vger.kernel.org X-Gm-Message-State: AOJu0YyVkvvyeT4QLrnSq8FmYYGpkGmJb4j1U/MTumPRWpSKlrojBMxp kYhQ8KbDpAvnhsIOJPFIXXti9+9T3bRsA2RaiOeg3Pvrew/q2Y1A1ufcry1sunQuKaOsXE76UPo MPWJ6LEn+4FSiBEEDUr64AIvh+11zM9QKNtQQIkIitB2mFsu3qaLCNIjhlAPWESaVaw== X-Gm-Gg: ASbGncudFyrA/mUBgt8Pen4Iu8HZSascPLNLmFjHbbR+oEmn6mUlkBGldf0U1fxu5eW nQc+DdxFjNlcuWODoTASTcqzvtVkm2sH4ci6UbeHgN88ilzPRE9wsF9q03kanjTBTwYIiZNAuhy UfVDx0gvnLIZKt6EMg1RC8iG9h2+tvPsBzIDnqXn5kL2viCvo/V9xtREnz2+bHhLOFgpdGUBY4T Uoy6U4XaWLxiGDDXThe/QaaWxquVvB8Mqp5H4b4xS1L23XjyKT6lWoGzZcEXnPSxsydqLtox6Vz UQinr3/VJxMN3ac6+9bv1VEUYvNfYVOwkQMjC0qSyamjrNy8LIUEuTPrVJPBgxNBZYxN1Dw0OWm gifTJHhxTPhO9Kx9hFI3l/C8= X-Received: by 2002:a17:902:ce89:b0:24d:64bc:1495 with SMTP id d9443c01a7336-25172e32f31mr234654895ad.41.1757562092559; Wed, 10 Sep 2025 20:41:32 -0700 (PDT) X-Google-Smtp-Source: AGHT+IH2XBrmFI7DZlf4E83+SRzoCLNep0uvy22/JAq8l7UDLF3EEcfP3TLMWQ4bKAYhHUdaEoQscg== X-Received: by 2002:a17:902:ce89:b0:24d:64bc:1495 with SMTP id d9443c01a7336-25172e32f31mr234654575ad.41.1757562092083; Wed, 10 Sep 2025 20:41:32 -0700 (PDT) Received: from hu-azarrabi-lv.qualcomm.com (Global_NAT1.qualcomm.com. [129.46.96.20]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-25c3b304f76sm2962275ad.130.2025.09.10.20.41.30 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 10 Sep 2025 20:41:31 -0700 (PDT) From: Amirreza Zarrabi Date: Wed, 10 Sep 2025 20:41:18 -0700 Subject: [PATCH v11 05/11] tee: add TEE_IOCTL_PARAM_ATTR_TYPE_UBUF Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20250910-qcom-tee-using-tee-ss-without-mem-obj-v11-5-520e867b3d74@oss.qualcomm.com> References: <20250910-qcom-tee-using-tee-ss-without-mem-obj-v11-0-520e867b3d74@oss.qualcomm.com> In-Reply-To: <20250910-qcom-tee-using-tee-ss-without-mem-obj-v11-0-520e867b3d74@oss.qualcomm.com> To: Jens Wiklander , Sumit Garg , Bjorn Andersson , Konrad Dybcio , Bartosz Golaszewski , Apurupa Pattapu , Kees Cook , "Gustavo A. R. Silva" , Sumit Semwal , =?utf-8?q?Christian_K=C3=B6nig?= Cc: Harshal Dev , linux-arm-msm@vger.kernel.org, op-tee@lists.trustedfirmware.org, linux-kernel@vger.kernel.org, linux-hardening@vger.kernel.org, dri-devel@lists.freedesktop.org, linaro-mm-sig@lists.linaro.org, linux-doc@vger.kernel.org, Amirreza Zarrabi , Sumit Garg , Neil Armstrong X-Mailer: b4 0.13.0 X-Proofpoint-Spam-Details-Enc: AW1haW4tMjUwOTA2MDAzOCBTYWx0ZWRfX0ID8/U6JN9HM iTGD5IdTPfbTfmNrTdCtRiBU0cC1A0T7S682nbvdfUA50C7TPb/1u7WPve38XC+w9oL3KK5Ff0P xbT/9h9l3ilZJyl0KG3UA3E2kk5+8pE3jIxPq65ScYXeVJKrsFeqYQYj1GcxVd4kRvVlPu7AB3+ l3sGYTFYp5iZ2PmZcsQe2T37dW/e1jWFLU7oEvnma3lODHN0VqMw4QMyP+RtVms9AM6bVb5oaPc e/RSZ7a2OHgGy4zjkJkm0p+nJ6yXn3d5BHXzaQZVMBnIUCaZcS5ZSrxgnKF2rdxtAoeVlXiU4+J Us/KR7uWG8TTAlpAs7d/uOIkiKSRUoNBwvLLU7G7tUZsi72xf8r7MePiqCHddFW8716EVKK+j1m JRKcu9Gd X-Authority-Analysis: v=2.4 cv=J66q7BnS c=1 sm=1 tr=0 ts=68c244ed cx=c_pps a=MTSHoo12Qbhz2p7MsH1ifg==:117 a=ouPCqIW2jiPt+lZRy3xVPw==:17 a=IkcTkHD0fZMA:10 a=yJojWOMRYYMA:10 a=EUspDBNiAAAA:8 a=KKAkSRfTAAAA:8 a=COk6AnOGAAAA:8 a=nExbU_x0mLWtth5-Sj8A:9 a=QEXdDO2ut3YA:10 a=GvdueXVYPmCkWapjIL-Q:22 a=cvBusfyB2V15izCimMoJ:22 a=TjNXssC_j7lpFel5tvFf:22 X-Proofpoint-GUID: DUvdZHwYGjlxdXM49qUB_NrZbPou-RXo X-Proofpoint-ORIG-GUID: DUvdZHwYGjlxdXM49qUB_NrZbPou-RXo X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1117,Hydra:6.1.9,FMLib:17.12.80.40 definitions=2025-09-10_04,2025-09-10_01,2025-03-28_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 impostorscore=0 malwarescore=0 clxscore=1015 spamscore=0 phishscore=0 adultscore=0 priorityscore=1501 suspectscore=0 bulkscore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.19.0-2507300000 definitions=main-2509060038 For drivers that can transfer data to the TEE without using shared memory from client, it is necessary to receive the user address directly, bypassing any processing by the TEE subsystem. Introduce TEE_IOCTL_PARAM_ATTR_TYPE_UBUF_INPUT/OUTPUT/INOUT to represent userspace buffers. Reviewed-by: Sumit Garg Tested-by: Neil Armstrong Tested-by: Harshal Dev Signed-off-by: Amirreza Zarrabi --- drivers/tee/tee_core.c | 33 +++++++++++++++++++++++++++++++++ include/linux/tee_drv.h | 6 ++++++ include/uapi/linux/tee.h | 22 ++++++++++++++++------ 3 files changed, 55 insertions(+), 6 deletions(-) diff --git a/drivers/tee/tee_core.c b/drivers/tee/tee_core.c index f8534a00c56c..bb2e3a6c23a3 100644 --- a/drivers/tee/tee_core.c +++ b/drivers/tee/tee_core.c @@ -457,6 +457,17 @@ static int params_from_user(struct tee_context *ctx, s= truct tee_param *params, params[n].u.value.b =3D ip.b; params[n].u.value.c =3D ip.c; break; + case TEE_IOCTL_PARAM_ATTR_TYPE_UBUF_INPUT: + case TEE_IOCTL_PARAM_ATTR_TYPE_UBUF_OUTPUT: + case TEE_IOCTL_PARAM_ATTR_TYPE_UBUF_INOUT: + params[n].u.ubuf.uaddr =3D u64_to_user_ptr(ip.a); + params[n].u.ubuf.size =3D ip.b; + + if (!access_ok(params[n].u.ubuf.uaddr, + params[n].u.ubuf.size)) + return -EFAULT; + + 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: @@ -490,6 +501,11 @@ static int params_to_user(struct tee_ioctl_param __use= r *uparams, put_user(p->u.value.c, &up->c)) return -EFAULT; break; + case TEE_IOCTL_PARAM_ATTR_TYPE_UBUF_OUTPUT: + case TEE_IOCTL_PARAM_ATTR_TYPE_UBUF_INOUT: + if (put_user((u64)p->u.ubuf.size, &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)) @@ -690,6 +706,13 @@ static int params_to_supp(struct tee_context *ctx, ip.b =3D p->u.value.b; ip.c =3D p->u.value.c; break; + case TEE_IOCTL_PARAM_ATTR_TYPE_UBUF_INPUT: + case TEE_IOCTL_PARAM_ATTR_TYPE_UBUF_OUTPUT: + case TEE_IOCTL_PARAM_ATTR_TYPE_UBUF_INOUT: + ip.a =3D (__force u64)p->u.ubuf.uaddr; + ip.b =3D p->u.ubuf.size; + ip.c =3D 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: @@ -792,6 +815,16 @@ static int params_from_supp(struct tee_param *params, = size_t num_params, p->u.value.b =3D ip.b; p->u.value.c =3D ip.c; break; + case TEE_IOCTL_PARAM_ATTR_TYPE_UBUF_OUTPUT: + case TEE_IOCTL_PARAM_ATTR_TYPE_UBUF_INOUT: + p->u.ubuf.uaddr =3D u64_to_user_ptr(ip.a); + p->u.ubuf.size =3D ip.b; + + if (!access_ok(params[n].u.ubuf.uaddr, + params[n].u.ubuf.size)) + return -EFAULT; + + break; case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT: case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT: /* diff --git a/include/linux/tee_drv.h b/include/linux/tee_drv.h index 824f1251de60..7915e8869cbd 100644 --- a/include/linux/tee_drv.h +++ b/include/linux/tee_drv.h @@ -82,6 +82,11 @@ struct tee_param_memref { struct tee_shm *shm; }; =20 +struct tee_param_ubuf { + void __user *uaddr; + size_t size; +}; + struct tee_param_value { u64 a; u64 b; @@ -92,6 +97,7 @@ struct tee_param { u64 attr; union { struct tee_param_memref memref; + struct tee_param_ubuf ubuf; struct tee_param_value value; } u; }; diff --git a/include/uapi/linux/tee.h b/include/uapi/linux/tee.h index d843cf980d98..0e3b735dcfca 100644 --- a/include/uapi/linux/tee.h +++ b/include/uapi/linux/tee.h @@ -151,6 +151,13 @@ struct tee_ioctl_buf_data { #define TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT 6 #define TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT 7 /* input and output */ =20 +/* + * These defines userspace buffer parameters. + */ +#define TEE_IOCTL_PARAM_ATTR_TYPE_UBUF_INPUT 8 +#define TEE_IOCTL_PARAM_ATTR_TYPE_UBUF_OUTPUT 9 +#define TEE_IOCTL_PARAM_ATTR_TYPE_UBUF_INOUT 10 /* input and output */ + /* * Mask for the type part of the attribute, leaves room for more types */ @@ -186,14 +193,17 @@ struct tee_ioctl_buf_data { /** * struct tee_ioctl_param - parameter * @attr: attributes - * @a: if a memref, offset into the shared memory object, else a value par= ameter - * @b: if a memref, size of the buffer, else a value parameter + * @a: if a memref, offset into the shared memory object, + * else if a ubuf, address of the user buffer, + * else a value parameter + * @b: if a memref or ubuf, size of the buffer, else a value parameter * @c: if a memref, shared memory identifier, else a value parameter * - * @attr & TEE_PARAM_ATTR_TYPE_MASK indicates if memref or value is used in - * the union. TEE_PARAM_ATTR_TYPE_VALUE_* indicates value and - * TEE_PARAM_ATTR_TYPE_MEMREF_* indicates memref. TEE_PARAM_ATTR_TYPE_NONE - * indicates that none of the members are used. + * @attr & TEE_PARAM_ATTR_TYPE_MASK indicates if memref, ubuf, 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_= UBUF_* + * indicates ubuf. TEE_PARAM_ATTR_TYPE_NONE indicates that none of the mem= bers + * are used. * * Shared memory is allocated with TEE_IOC_SHM_ALLOC which returns an * identifier representing the shared memory object. A memref can reference --=20 2.34.1 From nobody Thu Oct 2 20:38:43 2025 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 D1182261B78 for ; Thu, 11 Sep 2025 03:41:36 +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=1757562098; cv=none; b=Hp6ZN6kFbCHIRvWelB1RSp/mLLSPkHopI14qRAygBmcrrgujL7dUaOB5kh4Zv4PVKuMe/95kdm5380bDk3bxGsPAUxfk4dTBpwV4H3D8x6z5fhKjkjcP+tCtf2UZF6zPaequlqJy8BrMnWn5iZdzDvqcS30EqVhCxusiqXq8wTQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757562098; c=relaxed/simple; bh=zqf0PKhzIuZVIPaRYJ3I122DsU5RbCE/8tAyDoK/2S4=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=j6s5mowmLmUsh7olCyVNz8Kb8NivFtng8CGdSmGA7bHkzjAsfHMpL5Wfvla1C2LeNdss/o1VRXwoi6xj44I+Q+8DlyqL+fTd/rwqpKAWP44AxdN1jLRFcztH9q7+Ph3EMWShq+ifo2s7LSVrUNUMaFYaMfFCfrgIlKkRBXk9t58= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=oss.qualcomm.com; spf=pass smtp.mailfrom=oss.qualcomm.com; dkim=pass (2048-bit key) header.d=qualcomm.com header.i=@qualcomm.com header.b=GoPqovmV; arc=none smtp.client-ip=205.220.180.131 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=oss.qualcomm.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=oss.qualcomm.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=qualcomm.com header.i=@qualcomm.com header.b="GoPqovmV" Received: from pps.filterd (m0279871.ppops.net [127.0.0.1]) by mx0a-0031df01.pphosted.com (8.18.1.2/8.18.1.2) with ESMTP id 58B2J3jJ026568 for ; Thu, 11 Sep 2025 03:41:36 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=qualcomm.com; h= cc:content-transfer-encoding:content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to; s=qcppdkim1; bh= lnPPGOh2u3id2oIj+03M3qcTEgPraCSEg+DXVn0qZCM=; b=GoPqovmV74sc0BqI rm58SwWewvG7GY84U4gd8b6Aj0H9v3mbLSSG/q+gkS3EvJo2HZ398G7611nhCgpd +/lo/7EycJiQn7hE+dlhkP80xrb45qJJyx5V810FtG4JlUPul6J/mWnJAWapNa/C BRq2ybxme30VGTNId6nRPucoPuVGaTKO0jtb360TaaTfxog/45C6R5Dex4YNyqcX jzDMc4aC+GKm5r/gABZPKypjrYDxHtGz6LSyMPGTIbCGY2stoP3xlYAZUG0IeZNg K9B0Vo4o7VrObck+0I0MtO0Vxub3K4RhHHvrZomFG4gW/i4maMvEA/L3ZniAzpbX K4FlWw== Received: from mail-pl1-f197.google.com (mail-pl1-f197.google.com [209.85.214.197]) by mx0a-0031df01.pphosted.com (PPS) with ESMTPS id 490cj0x2vw-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128 verify=NOT) for ; Thu, 11 Sep 2025 03:41:35 +0000 (GMT) Received: by mail-pl1-f197.google.com with SMTP id d9443c01a7336-24caf28cce0so6394455ad.0 for ; Wed, 10 Sep 2025 20:41:35 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1757562094; x=1758166894; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=lnPPGOh2u3id2oIj+03M3qcTEgPraCSEg+DXVn0qZCM=; b=lctb7Qc/DrjpGWAEtO121Atwj9dJf2RxZvdmkXMBF0QsCbdNAnmoM0sIM7ucs5GjDk p1EYlen55TYSPx+gwexwNmuuzonryxLqYnrGX5SJVLOab9/yaBW2Zmd6GqUSrBy6yLFc mdZe5iYm27ru/soSPXSGvM6gDc+NIck4B0g5ZoSrWlk61Fz4EVoGTszudxQxQIb+eVQx q/1+8uMpeqXzFHJO424/Fmp+dYSOoz3ahCQaCcTiyjMnsV7d3j/Zkl+wtwYUsDucVVgf v3lU/izxGiEtlgy9vwNzCwwAaDzPiF57Vorwet6WbzoJF9cNTnN6464THI0tfBPBRSuW k+Mg== X-Forwarded-Encrypted: i=1; AJvYcCU8bzKvvzWccPZLrWgv+K3sXY6u4tCXoqG43EjfE1+IWYyPgbNeDh8ms7Y+KbZUtVLP7DeU1Zot7nyvVtU=@vger.kernel.org X-Gm-Message-State: AOJu0YxBpiMgZSdKoEvW48mdiZ9LEVpD8MhioRLdm9iFRvmp2V5lAQ4u YnWkq7JOrRNN5Qjc/B1tcxpZadxzo2tX+qFopnPeCQnb1xRNUDXWED4ZXGdyq21d261OQiBa9bJ e9Qhg1KjLV1cNmlKXRz9CaStUnVPvkCXVhwMGSWp8k76QNW+TJ7WJ+gA4dBS9IzGtTw== X-Gm-Gg: ASbGncvlnhqiDWdAnULuZXJ6w93ocaZ1tOwCiDobRc913ePcnjL8nYISjrvRTtsemIr pKCOqwUEwaapaOVtwL0WCnB/dqNERzkD3pU+Wfls3Ys7upAL/8P9SD0nT0bhprGEV+SvcqIWHeJ JzCQ/cLlWjLitIakwhFK5Nvm2Qi7JV1HVEYRsN4emv20XpWHd/3yWs/aG8LxRkfCMtCIxv/uTHc DKxteY4YZ3xPRA+DjUshP3wBQt5H45v+JHa/dIYktqqeAWFASpKHBrRdqJZsrW3+6AgYE4YdGOa MG9KQuk/FPiZ4YTsPmeifDWSbLy1sPP9hs3PzLrSxmc0VoBhShBhXLFDG5SU3eflJ0+bJ1s5oI8 9NrBpRLauM9hZwg9YzUpMQwc= X-Received: by 2002:a17:902:ea0e:b0:24e:bdfa:112b with SMTP id d9443c01a7336-251761616c1mr196529345ad.61.1757562094250; Wed, 10 Sep 2025 20:41:34 -0700 (PDT) X-Google-Smtp-Source: AGHT+IHc2o2B2TakKKR9adyaPwYn48rLpxlSHAUGfCjETACNGIgh3Mywg9h99vJL8ucU9Xt+o6xDaQ== X-Received: by 2002:a17:902:ea0e:b0:24e:bdfa:112b with SMTP id d9443c01a7336-251761616c1mr196529065ad.61.1757562093727; Wed, 10 Sep 2025 20:41:33 -0700 (PDT) Received: from hu-azarrabi-lv.qualcomm.com (Global_NAT1.qualcomm.com. [129.46.96.20]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-25c3b304f76sm2962275ad.130.2025.09.10.20.41.32 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 10 Sep 2025 20:41:33 -0700 (PDT) From: Amirreza Zarrabi Date: Wed, 10 Sep 2025 20:41:19 -0700 Subject: [PATCH v11 06/11] tee: add TEE_IOCTL_PARAM_ATTR_TYPE_OBJREF Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20250910-qcom-tee-using-tee-ss-without-mem-obj-v11-6-520e867b3d74@oss.qualcomm.com> References: <20250910-qcom-tee-using-tee-ss-without-mem-obj-v11-0-520e867b3d74@oss.qualcomm.com> In-Reply-To: <20250910-qcom-tee-using-tee-ss-without-mem-obj-v11-0-520e867b3d74@oss.qualcomm.com> To: Jens Wiklander , Sumit Garg , Bjorn Andersson , Konrad Dybcio , Bartosz Golaszewski , Apurupa Pattapu , Kees Cook , "Gustavo A. R. Silva" , Sumit Semwal , =?utf-8?q?Christian_K=C3=B6nig?= Cc: Harshal Dev , linux-arm-msm@vger.kernel.org, op-tee@lists.trustedfirmware.org, linux-kernel@vger.kernel.org, linux-hardening@vger.kernel.org, dri-devel@lists.freedesktop.org, linaro-mm-sig@lists.linaro.org, linux-doc@vger.kernel.org, Amirreza Zarrabi , Sumit Garg , Neil Armstrong X-Mailer: b4 0.13.0 X-Proofpoint-ORIG-GUID: qhh6kKKl_uZeMXam59cANN18Radjz86y X-Proofpoint-GUID: qhh6kKKl_uZeMXam59cANN18Radjz86y X-Proofpoint-Spam-Details-Enc: AW1haW4tMjUwOTA2MDAyNCBTYWx0ZWRfX8C+fdjtMYXL7 2cQe7B6O+1YX1tFLyHMQ0m1EIs9IOLdIpqtYpR5VXx2Dt3adWGJppnh4nDJiZGgbXTwvKb8FqfE A06/4tXzedYeZtvZV//rR2SZBwUZOZd/DEOh/8cp4v5HDZXkNSh2y5YHsDe1Gbd8Hq5BFX9coML DL2qmiInWidByj2NrAN3cJsZ3KRXTAAJrYckrDKnBseSE0gibnarspZXmephKnvuE/Cz7tJz+P3 3FkKu2awcyzEvZAstRquBDkmpQYq8Rw8oGwbAioBK+btk0W9X+t3JbP6lAntBBbOvOGIH79iZMd 8kmIp+Vh0K5Lq9muS1Rjhq0CQwqpos2vQd+Q5C9RIkWsTiIm5XI8cRn753MAqz6l8FCYHLYWpTc iK3Xp0LL X-Authority-Analysis: v=2.4 cv=QeFmvtbv c=1 sm=1 tr=0 ts=68c244ef cx=c_pps a=cmESyDAEBpBGqyK7t0alAg==:117 a=ouPCqIW2jiPt+lZRy3xVPw==:17 a=IkcTkHD0fZMA:10 a=yJojWOMRYYMA:10 a=EUspDBNiAAAA:8 a=KKAkSRfTAAAA:8 a=COk6AnOGAAAA:8 a=fw-SQdjKjSnpQ1BqlTsA:9 a=QEXdDO2ut3YA:10 a=1OuFwYUASf3TG4hYMiVC:22 a=cvBusfyB2V15izCimMoJ:22 a=TjNXssC_j7lpFel5tvFf:22 X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1117,Hydra:6.1.9,FMLib:17.12.80.40 definitions=2025-09-10_04,2025-09-10_01,2025-03-28_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 phishscore=0 priorityscore=1501 clxscore=1015 spamscore=0 impostorscore=0 bulkscore=0 suspectscore=0 adultscore=0 malwarescore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.19.0-2507300000 definitions=main-2509060024 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. Reviewed-by: Sumit Garg Tested-by: Neil Armstrong Tested-by: Harshal Dev 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 bb2e3a6c23a3..e22995e457f3 100644 --- a/drivers/tee/tee_core.c +++ b/drivers/tee/tee_core.c @@ -450,6 +450,7 @@ static int params_from_user(struct tee_context *ctx, st= ruct 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: @@ -468,6 +469,11 @@ static int params_from_user(struct tee_context *ctx, s= truct tee_param *params, return -EFAULT; =20 break; + case TEE_IOCTL_PARAM_ATTR_TYPE_OBJREF_INPUT: + case TEE_IOCTL_PARAM_ATTR_TYPE_OBJREF_INOUT: + params[n].u.objref.id =3D ip.a; + params[n].u.objref.flags =3D 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: @@ -506,6 +512,12 @@ static int params_to_user(struct tee_ioctl_param __use= r *uparams, if (put_user((u64)p->u.ubuf.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)) @@ -658,6 +670,66 @@ static int tee_ioctl_invoke(struct tee_context *ctx, return rc; } =20 +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 =3D NULL; + struct tee_param *params =3D 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 =3D 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) !=3D buf.buf_len) + return -EINVAL; + + if (arg.num_params) { + params =3D kcalloc(arg.num_params, sizeof(struct tee_param), + GFP_KERNEL); + if (!params) + return -ENOMEM; + uparams =3D uarg->params; + rc =3D params_from_user(ctx, params, arg.num_params, uparams); + if (rc) + goto out; + } + + rc =3D ctx->teedev->desc->ops->object_invoke_func(ctx, &arg, params); + if (rc) + goto out; + + if (put_user(arg.ret, &uarg->ret)) { + rc =3D -EFAULT; + goto out; + } + rc =3D params_to_user(uparams, arg.num_params, params); +out: + if (params) { + /* Decrease ref count for all valid shared memory pointers */ + for (n =3D 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) { @@ -713,6 +785,12 @@ static int params_to_supp(struct tee_context *ctx, ip.b =3D p->u.ubuf.size; ip.c =3D 0; break; + case TEE_IOCTL_PARAM_ATTR_TYPE_OBJREF_INPUT: + case TEE_IOCTL_PARAM_ATTR_TYPE_OBJREF_INOUT: + ip.a =3D p->u.objref.id; + ip.b =3D p->u.objref.flags; + ip.c =3D 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: @@ -825,6 +903,11 @@ static int params_from_supp(struct tee_param *params, = size_t num_params, return -EFAULT; =20 break; + case TEE_IOCTL_PARAM_ATTR_TYPE_OBJREF_OUTPUT: + case TEE_IOCTL_PARAM_ATTR_TYPE_OBJREF_INOUT: + p->u.objref.id =3D ip.a; + p->u.objref.flags =3D ip.b; + break; case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT: case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT: /* @@ -907,6 +990,8 @@ static long tee_ioctl(struct file *filp, unsigned int c= md, 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 456a940d4710..1f3e5dad6d0d 100644 --- a/include/linux/tee_core.h +++ b/include/linux/tee_core.h @@ -83,6 +83,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 a TEE 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 @@ -108,6 +109,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 7915e8869cbd..88a6f9697c89 100644 --- a/include/linux/tee_drv.h +++ b/include/linux/tee_drv.h @@ -87,6 +87,11 @@ struct tee_param_ubuf { size_t size; }; =20 +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_ubuf ubuf; struct tee_param_value value; } u; diff --git a/include/uapi/linux/tee.h b/include/uapi/linux/tee.h index 0e3b735dcfca..9abb0f299549 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 supplican= t) */ #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 */ =20 -#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 */ =20 /* * TEE Implementation ID @@ -158,6 +160,13 @@ struct tee_ioctl_buf_data { #define TEE_IOCTL_PARAM_ATTR_TYPE_UBUF_OUTPUT 9 #define TEE_IOCTL_PARAM_ATTR_TYPE_UBUF_INOUT 10 /* input and output */ =20 +/* + * 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 ubuf, address of the user buffer, - * else a value parameter - * @b: if a memref or ubuf, size of the buffer, else a value parameter + * else if an objref, object identifier, else a value parameter + * @b: if a memref or ubuf, size of the buffer, + * else if objref, flags for the 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, ubuf, 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_= UBUF_* - * indicates ubuf. TEE_PARAM_ATTR_TYPE_NONE indicates that none of the mem= bers - * are used. + * TEE_PARAM_ATTR_TYPE_MEMREF_* indicates memref, TEE_PARAM_ATTR_TYPE_UBUF= _* + * indicates ubuf, 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 @@ -442,4 +452,23 @@ struct tee_ioctl_shm_register_fd_data { * munmap(): unmaps previously shared memory */ =20 +/** + * struct tee_ioctl_invoke_func_arg - Invokes an object in a Trusted Appli= cation + * @id: [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 id; + __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*/ --=20 2.34.1 From nobody Thu Oct 2 20:38:43 2025 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 7062923A9AE for ; Thu, 11 Sep 2025 03:41:38 +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=1757562100; cv=none; b=FcQaZKhEo8ggc+xUDAZWJq1P8DInrszofZHL2sn3tsSSPeNd9qKkXtOF/ei8q1cnF1Wp3NBuSOVeD3J8l7FcEGvl05295ffiPfYsCUxu5vkXFyjWknj8tCLlonlE57MQ9WbCgQgwhvurqLmAsVr/ryoP0sWyjxkroxEijvWlGvQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757562100; c=relaxed/simple; bh=/lv6U+EjPMeafYia+qKbji5Tbq552Q5xbMPIUY9qAiA=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=kzAiK8JGqhICcQ/9p2VpRPIdnKa3exjFpz6f4JOhPak3ssF7Fxx33TM027xaNIQRVA5oiRbO28dqkTKKgMjlrblAR8BI/+sTfIS59vrRBBPOcaLVVYanOZtG3vxrIZ47QsIS0+BSrQqs1UQMAjWMjIpyZVly5ak28ZOlfz2ZNA4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=oss.qualcomm.com; spf=pass smtp.mailfrom=oss.qualcomm.com; dkim=pass (2048-bit key) header.d=qualcomm.com header.i=@qualcomm.com header.b=lD81zjBU; arc=none smtp.client-ip=205.220.180.131 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=oss.qualcomm.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=oss.qualcomm.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=qualcomm.com header.i=@qualcomm.com header.b="lD81zjBU" 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 58B2J3x0006616 for ; Thu, 11 Sep 2025 03:41:37 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=qualcomm.com; h= cc:content-transfer-encoding:content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to; s=qcppdkim1; bh= YP1F2mKERyMRZBFmEs3SVcCv9UXZBJL5UnDFWST/l1c=; b=lD81zjBUQ40u8W2l UmBOznX4JfGe5Uc8w5e1E5ljITBKS7BsvfJadjMBZVNwmuJjs3maPhCIm1VeKuP2 Ao1EYPK75Vl1bjpsY8ngMmzHKZJMqg/kyUOs/mM1gVHTBPi5vPIv4/Paxkp1ZtxD erCgNiZIJKFbKYts0VENwvk1WpXjnCiIhIvm2W8cRSYKTHEOHhy2H6YbiYeorEPc mVWJlM2tuNDJD/dNAzbweTL2u4WH/A+eNML53zt6A93mQ/ODNh2m3dFV4BlIZXUV vUwZV8xUkxkTnof9CAQsHGV1o6qJFJVmtH1RPcOpFN4jaTpyQGbzTVipJ5SsgssL SIU22w== Received: from mail-pl1-f197.google.com (mail-pl1-f197.google.com [209.85.214.197]) by mx0a-0031df01.pphosted.com (PPS) with ESMTPS id 491vc2a63e-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128 verify=NOT) for ; Thu, 11 Sep 2025 03:41:37 +0000 (GMT) Received: by mail-pl1-f197.google.com with SMTP id d9443c01a7336-25bdf8126ceso4956895ad.3 for ; Wed, 10 Sep 2025 20:41:37 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1757562096; x=1758166896; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=YP1F2mKERyMRZBFmEs3SVcCv9UXZBJL5UnDFWST/l1c=; b=V5YLeVyHzwU5pFAqS8A0ugmBIiC4P8j9WTpItlJUOpkFCjKw2aJgV85rdTbZEMf0gW JzYBC2vCNMFQz6FFLMNGiy86G2zFIGyVl/mYpuFLF0wgABSEIARXkqPFh494QhNBLStp nYHD+QSRolwlO9bP9fsVCQHfVl6MFtZrbWhceLhOZkYl4LxibJMjR+yEkV/tg0l/Vz2D B8nTkm4Bs2snWa8/nCEIhD/PgtxmfGkp0m5joXGnBFsWqpeAgQAh2VUvRGOaCfCNxxa/ nz9032pVF5LLNFz6uWJyyR+gE5UL0PJ9rEWFoNLFlswFirpWOuv9tkQPzD9wyNwcGNpQ +p3A== X-Forwarded-Encrypted: i=1; AJvYcCX1mIUK5KvV185Cmvz6lXjYz8MWMLgT92sUh4jtDdy6QZoFgSI2U1TfIZVjluKbh/yZh0NhuP9vgPbPNJU=@vger.kernel.org X-Gm-Message-State: AOJu0YzWhz8Somw6UHcvfDF87r26Uyyxs9EUDxKycROiXkzi5VJu4hPU 2HQKJIvGaZyA54Elxb4BEqaScHPzelKRzfwOkhYWN+zNfsX5R1zBIZdPjimrLQCAsVBNDEn9e4Y LG/lZezcpL2euvSy1M5oSRPVulEVOFXFyt4oOlspL1MwmJf8Tw1WjT8aeCByK8SstKQ== X-Gm-Gg: ASbGncsZPC9qnOkZsWTdtS5U4Qgf5hmwcawVx1R7AJcOziobcRHiW2kr3q+F5rWIZOj FbO07zZGhJev+BQG7DpUaKFdokiCNqbH7gLKewo/XjjjjbogOlT0WDYwfnKaQ/g885j3e4QoeE3 fzVGtPPaDMFGLkUzQsf4A2XQ3i0IZX6b9EijwrR485UHBoWXmip/hgbsjbHEW/GYCl9fXI9Pa15 D4PAfcDsMNiH8IuIY4N2buJUJPLEkWBDEJVqN5RXKHemlqvK54W7W6doLqbtZkokQYJ4cCkj95b bqDMx+jiMGJ79KsfoFIn9J8RQPPUe9SNvEUeHrRrPeJsHC/kqcMU4sozJi9SUxp6VjryZvLNQbz pD3gKJ/87xvMRUsV0HZLLQ1A= X-Received: by 2002:a17:903:2b05:b0:24c:ca55:6d90 with SMTP id d9443c01a7336-2517493a0bfmr195669755ad.61.1757562096056; Wed, 10 Sep 2025 20:41:36 -0700 (PDT) X-Google-Smtp-Source: AGHT+IHvQDQ9uOhNwBYBH4VDpBdDwefv3e3oaJPc/CzBPBFYYZmFclBHQ1LdmEcszkXBkPyeDRPZhw== X-Received: by 2002:a17:903:2b05:b0:24c:ca55:6d90 with SMTP id d9443c01a7336-2517493a0bfmr195669425ad.61.1757562095433; Wed, 10 Sep 2025 20:41:35 -0700 (PDT) Received: from hu-azarrabi-lv.qualcomm.com (Global_NAT1.qualcomm.com. [129.46.96.20]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-25c3b304f76sm2962275ad.130.2025.09.10.20.41.33 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 10 Sep 2025 20:41:34 -0700 (PDT) From: Amirreza Zarrabi Date: Wed, 10 Sep 2025 20:41:20 -0700 Subject: [PATCH v11 07/11] tee: increase TEE_MAX_ARG_SIZE to 4096 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20250910-qcom-tee-using-tee-ss-without-mem-obj-v11-7-520e867b3d74@oss.qualcomm.com> References: <20250910-qcom-tee-using-tee-ss-without-mem-obj-v11-0-520e867b3d74@oss.qualcomm.com> In-Reply-To: <20250910-qcom-tee-using-tee-ss-without-mem-obj-v11-0-520e867b3d74@oss.qualcomm.com> To: Jens Wiklander , Sumit Garg , Bjorn Andersson , Konrad Dybcio , Bartosz Golaszewski , Apurupa Pattapu , Kees Cook , "Gustavo A. R. Silva" , Sumit Semwal , =?utf-8?q?Christian_K=C3=B6nig?= Cc: Harshal Dev , linux-arm-msm@vger.kernel.org, op-tee@lists.trustedfirmware.org, linux-kernel@vger.kernel.org, linux-hardening@vger.kernel.org, dri-devel@lists.freedesktop.org, linaro-mm-sig@lists.linaro.org, linux-doc@vger.kernel.org, Amirreza Zarrabi , Sumit Garg X-Mailer: b4 0.13.0 X-Authority-Analysis: v=2.4 cv=FN4bx/os c=1 sm=1 tr=0 ts=68c244f1 cx=c_pps a=cmESyDAEBpBGqyK7t0alAg==:117 a=ouPCqIW2jiPt+lZRy3xVPw==:17 a=IkcTkHD0fZMA:10 a=yJojWOMRYYMA:10 a=EUspDBNiAAAA:8 a=COk6AnOGAAAA:8 a=JCP0Puskdh6qvuzBaLcA:9 a=QEXdDO2ut3YA:10 a=1OuFwYUASf3TG4hYMiVC:22 a=TjNXssC_j7lpFel5tvFf:22 X-Proofpoint-ORIG-GUID: CVepWvzXzYvpyxguqedN169lL0ZzS5Ep X-Proofpoint-GUID: CVepWvzXzYvpyxguqedN169lL0ZzS5Ep X-Proofpoint-Spam-Details-Enc: AW1haW4tMjUwOTA4MDA5NCBTYWx0ZWRfX4LvFQiX4SIae JxVEiOfhL+fH1EQq+keQRg9K5wZMYFs8vGJLJkRNSFmVVOSVmTgCZqIM0CPq+SX4EL4f7jmcQ9y m8fW0qD3LdDv9b4BX1Gb87Kk98AXaPOSEMw98MavcGRebFVmE1gmY/N7hJrtxpiAJFCmUpW2aoa SXDRaXwSBiBroik2o7wS8RrWwmCyuREj4LxdRoJj6YDYGyw2GIziUZlm1WiKuJg32RY4QUPW+a1 Pz828dFnDhL7wY04dfLl3zQe/QK4yDIelH0hXA1DqeuQBPmDg9RPJC1VXZj78m3VpPQrr2DnrgT ghqOY0hursp3YOHDATWxK5Z1wlKDUhwKkLEtMi7wRXYlb6cDxO84D01xawVJ++4q+LChtz2uosy wdNKj/r9 X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1117,Hydra:6.1.9,FMLib:17.12.80.40 definitions=2025-09-10_04,2025-09-10_01,2025-03-28_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 spamscore=0 priorityscore=1501 clxscore=1015 phishscore=0 adultscore=0 bulkscore=0 impostorscore=0 malwarescore=0 suspectscore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.19.0-2507300000 definitions=main-2509080094 Increase TEE_MAX_ARG_SIZE to accommodate worst-case scenarios where additional buffer space is required to pass all arguments to TEE. This change is necessary for upcoming support for Qualcomm TEE, which requires a larger buffer for argument marshaling. Reviewed-by: Sumit Garg Tested-by: Harshal Dev Signed-off-by: Amirreza Zarrabi --- include/uapi/linux/tee.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/uapi/linux/tee.h b/include/uapi/linux/tee.h index 9abb0f299549..a5466b503bfe 100644 --- a/include/uapi/linux/tee.h +++ b/include/uapi/linux/tee.h @@ -42,7 +42,7 @@ #define TEE_IOC_MAGIC 0xa4 #define TEE_IOC_BASE 0 =20 -#define TEE_MAX_ARG_SIZE 1024 +#define TEE_MAX_ARG_SIZE 4096 =20 #define TEE_GEN_CAP_GP (1 << 0)/* GlobalPlatform compliant TEE */ #define TEE_GEN_CAP_PRIVILEGED (1 << 1)/* Privileged device (for supplican= t) */ --=20 2.34.1 From nobody Thu Oct 2 20:38:43 2025 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 C903C27281C for ; Thu, 11 Sep 2025 03:41:45 +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=1757562111; cv=none; b=lz32cCVuM+73D+fEgQg9xtf+39yfDs+JDUbaC7sZ78UB8yPa6WkzdrHcJYNv9DSkuNKLL+dhrIo8mjDJlDl880P2kjUr3sxLf38sBZ0aCE3smEneEpO1DYfGHydUmSn4upIc46aTYCzzJmu+fwefocMBBhlVONtGSIZBMrca3WY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757562111; c=relaxed/simple; bh=ZMzh6yHLmbpvxKLuvh3h7QO9OFWfRB+nQDSOO+iueYc=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=ggztwGl4WVDMMXeyxybvyitCjzaZ+X4cNcg6rkF5k/YOTok0sgrCqw+VhXfOYNTP0Y4QLmDpu93aaVsyDlWDP/0ccd+ohyVjO0/TpUSXRzNXLLiBFXtBNAoj6gbI4Z/B+T+6I5sMTXqaD/LYMJ6koF3jOBxvWavreJkL93z+pQ4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=oss.qualcomm.com; spf=pass smtp.mailfrom=oss.qualcomm.com; dkim=pass (2048-bit key) header.d=qualcomm.com header.i=@qualcomm.com header.b=lrRnl/i9; arc=none smtp.client-ip=205.220.180.131 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=oss.qualcomm.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=oss.qualcomm.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=qualcomm.com header.i=@qualcomm.com header.b="lrRnl/i9" Received: from pps.filterd (m0279873.ppops.net [127.0.0.1]) by mx0a-0031df01.pphosted.com (8.18.1.2/8.18.1.2) with ESMTP id 58B2IuRm008865 for ; Thu, 11 Sep 2025 03:41:44 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=qualcomm.com; h= cc:content-transfer-encoding:content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to; s=qcppdkim1; bh= Z8vFq6Ttwd1UVJHZbNcClcM4pYypSuB8OM6sIPbjSjk=; b=lrRnl/i9NyamhkCu fLdVfGYepyKBArob8ERPnhhnSQ0xrlvsg1vJdV1mzmpArR8qq7olQOIwzIVM2qkI xynQL18lvMLK1I78J+813MSRNao0b4priMh70AZMkd7a4k77Lmc/WJumJ7+d2Yy4 uEuSZD292sXNzt2OLAJFiSh3OL6cJa967Newe+3Azn5rRAiAUwBTurofhBCyye1e NSvB3kits0UC6/Ds9fwzDZa7hmUjYpuPl5WhKr3+vxp/7OozQaD3j6v9I6BTNjUl wf8wsCVpKnJQC3pRuEpOSMHcQG5V/Dg7K9tOgKF25C9iuxcMWdSBeTntM4YKzsg2 4NUMTw== Received: from mail-pl1-f199.google.com (mail-pl1-f199.google.com [209.85.214.199]) by mx0a-0031df01.pphosted.com (PPS) with ESMTPS id 490aappdb2-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128 verify=NOT) for ; Thu, 11 Sep 2025 03:41:44 +0000 (GMT) Received: by mail-pl1-f199.google.com with SMTP id d9443c01a7336-24458345f5dso3336775ad.3 for ; Wed, 10 Sep 2025 20:41:44 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1757562103; x=1758166903; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=Z8vFq6Ttwd1UVJHZbNcClcM4pYypSuB8OM6sIPbjSjk=; b=khWCui9gEwDoItfoJjaeG0EQI7qVdBALibc2zlpc3qyWk4j3NCFMakTz0zq93V0ARd N/zh6sgeQrkQ0gzGGTIVAP/hZ0ThpZb40FOBdhkKNzDUqqqsVlFfkOzhyFAQMiTRbAIe qetCChYjZjKPVhj7mFEHn3OypsjojUzSedEUR2wqs0G6EG8Q6i6CPJC7oAVxe1XRc99T pxaaD2LE2PZFvsZWYjOC+XLijeNhV/LeiH2ADqaYVuGIGo2ECCp4JeHKMDD2Dl4oPFte 18P9mlLhkJ865Xo4vtpGPHLk2WU3V5lHSOWwVBJNKcXtFHuvy0P9bGB8VokLUQKxVSH9 YXfA== X-Forwarded-Encrypted: i=1; AJvYcCUL9Ejm10oE1qziL3Fl8xUJWzUTzyOiIk726AREZQqJpZ4SFSr+lRFDEd28s6iP7dvWzgoK+9DvtD9D4DQ=@vger.kernel.org X-Gm-Message-State: AOJu0YxBIaIZQgLYyju/YXn/YRvISv6i/xcdhVxQ29j8aMiK0EEdGXeZ whrd5CqDnwbAK3qqaeldIhNlNKNSi7lPtzddKkibYTbn1zYZXORamJBNyLlrzUhEQt5wk+oqyi3 5cCJ9BXd+s+uyC+8AjIXnB5UlQbWTaqWGodrCUQZgJ3nZ+P8Nxz9js6zDGKTASwaJAw== X-Gm-Gg: ASbGncticsvJKVo/gQpKVzzxIlMAGAZ9TQJzID0+pE+G/w0cnpYc3BXJmVEV8XmPMbc 4m7hIe14qY3SCrayvogk2WITYw/tJ/ed7wMqAAmBSv7tFO/ofAg9YNAqpZgZS8DNEdC0ujFyWVI W/o7PjnuSuisOjAZ8nb4z8ROLPj+93TQfL1QOSh/Kq0FDiRSblYJJtv33P3aptERPRNC8sjRNkX 4Gr2v04NQuinTil7X9gZOGIQNXxX3Z2oTc6jNyVbXKK/Wt3/IvUWKFcnP7dA4OuP99a3e2Ot3Lc R2m1HR80vPf86AHhIy5XNdqbJape/Mr2/rgjP/e57ySO74LXa674ddS3AqnmVDTz0V3EUt3R+2o u1lQNqNxwr9EU8oQuy5A/+/w= X-Received: by 2002:a17:903:284:b0:251:3606:755b with SMTP id d9443c01a7336-2516dbf1d20mr259350375ad.12.1757562099175; Wed, 10 Sep 2025 20:41:39 -0700 (PDT) X-Google-Smtp-Source: AGHT+IFOS7NpxAtusaKuVAbja6RjLY0IWsgoU/z1S2DTQ69MlygTVGjyFRQbNcWodQFKXNSGRbdmAw== X-Received: by 2002:a17:903:284:b0:251:3606:755b with SMTP id d9443c01a7336-2516dbf1d20mr259349335ad.12.1757562097322; Wed, 10 Sep 2025 20:41:37 -0700 (PDT) Received: from hu-azarrabi-lv.qualcomm.com (Global_NAT1.qualcomm.com. [129.46.96.20]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-25c3b304f76sm2962275ad.130.2025.09.10.20.41.35 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 10 Sep 2025 20:41:36 -0700 (PDT) From: Amirreza Zarrabi Date: Wed, 10 Sep 2025 20:41:21 -0700 Subject: [PATCH v11 08/11] tee: add Qualcomm TEE driver Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20250910-qcom-tee-using-tee-ss-without-mem-obj-v11-8-520e867b3d74@oss.qualcomm.com> References: <20250910-qcom-tee-using-tee-ss-without-mem-obj-v11-0-520e867b3d74@oss.qualcomm.com> In-Reply-To: <20250910-qcom-tee-using-tee-ss-without-mem-obj-v11-0-520e867b3d74@oss.qualcomm.com> To: Jens Wiklander , Sumit Garg , Bjorn Andersson , Konrad Dybcio , Bartosz Golaszewski , Apurupa Pattapu , Kees Cook , "Gustavo A. R. Silva" , Sumit Semwal , =?utf-8?q?Christian_K=C3=B6nig?= Cc: Harshal Dev , linux-arm-msm@vger.kernel.org, op-tee@lists.trustedfirmware.org, linux-kernel@vger.kernel.org, linux-hardening@vger.kernel.org, dri-devel@lists.freedesktop.org, linaro-mm-sig@lists.linaro.org, linux-doc@vger.kernel.org, Amirreza Zarrabi , Neil Armstrong , Sumit Garg X-Mailer: b4 0.13.0 X-Authority-Analysis: v=2.4 cv=eMETjGp1 c=1 sm=1 tr=0 ts=68c244f8 cx=c_pps a=JL+w9abYAAE89/QcEU+0QA==:117 a=ouPCqIW2jiPt+lZRy3xVPw==:17 a=IkcTkHD0fZMA:10 a=yJojWOMRYYMA:10 a=KKAkSRfTAAAA:8 a=COk6AnOGAAAA:8 a=EUspDBNiAAAA:8 a=VwQbUJbxAAAA:8 a=FIYBkLyJCLRzNh53S3wA:9 a=gRhY7TKi58elnMce:21 a=QEXdDO2ut3YA:10 a=324X-CrmTo6CU4MGRt3R:22 a=cvBusfyB2V15izCimMoJ:22 a=TjNXssC_j7lpFel5tvFf:22 X-Proofpoint-GUID: 6BJImIpDxZeTVBGdofNLO090_h7JT5yT X-Proofpoint-ORIG-GUID: 6BJImIpDxZeTVBGdofNLO090_h7JT5yT X-Proofpoint-Spam-Details-Enc: AW1haW4tMjUwOTA2MDAwMCBTYWx0ZWRfXwN/3ZJscEKOB c8+aB7kFfChnwRa7tllu1ZdlnbqYfHp01uFUpgIUjWHxPou04wnqKu1XHF+gRDFAMWH5NARE+wg g9QydCX9ZqCDfCKJFLXlcpkEbAIQrQoSIiaKtKjG8qAaIm6356ns9M5hkvnFZaTv2m8Zn8uICg5 9dsTTVbxKM6NdVlLBSdpmQdZ+srstyHtrzCqBOI+qvH0xDfaBTmU3/sYtzrOYyc1HjJ5+P6ZWlV foNpO4SHitl6kI0B3+7xDddZy8SOpvohEqGb6vStbJA0eFQgvkzR/oa+Qrutx2r3skWSvntDOrv sgTWlXVosUDU6cD6MmBBJ+r3GSHjOc1AWip7wkb+6VeOhqM37BEO9AiLjERRlfQvWMy/vvWrf/t bRAER3RQ X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1117,Hydra:6.1.9,FMLib:17.12.80.40 definitions=2025-09-10_04,2025-09-10_01,2025-03-28_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 impostorscore=0 priorityscore=1501 malwarescore=0 clxscore=1015 adultscore=0 bulkscore=0 phishscore=0 spamscore=0 suspectscore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.19.0-2507300000 definitions=main-2509060000 Introduce qcomtee_object, which represents an object in both QTEE and the kernel. QTEE clients can invoke an instance of qcomtee_object to access QTEE services. If this invocation produces a new object in QTEE, an instance of qcomtee_object will be returned. Similarly, QTEE can request services from by issuing a callback request, which invokes an instance of qcomtee_object. Implement initial support for exporting qcomtee_object to userspace and QTEE, enabling the invocation of objects hosted in QTEE and userspace through the TEE subsystem. Tested-by: Neil Armstrong Tested-by: Harshal Dev Acked-by: Sumit Garg Signed-off-by: Amirreza Zarrabi --- MAINTAINERS | 6 + drivers/tee/Kconfig | 1 + drivers/tee/Makefile | 1 + drivers/tee/qcomtee/Kconfig | 12 + drivers/tee/qcomtee/Makefile | 7 + drivers/tee/qcomtee/async.c | 182 +++++++ drivers/tee/qcomtee/call.c | 813 +++++++++++++++++++++++++++++++ drivers/tee/qcomtee/core.c | 906 +++++++++++++++++++++++++++++++= ++++ drivers/tee/qcomtee/qcomtee.h | 143 ++++++ drivers/tee/qcomtee/qcomtee_msg.h | 304 ++++++++++++ drivers/tee/qcomtee/qcomtee_object.h | 316 ++++++++++++ drivers/tee/qcomtee/shm.c | 153 ++++++ drivers/tee/qcomtee/user_obj.c | 692 ++++++++++++++++++++++++++ include/uapi/linux/tee.h | 1 + 14 files changed, 3537 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index daf520a13bdf..bde449308736 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -20856,6 +20856,12 @@ F: Documentation/networking/device_drivers/cellula= r/qualcomm/rmnet.rst F: drivers/net/ethernet/qualcomm/rmnet/ F: include/linux/if_rmnet.h =20 +QUALCOMM TEE (QCOMTEE) DRIVER +M: Amirreza Zarrabi +L: linux-arm-msm@vger.kernel.org +S: Maintained +F: drivers/tee/qcomtee/ + QUALCOMM TRUST ZONE MEMORY ALLOCATOR M: Bartosz Golaszewski L: linux-arm-msm@vger.kernel.org diff --git a/drivers/tee/Kconfig b/drivers/tee/Kconfig index d9ccb945a6bd..98c3ad083940 100644 --- a/drivers/tee/Kconfig +++ b/drivers/tee/Kconfig @@ -20,5 +20,6 @@ config TEE_DMABUF_HEAPS source "drivers/tee/optee/Kconfig" source "drivers/tee/amdtee/Kconfig" source "drivers/tee/tstee/Kconfig" +source "drivers/tee/qcomtee/Kconfig" =20 endif diff --git a/drivers/tee/Makefile b/drivers/tee/Makefile index 949a6a79fb06..3239b91dee96 100644 --- a/drivers/tee/Makefile +++ b/drivers/tee/Makefile @@ -7,3 +7,4 @@ tee-objs +=3D tee_shm_pool.o obj-$(CONFIG_OPTEE) +=3D optee/ obj-$(CONFIG_AMDTEE) +=3D amdtee/ obj-$(CONFIG_ARM_TSTEE) +=3D tstee/ +obj-$(CONFIG_QCOMTEE) +=3D qcomtee/ diff --git a/drivers/tee/qcomtee/Kconfig b/drivers/tee/qcomtee/Kconfig new file mode 100644 index 000000000000..927686abceb1 --- /dev/null +++ b/drivers/tee/qcomtee/Kconfig @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: GPL-2.0-only +# Qualcomm Trusted Execution Environment Configuration +config QCOMTEE + tristate "Qualcomm TEE Support" + depends on !CPU_BIG_ENDIAN + select QCOM_SCM + select QCOM_TZMEM_MODE_SHMBRIDGE + help + This option enables the Qualcomm Trusted Execution Environment (QTEE) + driver. It provides an API to access services offered by QTEE and + its loaded Trusted Applications (TAs). Additionally, it facilitates + the export of userspace services provided by supplicants to QTEE. diff --git a/drivers/tee/qcomtee/Makefile b/drivers/tee/qcomtee/Makefile new file mode 100644 index 000000000000..600af2b8f1c1 --- /dev/null +++ b/drivers/tee/qcomtee/Makefile @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: GPL-2.0-only +obj-$(CONFIG_QCOMTEE) +=3D qcomtee.o +qcomtee-objs +=3D async.o +qcomtee-objs +=3D call.o +qcomtee-objs +=3D core.o +qcomtee-objs +=3D shm.o +qcomtee-objs +=3D user_obj.o diff --git a/drivers/tee/qcomtee/async.c b/drivers/tee/qcomtee/async.c new file mode 100644 index 000000000000..31bff4309e67 --- /dev/null +++ b/drivers/tee/qcomtee/async.c @@ -0,0 +1,182 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include "qcomtee.h" + +#define QCOMTEE_ASYNC_VERSION_1_0 0x00010000U /* Maj: 0x0001, Min: 0x0000.= */ +#define QCOMTEE_ASYNC_VERSION_1_1 0x00010001U /* Maj: 0x0001, Min: 0x0001.= */ +#define QCOMTEE_ASYNC_VERSION_1_2 0x00010002U /* Maj: 0x0001, Min: 0x0002.= */ +#define QCOMTEE_ASYNC_VERSION_CURRENT QCOMTEE_ASYNC_VERSION_1_2 + +#define QCOMTEE_ASYNC_VERSION_MAJOR(n) upper_16_bits(n) +#define QCOMTEE_ASYNC_VERSION_MINOR(n) lower_16_bits(n) + +#define QCOMTEE_ASYNC_VERSION_CURRENT_MAJOR \ + QCOMTEE_ASYNC_VERSION_MAJOR(QCOMTEE_ASYNC_VERSION_CURRENT) +#define QCOMTEE_ASYNC_VERSION_CURRENT_MINOR \ + QCOMTEE_ASYNC_VERSION_MINOR(QCOMTEE_ASYNC_VERSION_CURRENT) + +/** + * struct qcomtee_async_msg_hdr - Asynchronous message header format. + * @version: current async protocol version of the remote endpoint. + * @op: async operation. + * + * @version specifies the endpoint's (QTEE or driver) supported async prot= ocol. + * For example, if QTEE sets @version to %QCOMTEE_ASYNC_VERSION_1_1, QTEE + * handles operations supported in %QCOMTEE_ASYNC_VERSION_1_1 or + * %QCOMTEE_ASYNC_VERSION_1_0. @op determines the message format. + */ +struct qcomtee_async_msg_hdr { + u32 version; + u32 op; +}; + +/* Size of an empty async message. */ +#define QCOMTEE_ASYNC_MSG_ZERO sizeof(struct qcomtee_async_msg_hdr) + +/** + * struct qcomtee_async_release_msg - Release asynchronous message. + * @hdr: message header as &struct qcomtee_async_msg_hdr. + * @counts: number of objects in @object_ids. + * @object_ids: array of object IDs that should be released. + * + * Available in Maj =3D 0x0001, Min >=3D 0x0000. + */ +struct qcomtee_async_release_msg { + struct qcomtee_async_msg_hdr hdr; + u32 counts; + u32 object_ids[] __counted_by(counts); +}; + +/** + * qcomtee_get_async_buffer() - Get the start of the asynchronous message. + * @oic: context used for the current invocation. + * @async_buffer: return buffer to extract from or fill in async messages. + * + * If @oic is used for direct object invocation, the whole outbound buffer + * is available for the async message. If @oic is used for a callback requ= est, + * the tail of the outbound buffer (after the callback request message) is + * available for the async message. + * + * The start of the async buffer is aligned, see qcomtee_msg_offset_align(= ). + */ +static void qcomtee_get_async_buffer(struct qcomtee_object_invoke_ctx *oic, + struct qcomtee_buffer *async_buffer) +{ + struct qcomtee_msg_callback *msg; + unsigned int offset; + int i; + + if (!(oic->flags & QCOMTEE_OIC_FLAG_BUSY)) { + /* The outbound buffer is empty. Using the whole buffer. */ + offset =3D 0; + } else { + msg =3D (struct qcomtee_msg_callback *)oic->out_msg.addr; + + /* Start offset in a message for buffer arguments. */ + offset =3D qcomtee_msg_buffer_args(struct qcomtee_msg_callback, + qcomtee_msg_args(msg)); + + /* Add size of IB arguments. */ + qcomtee_msg_for_each_input_buffer(i, msg) + offset +=3D qcomtee_msg_offset_align(msg->args[i].b.size); + + /* Add size of OB arguments. */ + qcomtee_msg_for_each_output_buffer(i, msg) + offset +=3D qcomtee_msg_offset_align(msg->args[i].b.size); + } + + async_buffer->addr =3D oic->out_msg.addr + offset; + async_buffer->size =3D oic->out_msg.size - offset; +} + +/** + * async_release() - Process QTEE async release requests. + * @oic: context used for the current invocation. + * @msg: async message for object release. + * @size: size of the async buffer available. + * + * Return: Size of the outbound buffer used when processing @msg. + */ +static size_t async_release(struct qcomtee_object_invoke_ctx *oic, + struct qcomtee_async_msg_hdr *async_msg, + size_t size) +{ + struct qcomtee_async_release_msg *msg; + struct qcomtee_object *object; + int i; + + msg =3D (struct qcomtee_async_release_msg *)async_msg; + + for (i =3D 0; i < msg->counts; i++) { + object =3D qcomtee_idx_erase(oic, msg->object_ids[i]); + qcomtee_object_put(object); + } + + return struct_size(msg, object_ids, msg->counts); +} + +/** + * qcomtee_fetch_async_reqs() - Fetch and process asynchronous messages. + * @oic: context used for the current invocation. + * + * Calls handlers to process the requested operations in the async message. + * Currently, only supports async release requests. + */ +void qcomtee_fetch_async_reqs(struct qcomtee_object_invoke_ctx *oic) +{ + struct qcomtee_async_msg_hdr *async_msg; + struct qcomtee_buffer async_buffer; + size_t consumed, used =3D 0; + u16 major_ver; + + qcomtee_get_async_buffer(oic, &async_buffer); + + while (async_buffer.size - used > QCOMTEE_ASYNC_MSG_ZERO) { + async_msg =3D (struct qcomtee_async_msg_hdr *)(async_buffer.addr + + used); + /* + * QTEE assumes that the unused space of the async buffer is + * zeroed; so if version is zero, the buffer is unused. + */ + if (async_msg->version =3D=3D 0) + goto out; + + major_ver =3D QCOMTEE_ASYNC_VERSION_MAJOR(async_msg->version); + /* Major version mismatch is a compatibility break. */ + if (major_ver !=3D QCOMTEE_ASYNC_VERSION_CURRENT_MAJOR) { + pr_err("Async message version mismatch (%u !=3D %u)\n", + major_ver, QCOMTEE_ASYNC_VERSION_CURRENT_MAJOR); + + goto out; + } + + switch (async_msg->op) { + case QCOMTEE_MSG_OBJECT_OP_RELEASE: + consumed =3D async_release(oic, async_msg, + async_buffer.size - used); + break; + default: + pr_err("Unsupported async message %u\n", async_msg->op); + goto out; + } + + /* Supported operation but unable to parse the message. */ + if (!consumed) { + pr_err("Unable to parse async message for op %u\n", + async_msg->op); + goto out; + } + + /* Next async message. */ + used +=3D qcomtee_msg_offset_align(consumed); + } + +out: + /* Reset the async buffer so async requests do not loop to QTEE. */ + memzero_explicit(async_buffer.addr, async_buffer.size); +} diff --git a/drivers/tee/qcomtee/call.c b/drivers/tee/qcomtee/call.c new file mode 100644 index 000000000000..33daa4d7033d --- /dev/null +++ b/drivers/tee/qcomtee/call.c @@ -0,0 +1,813 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include + +#include "qcomtee.h" + +static int find_qtee_object(struct qcomtee_object **object, unsigned long = id, + struct qcomtee_context_data *ctxdata) +{ + int err =3D 0; + + guard(rcu)(); + /* Object release is RCU protected. */ + *object =3D idr_find(&ctxdata->qtee_objects_idr, id); + if (!qcomtee_object_get(*object)) + err =3D -EINVAL; + + return err; +} + +static void del_qtee_object(unsigned long id, + struct qcomtee_context_data *ctxdata) +{ + struct qcomtee_object *object; + + scoped_guard(mutex, &ctxdata->qtee_lock) + object =3D idr_remove(&ctxdata->qtee_objects_idr, id); + + qcomtee_object_put(object); +} + +/** + * qcomtee_context_add_qtee_object() - Add a QTEE object to the context. + * @param: TEE parameter representing @object. + * @object: QTEE object. + * @ctx: context to add the object. + * + * It assumes @object is %QCOMTEE_OBJECT_TYPE_TEE and the caller has alrea= dy + * issued qcomtee_object_get() for @object. + * + * Return: On success, returns 0; on failure, returns < 0. + */ +int qcomtee_context_add_qtee_object(struct tee_param *param, + struct qcomtee_object *object, + struct tee_context *ctx) +{ + int ret; + struct qcomtee_context_data *ctxdata =3D ctx->data; + + scoped_guard(mutex, &ctxdata->qtee_lock) + ret =3D idr_alloc(&ctxdata->qtee_objects_idr, object, 0, 0, + GFP_KERNEL); + if (ret < 0) + return ret; + + param->u.objref.id =3D ret; + /* QTEE Object: QCOMTEE_OBJREF_FLAG_TEE set. */ + param->u.objref.flags =3D QCOMTEE_OBJREF_FLAG_TEE; + + return 0; +} + +/* Retrieve the QTEE object added with qcomtee_context_add_qtee_object(). = */ +int qcomtee_context_find_qtee_object(struct qcomtee_object **object, + struct tee_param *param, + struct tee_context *ctx) +{ + struct qcomtee_context_data *ctxdata =3D ctx->data; + + return find_qtee_object(object, param->u.objref.id, ctxdata); +} + +/** + * qcomtee_context_del_qtee_object() - Delete a QTEE object from the conte= xt. + * @param: TEE parameter representing @object. + * @ctx: context for deleting the object. + * + * The @param has been initialized by qcomtee_context_add_qtee_object(). + */ +void qcomtee_context_del_qtee_object(struct tee_param *param, + struct tee_context *ctx) +{ + struct qcomtee_context_data *ctxdata =3D ctx->data; + /* 'qtee_objects_idr' stores QTEE objects only. */ + if (param->u.objref.flags & QCOMTEE_OBJREF_FLAG_TEE) + del_qtee_object(param->u.objref.id, ctxdata); +} + +/** + * qcomtee_objref_to_arg() - Convert OBJREF parameter to QTEE argument. + * @arg: QTEE argument. + * @param: TEE parameter. + * @ctx: context in which the conversion should happen. + * + * It assumes @param is an OBJREF. + * It does not set @arg.type; the caller should initialize it to a correct + * &enum qcomtee_arg_type value. It gets the object's refcount in @arg; + * the caller should manage to put it afterward. + * + * Return: On success, returns 0; on failure, returns < 0. + */ +int qcomtee_objref_to_arg(struct qcomtee_arg *arg, struct tee_param *param, + struct tee_context *ctx) +{ + int err =3D -EINVAL; + + arg->o =3D NULL_QCOMTEE_OBJECT; + /* param is a NULL object: */ + if (param->u.objref.id =3D=3D TEE_OBJREF_NULL) + return 0; + + /* param is a callback object: */ + if (param->u.objref.flags & QCOMTEE_OBJREF_FLAG_USER) + err =3D qcomtee_user_param_to_object(&arg->o, param, ctx); + /* param is a QTEE object: */ + else if (param->u.objref.flags & QCOMTEE_OBJREF_FLAG_TEE) + err =3D qcomtee_context_find_qtee_object(&arg->o, param, ctx); + + /* + * For callback objects, call qcomtee_object_get() to keep a temporary + * copy for the driver, as these objects are released asynchronously + * and may disappear even before returning from QTEE. + * + * - For direct object invocations, the matching put is called in + * qcomtee_object_invoke() when parsing the QTEE response. + * - For callback responses, put is called in qcomtee_user_object_notify= () + * after QTEE has received its copies. + */ + + if (!err && (typeof_qcomtee_object(arg->o) =3D=3D QCOMTEE_OBJECT_TYPE_CB)) + qcomtee_object_get(arg->o); + + return err; +} + +/** + * qcomtee_objref_from_arg() - Convert QTEE argument to OBJREF param. + * @param: TEE parameter. + * @arg: QTEE argument. + * @ctx: context in which the conversion should happen. + * + * It assumes @arg is of %QCOMTEE_ARG_TYPE_IO or %QCOMTEE_ARG_TYPE_OO. + * It does not set @param.attr; the caller should initialize it to a + * correct type. + * + * Return: On success, returns 0; on failure, returns < 0. + */ +int qcomtee_objref_from_arg(struct tee_param *param, struct qcomtee_arg *a= rg, + struct tee_context *ctx) +{ + struct qcomtee_object *object =3D arg->o; + + switch (typeof_qcomtee_object(object)) { + case QCOMTEE_OBJECT_TYPE_NULL: + param->u.objref.id =3D TEE_OBJREF_NULL; + + return 0; + case QCOMTEE_OBJECT_TYPE_CB: + /* object is a callback object: */ + if (is_qcomtee_user_object(object)) + return qcomtee_user_param_from_object(param, object, + ctx); + + break; + case QCOMTEE_OBJECT_TYPE_TEE: + return qcomtee_context_add_qtee_object(param, object, ctx); + + case QCOMTEE_OBJECT_TYPE_ROOT: + default: + break; + } + + return -EINVAL; +} + +/** + * qcomtee_params_to_args() - Convert TEE parameters to QTEE arguments. + * @u: QTEE arguments. + * @params: TEE parameters. + * @num_params: number of elements in the parameter array. + * @ctx: context in which the conversion should happen. + * + * It assumes @u has at least @num_params + 1 entries and has been initial= ized + * with %QCOMTEE_ARG_TYPE_INV as &struct qcomtee_arg.type. + * + * Return: On success, returns 0; on failure, returns < 0. + */ +static int qcomtee_params_to_args(struct qcomtee_arg *u, + struct tee_param *params, int num_params, + struct tee_context *ctx) +{ + int i; + + for (i =3D 0; i < num_params; i++) { + switch (params[i].attr) { + case TEE_IOCTL_PARAM_ATTR_TYPE_UBUF_INPUT: + case TEE_IOCTL_PARAM_ATTR_TYPE_UBUF_OUTPUT: + u[i].flags =3D QCOMTEE_ARG_FLAGS_UADDR; + u[i].b.uaddr =3D params[i].u.ubuf.uaddr; + u[i].b.size =3D params[i].u.ubuf.size; + + if (params[i].attr =3D=3D + TEE_IOCTL_PARAM_ATTR_TYPE_UBUF_INPUT) + u[i].type =3D QCOMTEE_ARG_TYPE_IB; + else /* TEE_IOCTL_PARAM_ATTR_TYPE_UBUF_OUTPUT */ + u[i].type =3D QCOMTEE_ARG_TYPE_OB; + + break; + case TEE_IOCTL_PARAM_ATTR_TYPE_OBJREF_INPUT: + u[i].type =3D QCOMTEE_ARG_TYPE_IO; + if (qcomtee_objref_to_arg(&u[i], ¶ms[i], ctx)) + goto out_failed; + + break; + case TEE_IOCTL_PARAM_ATTR_TYPE_OBJREF_OUTPUT: + u[i].type =3D QCOMTEE_ARG_TYPE_OO; + u[i].o =3D NULL_QCOMTEE_OBJECT; + break; + default: + goto out_failed; + } + } + + return 0; + +out_failed: + /* Undo qcomtee_objref_to_arg(). */ + for (i--; i >=3D 0; i--) { + if (u[i].type !=3D QCOMTEE_ARG_TYPE_IO) + continue; + + qcomtee_user_object_set_notify(u[i].o, false); + /* See docs for qcomtee_objref_to_arg() for double put. */ + if (typeof_qcomtee_object(u[i].o) =3D=3D QCOMTEE_OBJECT_TYPE_CB) + qcomtee_object_put(u[i].o); + + qcomtee_object_put(u[i].o); + } + + return -EINVAL; +} + +/** + * qcomtee_params_from_args() - Convert QTEE arguments to TEE parameters. + * @params: TEE parameters. + * @u: QTEE arguments. + * @num_params: number of elements in the parameter array. + * @ctx: context in which the conversion should happen. + * + * @u should have already been initialized by qcomtee_params_to_args(). + * This also represents the end of a QTEE invocation that started with + * qcomtee_params_to_args() by releasing %QCOMTEE_ARG_TYPE_IO objects. + * + * Return: On success, returns 0; on failure, returns < 0. + */ +static int qcomtee_params_from_args(struct tee_param *params, + struct qcomtee_arg *u, int num_params, + struct tee_context *ctx) +{ + int i, np; + + qcomtee_arg_for_each(np, u) { + switch (u[np].type) { + case QCOMTEE_ARG_TYPE_OB: + /* TEE_IOCTL_PARAM_ATTR_TYPE_UBUF_OUTPUT */ + params[np].u.ubuf.size =3D u[np].b.size; + + break; + case QCOMTEE_ARG_TYPE_IO: + /* IEE_IOCTL_PARAM_ATTR_TYPE_OBJREF_INPUT */ + qcomtee_object_put(u[np].o); + + break; + case QCOMTEE_ARG_TYPE_OO: + /* TEE_IOCTL_PARAM_ATTR_TYPE_OBJREF_OUTPUT */ + if (qcomtee_objref_from_arg(¶ms[np], &u[np], ctx)) + goto out_failed; + + break; + case QCOMTEE_ARG_TYPE_IB: + default: + break; + } + } + + return 0; + +out_failed: + /* Undo qcomtee_objref_from_arg(). */ + for (i =3D 0; i < np; i++) { + if (params[i].attr =3D=3D TEE_IOCTL_PARAM_ATTR_TYPE_OBJREF_OUTPUT) + qcomtee_context_del_qtee_object(¶ms[i], ctx); + } + + /* Release any IO and OO objects not processed. */ + for (; u[i].type && i < num_params; i++) { + if (u[i].type =3D=3D QCOMTEE_ARG_TYPE_OO || + u[i].type =3D=3D QCOMTEE_ARG_TYPE_IO) + qcomtee_object_put(u[i].o); + } + + return -EINVAL; +} + +/* TEE Device Ops. */ + +static int qcomtee_params_check(struct tee_param *params, int num_params) +{ + int io =3D 0, oo =3D 0, ib =3D 0, ob =3D 0; + int i; + + /* QTEE can accept 64 arguments. */ + if (num_params > QCOMTEE_ARGS_MAX) + return -EINVAL; + + /* Supported parameter types. */ + for (i =3D 0; i < num_params; i++) { + switch (params[i].attr) { + case TEE_IOCTL_PARAM_ATTR_TYPE_UBUF_INPUT: + ib++; + break; + case TEE_IOCTL_PARAM_ATTR_TYPE_UBUF_OUTPUT: + ob++; + break; + case TEE_IOCTL_PARAM_ATTR_TYPE_OBJREF_INPUT: + io++; + break; + case TEE_IOCTL_PARAM_ATTR_TYPE_OBJREF_OUTPUT: + oo++; + break; + default: + return -EINVAL; + } + } + + /* QTEE can accept 16 arguments of each supported types. */ + if (io > QCOMTEE_ARGS_PER_TYPE || oo > QCOMTEE_ARGS_PER_TYPE || + ib > QCOMTEE_ARGS_PER_TYPE || ob > QCOMTEE_ARGS_PER_TYPE) + return -EINVAL; + + return 0; +} + +/* Check if an operation on ROOT_QCOMTEE_OBJECT from userspace is permitte= d. */ +static int qcomtee_root_object_check(u32 op, struct tee_param *params, + int num_params) +{ + /* Some privileged operations recognized by QTEE. */ + if (op =3D=3D QCOMTEE_ROOT_OP_NOTIFY_DOMAIN_CHANGE || + op =3D=3D QCOMTEE_ROOT_OP_ADCI_ACCEPT || + op =3D=3D QCOMTEE_ROOT_OP_ADCI_SHUTDOWN) + return -EINVAL; + + /* + * QCOMTEE_ROOT_OP_REG_WITH_CREDENTIALS is to register with QTEE + * by passing a credential object as input OBJREF. TEE_OBJREF_NULL as a + * credential object represents a privileged client for QTEE and + * is used by the kernel only. + */ + if (op =3D=3D QCOMTEE_ROOT_OP_REG_WITH_CREDENTIALS && num_params =3D=3D 2= ) { + if (params[0].attr =3D=3D TEE_IOCTL_PARAM_ATTR_TYPE_OBJREF_INPUT && + params[1].attr =3D=3D TEE_IOCTL_PARAM_ATTR_TYPE_OBJREF_OUTPUT) { + if (params[0].u.objref.id =3D=3D TEE_OBJREF_NULL) + return -EINVAL; + } + } + + return 0; +} + +/** + * qcomtee_object_invoke() - Invoke a QTEE object. + * @ctx: TEE context. + * @arg: ioctl arguments. + * @params: parameters for the object. + * + * Return: On success, returns 0; on failure, returns < 0. + */ +static int qcomtee_object_invoke(struct tee_context *ctx, + struct tee_ioctl_object_invoke_arg *arg, + struct tee_param *params) +{ + struct qcomtee_object_invoke_ctx *oic __free(kfree) =3D NULL; + struct qcomtee_context_data *ctxdata =3D ctx->data; + struct qcomtee_arg *u __free(kfree) =3D NULL; + struct qcomtee_object *object; + int i, ret, result; + + if (qcomtee_params_check(params, arg->num_params)) + return -EINVAL; + + /* First, handle reserved operations: */ + if (arg->op =3D=3D QCOMTEE_MSG_OBJECT_OP_RELEASE) { + del_qtee_object(arg->id, ctxdata); + + return 0; + } + + /* Otherwise, invoke a QTEE object: */ + oic =3D qcomtee_object_invoke_ctx_alloc(ctx); + if (!oic) + return -ENOMEM; + + /* +1 for ending QCOMTEE_ARG_TYPE_INV. */ + u =3D kcalloc(arg->num_params + 1, sizeof(*u), GFP_KERNEL); + if (!u) + return -ENOMEM; + + /* Get an object to invoke. */ + if (arg->id =3D=3D TEE_OBJREF_NULL) { + /* Use ROOT if TEE_OBJREF_NULL is invoked. */ + if (qcomtee_root_object_check(arg->op, params, arg->num_params)) + return -EINVAL; + + object =3D ROOT_QCOMTEE_OBJECT; + } else if (find_qtee_object(&object, arg->id, ctxdata)) { + return -EINVAL; + } + + ret =3D qcomtee_params_to_args(u, params, arg->num_params, ctx); + if (ret) + goto out; + + ret =3D qcomtee_object_do_invoke(oic, object, arg->op, u, &result); + if (ret) { + qcomtee_arg_for_each_input_object(i, u) { + qcomtee_user_object_set_notify(u[i].o, false); + qcomtee_object_put(u[i].o); + } + + goto out; + } + + /* Prase QTEE response and put driver's object copies: */ + + if (!result) { + /* Assume service is UNAVAIL if unable to process the result. */ + if (qcomtee_params_from_args(params, u, arg->num_params, ctx)) + result =3D QCOMTEE_MSG_ERROR_UNAVAIL; + } else { + /* + * qcomtee_params_to_args() gets a copy of IO for the driver to + * make sure they do not get released while in the middle of + * invocation. On success (!result), qcomtee_params_from_args() + * puts them; Otherwise, put them here. + */ + qcomtee_arg_for_each_input_object(i, u) + qcomtee_object_put(u[i].o); + } + + arg->ret =3D result; +out: + qcomtee_object_put(object); + + return ret; +} + +/** + * qcomtee_supp_recv() - Wait for a request for the supplicant. + * @ctx: TEE context. + * @op: requested operation on the object. + * @num_params: number of elements in the parameter array. + * @params: parameters for @op. + * + * The first parameter is a meta %TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT. + * On input, it provides a user buffer. This buffer is used for parameters= of + * type %TEE_IOCTL_PARAM_ATTR_TYPE_UBUF_INPUT in qcomtee_cb_params_from_ar= gs(). + * On output, the object ID and request ID are stored in the meta paramete= r. + * + * @num_params is updated to the number of parameters that actually exist + * in @params on return. + * + * Return: On success, returns 0; on failure, returns < 0. + */ +static int qcomtee_supp_recv(struct tee_context *ctx, u32 *op, u32 *num_pa= rams, + struct tee_param *params) +{ + struct qcomtee_user_object_request_data data; + void __user *uaddr; + size_t ubuf_size; + int i, ret; + + if (!*num_params) + return -EINVAL; + + /* First parameter should be an INOUT + meta parameter. */ + if (params->attr !=3D + (TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT | TEE_IOCTL_PARAM_ATTR_META)) + return -EINVAL; + + /* Other parameters are none. */ + for (i =3D 1; i < *num_params; i++) + if (params[i].attr) + return -EINVAL; + + if (!IS_ALIGNED(params->u.value.a, 8)) + return -EINVAL; + + /* User buffer and size from meta parameter. */ + uaddr =3D u64_to_user_ptr(params->u.value.a); + ubuf_size =3D params->u.value.b; + /* Process TEE parameters. +/-1 to ignore the meta parameter. */ + ret =3D qcomtee_user_object_select(ctx, params + 1, *num_params - 1, + uaddr, ubuf_size, &data); + if (ret) + return ret; + + params->u.value.a =3D data.object_id; + params->u.value.b =3D data.id; + params->u.value.c =3D 0; + *op =3D data.op; + *num_params =3D data.np + 1; + + return 0; +} + +/** + * qcomtee_supp_send() - Submit a response for a request. + * @ctx: TEE context. + * @errno: return value for the request. + * @num_params: number of elements in the parameter array. + * @params: returned parameters. + * + * The first parameter is a meta %TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT. + * It specifies the request ID this response belongs to. + * + * Return: On success, returns 0; on failure, returns < 0. + */ +static int qcomtee_supp_send(struct tee_context *ctx, u32 errno, u32 num_p= arams, + struct tee_param *params) +{ + int req_id; + + if (!num_params) + return -EINVAL; + + /* First parameter should be an OUTPUT + meta parameter. */ + if (params->attr !=3D (TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT | + TEE_IOCTL_PARAM_ATTR_META)) + return -EINVAL; + + req_id =3D params->u.value.a; + /* Process TEE parameters. +/-1 to ignore the meta parameter. */ + return qcomtee_user_object_submit(ctx, params + 1, num_params - 1, + req_id, errno); +} + +static int qcomtee_open(struct tee_context *ctx) +{ + struct qcomtee_context_data *ctxdata __free(kfree) =3D NULL; + + ctxdata =3D kzalloc(sizeof(*ctxdata), GFP_KERNEL); + if (!ctxdata) + return -ENOMEM; + + /* + * In the QTEE driver, the same context is used to refcount resources + * shared by QTEE. For example, teedev_ctx_get() is called for any + * instance of callback objects (see qcomtee_user_param_to_object()). + * + * Maintain a copy of teedev for QTEE as it serves as a direct user of + * this context. The teedev will be released in the context's release(). + * + * tee_device_unregister() will remain blocked until all contexts + * are released. This includes contexts owned by the user, which are + * closed by teedev_close_context(), as well as those owned by QTEE + * closed by teedev_ctx_put() in object's release(). + */ + if (!tee_device_get(ctx->teedev)) + return -EINVAL; + + idr_init(&ctxdata->qtee_objects_idr); + mutex_init(&ctxdata->qtee_lock); + idr_init(&ctxdata->reqs_idr); + INIT_LIST_HEAD(&ctxdata->reqs_list); + mutex_init(&ctxdata->reqs_lock); + init_completion(&ctxdata->req_c); + + ctx->data =3D no_free_ptr(ctxdata); + + return 0; +} + +/* Gets called when the user closes the device */ +static void qcomtee_close_context(struct tee_context *ctx) +{ + struct qcomtee_context_data *ctxdata =3D ctx->data; + struct qcomtee_object *object; + int id; + + /* Process QUEUED or PROCESSING requests. */ + qcomtee_requests_destroy(ctxdata); + /* Release QTEE objects. */ + idr_for_each_entry(&ctxdata->qtee_objects_idr, object, id) + qcomtee_object_put(object); +} + +/* Gets called when the final reference to the context goes away. */ +static void qcomtee_release(struct tee_context *ctx) +{ + struct qcomtee_context_data *ctxdata =3D ctx->data; + + idr_destroy(&ctxdata->qtee_objects_idr); + idr_destroy(&ctxdata->reqs_idr); + kfree(ctxdata); + + /* There is nothing shared in this context with QTEE. */ + tee_device_put(ctx->teedev); +} + +static void qcomtee_get_version(struct tee_device *teedev, + struct tee_ioctl_version_data *vers) +{ + struct tee_ioctl_version_data v =3D { + .impl_id =3D TEE_IMPL_ID_QTEE, + .gen_caps =3D TEE_GEN_CAP_OBJREF, + }; + + *vers =3D v; +} + +/** + * qcomtee_get_qtee_feature_list() - Query QTEE features versions. + * @ctx: TEE context. + * @id: ID of the feature to query. + * @version: version of the feature. + * + * Used to query the verion of features supported by QTEE. + */ +static void qcomtee_get_qtee_feature_list(struct tee_context *ctx, u32 id, + u32 *version) +{ + struct qcomtee_object_invoke_ctx *oic __free(kfree); + struct qcomtee_object *client_env, *service; + struct qcomtee_arg u[3] =3D { 0 }; + int result; + + oic =3D qcomtee_object_invoke_ctx_alloc(ctx); + if (!oic) + return; + + client_env =3D qcomtee_object_get_client_env(oic); + if (client_env =3D=3D NULL_QCOMTEE_OBJECT) + return; + + /* Get ''FeatureVersions Service'' object. */ + service =3D qcomtee_object_get_service(oic, client_env, + QCOMTEE_FEATURE_VER_UID); + if (service =3D=3D NULL_QCOMTEE_OBJECT) + goto out_failed; + + /* IB: Feature to query. */ + u[0].b.addr =3D &id; + u[0].b.size =3D sizeof(id); + u[0].type =3D QCOMTEE_ARG_TYPE_IB; + + /* OB: Version returned. */ + u[1].b.addr =3D version; + u[1].b.size =3D sizeof(*version); + u[1].type =3D QCOMTEE_ARG_TYPE_OB; + + qcomtee_object_do_invoke(oic, service, QCOMTEE_FEATURE_VER_OP_GET, u, + &result); + +out_failed: + qcomtee_object_put(service); + qcomtee_object_put(client_env); +} + +static const struct tee_driver_ops qcomtee_ops =3D { + .get_version =3D qcomtee_get_version, + .open =3D qcomtee_open, + .close_context =3D qcomtee_close_context, + .release =3D qcomtee_release, + .object_invoke_func =3D qcomtee_object_invoke, + .supp_recv =3D qcomtee_supp_recv, + .supp_send =3D qcomtee_supp_send, +}; + +static const struct tee_desc qcomtee_desc =3D { + .name =3D "qcomtee", + .ops =3D &qcomtee_ops, + .owner =3D THIS_MODULE, +}; + +static int qcomtee_probe(struct platform_device *pdev) +{ + struct workqueue_struct *async_wq; + struct tee_device *teedev; + struct tee_shm_pool *pool; + struct tee_context *ctx; + struct qcomtee *qcomtee; + int err; + + qcomtee =3D kzalloc(sizeof(*qcomtee), GFP_KERNEL); + if (!qcomtee) + return -ENOMEM; + + pool =3D qcomtee_shm_pool_alloc(); + if (IS_ERR(pool)) { + err =3D PTR_ERR(pool); + + goto err_free_qcomtee; + } + + teedev =3D tee_device_alloc(&qcomtee_desc, NULL, pool, qcomtee); + if (IS_ERR(teedev)) { + err =3D PTR_ERR(teedev); + + goto err_pool_destroy; + } + + qcomtee->teedev =3D teedev; + qcomtee->pool =3D pool; + err =3D tee_device_register(qcomtee->teedev); + if (err) + goto err_unreg_teedev; + + platform_set_drvdata(pdev, qcomtee); + /* Start async wq. */ + async_wq =3D alloc_ordered_workqueue("qcomtee_wq", 0); + if (!async_wq) { + err =3D -ENOMEM; + + goto err_unreg_teedev; + } + + qcomtee->wq =3D async_wq; + /* Driver context used for async operations of teedev. */ + ctx =3D teedev_open(qcomtee->teedev); + if (IS_ERR(ctx)) { + err =3D PTR_ERR(ctx); + + goto err_dest_wq; + } + + qcomtee->ctx =3D ctx; + /* Init Object table. */ + qcomtee->xa_last_id =3D 0; + xa_init_flags(&qcomtee->xa_local_objects, XA_FLAGS_ALLOC); + /* Get QTEE verion. */ + qcomtee_get_qtee_feature_list(qcomtee->ctx, + QCOMTEE_FEATURE_VER_OP_GET_QTEE_ID, + &qcomtee->qtee_version); + + pr_info("QTEE version %u.%u.%u\n", + QTEE_VERSION_GET_MAJOR(qcomtee->qtee_version), + QTEE_VERSION_GET_MINOR(qcomtee->qtee_version), + QTEE_VERSION_GET_PATCH(qcomtee->qtee_version)); + + return 0; + +err_dest_wq: + destroy_workqueue(qcomtee->wq); +err_unreg_teedev: + tee_device_unregister(qcomtee->teedev); +err_pool_destroy: + tee_shm_pool_free(pool); +err_free_qcomtee: + kfree(qcomtee); + + return err; +} + +/** + * qcomtee_remove() - Device Removal Routine. + * @pdev: platform device information struct. + * + * It is called by the platform subsystem to alert the driver that it shou= ld + * release the device. + * + * QTEE does not provide an API to inform it about a callback object going= away. + * However, when releasing QTEE objects, any callback object sent to QTEE + * previously would be released by QTEE as part of the object release. + */ +static void qcomtee_remove(struct platform_device *pdev) +{ + struct qcomtee *qcomtee =3D platform_get_drvdata(pdev); + + teedev_close_context(qcomtee->ctx); + /* Wait for RELEASE operations to be processed for QTEE objects. */ + tee_device_unregister(qcomtee->teedev); + destroy_workqueue(qcomtee->wq); + tee_shm_pool_free(qcomtee->pool); + kfree(qcomtee); +} + +static const struct platform_device_id qcomtee_ids[] =3D { { "qcomtee", 0 = }, {} }; +MODULE_DEVICE_TABLE(platform, qcomtee_ids); + +static struct platform_driver qcomtee_platform_driver =3D { + .probe =3D qcomtee_probe, + .remove =3D qcomtee_remove, + .driver =3D { + .name =3D "qcomtee", + }, + .id_table =3D qcomtee_ids, +}; + +module_platform_driver(qcomtee_platform_driver); + +MODULE_AUTHOR("Qualcomm"); +MODULE_DESCRIPTION("QTEE driver"); +MODULE_VERSION("1.0"); +MODULE_LICENSE("GPL"); diff --git a/drivers/tee/qcomtee/core.c b/drivers/tee/qcomtee/core.c new file mode 100644 index 000000000000..b6931ed6f200 --- /dev/null +++ b/drivers/tee/qcomtee/core.c @@ -0,0 +1,906 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include + +#include "qcomtee.h" + +/* QTEE root object. */ +struct qcomtee_object qcomtee_object_root =3D { + .name =3D "root", + .object_type =3D QCOMTEE_OBJECT_TYPE_ROOT, + .info.qtee_id =3D QCOMTEE_MSG_OBJECT_ROOT, +}; + +/* Next argument of type @type after index @i. */ +int qcomtee_next_arg_type(struct qcomtee_arg *u, int i, + enum qcomtee_arg_type type) +{ + while (u[i].type !=3D QCOMTEE_ARG_TYPE_INV && u[i].type !=3D type) + i++; + return i; +} + +/* + * QTEE expects IDs with the QCOMTEE_MSG_OBJECT_NS_BIT set for objects + * of the QCOMTEE_OBJECT_TYPE_CB type. + */ +#define QCOMTEE_OBJECT_ID_START (QCOMTEE_MSG_OBJECT_NS_BIT + 1) +#define QCOMTEE_OBJECT_ID_END (U32_MAX) + +#define QCOMTEE_OBJECT_SET(p, type, ...) \ + __QCOMTEE_OBJECT_SET(p, type, ##__VA_ARGS__, 0UL) +#define __QCOMTEE_OBJECT_SET(p, type, optr, ...) \ + do { \ + (p)->object_type =3D (type); \ + (p)->info.qtee_id =3D (unsigned long)(optr); \ + } while (0) + +static struct qcomtee_object * +qcomtee_qtee_object_alloc(struct qcomtee_object_invoke_ctx *oic, + unsigned int object_id) +{ + struct qcomtee *qcomtee =3D tee_get_drvdata(oic->ctx->teedev); + struct qcomtee_object *object; + + object =3D kzalloc(sizeof(*object), GFP_KERNEL); + if (!object) + return NULL_QCOMTEE_OBJECT; + + /* If failed, "no-name". */ + object->name =3D kasprintf(GFP_KERNEL, "qcomtee-%u", object_id); + QCOMTEE_OBJECT_SET(object, QCOMTEE_OBJECT_TYPE_TEE, object_id); + kref_init(&object->refcount); + /* A QTEE object requires a context for async operations. */ + object->info.qcomtee_async_ctx =3D qcomtee->ctx; + teedev_ctx_get(object->info.qcomtee_async_ctx); + + return object; +} + +static void qcomtee_qtee_object_free(struct qcomtee_object *object) +{ + /* See qcomtee_qtee_object_alloc(). */ + teedev_ctx_put(object->info.qcomtee_async_ctx); + + kfree(object->name); + kfree(object); +} + +static void qcomtee_do_release_qtee_object(struct work_struct *work) +{ + struct qcomtee_object *object; + struct qcomtee *qcomtee; + int ret, result; + + /* RELEASE does not require any argument. */ + struct qcomtee_arg args[] =3D { { .type =3D QCOMTEE_ARG_TYPE_INV } }; + + object =3D container_of(work, struct qcomtee_object, work); + qcomtee =3D tee_get_drvdata(object->info.qcomtee_async_ctx->teedev); + /* Get the TEE context used for asynchronous operations. */ + qcomtee->oic.ctx =3D object->info.qcomtee_async_ctx; + + ret =3D qcomtee_object_do_invoke_internal(&qcomtee->oic, object, + QCOMTEE_MSG_OBJECT_OP_RELEASE, + args, &result); + + /* Is it safe to retry the release? */ + if (ret && ret !=3D -ENODEV) { + queue_work(qcomtee->wq, &object->work); + } else { + if (ret || result) + pr_err("%s release failed, ret =3D %d (%x)\n", + qcomtee_object_name(object), ret, result); + qcomtee_qtee_object_free(object); + } +} + +static void qcomtee_release_qtee_object(struct qcomtee_object *object) +{ + struct qcomtee *qcomtee =3D + tee_get_drvdata(object->info.qcomtee_async_ctx->teedev); + + INIT_WORK(&object->work, qcomtee_do_release_qtee_object); + queue_work(qcomtee->wq, &object->work); +} + +static void qcomtee_object_release(struct kref *refcount) +{ + struct qcomtee_object *object; + const char *name; + + object =3D container_of(refcount, struct qcomtee_object, refcount); + + /* + * qcomtee_object_get() is called in a RCU read lock. synchronize_rcu() + * to avoid releasing the object while it is being accessed in + * qcomtee_object_get(). + */ + synchronize_rcu(); + + switch (typeof_qcomtee_object(object)) { + case QCOMTEE_OBJECT_TYPE_TEE: + qcomtee_release_qtee_object(object); + + break; + case QCOMTEE_OBJECT_TYPE_CB: + name =3D object->name; + + if (object->ops->release) + object->ops->release(object); + + kfree_const(name); + + break; + case QCOMTEE_OBJECT_TYPE_ROOT: + case QCOMTEE_OBJECT_TYPE_NULL: + default: + break; + } +} + +/** + * qcomtee_object_get() - Increase the object's reference count. + * @object: object to increase the reference count. + * + * Context: The caller should hold RCU read lock. + */ +int qcomtee_object_get(struct qcomtee_object *object) +{ + if (object !=3D NULL_QCOMTEE_OBJECT && object !=3D ROOT_QCOMTEE_OBJECT) + return kref_get_unless_zero(&object->refcount); + + return 0; +} + +/** + * qcomtee_object_put() - Decrease the object's reference count. + * @object: object to decrease the reference count. + */ +void qcomtee_object_put(struct qcomtee_object *object) +{ + if (object !=3D NULL_QCOMTEE_OBJECT && object !=3D ROOT_QCOMTEE_OBJECT) + kref_put(&object->refcount, qcomtee_object_release); +} + +static int qcomtee_idx_alloc(struct qcomtee_object_invoke_ctx *oic, u32 *i= dx, + struct qcomtee_object *object) +{ + struct qcomtee *qcomtee =3D tee_get_drvdata(oic->ctx->teedev); + + /* Every ID allocated here has QCOMTEE_MSG_OBJECT_NS_BIT set. */ + return xa_alloc_cyclic(&qcomtee->xa_local_objects, idx, object, + XA_LIMIT(QCOMTEE_OBJECT_ID_START, + QCOMTEE_OBJECT_ID_END), + &qcomtee->xa_last_id, GFP_KERNEL); +} + +struct qcomtee_object *qcomtee_idx_erase(struct qcomtee_object_invoke_ctx = *oic, + u32 idx) +{ + struct qcomtee *qcomtee =3D tee_get_drvdata(oic->ctx->teedev); + + if (idx < QCOMTEE_OBJECT_ID_START || idx > QCOMTEE_OBJECT_ID_END) + return NULL_QCOMTEE_OBJECT; + + return xa_erase(&qcomtee->xa_local_objects, idx); +} + +/** + * qcomtee_object_id_get() - Get an ID for an object to send to QTEE. + * @oic: context to use for the invocation. + * @object: object to assign an ID. + * @object_id: object ID. + * + * Called on the path to QTEE to construct the message; see + * qcomtee_prepare_msg() and qcomtee_update_msg(). + * + * Return: On success, returns 0; on failure, returns < 0. + */ +static int qcomtee_object_id_get(struct qcomtee_object_invoke_ctx *oic, + struct qcomtee_object *object, + unsigned int *object_id) +{ + u32 idx; + + switch (typeof_qcomtee_object(object)) { + case QCOMTEE_OBJECT_TYPE_CB: + if (qcomtee_idx_alloc(oic, &idx, object) < 0) + return -ENOSPC; + + *object_id =3D idx; + + break; + case QCOMTEE_OBJECT_TYPE_ROOT: + case QCOMTEE_OBJECT_TYPE_TEE: + *object_id =3D object->info.qtee_id; + + break; + case QCOMTEE_OBJECT_TYPE_NULL: + *object_id =3D QCOMTEE_MSG_OBJECT_NULL; + + break; + } + + return 0; +} + +/* Release object ID assigned in qcomtee_object_id_get. */ +static void qcomtee_object_id_put(struct qcomtee_object_invoke_ctx *oic, + unsigned int object_id) +{ + qcomtee_idx_erase(oic, object_id); +} + +/** + * qcomtee_local_object_get() - Get the object referenced by the ID. + * @oic: context to use for the invocation. + * @object_id: object ID. + * + * It is called on the path from QTEE. + * It is called on behalf of QTEE to obtain an instance of an object + * for a given ID. It increases the object's reference count on success. + * + * Return: On error, returns %NULL_QCOMTEE_OBJECT. + * On success, returns the object. + */ +static struct qcomtee_object * +qcomtee_local_object_get(struct qcomtee_object_invoke_ctx *oic, + unsigned int object_id) +{ + struct qcomtee *qcomtee =3D tee_get_drvdata(oic->ctx->teedev); + struct qcomtee_object *object; + + guard(rcu)(); + object =3D xa_load(&qcomtee->xa_local_objects, object_id); + /* It already checks for %NULL_QCOMTEE_OBJECT. */ + qcomtee_object_get(object); + + return object; +} + +/** + * qcomtee_object_user_init() - Initialize an object for the user. + * @object: object to initialize. + * @ot: type of object as &enum qcomtee_object_type. + * @ops: instance of callbacks. + * @fmt: name assigned to the object. + * + * Return: On success, returns 0; on failure, returns < 0. + */ +int qcomtee_object_user_init(struct qcomtee_object *object, + enum qcomtee_object_type ot, + struct qcomtee_object_operations *ops, + const char *fmt, ...) +{ + va_list ap; + int ret; + + kref_init(&object->refcount); + QCOMTEE_OBJECT_SET(object, QCOMTEE_OBJECT_TYPE_NULL); + + va_start(ap, fmt); + switch (ot) { + case QCOMTEE_OBJECT_TYPE_NULL: + ret =3D 0; + + break; + case QCOMTEE_OBJECT_TYPE_CB: + object->ops =3D ops; + if (!object->ops->dispatch) + return -EINVAL; + + /* If failed, "no-name". */ + object->name =3D kvasprintf_const(GFP_KERNEL, fmt, ap); + QCOMTEE_OBJECT_SET(object, QCOMTEE_OBJECT_TYPE_CB); + + ret =3D 0; + break; + case QCOMTEE_OBJECT_TYPE_ROOT: + case QCOMTEE_OBJECT_TYPE_TEE: + default: + ret =3D -EINVAL; + } + va_end(ap); + + return ret; +} + +/** + * qcomtee_object_type() - Returns the type of object represented by an ID. + * @object_id: object ID for the object. + * + * Similar to typeof_qcomtee_object(), but instead of receiving an object = as + * an argument, it receives an object ID. It is used internally on the ret= urn + * path from QTEE. + * + * Return: Returns the type of object referenced by @object_id. + */ +static enum qcomtee_object_type qcomtee_object_type(unsigned int object_id) +{ + if (object_id =3D=3D QCOMTEE_MSG_OBJECT_NULL) + return QCOMTEE_OBJECT_TYPE_NULL; + + if (object_id & QCOMTEE_MSG_OBJECT_NS_BIT) + return QCOMTEE_OBJECT_TYPE_CB; + + return QCOMTEE_OBJECT_TYPE_TEE; +} + +/** + * qcomtee_object_qtee_init() - Initialize an object for QTEE. + * @oic: context to use for the invocation. + * @object: object returned. + * @object_id: object ID received from QTEE. + * + * Return: On failure, returns < 0 and sets @object to %NULL_QCOMTEE_OBJEC= T. + * On success, returns 0 + */ +static int qcomtee_object_qtee_init(struct qcomtee_object_invoke_ctx *oic, + struct qcomtee_object **object, + unsigned int object_id) +{ + int ret =3D 0; + + switch (qcomtee_object_type(object_id)) { + case QCOMTEE_OBJECT_TYPE_NULL: + *object =3D NULL_QCOMTEE_OBJECT; + + break; + case QCOMTEE_OBJECT_TYPE_CB: + *object =3D qcomtee_local_object_get(oic, object_id); + if (*object =3D=3D NULL_QCOMTEE_OBJECT) + ret =3D -EINVAL; + + break; + + default: /* QCOMTEE_OBJECT_TYPE_TEE */ + *object =3D qcomtee_qtee_object_alloc(oic, object_id); + if (*object =3D=3D NULL_QCOMTEE_OBJECT) + ret =3D -ENOMEM; + + break; + } + + return ret; +} + +/* + * ''Marshaling API'' + * qcomtee_prepare_msg - Prepare the inbound buffer for sending to QTEE + * qcomtee_update_args - Parse the QTEE response in the inbound buffer + * qcomtee_prepare_args - Parse the QTEE request from the outbound buffer + * qcomtee_update_msg - Update the outbound buffer with the response for= QTEE + */ + +static int qcomtee_prepare_msg(struct qcomtee_object_invoke_ctx *oic, + struct qcomtee_object *object, u32 op, + struct qcomtee_arg *u) +{ + struct qcomtee_msg_object_invoke *msg; + unsigned int object_id; + int i, ib, ob, io, oo; + size_t offset; + + /* Use the input message buffer in 'oic'. */ + msg =3D oic->in_msg.addr; + + /* Start offset in a message for buffer arguments. */ + offset =3D qcomtee_msg_buffer_args(struct qcomtee_msg_object_invoke, + qcomtee_args_len(u)); + + /* Get the ID of the object being invoked. */ + if (qcomtee_object_id_get(oic, object, &object_id)) + return -ENOSPC; + + ib =3D 0; + qcomtee_arg_for_each_input_buffer(i, u) { + void *msgptr; /* Address of buffer payload: */ + /* Overflow already checked in qcomtee_msg_buffers_alloc(). */ + msg->args[ib].b.offset =3D offset; + msg->args[ib].b.size =3D u[i].b.size; + + msgptr =3D qcomtee_msg_offset_to_ptr(msg, offset); + /* Userspace client or kernel client!? */ + if (!(u[i].flags & QCOMTEE_ARG_FLAGS_UADDR)) + memcpy(msgptr, u[i].b.addr, u[i].b.size); + else if (copy_from_user(msgptr, u[i].b.uaddr, u[i].b.size)) + return -EINVAL; + + offset +=3D qcomtee_msg_offset_align(u[i].b.size); + ib++; + } + + ob =3D ib; + qcomtee_arg_for_each_output_buffer(i, u) { + /* Overflow already checked in qcomtee_msg_buffers_alloc(). */ + msg->args[ob].b.offset =3D offset; + msg->args[ob].b.size =3D u[i].b.size; + + offset +=3D qcomtee_msg_offset_align(u[i].b.size); + ob++; + } + + io =3D ob; + qcomtee_arg_for_each_input_object(i, u) { + if (qcomtee_object_id_get(oic, u[i].o, &msg->args[io].o)) { + qcomtee_object_id_put(oic, object_id); + for (io--; io >=3D ob; io--) + qcomtee_object_id_put(oic, msg->args[io].o); + + return -ENOSPC; + } + + io++; + } + + oo =3D io; + qcomtee_arg_for_each_output_object(i, u) + oo++; + + /* Set object, operation, and argument counts. */ + qcomtee_msg_init(msg, object_id, op, ib, ob, io, oo); + + return 0; +} + +/** + * qcomtee_update_args() - Parse the QTEE response in the inbound buffer. + * @u: array of arguments for the invocation. + * @oic: context to use for the invocation. + * + * @u must be the same as the one used in qcomtee_prepare_msg() when + * initializing the inbound buffer. + * + * On failure, it continues processing the QTEE message. The caller should + * do the necessary cleanup, including calling qcomtee_object_put() + * on the output objects. + * + * Return: On success, returns 0; on failure, returns < 0. + */ +static int qcomtee_update_args(struct qcomtee_arg *u, + struct qcomtee_object_invoke_ctx *oic) +{ + struct qcomtee_msg_object_invoke *msg; + int i, ib, ob, io, oo; + int ret =3D 0; + + /* Use the input message buffer in 'oic'. */ + msg =3D oic->in_msg.addr; + + ib =3D 0; + qcomtee_arg_for_each_input_buffer(i, u) + ib++; + + ob =3D ib; + qcomtee_arg_for_each_output_buffer(i, u) { + void *msgptr; /* Address of buffer payload: */ + /* QTEE can override the size to a smaller value. */ + u[i].b.size =3D msg->args[ob].b.size; + + msgptr =3D qcomtee_msg_offset_to_ptr(msg, msg->args[ob].b.offset); + /* Userspace client or kernel client!? */ + if (!(u[i].flags & QCOMTEE_ARG_FLAGS_UADDR)) + memcpy(u[i].b.addr, msgptr, u[i].b.size); + else if (copy_to_user(u[i].b.uaddr, msgptr, u[i].b.size)) + ret =3D -EINVAL; + + ob++; + } + + io =3D ob; + qcomtee_arg_for_each_input_object(i, u) + io++; + + oo =3D io; + qcomtee_arg_for_each_output_object(i, u) { + if (qcomtee_object_qtee_init(oic, &u[i].o, msg->args[oo].o)) + ret =3D -EINVAL; + + oo++; + } + + return ret; +} + +/** + * qcomtee_prepare_args() - Parse the QTEE request from the outbound buffe= r. + * @oic: context to use for the invocation. + * + * It initializes &qcomtee_object_invoke_ctx->u based on the QTEE request = in + * the outbound buffer. It sets %QCOMTEE_ARG_TYPE_INV at the end of the ar= ray. + * + * On failure, it continues processing the QTEE message. The caller should + * do the necessary cleanup, including calling qcomtee_object_put() + * on the input objects. + * + * Return: On success, returns 0; on failure, returns < 0. + */ +static int qcomtee_prepare_args(struct qcomtee_object_invoke_ctx *oic) +{ + struct qcomtee_msg_callback *msg; + int i, ret =3D 0; + + /* Use the output message buffer in 'oic'. */ + msg =3D oic->out_msg.addr; + + qcomtee_msg_for_each_input_buffer(i, msg) { + oic->u[i].b.addr =3D + qcomtee_msg_offset_to_ptr(msg, msg->args[i].b.offset); + oic->u[i].b.size =3D msg->args[i].b.size; + oic->u[i].type =3D QCOMTEE_ARG_TYPE_IB; + } + + qcomtee_msg_for_each_output_buffer(i, msg) { + oic->u[i].b.addr =3D + qcomtee_msg_offset_to_ptr(msg, msg->args[i].b.offset); + oic->u[i].b.size =3D msg->args[i].b.size; + oic->u[i].type =3D QCOMTEE_ARG_TYPE_OB; + } + + qcomtee_msg_for_each_input_object(i, msg) { + if (qcomtee_object_qtee_init(oic, &oic->u[i].o, msg->args[i].o)) + ret =3D -EINVAL; + + oic->u[i].type =3D QCOMTEE_ARG_TYPE_IO; + } + + qcomtee_msg_for_each_output_object(i, msg) + oic->u[i].type =3D QCOMTEE_ARG_TYPE_OO; + + /* End of Arguments. */ + oic->u[i].type =3D QCOMTEE_ARG_TYPE_INV; + + return ret; +} + +static int qcomtee_update_msg(struct qcomtee_object_invoke_ctx *oic) +{ + struct qcomtee_msg_callback *msg; + int i, ib, ob, io, oo; + + /* Use the output message buffer in 'oic'. */ + msg =3D oic->out_msg.addr; + + ib =3D 0; + qcomtee_arg_for_each_input_buffer(i, oic->u) + ib++; + + ob =3D ib; + qcomtee_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 =3D oic->u[i].b.size; + ob++; + } + + io =3D ob; + qcomtee_arg_for_each_input_object(i, oic->u) + io++; + + oo =3D io; + qcomtee_arg_for_each_output_object(i, oic->u) { + if (qcomtee_object_id_get(oic, oic->u[i].o, &msg->args[oo].o)) { + for (oo--; oo >=3D io; oo--) + qcomtee_object_id_put(oic, msg->args[oo].o); + + return -ENOSPC; + } + + oo++; + } + + return 0; +} + +/* Invoke a callback object. */ +static void qcomtee_cb_object_invoke(struct qcomtee_object_invoke_ctx *oic, + struct qcomtee_msg_callback *msg) +{ + int i, errno; + u32 op; + + /* Get the object being invoked. */ + unsigned int object_id =3D msg->cxt; + struct qcomtee_object *object; + + /* QTEE cannot invoke a NULL object or objects it hosts. */ + if (qcomtee_object_type(object_id) =3D=3D QCOMTEE_OBJECT_TYPE_NULL || + qcomtee_object_type(object_id) =3D=3D QCOMTEE_OBJECT_TYPE_TEE) { + errno =3D -EINVAL; + goto out; + } + + object =3D qcomtee_local_object_get(oic, object_id); + if (object =3D=3D NULL_QCOMTEE_OBJECT) { + errno =3D -EINVAL; + goto out; + } + + oic->object =3D object; + + /* Filter bits used by transport. */ + op =3D msg->op & QCOMTEE_MSG_OBJECT_OP_MASK; + + switch (op) { + case QCOMTEE_MSG_OBJECT_OP_RELEASE: + qcomtee_object_id_put(oic, object_id); + qcomtee_object_put(object); + errno =3D 0; + + break; + case QCOMTEE_MSG_OBJECT_OP_RETAIN: + qcomtee_object_get(object); + errno =3D 0; + + break; + default: + errno =3D qcomtee_prepare_args(oic); + if (errno) { + /* Release any object that arrived as input. */ + qcomtee_arg_for_each_input_buffer(i, oic->u) + qcomtee_object_put(oic->u[i].o); + + break; + } + + errno =3D object->ops->dispatch(oic, object, op, oic->u); + if (!errno) { + /* On success, notify at the appropriate time. */ + oic->flags |=3D QCOMTEE_OIC_FLAG_NOTIFY; + } + } + +out: + + oic->errno =3D errno; +} + +static int +qcomtee_object_invoke_ctx_invoke(struct qcomtee_object_invoke_ctx *oic, + int *result, u64 *res_type) +{ + phys_addr_t out_msg_paddr; + phys_addr_t in_msg_paddr; + int ret; + u64 res; + + tee_shm_get_pa(oic->out_shm, 0, &out_msg_paddr); + tee_shm_get_pa(oic->in_shm, 0, &in_msg_paddr); + if (!(oic->flags & QCOMTEE_OIC_FLAG_BUSY)) + ret =3D qcom_scm_qtee_invoke_smc(in_msg_paddr, oic->in_msg.size, + out_msg_paddr, oic->out_msg.size, + &res, res_type); + else + ret =3D qcom_scm_qtee_callback_response(out_msg_paddr, + oic->out_msg.size, + &res, res_type); + + if (ret) + pr_err("QTEE returned with %d.\n", ret); + else + *result =3D (int)res; + + return ret; +} + +/** + * qcomtee_qtee_objects_put() - Put the callback objects in the argument a= rray. + * @u: array of arguments. + * + * When qcomtee_object_do_invoke_internal() is successfully invoked, + * QTEE takes ownership of the callback objects. If the invocation fails, + * qcomtee_object_do_invoke_internal() calls qcomtee_qtee_objects_put() + * to mimic the release of callback objects by QTEE. + */ +static void qcomtee_qtee_objects_put(struct qcomtee_arg *u) +{ + int i; + + qcomtee_arg_for_each_input_object(i, u) { + if (typeof_qcomtee_object(u[i].o) =3D=3D QCOMTEE_OBJECT_TYPE_CB) + qcomtee_object_put(u[i].o); + } +} + +/** + * qcomtee_object_do_invoke_internal() - Submit an invocation for an objec= t. + * @oic: context to use for the current invocation. + * @object: object being invoked. + * @op: requested operation on the object. + * @u: array of arguments for the current invocation. + * @result: result returned from QTEE. + * + * The caller is responsible for keeping track of the refcount for each + * object, including @object. On return, the caller loses ownership of all + * input objects of type %QCOMTEE_OBJECT_TYPE_CB. + * + * Return: On success, returns 0; on failure, returns < 0. + */ +int qcomtee_object_do_invoke_internal(struct qcomtee_object_invoke_ctx *oi= c, + struct qcomtee_object *object, u32 op, + struct qcomtee_arg *u, int *result) +{ + struct qcomtee_msg_callback *cb_msg; + struct qcomtee_object *qto; + int i, ret, errno; + u64 res_type; + + /* Allocate inbound and outbound buffers. */ + ret =3D qcomtee_msg_buffers_alloc(oic, u); + if (ret) { + qcomtee_qtee_objects_put(u); + + return ret; + } + + ret =3D qcomtee_prepare_msg(oic, object, op, u); + if (ret) { + qcomtee_qtee_objects_put(u); + + goto out; + } + + /* Use input message buffer in 'oic'. */ + cb_msg =3D oic->out_msg.addr; + + while (1) { + if (oic->flags & QCOMTEE_OIC_FLAG_BUSY) { + errno =3D oic->errno; + if (!errno) + errno =3D qcomtee_update_msg(oic); + qcomtee_msg_set_result(cb_msg, errno); + } + + /* Invoke the remote object. */ + ret =3D qcomtee_object_invoke_ctx_invoke(oic, result, &res_type); + /* Return form callback objects result submission: */ + if (oic->flags & QCOMTEE_OIC_FLAG_BUSY) { + qto =3D oic->object; + if (qto) { + if (oic->flags & QCOMTEE_OIC_FLAG_NOTIFY) { + if (qto->ops->notify) + qto->ops->notify(oic, qto, + errno || ret); + } + + /* Get is in qcomtee_cb_object_invoke(). */ + qcomtee_object_put(qto); + } + + oic->object =3D NULL_QCOMTEE_OBJECT; + oic->flags &=3D ~(QCOMTEE_OIC_FLAG_BUSY | + QCOMTEE_OIC_FLAG_NOTIFY); + } + + if (ret) { + /* + * Unable to finished the invocation. + * If QCOMTEE_OIC_FLAG_SHARED is not set, put + * QCOMTEE_OBJECT_TYPE_CB input objects. + */ + if (!(oic->flags & QCOMTEE_OIC_FLAG_SHARED)) + qcomtee_qtee_objects_put(u); + else + ret =3D -ENODEV; + + goto out; + + } else { + /* + * QTEE obtained ownership of QCOMTEE_OBJECT_TYPE_CB + * input objects in 'u'. On further failure, QTEE is + * responsible for releasing them. + */ + oic->flags |=3D QCOMTEE_OIC_FLAG_SHARED; + } + + /* Is it a callback request? */ + if (res_type !=3D QCOMTEE_RESULT_INBOUND_REQ_NEEDED) { + /* + * Parse results. If failed, assume the service + * was unavailable (i.e. QCOMTEE_MSG_ERROR_UNAVAIL) + * and put output objects to initiate cleanup. + */ + if (!*result && qcomtee_update_args(u, oic)) { + *result =3D QCOMTEE_MSG_ERROR_UNAVAIL; + qcomtee_arg_for_each_output_object(i, u) + qcomtee_object_put(u[i].o); + } + + break; + + } else { + oic->flags |=3D QCOMTEE_OIC_FLAG_BUSY; + qcomtee_fetch_async_reqs(oic); + qcomtee_cb_object_invoke(oic, cb_msg); + } + } + + qcomtee_fetch_async_reqs(oic); +out: + qcomtee_msg_buffers_free(oic); + + return ret; +} + +int qcomtee_object_do_invoke(struct qcomtee_object_invoke_ctx *oic, + struct qcomtee_object *object, u32 op, + struct qcomtee_arg *u, int *result) +{ + /* User can not set bits used by transport. */ + if (op & ~QCOMTEE_MSG_OBJECT_OP_MASK) + return -EINVAL; + + /* User can only invoke QTEE hosted objects. */ + if (typeof_qcomtee_object(object) !=3D QCOMTEE_OBJECT_TYPE_TEE && + typeof_qcomtee_object(object) !=3D QCOMTEE_OBJECT_TYPE_ROOT) + return -EINVAL; + + /* User cannot directly issue these operations to QTEE. */ + if (op =3D=3D QCOMTEE_MSG_OBJECT_OP_RELEASE || + op =3D=3D QCOMTEE_MSG_OBJECT_OP_RETAIN) + return -EINVAL; + + return qcomtee_object_do_invoke_internal(oic, object, op, u, result); +} + +/** + * qcomtee_object_get_client_env() - Get a privileged client env. object. + * @oic: context to use for the current invocation. + * + * The caller should call qcomtee_object_put() on the returned object + * to release it. + * + * Return: On error, returns %NULL_QCOMTEE_OBJECT. + * On success, returns the object. + */ +struct qcomtee_object * +qcomtee_object_get_client_env(struct qcomtee_object_invoke_ctx *oic) +{ + struct qcomtee_arg u[3] =3D { 0 }; + int ret, result; + + u[0].o =3D NULL_QCOMTEE_OBJECT; + u[0].type =3D QCOMTEE_ARG_TYPE_IO; + u[1].type =3D QCOMTEE_ARG_TYPE_OO; + ret =3D qcomtee_object_do_invoke(oic, ROOT_QCOMTEE_OBJECT, + QCOMTEE_ROOT_OP_REG_WITH_CREDENTIALS, u, + &result); + if (ret || result) + return NULL_QCOMTEE_OBJECT; + + return u[1].o; +} + +struct qcomtee_object * +qcomtee_object_get_service(struct qcomtee_object_invoke_ctx *oic, + struct qcomtee_object *client_env, u32 uid) +{ + struct qcomtee_arg u[3] =3D { 0 }; + int ret, result; + + u[0].b.addr =3D &uid; + u[0].b.size =3D sizeof(uid); + u[0].type =3D QCOMTEE_ARG_TYPE_IB; + u[1].type =3D QCOMTEE_ARG_TYPE_OO; + ret =3D qcomtee_object_do_invoke(oic, client_env, QCOMTEE_CLIENT_ENV_OPEN, + u, &result); + + if (ret || result) + return NULL_QCOMTEE_OBJECT; + + return u[1].o; +} diff --git a/drivers/tee/qcomtee/qcomtee.h b/drivers/tee/qcomtee/qcomtee.h new file mode 100644 index 000000000000..f34be992e68b --- /dev/null +++ b/drivers/tee/qcomtee/qcomtee.h @@ -0,0 +1,143 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#ifndef QCOMTEE_H +#define QCOMTEE_H + +#include +#include + +#include "qcomtee_msg.h" +#include "qcomtee_object.h" + +/* Flags relating to object reference. */ +#define QCOMTEE_OBJREF_FLAG_TEE BIT(0) +#define QCOMTEE_OBJREF_FLAG_USER BIT(1) + +/** + * struct qcomtee - Main service struct. + * @teedev: client device. + * @pool: shared memory pool. + * @ctx: driver private context. + * @oic: context to use for the current driver invocation. + * @wq: workqueue for QTEE async operations. + * @xa_local_objects: array of objects exported to QTEE. + * @xa_last_id: next ID to allocate. + * @qtee_version: QTEE version. + */ +struct qcomtee { + struct tee_device *teedev; + struct tee_shm_pool *pool; + struct tee_context *ctx; + struct qcomtee_object_invoke_ctx oic; + struct workqueue_struct *wq; + struct xarray xa_local_objects; + u32 xa_last_id; + u32 qtee_version; +}; + +void qcomtee_fetch_async_reqs(struct qcomtee_object_invoke_ctx *oic); +struct qcomtee_object *qcomtee_idx_erase(struct qcomtee_object_invoke_ctx = *oic, + u32 idx); + +struct tee_shm_pool *qcomtee_shm_pool_alloc(void); +void qcomtee_msg_buffers_free(struct qcomtee_object_invoke_ctx *oic); +int qcomtee_msg_buffers_alloc(struct qcomtee_object_invoke_ctx *oic, + struct qcomtee_arg *u); + +/** + * qcomtee_object_do_invoke_internal() - Submit an invocation for an objec= t. + * @oic: context to use for the current invocation. + * @object: object being invoked. + * @op: requested operation on the object. + * @u: array of arguments for the current invocation. + * @result: result returned from QTEE. + * + * The caller is responsible for keeping track of the refcount for each + * object, including @object. On return, the caller loses ownership of all + * input objects of type %QCOMTEE_OBJECT_TYPE_CB. + * + * Return: On success, returns 0; on failure, returns < 0. + */ +int qcomtee_object_do_invoke_internal(struct qcomtee_object_invoke_ctx *oi= c, + struct qcomtee_object *object, u32 op, + struct qcomtee_arg *u, int *result); + +/** + * struct qcomtee_context_data - Clients' or supplicants' context. + * @qtee_objects_idr: QTEE objects in this context. + * @qtee_lock: mutex for @qtee_objects_idr. + * @reqs_idr: requests in this context that hold ID. + * @reqs_list: FIFO for requests in PROCESSING or QUEUED state. + * @reqs_lock: mutex for @reqs_idr, @reqs_list and request states. + * @req_c: completion used when the supplicant is waiting for requests. + * @released: state of this context. + */ +struct qcomtee_context_data { + struct idr qtee_objects_idr; + /* Synchronize access to @qtee_objects_idr. */ + struct mutex qtee_lock; + + struct idr reqs_idr; + struct list_head reqs_list; + /* Synchronize access to @reqs_idr, @reqs_list and updating requests stat= es. */ + struct mutex reqs_lock; + + struct completion req_c; + + bool released; +}; + +int qcomtee_context_add_qtee_object(struct tee_param *param, + struct qcomtee_object *object, + struct tee_context *ctx); +int qcomtee_context_find_qtee_object(struct qcomtee_object **object, + struct tee_param *param, + struct tee_context *ctx); +void qcomtee_context_del_qtee_object(struct tee_param *param, + struct tee_context *ctx); + +int qcomtee_objref_to_arg(struct qcomtee_arg *arg, struct tee_param *param, + struct tee_context *ctx); +int qcomtee_objref_from_arg(struct tee_param *param, struct qcomtee_arg *a= rg, + struct tee_context *ctx); + +/* OBJECTS: */ + +/* (1) User Object API. */ + +int is_qcomtee_user_object(struct qcomtee_object *object); +void qcomtee_user_object_set_notify(struct qcomtee_object *object, bool no= tify); +void qcomtee_requests_destroy(struct qcomtee_context_data *ctxdata); +int qcomtee_user_param_to_object(struct qcomtee_object **object, + struct tee_param *param, + struct tee_context *ctx); +int qcomtee_user_param_from_object(struct tee_param *param, + struct qcomtee_object *object, + struct tee_context *ctx); + +/** + * struct qcomtee_user_object_request_data - Data for user object request. + * @id: ID assigned to the request. + * @object_id: Object ID being invoked by QTEE. + * @op: Requested operation on object. + * @np: Number of parameters in the request. + */ +struct qcomtee_user_object_request_data { + int id; + u64 object_id; + u32 op; + int np; +}; + +int qcomtee_user_object_select(struct tee_context *ctx, + struct tee_param *params, int num_params, + void __user *uaddr, size_t size, + struct qcomtee_user_object_request_data *data); +int qcomtee_user_object_submit(struct tee_context *ctx, + struct tee_param *params, int num_params, + int req_id, int errno); + +#endif /* QCOMTEE_H */ diff --git a/drivers/tee/qcomtee/qcomtee_msg.h b/drivers/tee/qcomtee/qcomte= e_msg.h new file mode 100644 index 000000000000..878f70178a5b --- /dev/null +++ b/drivers/tee/qcomtee/qcomtee_msg.h @@ -0,0 +1,304 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#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 outbou= nd + * buffer is used to make a request from QTEE to the kernel; i.e., a callb= ack + * request. + * + * The unused tail of the outbound buffer is also used for sending and + * receiving asynchronous messages. An asynchronous message is independent= of + * the current object invocation (i.e., contents of the inbound buffer) or + * callback request (i.e., the head of the outbound buffer); see + * qcomtee_get_async_buffer(). It is used by endpoints (QTEE or kernel) as= an + * optimization to reduce the number of context switches between the secur= e and + * non-secure worlds. + * + * For instance, QTEE never sends an explicit callback request to release = an + * object in the kernel. Instead, it sends asynchronous release messages i= n the + * outbound buffer when QTEE returns from the previous direct object invoc= ation, + * or appends asynchronous release messages after the current callback req= uest. + * + * 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. Buff= er + * arguments hold (offset, size) pairs into the inbound or outbound buffer= s. + * + * QTEE holds an object table for objects it hosts and exposes to the kern= el. + * An object ID is an index to the object table in QTEE. + * + * For the direct object invocation message format in the inbound buffer, = see + * &struct qcomtee_msg_object_invoke. For the callback request message for= mat + * in the outbound buffer, see &struct qcomtee_msg_callback. For the messa= ge + * format for asynchronous messages in the outbound buffer, see + * &struct qcomtee_async_msg_hdr. + */ + +/** + * define QCOMTEE_MSG_OBJECT_NS_BIT - Non-secure bit + * + * Object ID is a globally unique 32-bit number. IDs referencing objects + * in the kernel should have %QCOMTEE_MSG_OBJECT_NS_BIT set. + */ +#define QCOMTEE_MSG_OBJECT_NS_BIT BIT(31) + +/* Static object IDs recognized by QTEE. */ +#define QCOMTEE_MSG_OBJECT_NULL (0U) +#define QCOMTEE_MSG_OBJECT_ROOT (1U) + +/* Definitions from QTEE as part of the transport protocol. */ + +/* qcomtee_msg_arg is an argument as recognized by QTEE. */ +union qcomtee_msg_arg { + struct { + u32 offset; + u32 size; + } b; + u32 o; +}; + +/* BI and BO payloads in QTEE messages should be at 64-bit boundaries. */ +#define qcomtee_msg_offset_align(o) ALIGN((o), sizeof(u64)) + +/* Operations for objects are 32-bit. Transport uses the upper 16 bits. */ +#define QCOMTEE_MSG_OBJECT_OP_MASK GENMASK(15, 0) + +/* Reserved Operation IDs sent to QTEE: */ +/* QCOMTEE_MSG_OBJECT_OP_RELEASE - Reduces the refcount and releases the o= bject. + * QCOMTEE_MSG_OBJECT_OP_RETAIN - Increases the refcount. + * + * These operation IDs are valid for all objects. + */ + +#define QCOMTEE_MSG_OBJECT_OP_RELEASE (QCOMTEE_MSG_OBJECT_OP_MASK - 0) +#define QCOMTEE_MSG_OBJECT_OP_RETAIN (QCOMTEE_MSG_OBJECT_OP_MASK - 1) + +/* Subset of operations supported by QTEE root object. */ + +#define QCOMTEE_ROOT_OP_REG_WITH_CREDENTIALS 5 +#define QCOMTEE_ROOT_OP_NOTIFY_DOMAIN_CHANGE 4 +#define QCOMTEE_ROOT_OP_ADCI_ACCEPT 8 +#define QCOMTEE_ROOT_OP_ADCI_SHUTDOWN 9 + +/* Subset of operations supported by client_env object. */ + +#define QCOMTEE_CLIENT_ENV_OPEN 0 + +/* List of available QTEE service UIDs and subset of operations. */ + +#define QCOMTEE_FEATURE_VER_UID 2033 +#define QCOMTEE_FEATURE_VER_OP_GET 0 +/* Get QTEE version number. */ +#define QCOMTEE_FEATURE_VER_OP_GET_QTEE_ID 10 +#define QTEE_VERSION_GET_MAJOR(x) (((x) >> 22) & 0xffU) +#define QTEE_VERSION_GET_MINOR(x) (((x) >> 12) & 0xffU) +#define QTEE_VERSION_GET_PATCH(x) ((x) >> 0 & 0xfffU) + +/* Response types as returned from qcomtee_object_invoke_ctx_invoke(). */ + +/* The message contains a callback request. */ +#define QCOMTEE_RESULT_INBOUND_REQ_NEEDED 3 + +/** + * struct qcomtee_msg_object_invoke - Direct object invocation message. + * @ctx: object ID hosted in QTEE. + * @op: operation for the object. + * @counts: number of different types of arguments in @args. + * @args: array of arguments. + * + * @counts consists of 4 * 4-bit fields. Bits 0 - 3 represent the number of + * input buffers, bits 4 - 7 represent the number of output buffers, + * bits 8 - 11 represent the number of input objects, and bits 12 - 15 + * represent the number of output objects. The remaining bits should be ze= ro. + * + * 15 12 11 8 7 4 3 0 + * +----------------+----------------+----------------+----------------+ + * | #OO objects | #IO objects | #OB buffers | #IB buffers | + * +----------------+----------------+----------------+----------------+ + * + * The maximum number of arguments of each type is defined by + * %QCOMTEE_ARGS_PER_TYPE. + */ +struct qcomtee_msg_object_invoke { + u32 cxt; + u32 op; + u32 counts; + union qcomtee_msg_arg args[]; +}; + +/* Bit masks for the four 4-bit nibbles holding the counts. */ +#define QCOMTEE_MASK_IB GENMASK(3, 0) +#define QCOMTEE_MASK_OB GENMASK(7, 4) +#define QCOMTEE_MASK_IO GENMASK(11, 8) +#define QCOMTEE_MASK_OO GENMASK(15, 12) + +/** + * struct qcomtee_msg_callback - Callback request message. + * @result: result of operation @op on the object referenced by @cxt. + * @cxt: object ID hosted in the kernel. + * @op: operation for the object. + * @counts: number of different types of arguments in @args. + * @args: array of arguments. + * + * For details of @counts, see &qcomtee_msg_object_invoke.counts. + */ +struct qcomtee_msg_callback { + u32 result; + u32 cxt; + u32 op; + u32 counts; + union qcomtee_msg_arg args[]; +}; + +/* Offset in the message for the beginning of the buffer argument's conten= ts. */ +#define qcomtee_msg_buffer_args(t, n) \ + qcomtee_msg_offset_align(struct_size_t(t, args, n)) +/* Pointer to the beginning of a buffer argument's content at an offset. */ +#define qcomtee_msg_offset_to_ptr(m, off) ((void *)&((char *)(m))[(off)]) + +/* Some helpers to manage msg.counts. */ + +static inline unsigned int qcomtee_msg_num_ib(u32 counts) +{ + return FIELD_GET(QCOMTEE_MASK_IB, counts); +} + +static inline unsigned int qcomtee_msg_num_ob(u32 counts) +{ + return FIELD_GET(QCOMTEE_MASK_OB, counts); +} + +static inline unsigned int qcomtee_msg_num_io(u32 counts) +{ + return FIELD_GET(QCOMTEE_MASK_IO, counts); +} + +static inline unsigned int qcomtee_msg_num_oo(u32 counts) +{ + return FIELD_GET(QCOMTEE_MASK_OO, counts); +} + +static inline unsigned int qcomtee_msg_idx_ib(u32 counts) +{ + return 0; +} + +static inline unsigned int qcomtee_msg_idx_ob(u32 counts) +{ + return qcomtee_msg_num_ib(counts); +} + +static inline unsigned int qcomtee_msg_idx_io(u32 counts) +{ + return qcomtee_msg_idx_ob(counts) + qcomtee_msg_num_ob(counts); +} + +static inline unsigned int qcomtee_msg_idx_oo(u32 counts) +{ + return qcomtee_msg_idx_io(counts) + qcomtee_msg_num_io(counts); +} + +#define qcomtee_msg_for_each(i, first, num) \ + for ((i) =3D (first); (i) < (first) + (num); (i)++) + +#define qcomtee_msg_for_each_input_buffer(i, m) \ + qcomtee_msg_for_each(i, qcomtee_msg_idx_ib((m)->counts), \ + qcomtee_msg_num_ib((m)->counts)) + +#define qcomtee_msg_for_each_output_buffer(i, m) \ + qcomtee_msg_for_each(i, qcomtee_msg_idx_ob((m)->counts), \ + qcomtee_msg_num_ob((m)->counts)) + +#define qcomtee_msg_for_each_input_object(i, m) \ + qcomtee_msg_for_each(i, qcomtee_msg_idx_io((m)->counts), \ + qcomtee_msg_num_io((m)->counts)) + +#define qcomtee_msg_for_each_output_object(i, m) \ + qcomtee_msg_for_each(i, qcomtee_msg_idx_oo((m)->counts), \ + qcomtee_msg_num_oo((m)->counts)) + +/* Sum of arguments in a message. */ +#define qcomtee_msg_args(m) \ + (qcomtee_msg_idx_oo((m)->counts) + qcomtee_msg_num_oo((m)->counts)) + +static inline void qcomtee_msg_init(struct qcomtee_msg_object_invoke *msg, + u32 cxt, u32 op, int in_buffer, + int out_buffer, int in_object, + int out_object) +{ + u32 counts =3D 0; + + counts |=3D (in_buffer & 0xfU); + counts |=3D ((out_buffer - in_buffer) & 0xfU) << 4; + counts |=3D ((in_object - out_buffer) & 0xfU) << 8; + counts |=3D ((out_object - in_object) & 0xfU) << 12; + + msg->cxt =3D cxt; + msg->op =3D op; + msg->counts =3D counts; +} + +/* Generic error codes. */ +#define QCOMTEE_MSG_OK 0 /* non-specific success code. */ +#define QCOMTEE_MSG_ERROR 1 /* non-specific error. */ +#define QCOMTEE_MSG_ERROR_INVALID 2 /* unsupported/unrecognized request. */ +#define QCOMTEE_MSG_ERROR_SIZE_IN 3 /* supplied buffer/string too large. */ +#define QCOMTEE_MSG_ERROR_SIZE_OUT 4 /* supplied output buffer too small. = */ +#define QCOMTEE_MSG_ERROR_USERBASE 10 /* start of user-defined error range= . */ + +/* Transport layer error codes. */ +#define QCOMTEE_MSG_ERROR_DEFUNCT -90 /* object no longer exists. */ +#define QCOMTEE_MSG_ERROR_ABORT -91 /* calling thread must exit. */ +#define QCOMTEE_MSG_ERROR_BADOBJ -92 /* invalid object context. */ +#define QCOMTEE_MSG_ERROR_NOSLOTS -93 /* caller's object table full. */ +#define QCOMTEE_MSG_ERROR_MAXARGS -94 /* too many args. */ +#define QCOMTEE_MSG_ERROR_MAXDATA -95 /* buffers too large. */ +#define QCOMTEE_MSG_ERROR_UNAVAIL -96 /* the request could not be processe= d. */ +#define QCOMTEE_MSG_ERROR_KMEM -97 /* kernel out of memory. */ +#define QCOMTEE_MSG_ERROR_REMOTE -98 /* local method sent to remote object= . */ +#define QCOMTEE_MSG_ERROR_BUSY -99 /* Object is busy. */ +#define QCOMTEE_MSG_ERROR_TIMEOUT -103 /* Call Back Object invocation time= d out. */ + +static inline void qcomtee_msg_set_result(struct qcomtee_msg_callback *cb_= msg, + int err) +{ + if (!err) { + cb_msg->result =3D QCOMTEE_MSG_OK; + } else if (err < 0) { + /* If err < 0, then it is a transport error. */ + switch (err) { + case -ENOMEM: + cb_msg->result =3D QCOMTEE_MSG_ERROR_KMEM; + break; + case -ENODEV: + cb_msg->result =3D QCOMTEE_MSG_ERROR_DEFUNCT; + break; + case -ENOSPC: + case -EBUSY: + cb_msg->result =3D QCOMTEE_MSG_ERROR_BUSY; + break; + case -EBADF: + case -EINVAL: + cb_msg->result =3D QCOMTEE_MSG_ERROR_UNAVAIL; + break; + default: + cb_msg->result =3D QCOMTEE_MSG_ERROR; + } + } else { + /* If err > 0, then it is user defined error, pass it as is. */ + cb_msg->result =3D err; + } +} + +#endif /* QCOMTEE_MSG_H */ diff --git a/drivers/tee/qcomtee/qcomtee_object.h b/drivers/tee/qcomtee/qco= mtee_object.h new file mode 100644 index 000000000000..5221449be7db --- /dev/null +++ b/drivers/tee/qcomtee/qcomtee_object.h @@ -0,0 +1,316 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#ifndef QCOMTEE_OBJECT_H +#define QCOMTEE_OBJECT_H + +#include +#include +#include +#include + +struct qcomtee_object; + +/** + * DOC: Overview + * + * qcomtee_object provides object refcounting, ID allocation for objects h= osted + * in the kernel, and necessary message marshaling for Qualcomm TEE (QTEE). + * + * To invoke an object in QTEE, the user calls qcomtee_object_do_invoke() + * while passing an instance of &struct qcomtee_object and the requested + * operation + arguments. + * + * After boot, QTEE provides a static object %ROOT_QCOMTEE_OBJECT (type of + * %QCOMTEE_OBJECT_TYPE_ROOT). The root object is invoked to pass the user= 's + * credentials and obtain other instances of &struct qcomtee_object (type = of + * %QCOMTEE_OBJECT_TYPE_TEE) that represent services and TAs in QTEE; + * see &enum qcomtee_object_type. + * + * The objects received from QTEE are refcounted. So the owner of these ob= jects + * can issue qcomtee_object_get() to increase the refcount and pass objects + * to other clients, or issue qcomtee_object_put() to decrease the refcount + * and release the resources in QTEE. + * + * The kernel can host services accessible to QTEE. A driver should embed + * an instance of &struct qcomtee_object in the struct it wants to export = to + * QTEE (this is called a callback object). It issues qcomtee_object_user_= init() + * to set the dispatch() operation for the callback object and set its type + * to %QCOMTEE_OBJECT_TYPE_CB. + * + * core.c holds an object table for callback objects. An object ID is assi= gned + * to each callback object, which is an index to the object table. QTEE us= es + * these IDs to reference or invoke callback objects. + * + * If QTEE invokes a callback object in the kernel, the dispatch() operati= on is + * called in the context of the thread that originally called + * qcomtee_object_do_invoke(). + */ + +/** + * enum qcomtee_object_type - Object types. + * @QCOMTEE_OBJECT_TYPE_TEE: object hosted on QTEE. + * @QCOMTEE_OBJECT_TYPE_CB: object hosted on kernel. + * @QCOMTEE_OBJECT_TYPE_ROOT: 'primordial' object. + * @QCOMTEE_OBJECT_TYPE_NULL: NULL object. + * + * The primordial object is used for bootstrapping the IPC connection betw= een + * the kernel and QTEE. It is invoked by the kernel when it wants to get a + * 'client env'. + */ +enum qcomtee_object_type { + QCOMTEE_OBJECT_TYPE_TEE, + QCOMTEE_OBJECT_TYPE_CB, + QCOMTEE_OBJECT_TYPE_ROOT, + QCOMTEE_OBJECT_TYPE_NULL, +}; + +/** + * enum qcomtee_arg_type - Type of QTEE argument. + * @QCOMTEE_ARG_TYPE_INV: invalid type. + * @QCOMTEE_ARG_TYPE_OB: output buffer (OB). + * @QCOMTEE_ARG_TYPE_OO: output object (OO). + * @QCOMTEE_ARG_TYPE_IB: input buffer (IB). + * @QCOMTEE_ARG_TYPE_IO: input object (IO). + * + * Use the invalid type to specify the end of the argument array. + */ +enum qcomtee_arg_type { + QCOMTEE_ARG_TYPE_INV =3D 0, + QCOMTEE_ARG_TYPE_OB, + QCOMTEE_ARG_TYPE_OO, + QCOMTEE_ARG_TYPE_IB, + QCOMTEE_ARG_TYPE_IO, + QCOMTEE_ARG_TYPE_NR, +}; + +/** + * define QCOMTEE_ARGS_PER_TYPE - Maximum arguments of a specific type. + * + * The QTEE transport protocol limits the maximum number of arguments of + * a specific type (i.e., IB, OB, IO, and OO). + */ +#define QCOMTEE_ARGS_PER_TYPE 16 + +/* Maximum arguments that can fit in a QTEE message, ignoring the type. */ +#define QCOMTEE_ARGS_MAX (QCOMTEE_ARGS_PER_TYPE * (QCOMTEE_ARG_TYPE_NR - 1= )) + +struct qcomtee_buffer { + union { + void *addr; + void __user *uaddr; + }; + size_t size; +}; + +/** + * struct qcomtee_arg - Argument for QTEE object invocation. + * @type: type of argument as &enum qcomtee_arg_type. + * @flags: extra flags. + * @b: address and size if the type of argument is a buffer. + * @o: object instance if the type of argument is an object. + * + * &qcomtee_arg.flags only accepts %QCOMTEE_ARG_FLAGS_UADDR for now, which + * states that &qcomtee_arg.b contains a userspace address in uaddr. + */ +struct qcomtee_arg { + enum qcomtee_arg_type type; +/* 'b.uaddr' holds a __user address. */ +#define QCOMTEE_ARG_FLAGS_UADDR BIT(0) + unsigned int flags; + union { + struct qcomtee_buffer b; + struct qcomtee_object *o; + }; +}; + +static inline int qcomtee_args_len(struct qcomtee_arg *args) +{ + int i =3D 0; + + while (args[i].type !=3D QCOMTEE_ARG_TYPE_INV) + i++; + return i; +} + +/* Context is busy (callback is in progress). */ +#define QCOMTEE_OIC_FLAG_BUSY BIT(1) +/* Context needs to notify the current object. */ +#define QCOMTEE_OIC_FLAG_NOTIFY BIT(2) +/* Context has shared state with QTEE. */ +#define QCOMTEE_OIC_FLAG_SHARED BIT(3) + +/** + * struct qcomtee_object_invoke_ctx - QTEE context for object invocation. + * @ctx: TEE context for this invocation. + * @flags: flags for the invocation context. + * @errno: error code for the invocation. + * @object: current object invoked in this callback context. + * @u: array of arguments for the current invocation (+1 for ending arg). + * @in_msg: inbound buffer shared with QTEE. + * @out_msg: outbound buffer shared with QTEE. + * @in_shm: TEE shm allocated for inbound buffer. + * @out_shm: TEE shm allocated for outbound buffer. + * @data: extra data attached to this context. + */ +struct qcomtee_object_invoke_ctx { + struct tee_context *ctx; + unsigned long flags; + int errno; + + struct qcomtee_object *object; + struct qcomtee_arg u[QCOMTEE_ARGS_MAX + 1]; + + struct qcomtee_buffer in_msg; + struct qcomtee_buffer out_msg; + struct tee_shm *in_shm; + struct tee_shm *out_shm; + + void *data; +}; + +static inline struct qcomtee_object_invoke_ctx * +qcomtee_object_invoke_ctx_alloc(struct tee_context *ctx) +{ + struct qcomtee_object_invoke_ctx *oic; + + oic =3D kzalloc(sizeof(*oic), GFP_KERNEL); + if (oic) + oic->ctx =3D ctx; + return oic; +} + +/** + * qcomtee_object_do_invoke() - Submit an invocation for an object. + * @oic: context to use for the current invocation. + * @object: object being invoked. + * @op: requested operation on the object. + * @u: array of arguments for the current invocation. + * @result: result returned from QTEE. + * + * The caller is responsible for keeping track of the refcount for each ob= ject, + * including @object. On return, the caller loses ownership of all input + * objects of type %QCOMTEE_OBJECT_TYPE_CB. + * + * @object can be of %QCOMTEE_OBJECT_TYPE_ROOT or %QCOMTEE_OBJECT_TYPE_TEE. + * + * Return: On success, returns 0; on failure, returns < 0. + */ +int qcomtee_object_do_invoke(struct qcomtee_object_invoke_ctx *oic, + struct qcomtee_object *object, u32 op, + struct qcomtee_arg *u, int *result); + +/** + * struct qcomtee_object_operations - Callback object operations. + * @release: release the object if QTEE is not using it. + * @dispatch: dispatch the operation requested by QTEE. + * @notify: report the status of any pending response submitted by @dispat= ch. + */ +struct qcomtee_object_operations { + void (*release)(struct qcomtee_object *object); + int (*dispatch)(struct qcomtee_object_invoke_ctx *oic, + struct qcomtee_object *object, u32 op, + struct qcomtee_arg *args); + void (*notify)(struct qcomtee_object_invoke_ctx *oic, + struct qcomtee_object *object, int err); +}; + +/** + * struct qcomtee_object - QTEE or kernel object. + * @name: object name. + * @refcount: reference counter. + * @object_type: object type as &enum qcomtee_object_type. + * @info: extra information for the object. + * @ops: callback operations for objects of type %QCOMTEE_OBJECT_TYPE_CB. + * @work: work for async operations on the object. + * + * @work is used for releasing objects of %QCOMTEE_OBJECT_TYPE_TEE type. + */ +struct qcomtee_object { + const char *name; + struct kref refcount; + + enum qcomtee_object_type object_type; + struct object_info { + unsigned long qtee_id; + /* TEE context for QTEE object async requests. */ + struct tee_context *qcomtee_async_ctx; + } info; + + struct qcomtee_object_operations *ops; + struct work_struct work; +}; + +/* Static instances of qcomtee_object objects. */ +#define NULL_QCOMTEE_OBJECT ((struct qcomtee_object *)(0)) +extern struct qcomtee_object qcomtee_object_root; +#define ROOT_QCOMTEE_OBJECT (&qcomtee_object_root) + +static inline enum qcomtee_object_type +typeof_qcomtee_object(struct qcomtee_object *object) +{ + if (object =3D=3D NULL_QCOMTEE_OBJECT) + return QCOMTEE_OBJECT_TYPE_NULL; + return object->object_type; +} + +static inline const char *qcomtee_object_name(struct qcomtee_object *objec= t) +{ + if (object =3D=3D NULL_QCOMTEE_OBJECT) + return "null"; + + if (!object->name) + return "no-name"; + return object->name; +} + +/** + * qcomtee_object_user_init() - Initialize an object for the user. + * @object: object to initialize. + * @ot: type of object as &enum qcomtee_object_type. + * @ops: instance of callbacks. + * @fmt: name assigned to the object. + * + * Return: On success, returns 0; on failure, returns < 0. + */ +int qcomtee_object_user_init(struct qcomtee_object *object, + enum qcomtee_object_type ot, + struct qcomtee_object_operations *ops, + const char *fmt, ...) __printf(4, 5); + +/* Object release is RCU protected. */ +int qcomtee_object_get(struct qcomtee_object *object); +void qcomtee_object_put(struct qcomtee_object *object); + +#define qcomtee_arg_for_each(i, args) \ + for (i =3D 0; args[i].type !=3D QCOMTEE_ARG_TYPE_INV; i++) + +/* Next argument of type @type after index @i. */ +int qcomtee_next_arg_type(struct qcomtee_arg *u, int i, + enum qcomtee_arg_type type); + +/* Iterate over argument of given type. */ +#define qcomtee_arg_for_each_type(i, args, at) \ + for (i =3D qcomtee_next_arg_type(args, 0, at); \ + args[i].type !=3D QCOMTEE_ARG_TYPE_INV; \ + i =3D qcomtee_next_arg_type(args, i + 1, at)) + +#define qcomtee_arg_for_each_input_buffer(i, args) \ + qcomtee_arg_for_each_type(i, args, QCOMTEE_ARG_TYPE_IB) +#define qcomtee_arg_for_each_output_buffer(i, args) \ + qcomtee_arg_for_each_type(i, args, QCOMTEE_ARG_TYPE_OB) +#define qcomtee_arg_for_each_input_object(i, args) \ + qcomtee_arg_for_each_type(i, args, QCOMTEE_ARG_TYPE_IO) +#define qcomtee_arg_for_each_output_object(i, args) \ + qcomtee_arg_for_each_type(i, args, QCOMTEE_ARG_TYPE_OO) + +struct qcomtee_object * +qcomtee_object_get_client_env(struct qcomtee_object_invoke_ctx *oic); + +struct qcomtee_object * +qcomtee_object_get_service(struct qcomtee_object_invoke_ctx *oic, + struct qcomtee_object *client_env, u32 uid); + +#endif /* QCOMTEE_OBJECT_H */ diff --git a/drivers/tee/qcomtee/shm.c b/drivers/tee/qcomtee/shm.c new file mode 100644 index 000000000000..2aea76487372 --- /dev/null +++ b/drivers/tee/qcomtee/shm.c @@ -0,0 +1,153 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include + +#include "qcomtee.h" + +/** + * define MAX_OUTBOUND_BUFFER_SIZE - Maximum size of outbound buffers. + * + * The size of outbound buffer depends on QTEE callback requests. + */ +#define MAX_OUTBOUND_BUFFER_SIZE SZ_4K + +/** + * define MAX_INBOUND_BUFFER_SIZE - Maximum size of the inbound buffer. + * + * The size of the inbound buffer depends on the user's requests, + * specifically the number of IB and OB arguments. If an invocation + * requires a size larger than %MAX_INBOUND_BUFFER_SIZE, the user should + * consider using another form of shared memory with QTEE. + */ +#define MAX_INBOUND_BUFFER_SIZE SZ_4M + +/** + * qcomtee_msg_buffers_alloc() - Allocate inbound and outbound buffers. + * @oic: context to use for the current invocation. + * @u: array of arguments for the current invocation. + * + * It calculates the size of inbound and outbound buffers based on the + * arguments in @u. It allocates the buffers from the teedev pool. + * + * Return: On success, returns 0. On error, returns < 0. + */ +int qcomtee_msg_buffers_alloc(struct qcomtee_object_invoke_ctx *oic, + struct qcomtee_arg *u) +{ + struct tee_context *ctx =3D oic->ctx; + struct tee_shm *shm; + size_t size; + int i; + + /* Start offset in a message for buffer arguments. */ + size =3D qcomtee_msg_buffer_args(struct qcomtee_msg_object_invoke, + qcomtee_args_len(u)); + if (size > MAX_INBOUND_BUFFER_SIZE) + return -EINVAL; + + /* Add size of IB arguments. */ + qcomtee_arg_for_each_input_buffer(i, u) { + size =3D size_add(size, qcomtee_msg_offset_align(u[i].b.size)); + if (size > MAX_INBOUND_BUFFER_SIZE) + return -EINVAL; + } + + /* Add size of OB arguments. */ + qcomtee_arg_for_each_output_buffer(i, u) { + size =3D size_add(size, qcomtee_msg_offset_align(u[i].b.size)); + if (size > MAX_INBOUND_BUFFER_SIZE) + return -EINVAL; + } + + shm =3D tee_shm_alloc_priv_buf(ctx, size); + if (IS_ERR(shm)) + return PTR_ERR(shm); + + /* Allocate inbound buffer. */ + oic->in_shm =3D shm; + shm =3D tee_shm_alloc_priv_buf(ctx, MAX_OUTBOUND_BUFFER_SIZE); + if (IS_ERR(shm)) { + tee_shm_free(oic->in_shm); + + return PTR_ERR(shm); + } + /* Allocate outbound buffer. */ + oic->out_shm =3D shm; + + oic->in_msg.addr =3D tee_shm_get_va(oic->in_shm, 0); + oic->in_msg.size =3D tee_shm_get_size(oic->in_shm); + oic->out_msg.addr =3D tee_shm_get_va(oic->out_shm, 0); + oic->out_msg.size =3D tee_shm_get_size(oic->out_shm); + /* QTEE assume unused buffers are zeroed. */ + memzero_explicit(oic->in_msg.addr, oic->in_msg.size); + memzero_explicit(oic->out_msg.addr, oic->out_msg.size); + + return 0; +} + +void qcomtee_msg_buffers_free(struct qcomtee_object_invoke_ctx *oic) +{ + tee_shm_free(oic->in_shm); + tee_shm_free(oic->out_shm); +} + +/* Dynamic shared memory pool based on tee_dyn_shm_alloc_helper(). */ + +static int qcomtee_shm_register(struct tee_context *ctx, struct tee_shm *s= hm, + struct page **pages, size_t num_pages, + unsigned long start) +{ + return qcom_tzmem_shm_bridge_create(shm->paddr, shm->size, + &shm->sec_world_id); +} + +static int qcomtee_shm_unregister(struct tee_context *ctx, struct tee_shm = *shm) +{ + qcom_tzmem_shm_bridge_delete(shm->sec_world_id); + + return 0; +} + +static int pool_op_alloc(struct tee_shm_pool *pool, struct tee_shm *shm, + size_t size, size_t align) +{ + if (!(shm->flags & TEE_SHM_PRIV)) + return -ENOMEM; + + return tee_dyn_shm_alloc_helper(shm, size, align, qcomtee_shm_register); +} + +static void pool_op_free(struct tee_shm_pool *pool, struct tee_shm *shm) +{ + tee_dyn_shm_free_helper(shm, qcomtee_shm_unregister); +} + +static void pool_op_destroy_pool(struct tee_shm_pool *pool) +{ + kfree(pool); +} + +static const struct tee_shm_pool_ops pool_ops =3D { + .alloc =3D pool_op_alloc, + .free =3D pool_op_free, + .destroy_pool =3D pool_op_destroy_pool, +}; + +struct tee_shm_pool *qcomtee_shm_pool_alloc(void) +{ + struct tee_shm_pool *pool; + + pool =3D kzalloc(sizeof(*pool), GFP_KERNEL); + if (!pool) + return ERR_PTR(-ENOMEM); + + pool->ops =3D &pool_ops; + + return pool; +} diff --git a/drivers/tee/qcomtee/user_obj.c b/drivers/tee/qcomtee/user_obj.c new file mode 100644 index 000000000000..0139905f2684 --- /dev/null +++ b/drivers/tee/qcomtee/user_obj.c @@ -0,0 +1,692 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include + +#include "qcomtee.h" + +/** + * DOC: User Objects aka Supplicants + * + * Any userspace process with access to the TEE device file can behave as a + * supplicant by creating a user object. Any TEE parameter of type OBJREF = with + * %QCOMTEE_OBJREF_FLAG_USER flag set is considered a user object. + * + * A supplicant uses qcomtee_user_object_select() (i.e. TEE_IOC_SUPPL_RECV= ) to + * receive a QTEE user object request and qcomtee_user_object_submit() + * (i.e. TEE_IOC_SUPPL_SEND) to submit a response. QTEE expects to receive= the + * response, including OB and OO in a specific order in the message; param= eters + * submitted with qcomtee_user_object_submit() should maintain this order. + */ + +/** + * struct qcomtee_user_object - User object. + * @object: &struct qcomtee_object representing the user object. + * @ctx: context for which the user object is defined. + * @object_id: object ID in @ctx. + * @notify: notify on release. + * + * Any object managed in userspace is represented by this struct. + * If @notify is set, a notification message is sent back to userspace + * upon release. + */ +struct qcomtee_user_object { + struct qcomtee_object object; + struct tee_context *ctx; + u64 object_id; + bool notify; +}; + +#define to_qcomtee_user_object(o) \ + container_of((o), struct qcomtee_user_object, object) + +static struct qcomtee_object_operations qcomtee_user_object_ops; + +/* Is it a user object? */ +int is_qcomtee_user_object(struct qcomtee_object *object) +{ + return object !=3D NULL_QCOMTEE_OBJECT && + typeof_qcomtee_object(object) =3D=3D QCOMTEE_OBJECT_TYPE_CB && + object->ops =3D=3D &qcomtee_user_object_ops; +} + +/* Set the user object's 'notify on release' flag. */ +void qcomtee_user_object_set_notify(struct qcomtee_object *object, bool no= tify) +{ + if (is_qcomtee_user_object(object)) + to_qcomtee_user_object(object)->notify =3D notify; +} + +/* Supplicant Requests: */ + +/** + * enum qcomtee_req_state - Current state of request. + * @QCOMTEE_REQ_QUEUED: Request is waiting for supplicant. + * @QCOMTEE_REQ_PROCESSING: Request has been picked by the supplicant. + * @QCOMTEE_REQ_PROCESSED: Response has been submitted for the request. + */ +enum qcomtee_req_state { + QCOMTEE_REQ_QUEUED =3D 1, + QCOMTEE_REQ_PROCESSING, + QCOMTEE_REQ_PROCESSED, +}; + +/* User requests sent to supplicants. */ +struct qcomtee_ureq { + enum qcomtee_req_state state; + + /* User Request: */ + int req_id; + u64 object_id; + u32 op; + struct qcomtee_arg *args; + int errno; + + struct list_head node; + struct completion c; /* Completion for whoever wait. */ +}; + +/* + * Placeholder for a PROCESSING request in qcomtee_context.reqs_idr. + * + * If the thread that calls qcomtee_object_invoke() dies and the supplicant + * is processing the request, replace the entry in qcomtee_context.reqs_idr + * with empty_ureq. This ensures that (1) the req_id remains busy and is n= ot + * reused, and (2) the supplicant fails to submit the response and performs + * the necessary rollback. + */ +static struct qcomtee_ureq empty_ureq =3D { .state =3D QCOMTEE_REQ_PROCESS= ING }; + +/* Enqueue a user request for a context and assign a request ID. */ +static int ureq_enqueue(struct qcomtee_context_data *ctxdata, + struct qcomtee_ureq *ureq) +{ + int ret; + + guard(mutex)(&ctxdata->reqs_lock); + /* Supplicant is dying. */ + if (ctxdata->released) + return -ENODEV; + + /* Allocate an ID and queue the request. */ + ret =3D idr_alloc(&ctxdata->reqs_idr, ureq, 0, 0, GFP_KERNEL); + if (ret < 0) + return ret; + + ureq->req_id =3D ret; + ureq->state =3D QCOMTEE_REQ_QUEUED; + list_add_tail(&ureq->node, &ctxdata->reqs_list); + + return 0; +} + +/** + * ureq_dequeue() - Dequeue a user request from a context. + * @ctxdata: context data for a context to dequeue the request. + * @req_id: ID of the request to be dequeued. + * + * It dequeues a user request and releases its request ID. + * + * Context: The caller should hold &qcomtee_context_data->reqs_lock. + * Return: Returns the user request associated with this ID; otherwise, NU= LL. + */ +static struct qcomtee_ureq *ureq_dequeue(struct qcomtee_context_data *ctxd= ata, + int req_id) +{ + struct qcomtee_ureq *ureq; + + ureq =3D idr_remove(&ctxdata->reqs_idr, req_id); + if (ureq =3D=3D &empty_ureq || !ureq) + return NULL; + + list_del(&ureq->node); + + return ureq; +} + +/** + * ureq_select() - Select the next request in a context. + * @ctxdata: context data for a context to pop a request. + * @ubuf_size: size of the available buffer for UBUF parameters. + * @num_params: number of entries for the TEE parameter array. + * + * It checks if @num_params is large enough to fit the next request argume= nts. + * It checks if @ubuf_size is large enough to fit IB buffer arguments. + * + * Context: The caller should hold &qcomtee_context_data->reqs_lock. + * Return: On success, returns a request; + * on failure, returns NULL and ERR_PTR. + */ +static struct qcomtee_ureq *ureq_select(struct qcomtee_context_data *ctxda= ta, + size_t ubuf_size, int num_params) +{ + struct qcomtee_ureq *req, *ureq =3D NULL; + struct qcomtee_arg *u; + int i; + + /* Find the a queued request. */ + list_for_each_entry(req, &ctxdata->reqs_list, node) { + if (req->state =3D=3D QCOMTEE_REQ_QUEUED) { + ureq =3D req; + break; + } + } + + if (!ureq) + return NULL; + + u =3D ureq->args; + /* (1) Is there enough TEE parameters? */ + if (num_params < qcomtee_args_len(u)) + return ERR_PTR(-EINVAL); + /* (2) Is there enough space to pass input buffers? */ + qcomtee_arg_for_each_input_buffer(i, u) { + ubuf_size =3D size_sub(ubuf_size, u[i].b.size); + if (ubuf_size =3D=3D SIZE_MAX) + return ERR_PTR(-EINVAL); + + ubuf_size =3D round_down(ubuf_size, 8); + } + + return ureq; +} + +/* Gets called when the user closes the device. */ +void qcomtee_requests_destroy(struct qcomtee_context_data *ctxdata) +{ + struct qcomtee_ureq *req, *ureq; + + guard(mutex)(&ctxdata->reqs_lock); + /* So ureq_enqueue() refuses new requests from QTEE. */ + ctxdata->released =3D true; + /* ureqs in reqs_list are in QUEUED or PROCESSING (!=3D empty_ureq) state= . */ + list_for_each_entry_safe(ureq, req, &ctxdata->reqs_list, node) { + ureq_dequeue(ctxdata, ureq->req_id); + + if (ureq->op !=3D QCOMTEE_MSG_OBJECT_OP_RELEASE) { + ureq->state =3D QCOMTEE_REQ_PROCESSED; + ureq->errno =3D -ENODEV; + + complete(&ureq->c); + } else { + kfree(ureq); + } + } +} + +/* User Object API. */ + +/* User object dispatcher. */ +static int qcomtee_user_object_dispatch(struct qcomtee_object_invoke_ctx *= oic, + struct qcomtee_object *object, u32 op, + struct qcomtee_arg *args) +{ + struct qcomtee_user_object *uo =3D to_qcomtee_user_object(object); + struct qcomtee_context_data *ctxdata =3D uo->ctx->data; + struct qcomtee_ureq *ureq __free(kfree) =3D NULL; + int errno; + + ureq =3D kzalloc(sizeof(*ureq), GFP_KERNEL); + if (!ureq) + return -ENOMEM; + + init_completion(&ureq->c); + ureq->object_id =3D uo->object_id; + ureq->op =3D op; + ureq->args =3D args; + + /* Queue the request. */ + if (ureq_enqueue(ctxdata, ureq)) + return -ENODEV; + /* Wakeup supplicant to process it. */ + complete(&ctxdata->req_c); + + /* + * Wait for the supplicant to process the request. Wait as KILLABLE + * in case the supplicant and invoke thread are both running from the + * same process, the supplicant crashes, or the shutdown sequence + * starts with supplicant dies first; otherwise, it stuck indefinitely. + * + * If the supplicant processes long-running requests, also use + * TASK_FREEZABLE to allow the device to safely suspend if needed. + */ + if (!wait_for_completion_state(&ureq->c, + TASK_KILLABLE | TASK_FREEZABLE)) { + errno =3D ureq->errno; + if (!errno) + oic->data =3D no_free_ptr(ureq); + } else { + enum qcomtee_req_state prev_state; + + errno =3D -ENODEV; + + scoped_guard(mutex, &ctxdata->reqs_lock) { + prev_state =3D ureq->state; + /* Replace with empty_ureq to keep req_id reserved. */ + if (prev_state =3D=3D QCOMTEE_REQ_PROCESSING) { + list_del(&ureq->node); + idr_replace(&ctxdata->reqs_idr, + &empty_ureq, ureq->req_id); + + /* Remove as supplicant has never seen this request. */ + } else if (prev_state =3D=3D QCOMTEE_REQ_QUEUED) { + ureq_dequeue(ctxdata, ureq->req_id); + } + } + + /* Supplicant did some work, do not discard it. */ + if (prev_state =3D=3D QCOMTEE_REQ_PROCESSED) { + errno =3D ureq->errno; + if (!errno) + oic->data =3D no_free_ptr(ureq); + } + } + + return errno; +} + +/* Gets called after submitting the dispatcher response. */ +static void qcomtee_user_object_notify(struct qcomtee_object_invoke_ctx *o= ic, + struct qcomtee_object *unused_object, + int err) +{ + struct qcomtee_ureq *ureq =3D oic->data; + struct qcomtee_arg *u =3D ureq->args; + int i; + + /* + * If err, there was a transport issue, and QTEE did not receive the + * response for the dispatcher. Release the callback object created for + * QTEE, in addition to the copies of objects kept for the drivers. + */ + qcomtee_arg_for_each_output_object(i, u) { + if (err && + (typeof_qcomtee_object(u[i].o) =3D=3D QCOMTEE_OBJECT_TYPE_CB)) + qcomtee_object_put(u[i].o); + qcomtee_object_put(u[i].o); + } + + kfree(ureq); +} + +static void qcomtee_user_object_release(struct qcomtee_object *object) +{ + struct qcomtee_user_object *uo =3D to_qcomtee_user_object(object); + struct qcomtee_context_data *ctxdata =3D uo->ctx->data; + struct qcomtee_ureq *ureq; + + /* RELEASE does not require any argument. */ + static struct qcomtee_arg args[] =3D { { .type =3D QCOMTEE_ARG_TYPE_INV }= }; + + if (!uo->notify) + goto out_no_notify; + + ureq =3D kzalloc(sizeof(*ureq), GFP_KERNEL); + if (!ureq) + goto out_no_notify; + + /* QUEUE a release request: */ + ureq->object_id =3D uo->object_id; + ureq->op =3D QCOMTEE_MSG_OBJECT_OP_RELEASE; + ureq->args =3D args; + if (ureq_enqueue(ctxdata, ureq)) { + kfree(ureq); + /* Ignore the notification if it cannot be queued. */ + goto out_no_notify; + } + + complete(&ctxdata->req_c); + +out_no_notify: + teedev_ctx_put(uo->ctx); + kfree(uo); +} + +static struct qcomtee_object_operations qcomtee_user_object_ops =3D { + .release =3D qcomtee_user_object_release, + .notify =3D qcomtee_user_object_notify, + .dispatch =3D qcomtee_user_object_dispatch, +}; + +/** + * qcomtee_user_param_to_object() - OBJREF parameter to &struct qcomtee_ob= ject. + * @object: object returned. + * @param: TEE parameter. + * @ctx: context in which the conversion should happen. + * + * @param is an OBJREF with %QCOMTEE_OBJREF_FLAG_USER flags. + * + * Return: On success, returns 0; on failure, returns < 0. + */ +int qcomtee_user_param_to_object(struct qcomtee_object **object, + struct tee_param *param, + struct tee_context *ctx) +{ + struct qcomtee_user_object *user_object __free(kfree) =3D NULL; + int err; + + user_object =3D kzalloc(sizeof(*user_object), GFP_KERNEL); + if (!user_object) + return -ENOMEM; + + user_object->ctx =3D ctx; + user_object->object_id =3D param->u.objref.id; + /* By default, always notify userspace upon release. */ + user_object->notify =3D true; + err =3D qcomtee_object_user_init(&user_object->object, + QCOMTEE_OBJECT_TYPE_CB, + &qcomtee_user_object_ops, "uo-%llu", + param->u.objref.id); + if (err) + return err; + /* Matching teedev_ctx_put() is in qcomtee_user_object_release(). */ + teedev_ctx_get(ctx); + + *object =3D &no_free_ptr(user_object)->object; + + return 0; +} + +/* Reverse what qcomtee_user_param_to_object() does. */ +int qcomtee_user_param_from_object(struct tee_param *param, + struct qcomtee_object *object, + struct tee_context *ctx) +{ + struct qcomtee_user_object *uo; + + uo =3D to_qcomtee_user_object(object); + /* Ensure the object is in the same context as the caller. */ + if (uo->ctx !=3D ctx) + return -EINVAL; + + param->u.objref.id =3D uo->object_id; + param->u.objref.flags =3D QCOMTEE_OBJREF_FLAG_USER; + + /* User objects are valid in userspace; do not keep a copy. */ + qcomtee_object_put(object); + + return 0; +} + +/** + * qcomtee_cb_params_from_args() - Convert QTEE arguments to TEE parameter= s. + * @params: TEE parameters. + * @u: QTEE arguments. + * @num_params: number of elements in the parameter array. + * @ubuf_addr: user buffer for arguments of type %QCOMTEE_ARG_TYPE_IB. + * @ubuf_size: size of the user buffer. + * @ctx: context in which the conversion should happen. + * + * It expects @params to have enough entries for @u. Entries in @params ar= e of + * %TEE_IOCTL_PARAM_ATTR_TYPE_NONE. + * + * Return: On success, returns the number of input parameters; + * on failure, returns < 0. + */ +static int qcomtee_cb_params_from_args(struct tee_param *params, + struct qcomtee_arg *u, int num_params, + void __user *ubuf_addr, size_t ubuf_size, + struct tee_context *ctx) +{ + int i, np; + void __user *uaddr; + + qcomtee_arg_for_each(i, u) { + switch (u[i].type) { + case QCOMTEE_ARG_TYPE_IB: + params[i].attr =3D TEE_IOCTL_PARAM_ATTR_TYPE_UBUF_INPUT; + + /* Underflow already checked in ureq_select(). */ + ubuf_size =3D round_down(ubuf_size - u[i].b.size, 8); + uaddr =3D (void __user *)(ubuf_addr + ubuf_size); + + params[i].u.ubuf.uaddr =3D uaddr; + params[i].u.ubuf.size =3D u[i].b.size; + if (copy_to_user(params[i].u.ubuf.uaddr, u[i].b.addr, + u[i].b.size)) + goto out_failed; + + break; + case QCOMTEE_ARG_TYPE_OB: + params[i].attr =3D TEE_IOCTL_PARAM_ATTR_TYPE_UBUF_OUTPUT; + /* Let the user knows the maximum size QTEE expects. */ + params[i].u.ubuf.size =3D u[i].b.size; + + break; + case QCOMTEE_ARG_TYPE_IO: + params[i].attr =3D TEE_IOCTL_PARAM_ATTR_TYPE_OBJREF_INPUT; + if (qcomtee_objref_from_arg(¶ms[i], &u[i], ctx)) + goto out_failed; + + break; + case QCOMTEE_ARG_TYPE_OO: + params[i].attr =3D + TEE_IOCTL_PARAM_ATTR_TYPE_OBJREF_OUTPUT; + + break; + default: /* Never get here! */ + goto out_failed; + } + } + + return i; + +out_failed: + /* Undo qcomtee_objref_from_arg(). */ + for (np =3D i; np >=3D 0; np--) { + if (params[np].attr =3D=3D TEE_IOCTL_PARAM_ATTR_TYPE_OBJREF_INPUT) + qcomtee_context_del_qtee_object(¶ms[np], ctx); + } + + /* Release any IO objects not processed. */ + for (; u[i].type; i++) { + if (u[i].type =3D=3D QCOMTEE_ARG_TYPE_IO) + qcomtee_object_put(u[i].o); + } + + return -EINVAL; +} + +/** + * qcomtee_cb_params_to_args() - Convert TEE parameters to QTEE arguments. + * @u: QTEE arguments. + * @params: TEE parameters. + * @num_params: number of elements in the parameter array. + * @ctx: context in which the conversion should happen. + * + * Return: On success, returns 0; on failure, returns < 0. + */ +static int qcomtee_cb_params_to_args(struct qcomtee_arg *u, + struct tee_param *params, int num_params, + struct tee_context *ctx) +{ + int i; + + qcomtee_arg_for_each(i, u) { + switch (u[i].type) { + case QCOMTEE_ARG_TYPE_IB: + if (params[i].attr !=3D + TEE_IOCTL_PARAM_ATTR_TYPE_UBUF_INPUT) + goto out_failed; + + break; + case QCOMTEE_ARG_TYPE_OB: + if (params[i].attr !=3D + TEE_IOCTL_PARAM_ATTR_TYPE_UBUF_OUTPUT) + goto out_failed; + + /* Client can not send more data than requested. */ + if (params[i].u.ubuf.size > u[i].b.size) + goto out_failed; + + if (copy_from_user(u[i].b.addr, params[i].u.ubuf.uaddr, + params[i].u.ubuf.size)) + goto out_failed; + + u[i].b.size =3D params[i].u.ubuf.size; + + break; + case QCOMTEE_ARG_TYPE_IO: + if (params[i].attr !=3D + TEE_IOCTL_PARAM_ATTR_TYPE_OBJREF_INPUT) + goto out_failed; + + break; + case QCOMTEE_ARG_TYPE_OO: + if (params[i].attr !=3D + TEE_IOCTL_PARAM_ATTR_TYPE_OBJREF_OUTPUT) + goto out_failed; + + if (qcomtee_objref_to_arg(&u[i], ¶ms[i], ctx)) + goto out_failed; + + break; + default: /* Never get here! */ + goto out_failed; + } + } + + return 0; + +out_failed: + /* Undo qcomtee_objref_to_arg(). */ + for (i--; i >=3D 0; i--) { + if (u[i].type !=3D QCOMTEE_ARG_TYPE_OO) + continue; + + qcomtee_user_object_set_notify(u[i].o, false); + if (typeof_qcomtee_object(u[i].o) =3D=3D QCOMTEE_OBJECT_TYPE_CB) + qcomtee_object_put(u[i].o); + + qcomtee_object_put(u[i].o); + } + + return -EINVAL; +} + +/** + * qcomtee_user_object_select() - Select a request for a user object. + * @ctx: context to look for a user object. + * @params: parameters for @op. + * @num_params: number of elements in the parameter array. + * @uaddr: user buffer for output UBUF parameters. + * @size: size of user buffer @uaddr. + * @data: information for the selected request. + * + * @params is filled along with @data for the selected request. + * + * Return: On success, returns 0; on failure, returns < 0. + */ +int qcomtee_user_object_select(struct tee_context *ctx, + struct tee_param *params, int num_params, + void __user *uaddr, size_t size, + struct qcomtee_user_object_request_data *data) +{ + struct qcomtee_context_data *ctxdata =3D ctx->data; + struct qcomtee_ureq *ureq; + int ret; + + /* + * Hold the reqs_lock not only for ureq_select() and updating the ureq + * state to PROCESSING but for the entire duration of ureq access. + * This prevents qcomtee_user_object_dispatch() from freeing + * ureq while it is still in use, if client dies. + */ + + while (1) { + scoped_guard(mutex, &ctxdata->reqs_lock) { + ureq =3D ureq_select(ctxdata, size, num_params); + if (!ureq) + goto wait_for_request; + + if (IS_ERR(ureq)) + return PTR_ERR(ureq); + + /* Processing the request 'QUEUED -> PROCESSING'. */ + ureq->state =3D QCOMTEE_REQ_PROCESSING; + /* ''Prepare user request:'' */ + data->id =3D ureq->req_id; + data->object_id =3D ureq->object_id; + data->op =3D ureq->op; + ret =3D qcomtee_cb_params_from_args(params, ureq->args, + num_params, uaddr, + size, ctx); + if (ret >=3D 0) + goto done_request; + + /* Something is wrong with the request: */ + ureq_dequeue(ctxdata, data->id); + /* Send error to QTEE. */ + ureq->state =3D QCOMTEE_REQ_PROCESSED; + ureq->errno =3D ret; + + complete(&ureq->c); + } + + continue; +wait_for_request: + /* Wait for a new QUEUED request. */ + if (wait_for_completion_interruptible(&ctxdata->req_c)) + return -ERESTARTSYS; + } + +done_request: + /* No one is waiting for the response. */ + if (data->op =3D=3D QCOMTEE_MSG_OBJECT_OP_RELEASE) { + scoped_guard(mutex, &ctxdata->reqs_lock) + ureq_dequeue(ctxdata, data->id); + kfree(ureq); + } + + data->np =3D ret; + + return 0; +} + +/** + * qcomtee_user_object_submit() - Submit a response for a user object. + * @ctx: context to look for a user object. + * @params: returned parameters. + * @num_params: number of elements in the parameter array. + * @req_id: request ID for the response. + * @errno: result of user object invocation. + * + * Return: On success, returns 0; on failure, returns < 0. + */ +int qcomtee_user_object_submit(struct tee_context *ctx, + struct tee_param *params, int num_params, + int req_id, int errno) +{ + struct qcomtee_context_data *ctxdata =3D ctx->data; + struct qcomtee_ureq *ureq; + + /* See comments for reqs_lock in qcomtee_user_object_select(). */ + guard(mutex)(&ctxdata->reqs_lock); + + ureq =3D ureq_dequeue(ctxdata, req_id); + if (!ureq) + return -EINVAL; + + ureq->state =3D QCOMTEE_REQ_PROCESSED; + + if (!errno) + ureq->errno =3D qcomtee_cb_params_to_args(ureq->args, params, + num_params, ctx); + else + ureq->errno =3D errno; + /* Return errno if qcomtee_cb_params_to_args() failed; otherwise 0. */ + if (!errno && ureq->errno) + errno =3D ureq->errno; + else + errno =3D 0; + + /* Send result to QTEE. */ + complete(&ureq->c); + + return errno; +} diff --git a/include/uapi/linux/tee.h b/include/uapi/linux/tee.h index a5466b503bfe..386ad36f1a0a 100644 --- a/include/uapi/linux/tee.h +++ b/include/uapi/linux/tee.h @@ -59,6 +59,7 @@ #define TEE_IMPL_ID_OPTEE 1 #define TEE_IMPL_ID_AMDTEE 2 #define TEE_IMPL_ID_TSTEE 3 +#define TEE_IMPL_ID_QTEE 4 =20 /* * OP-TEE specific capabilities --=20 2.34.1 From nobody Thu Oct 2 20:38:43 2025 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 0F49626C3A7 for ; Thu, 11 Sep 2025 03:41:40 +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=1757562102; cv=none; b=dw6T4rfCfJcnE4tUtNcAf4GlsnZWKXgQnTakcANpQOxutX30VKylQyp0scFMqvk5zwfqdCRO4Ldgnnoa1cFOt6zOovr+sjDnTpQI8ntlCM/2LcvFI1DWprP+TIRe2+UpQ/99c5g+3l0ozXt3HBEaEdtc1XA5oNvCx+itIiCuYqc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757562102; c=relaxed/simple; bh=+8dSfgrMG4eFIFtqJ20ROAswX13YmpqsL2XfyfUksAU=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=SreXekem5omllrkCH2veF9j9S2R8283TfPqGRrXVrs2zH2CuQMfQ6b4tUSGV7EBWo4NgknCpTSz1ChrdtufBkwuXq5GR0LXWi6DSnTZMgbM7hkZRVLqoflZHOMechYeiHT3oCsSHvQHWTjlNg4BDnqfSxo4cuegB80Nf+0IoTPo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=oss.qualcomm.com; spf=pass smtp.mailfrom=oss.qualcomm.com; dkim=pass (2048-bit key) header.d=qualcomm.com header.i=@qualcomm.com header.b=OO9tQCMz; arc=none smtp.client-ip=205.220.168.131 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=oss.qualcomm.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=oss.qualcomm.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=qualcomm.com header.i=@qualcomm.com header.b="OO9tQCMz" 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 58B2Ik2e006784 for ; Thu, 11 Sep 2025 03:41:40 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=qualcomm.com; h= cc:content-transfer-encoding:content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to; s=qcppdkim1; bh= GaTc6vdim5GJ1OsrX7tFizDxK1+T66nxGle441QICfs=; b=OO9tQCMz3Qb0Xccs QwhFB5TXi3WfB03/jC3Rg/Cb+9tK5aAml1hj72dd5vr2jgo9JYPB4YVThbd683Gq d0y8+GfsWfa3p6ee+xa+/n5r/W2vlRtgRdyHL2J1/iC3w7Cv1KFWHk4qR7Ez/+sI wHypqJja54zeYg5/uh78BDG+TPuNr63BHCeqvKExLC8Lwcku9AXkBuP1UG9g47Zu 1xFzNbSmTiltMEStYVH0b1JyH+u8F02B055escaZk1rKCCPm/16je63+rRtmT16Y 4dCGFW4FuC6n8VcxklhsyYlzKyNeeXRlfG4IF/Md2kBRN9vbpr4WzaARy5qZL6Yo VkCmpg== Received: from mail-pj1-f72.google.com (mail-pj1-f72.google.com [209.85.216.72]) by mx0a-0031df01.pphosted.com (PPS) with ESMTPS id 490e8ae3fa-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128 verify=NOT) for ; Thu, 11 Sep 2025 03:41:40 +0000 (GMT) Received: by mail-pj1-f72.google.com with SMTP id 98e67ed59e1d1-329745d6b89so497417a91.1 for ; Wed, 10 Sep 2025 20:41:40 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1757562099; x=1758166899; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=GaTc6vdim5GJ1OsrX7tFizDxK1+T66nxGle441QICfs=; b=DM6o0NB/Wl8HRS3UNqu94trI8VqpBUdeYBFtMKa6yiMYjOeaR4VIJV4Ssw9pWXzQVr iDK+n/6oFVGS4jBQzGAcc9FGYcDMmjKs3vtFn3MPBEuA07VxGAHL2Y14gfF5NY1H2h5t 6g88WNgLEvkci2r0vj34Gir2PWFncjb0BrJzl4iLl+ghY8h4joUe/INI63FLm9lG9w1G DtPiUeMPMfR/FUJvCcK+6zWpyGbV/UW7CWUipsUPZEqnbSYwVlf60zIgLioXDhY47rmI S7ayGi8Xzf6bP+1oQt5p02l0o2QHsXsZNn/xrN8jofr77QoCY2Y5zCbtApQ0DBNR/F30 Kpyg== X-Forwarded-Encrypted: i=1; AJvYcCWNO+ZcUV8qjiY8Qh+nmNBjzFTyLCIJXR/bOc2gkm+0bn/MKh1dEDRVeoApEX45VFsTbdM9VV8q5cRPK+s=@vger.kernel.org X-Gm-Message-State: AOJu0YwRpxv2WDgXMb0EXO5xplKX6WUloi7yWCh7ujus57sYGSwQSwk3 EJEs5QKV0Tqt4ATurLnYt276jwOjsfjXNvjkA/EzRE2S+ZBmHLL/g0Ufi++FSGCYE4jJCkBJC5U NDsHjR5RkvEGq03gjdC1O8Na1OvixZJlYYL+KcJoiercort8g/m3p7i5TlyzF/lCoUA== X-Gm-Gg: ASbGncutvKgB1P/mmxhoiATgzHzqej/zyC9WC3/aBBkhMV96ELLTZ0SvO37OJeF+Net z4Q/fx28vK2elE+cEUo2GxPVUGEx2o2LWqn0Gwkd+aKDXucPsx292q9fOgIgeXHwZJYCmvq4LmQ tfNrUy4w+P1OBP8Vg4GSXQhOvlQUK+CdckNGi/nxTyPYB2hqz+7g9VP/4f4rs35lHmUJb67fbuT a7MHjZs6nxJIZB7+A4UKANSDnkcQXTG7XCXx6gEviZjDTZ2raez+KeLrxJuxR/0jLmNIasdnjWf DJ995gkSvMvQPjt9qqxrbltNRmTB6gSNtkdu/S0HGKU2S8CEJ32+EFshhElbn3F7gAfMnyrtqAv isqd8x9qoUrsoHGk9BXZGcNY= X-Received: by 2002:a17:903:189:b0:24c:ce43:e60b with SMTP id d9443c01a7336-2516e2bddf9mr240695615ad.18.1757562099295; Wed, 10 Sep 2025 20:41:39 -0700 (PDT) X-Google-Smtp-Source: AGHT+IF/i6ecLj5MYiXQ9AmYwku7JyAUYSshq8Oq7pjTWJmAC0pSVc3B/lcSH6c85M2ciudDJ2NEmA== X-Received: by 2002:a17:903:189:b0:24c:ce43:e60b with SMTP id d9443c01a7336-2516e2bddf9mr240695395ad.18.1757562098800; Wed, 10 Sep 2025 20:41:38 -0700 (PDT) Received: from hu-azarrabi-lv.qualcomm.com (Global_NAT1.qualcomm.com. [129.46.96.20]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-25c3b304f76sm2962275ad.130.2025.09.10.20.41.37 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 10 Sep 2025 20:41:38 -0700 (PDT) From: Amirreza Zarrabi Date: Wed, 10 Sep 2025 20:41:22 -0700 Subject: [PATCH v11 09/11] tee: qcom: add primordial object Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20250910-qcom-tee-using-tee-ss-without-mem-obj-v11-9-520e867b3d74@oss.qualcomm.com> References: <20250910-qcom-tee-using-tee-ss-without-mem-obj-v11-0-520e867b3d74@oss.qualcomm.com> In-Reply-To: <20250910-qcom-tee-using-tee-ss-without-mem-obj-v11-0-520e867b3d74@oss.qualcomm.com> To: Jens Wiklander , Sumit Garg , Bjorn Andersson , Konrad Dybcio , Bartosz Golaszewski , Apurupa Pattapu , Kees Cook , "Gustavo A. R. Silva" , Sumit Semwal , =?utf-8?q?Christian_K=C3=B6nig?= Cc: Harshal Dev , linux-arm-msm@vger.kernel.org, op-tee@lists.trustedfirmware.org, linux-kernel@vger.kernel.org, linux-hardening@vger.kernel.org, dri-devel@lists.freedesktop.org, linaro-mm-sig@lists.linaro.org, linux-doc@vger.kernel.org, Amirreza Zarrabi , Sumit Garg , Neil Armstrong X-Mailer: b4 0.13.0 X-Authority-Analysis: v=2.4 cv=H7Dbw/Yi c=1 sm=1 tr=0 ts=68c244f4 cx=c_pps a=RP+M6JBNLl+fLTcSJhASfg==:117 a=ouPCqIW2jiPt+lZRy3xVPw==:17 a=IkcTkHD0fZMA:10 a=yJojWOMRYYMA:10 a=EUspDBNiAAAA:8 a=KKAkSRfTAAAA:8 a=COk6AnOGAAAA:8 a=6dJEewf6gjddJ4Qna_sA:9 a=QEXdDO2ut3YA:10 a=iS9zxrgQBfv6-_F4QbHw:22 a=cvBusfyB2V15izCimMoJ:22 a=TjNXssC_j7lpFel5tvFf:22 X-Proofpoint-GUID: 1_oe5Y7N2K8HORL9TFJOQnKfh_EwtTZc X-Proofpoint-ORIG-GUID: 1_oe5Y7N2K8HORL9TFJOQnKfh_EwtTZc X-Proofpoint-Spam-Details-Enc: AW1haW4tMjUwOTA2MDAzOSBTYWx0ZWRfX+ticIrjZrQUR iQVJ2+9T1mls4KbCSyOFuGIOk8/7AIgVazXl1pUU7fSWWnpnxEQf0da+FG9lGjiicySFMydiFkX 4u6kfjoz9pwsSjqpPzDdJBa/ruI4/fBad8S5hWhzB/wqfymHXjAIJYXaHbtaR8d3SXjZfuqkpUn 0zwl2Wk9gU6XjUiS5Qfjcw+ayDFTMdDFSJE7xHKxLV/MIY3iHojQ5NrlcGJiMZnthRxmqsPvCnd BDLoXcJ7BZhKFZCnhvutQq6jjZKKFldkxzzeOFR0m1h8Gb41Nx8cgJSzxWq9YZFy+yzHCQVKO6/ UYZHclzm2H4R0HJWPAl9WvGYiNoweC2wsyDA87QK4iRzuRwupXFjxh+wXDtSH9zLMhbYDY0fZOv vA6tdAgx X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1117,Hydra:6.1.9,FMLib:17.12.80.40 definitions=2025-09-10_04,2025-09-10_01,2025-03-28_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 malwarescore=0 bulkscore=0 impostorscore=0 adultscore=0 phishscore=0 clxscore=1015 suspectscore=0 priorityscore=1501 spamscore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.19.0-2507300000 definitions=main-2509060039 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. Acked-by: Sumit Garg Tested-by: Neil Armstrong Tested-by: Harshal Dev Signed-off-by: Amirreza Zarrabi --- drivers/tee/qcomtee/Makefile | 1 + drivers/tee/qcomtee/core.c | 19 ++++++++--- drivers/tee/qcomtee/primordial_obj.c | 63 ++++++++++++++++++++++++++++++++= ++++ drivers/tee/qcomtee/qcomtee.h | 3 ++ 4 files changed, 81 insertions(+), 5 deletions(-) diff --git a/drivers/tee/qcomtee/Makefile b/drivers/tee/qcomtee/Makefile index 600af2b8f1c1..78f8e899d143 100644 --- a/drivers/tee/qcomtee/Makefile +++ b/drivers/tee/qcomtee/Makefile @@ -3,5 +3,6 @@ obj-$(CONFIG_QCOMTEE) +=3D qcomtee.o qcomtee-objs +=3D async.o qcomtee-objs +=3D call.o qcomtee-objs +=3D core.o +qcomtee-objs +=3D primordial_obj.o qcomtee-objs +=3D shm.o qcomtee-objs +=3D user_obj.o diff --git a/drivers/tee/qcomtee/core.c b/drivers/tee/qcomtee/core.c index b6931ed6f200..783acc59cfa9 100644 --- a/drivers/tee/qcomtee/core.c +++ b/drivers/tee/qcomtee/core.c @@ -31,10 +31,12 @@ int qcomtee_next_arg_type(struct qcomtee_arg *u, int i, } =20 /* - * QTEE expects IDs with the QCOMTEE_MSG_OBJECT_NS_BIT set for objects - * of the QCOMTEE_OBJECT_TYPE_CB type. + * QTEE expects IDs with QCOMTEE_MSG_OBJECT_NS_BIT set for objects of + * QCOMTEE_OBJECT_TYPE_CB type. The first ID with QCOMTEE_MSG_OBJECT_NS_BIT + * set is reserved for the primordial object. */ -#define QCOMTEE_OBJECT_ID_START (QCOMTEE_MSG_OBJECT_NS_BIT + 1) +#define QCOMTEE_OBJECT_PRIMORDIAL (QCOMTEE_MSG_OBJECT_NS_BIT) +#define QCOMTEE_OBJECT_ID_START (QCOMTEE_OBJECT_PRIMORDIAL + 1) #define QCOMTEE_OBJECT_ID_END (U32_MAX) =20 #define QCOMTEE_OBJECT_SET(p, type, ...) \ @@ -157,7 +159,9 @@ static void qcomtee_object_release(struct kref *refcoun= t) */ int qcomtee_object_get(struct qcomtee_object *object) { - if (object !=3D NULL_QCOMTEE_OBJECT && object !=3D ROOT_QCOMTEE_OBJECT) + if (object !=3D &qcomtee_primordial_object && + object !=3D NULL_QCOMTEE_OBJECT && + object !=3D ROOT_QCOMTEE_OBJECT) return kref_get_unless_zero(&object->refcount); =20 return 0; @@ -169,7 +173,9 @@ int qcomtee_object_get(struct qcomtee_object *object) */ void qcomtee_object_put(struct qcomtee_object *object) { - if (object !=3D NULL_QCOMTEE_OBJECT && object !=3D ROOT_QCOMTEE_OBJECT) + if (object !=3D &qcomtee_primordial_object && + object !=3D NULL_QCOMTEE_OBJECT && + object !=3D ROOT_QCOMTEE_OBJECT) kref_put(&object->refcount, qcomtee_object_release); } =20 @@ -261,6 +267,9 @@ qcomtee_local_object_get(struct qcomtee_object_invoke_c= tx *oic, struct qcomtee *qcomtee =3D tee_get_drvdata(oic->ctx->teedev); struct qcomtee_object *object; =20 + if (object_id =3D=3D QCOMTEE_OBJECT_PRIMORDIAL) + return &qcomtee_primordial_object; + guard(rcu)(); object =3D xa_load(&qcomtee->xa_local_objects, object_id); /* It already checks for %NULL_QCOMTEE_OBJECT. */ diff --git a/drivers/tee/qcomtee/primordial_obj.c b/drivers/tee/qcomtee/pri= mordial_obj.c new file mode 100644 index 000000000000..0e43f04493e2 --- /dev/null +++ b/drivers/tee/qcomtee/primordial_obj.c @@ -0,0 +1,63 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#include +#include "qcomtee.h" + +/** + * DOC: Primordial Object + * + * After boot, the kernel provides a static object of type + * %QCOMTEE_OBJECT_TYPE_CB called the primordial object. This object is us= ed + * for native kernel services or privileged operations. + * + * We support: + * - %QCOMTEE_OBJECT_OP_YIELD to yield by the thread running in QTEE. + * - %QCOMTEE_OBJECT_OP_SLEEP to wait for a period of time. + */ + +#define QCOMTEE_OBJECT_OP_YIELD 1 +#define QCOMTEE_OBJECT_OP_SLEEP 2 + +static int +qcomtee_primordial_obj_dispatch(struct qcomtee_object_invoke_ctx *oic, + struct qcomtee_object *primordial_object_unused, + u32 op, struct qcomtee_arg *args) +{ + int err =3D 0; + + switch (op) { + case QCOMTEE_OBJECT_OP_YIELD: + cond_resched(); + /* No output object. */ + oic->data =3D NULL; + break; + case QCOMTEE_OBJECT_OP_SLEEP: + /* Check message format matched QCOMTEE_OBJECT_OP_SLEEP op. */ + if (qcomtee_args_len(args) !=3D 1 || + args[0].type !=3D QCOMTEE_ARG_TYPE_IB || + args[0].b.size < sizeof(u32)) + return -EINVAL; + + msleep(*(u32 *)(args[0].b.addr)); + /* No output object. */ + oic->data =3D NULL; + break; + default: + err =3D -EINVAL; + } + + return err; +} + +static struct qcomtee_object_operations qcomtee_primordial_obj_ops =3D { + .dispatch =3D qcomtee_primordial_obj_dispatch, +}; + +struct qcomtee_object qcomtee_primordial_object =3D { + .name =3D "primordial", + .object_type =3D QCOMTEE_OBJECT_TYPE_CB, + .ops =3D &qcomtee_primordial_obj_ops +}; diff --git a/drivers/tee/qcomtee/qcomtee.h b/drivers/tee/qcomtee/qcomtee.h index f34be992e68b..084b3882017e 100644 --- a/drivers/tee/qcomtee/qcomtee.h +++ b/drivers/tee/qcomtee/qcomtee.h @@ -140,4 +140,7 @@ int qcomtee_user_object_submit(struct tee_context *ctx, struct tee_param *params, int num_params, int req_id, int errno); =20 +/* (2) Primordial Object. */ +extern struct qcomtee_object qcomtee_primordial_object; + #endif /* QCOMTEE_H */ --=20 2.34.1 From nobody Thu Oct 2 20:38:43 2025 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 F414626E708 for ; Thu, 11 Sep 2025 03:41:42 +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=1757562105; cv=none; b=R5h/xeGROvLckOClvYaT/PyF074iikphi0QnicHUpi7TVIkVlsl9l4wJ2+cE2CmiJTmiRt9i1q7L582zCMPSZUGZ+16jJkRGwLV2zAmABxRtagCXILjKyvKXn/Kb+OrxnAs6kloXmrN3CeFx1whhwwNgJ70r/xuKKhltZ9mX9sE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757562105; c=relaxed/simple; bh=kENdZrweqhHGnJf6wEosVdgBKcM0+mk+sFhIIGNHgqs=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=S1twRHHUO+GpF1q9s5xgw604uMG+WYb3Lbof1gBfOs1w7vnNgO14iJ99g4L/O5zrZGfoGDOoq8VJFgsPvYRfqCzZlyjUcAlKSp091A8jZzkQeUl0oCnX8f+TgVPcW37lSH4kl8FNdTV8nfzkl5Ie8QLjr17jskTO4Tp3TZaq2mA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=oss.qualcomm.com; spf=pass smtp.mailfrom=oss.qualcomm.com; dkim=pass (2048-bit key) header.d=qualcomm.com header.i=@qualcomm.com header.b=f6ZHaDw0; arc=none smtp.client-ip=205.220.168.131 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=oss.qualcomm.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=oss.qualcomm.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=qualcomm.com header.i=@qualcomm.com header.b="f6ZHaDw0" 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 58B2IV9O016087 for ; Thu, 11 Sep 2025 03:41:42 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=qualcomm.com; h= cc:content-transfer-encoding:content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to; s=qcppdkim1; bh= XwnYng4J7ze/dOFBSejFi7aWyaFRlAnXEGBPJ3w6NTU=; b=f6ZHaDw03bB5c9Ox NaMlewikrPImO0mDizXC8kEsIjpqUjuHrvu6aDibRSb9utvy5EJiZs79KtfibNxK K06CZoB5jGMBCshmTiuuPh1E0hYJwXwOkPcp4f54kH4jC2hTy28QGWRVD+bTsB+8 IR7HUiTXd+ZDXYHZMvi7c5y4auj0k+JOXl+E31uOAuBpc40/cmG5NElMTmyPQBDk A/DQHaJJ2TyY8qmt5+DCYgWketL9/scn/ie1OMdnhGpFE834TxIkdHdDw0ICzM+M EVdT11Ii33pvw9q0AuOrKRbDuwDOIrJoocXlzM2wxo2LhtzxTNRPxb0aEMrpzNzN INZUTw== Received: from mail-pj1-f72.google.com (mail-pj1-f72.google.com [209.85.216.72]) by mx0a-0031df01.pphosted.com (PPS) with ESMTPS id 491t382m51-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128 verify=NOT) for ; Thu, 11 Sep 2025 03:41:42 +0000 (GMT) Received: by mail-pj1-f72.google.com with SMTP id 98e67ed59e1d1-32db3d5f205so423615a91.2 for ; Wed, 10 Sep 2025 20:41:42 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1757562101; x=1758166901; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=XwnYng4J7ze/dOFBSejFi7aWyaFRlAnXEGBPJ3w6NTU=; b=khavnGBQDWUnxJKhQ/rqVtlZTLVOpKcbcHlfsj+H8iT5bStnnBOssNS8E/jaXfLC2j RQwqtfVXBHWJzKNq2/kIwLk7A+hIdLYNChhkaq3SlKkrcU9odsRcWDQ67A/t6WgsrY/D qRylDr1wYwnGisqLcOWY0KFeQmRfPmgZs8fWWObl/QqPT3GRAp07YL6WY/ZMZJfjdtNv 4k4C077U6oBJLuvG5VdvXY+3NoIAtHWot5UHw2uPGNVSfacdnRZV33Jn8Hl5HGowx+Dn WNIAcqjDN6/YefN5L/0vgQDbuLGf/ekNcqRtjZnXQTdD5+Y4J9zWst7yY+N6vkIuqViF bB7Q== X-Forwarded-Encrypted: i=1; AJvYcCWRsnp0Qlet4ahjpoojXciFxibs2j2NUh84tyOqeR515ZpA8fbje2g/CePyn7Lnw7iaVAl/kLrGLKldE2k=@vger.kernel.org X-Gm-Message-State: AOJu0YzodTUy+m9nEV4z5BZdd0qnm9mvUKRncTrTA3kzsAIpG6XQJphO NNpQeW3sBMgecyxsUc5h2uJua1fhhr6Cli2XN1HpLeRSM5DRMHo9OgaIuiwwwu6P3D+vQVFTgAg sC5RBgUNxJGGoXBE965qypZfcgTGWv1pZ+4ZI3hSBLUuqimW1LEphGX/Mxxf6nees7g== X-Gm-Gg: ASbGnctZViNjRScgBxYpueIX1popKDikqAt8uKfT1ngldL1UDfjBWPVJn0sPbIZglQ4 51cxLgork4TVtWqoYoxn1OBC897lBnGbJFboFSQDyH56wO3Ng5Zm4yIWZFRL11SLNFrMMwi4qMy Ae6H0nliXlMQ8Tf5/wf16Q8A1/wULTkdHHgWvc9vc5w/ko3g05JTVkqkpwwHB866tXelsmke+BU 9PCKk7rxjc9x0J3LpxZI8XRFIT1SvbBp3mF4fPKGNXZKtxzZF6ykbaIv9sv5NfIOYRmRrD/Xvi8 RGZzR+U3QJcrAetOTeLTF2Qi/EkxgGI1FyXA34y7e4ZQxXZ3qOxAe34n9DVG++F1KWgCJEhIqhM knMvDda0HhENGQapRHeHIR+g= X-Received: by 2002:a17:902:dac8:b0:25c:2ed4:fd95 with SMTP id d9443c01a7336-25c2ed5005dmr6815275ad.59.1757562100978; Wed, 10 Sep 2025 20:41:40 -0700 (PDT) X-Google-Smtp-Source: AGHT+IH3oevox7nqXEWF2DYBxqUbHqFTlhVuAe4cuBaS+gdJ0kKth+OfDN91fqSo5gDIycSAYiYQ6g== X-Received: by 2002:a17:902:dac8:b0:25c:2ed4:fd95 with SMTP id d9443c01a7336-25c2ed5005dmr6814725ad.59.1757562100314; Wed, 10 Sep 2025 20:41:40 -0700 (PDT) Received: from hu-azarrabi-lv.qualcomm.com (Global_NAT1.qualcomm.com. [129.46.96.20]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-25c3b304f76sm2962275ad.130.2025.09.10.20.41.38 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 10 Sep 2025 20:41:39 -0700 (PDT) From: Amirreza Zarrabi Date: Wed, 10 Sep 2025 20:41:23 -0700 Subject: [PATCH v11 10/11] tee: qcom: enable TEE_IOC_SHM_ALLOC ioctl Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20250910-qcom-tee-using-tee-ss-without-mem-obj-v11-10-520e867b3d74@oss.qualcomm.com> References: <20250910-qcom-tee-using-tee-ss-without-mem-obj-v11-0-520e867b3d74@oss.qualcomm.com> In-Reply-To: <20250910-qcom-tee-using-tee-ss-without-mem-obj-v11-0-520e867b3d74@oss.qualcomm.com> To: Jens Wiklander , Sumit Garg , Bjorn Andersson , Konrad Dybcio , Bartosz Golaszewski , Apurupa Pattapu , Kees Cook , "Gustavo A. R. Silva" , Sumit Semwal , =?utf-8?q?Christian_K=C3=B6nig?= Cc: Harshal Dev , linux-arm-msm@vger.kernel.org, op-tee@lists.trustedfirmware.org, linux-kernel@vger.kernel.org, linux-hardening@vger.kernel.org, dri-devel@lists.freedesktop.org, linaro-mm-sig@lists.linaro.org, linux-doc@vger.kernel.org, Amirreza Zarrabi , Neil Armstrong , Sumit Garg X-Mailer: b4 0.13.0 X-Proofpoint-ORIG-GUID: q_CI4QI88w723JeuQxLaeQn2NT6abfvh X-Proofpoint-GUID: q_CI4QI88w723JeuQxLaeQn2NT6abfvh X-Authority-Analysis: v=2.4 cv=NdLm13D4 c=1 sm=1 tr=0 ts=68c244f6 cx=c_pps a=RP+M6JBNLl+fLTcSJhASfg==:117 a=ouPCqIW2jiPt+lZRy3xVPw==:17 a=IkcTkHD0fZMA:10 a=yJojWOMRYYMA:10 a=KKAkSRfTAAAA:8 a=EUspDBNiAAAA:8 a=COk6AnOGAAAA:8 a=OR1utrCcES5rRZ7Z870A:9 a=DPARgtBJioFDCh1s:21 a=QEXdDO2ut3YA:10 a=iS9zxrgQBfv6-_F4QbHw:22 a=cvBusfyB2V15izCimMoJ:22 a=TjNXssC_j7lpFel5tvFf:22 X-Proofpoint-Spam-Details-Enc: AW1haW4tMjUwOTA4MDA2NiBTYWx0ZWRfX06DxtJBrTNAC ImYP48yZVW7CmhmT7A7GFKP/ZP17vu3EhNLXRqh1PFdViP+TAWr32C8K33ab2fJzGecebkERJXQ QsDuXugGDIZ9hfmzWFmdM98298VLMgjhhEggtodGCw+cR8bPKCQzljUPjKsb4dRzCFFYlV0amla AkQGJMGhzFYlxdQf/GeTNXFEoe2lK4S9IA68aIKJiepeCKt41dHcmTH/2ABUb3kRop+BgqVz/D0 iT08O9jA/L1iaUVT7enFfo03dpfW2lZ10aJo8wV+7X5ucbS09W+E78cqKNjC6ALEyKiYhGlfoyR L/yNT/SlzvAAoFexoc2Shn2ZBbb7LdHbKbgCqbz0LZMCi/9fyYslr1TlwoTpvg5W4rN5GcwUhb+ Giid/EeQ X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1117,Hydra:6.1.9,FMLib:17.12.80.40 definitions=2025-09-10_04,2025-09-10_01,2025-03-28_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 malwarescore=0 bulkscore=0 adultscore=0 suspectscore=0 phishscore=0 clxscore=1015 impostorscore=0 spamscore=0 priorityscore=1501 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.19.0-2507300000 definitions=main-2509080066 Enable userspace to allocate shared memory with QTEE. Since QTEE handles shared memory as object, a wrapper is implemented to represent tee_shm as an object. The shared memory identifier, obtained through TEE_IOC_SHM_ALLOC, is transferred to the driver using TEE_IOCTL_PARAM_ATTR_TYPE_OBJREF_INPUT/OUTPUT. Tested-by: Neil Armstrong Acked-by: Sumit Garg Tested-by: Harshal Dev Signed-off-by: Amirreza Zarrabi --- drivers/tee/qcomtee/Makefile | 1 + drivers/tee/qcomtee/call.c | 9 +- drivers/tee/qcomtee/mem_obj.c | 169 +++++++++++++++++++++++++++++++= ++++ drivers/tee/qcomtee/primordial_obj.c | 50 +++++++++++ drivers/tee/qcomtee/qcomtee.h | 39 ++++++++ drivers/tee/qcomtee/shm.c | 3 - 6 files changed, 267 insertions(+), 4 deletions(-) diff --git a/drivers/tee/qcomtee/Makefile b/drivers/tee/qcomtee/Makefile index 78f8e899d143..7c466c9f32af 100644 --- a/drivers/tee/qcomtee/Makefile +++ b/drivers/tee/qcomtee/Makefile @@ -3,6 +3,7 @@ obj-$(CONFIG_QCOMTEE) +=3D qcomtee.o qcomtee-objs +=3D async.o qcomtee-objs +=3D call.o qcomtee-objs +=3D core.o +qcomtee-objs +=3D mem_obj.o qcomtee-objs +=3D primordial_obj.o qcomtee-objs +=3D shm.o qcomtee-objs +=3D user_obj.o diff --git a/drivers/tee/qcomtee/call.c b/drivers/tee/qcomtee/call.c index 33daa4d7033d..cc17a48d0ab7 100644 --- a/drivers/tee/qcomtee/call.c +++ b/drivers/tee/qcomtee/call.c @@ -122,7 +122,10 @@ int qcomtee_objref_to_arg(struct qcomtee_arg *arg, str= uct tee_param *param, err =3D qcomtee_user_param_to_object(&arg->o, param, ctx); /* param is a QTEE object: */ else if (param->u.objref.flags & QCOMTEE_OBJREF_FLAG_TEE) - err =3D qcomtee_context_find_qtee_object(&arg->o, param, ctx); + err =3D qcomtee_context_find_qtee_object(&arg->o, param, ctx); + /* param is a memory object: */ + else if (param->u.objref.flags & QCOMTEE_OBJREF_FLAG_MEM) + err =3D qcomtee_memobj_param_to_object(&arg->o, param, ctx); =20 /* * For callback objects, call qcomtee_object_get() to keep a temporary @@ -168,6 +171,10 @@ int qcomtee_objref_from_arg(struct tee_param *param, s= truct qcomtee_arg *arg, if (is_qcomtee_user_object(object)) return qcomtee_user_param_from_object(param, object, ctx); + /* object is a memory object: */ + else if (is_qcomtee_memobj_object(object)) + return qcomtee_memobj_param_from_object(param, object, + ctx); =20 break; case QCOMTEE_OBJECT_TYPE_TEE: diff --git a/drivers/tee/qcomtee/mem_obj.c b/drivers/tee/qcomtee/mem_obj.c new file mode 100644 index 000000000000..228a3e30a31b --- /dev/null +++ b/drivers/tee/qcomtee/mem_obj.c @@ -0,0 +1,169 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include + +#include "qcomtee.h" + +/** + * DOC: Memory and Mapping Objects + * + * QTEE uses memory objects for memory sharing with Linux. + * A memory object can be a standard dma_buf or a contiguous memory range, + * e.g., tee_shm. A memory object should support one operation: map. When + * invoked by QTEE, a mapping object is generated. A mapping object suppor= ts + * one operation: unmap. + * + * (1) To map a memory object, QTEE invokes the primordial object with + * %QCOMTEE_OBJECT_OP_MAP_REGION operation; see + * qcomtee_primordial_obj_dispatch(). + * (2) To unmap a memory object, QTEE releases the mapping object which + * calls qcomtee_mem_object_release(). + * + * The map operation is implemented in the primordial object as a privileg= ed + * operation instead of qcomtee_mem_object_dispatch(). Otherwise, on + * platforms without shm_bridge, a user can trick QTEE into writing to the + * kernel memory by passing a user object as a memory object and returning= a + * random physical address as the result of the mapping request. + */ + +struct qcomtee_mem_object { + struct qcomtee_object object; + struct tee_shm *shm; + /* QTEE requires these felids to be page aligned. */ + phys_addr_t paddr; /* Physical address of range. */ + size_t size; /* Size of the range. */ +}; + +#define to_qcomtee_mem_object(o) \ + container_of((o), struct qcomtee_mem_object, object) + +static struct qcomtee_object_operations qcomtee_mem_object_ops; + +/* Is it a memory object using tee_shm? */ +int is_qcomtee_memobj_object(struct qcomtee_object *object) +{ + return object !=3D NULL_QCOMTEE_OBJECT && + typeof_qcomtee_object(object) =3D=3D QCOMTEE_OBJECT_TYPE_CB && + object->ops =3D=3D &qcomtee_mem_object_ops; +} + +static int qcomtee_mem_object_dispatch(struct qcomtee_object_invoke_ctx *o= ic, + struct qcomtee_object *object, u32 op, + struct qcomtee_arg *args) +{ + return -EINVAL; +} + +static void qcomtee_mem_object_release(struct qcomtee_object *object) +{ + struct qcomtee_mem_object *mem_object =3D to_qcomtee_mem_object(object); + + /* Matching get is in qcomtee_memobj_param_to_object(). */ + tee_shm_put(mem_object->shm); + kfree(mem_object); +} + +static struct qcomtee_object_operations qcomtee_mem_object_ops =3D { + .release =3D qcomtee_mem_object_release, + .dispatch =3D qcomtee_mem_object_dispatch, +}; + +/** + * qcomtee_memobj_param_to_object() - OBJREF parameter to &struct qcomtee_= object. + * @object: object returned. + * @param: TEE parameter. + * @ctx: context in which the conversion should happen. + * + * @param is an OBJREF with %QCOMTEE_OBJREF_FLAG_MEM flags. + * + * Return: On success return 0 or <0 on failure. + */ +int qcomtee_memobj_param_to_object(struct qcomtee_object **object, + struct tee_param *param, + struct tee_context *ctx) +{ + struct qcomtee_mem_object *mem_object __free(kfree) =3D NULL; + struct tee_shm *shm; + int err; + + mem_object =3D kzalloc(sizeof(*mem_object), GFP_KERNEL); + if (!mem_object) + return -ENOMEM; + + shm =3D tee_shm_get_from_id(ctx, param->u.objref.id); + if (IS_ERR(shm)) + return PTR_ERR(shm); + + /* mem-object wrapping the memref. */ + err =3D qcomtee_object_user_init(&mem_object->object, + QCOMTEE_OBJECT_TYPE_CB, + &qcomtee_mem_object_ops, "tee-shm-%d", + shm->id); + if (err) { + tee_shm_put(shm); + + return err; + } + + mem_object->paddr =3D shm->paddr; + mem_object->size =3D shm->size; + mem_object->shm =3D shm; + + *object =3D &no_free_ptr(mem_object)->object; + + return 0; +} + +/* Reverse what qcomtee_memobj_param_to_object() does. */ +int qcomtee_memobj_param_from_object(struct tee_param *param, + struct qcomtee_object *object, + struct tee_context *ctx) +{ + struct qcomtee_mem_object *mem_object; + + mem_object =3D to_qcomtee_mem_object(object); + /* Sure if the memobj is in a same context it is originated from. */ + if (mem_object->shm->ctx !=3D ctx) + return -EINVAL; + + param->u.objref.id =3D mem_object->shm->id; + param->u.objref.flags =3D QCOMTEE_OBJREF_FLAG_MEM; + + /* Passing shm->id to userspace; drop the reference. */ + qcomtee_object_put(object); + + return 0; +} + +/** + * qcomtee_mem_object_map() - Map a memory object. + * @object: memory object. + * @map_object: created mapping object. + * @mem_paddr: physical address of the memory. + * @mem_size: size of the memory. + * @perms: QTEE access permissions. + * + * Return: On success return 0 or <0 on failure. + */ +int qcomtee_mem_object_map(struct qcomtee_object *object, + struct qcomtee_object **map_object, u64 *mem_paddr, + u64 *mem_size, u32 *perms) +{ + struct qcomtee_mem_object *mem_object =3D to_qcomtee_mem_object(object); + + /* Reuses the memory object as a mapping object by re-sharing it. */ + qcomtee_object_get(&mem_object->object); + + *map_object =3D &mem_object->object; + *mem_paddr =3D mem_object->paddr; + *mem_size =3D mem_object->size; + *perms =3D QCOM_SCM_PERM_RW; + + return 0; +} diff --git a/drivers/tee/qcomtee/primordial_obj.c b/drivers/tee/qcomtee/pri= mordial_obj.c index 0e43f04493e2..b6f811e83b11 100644 --- a/drivers/tee/qcomtee/primordial_obj.c +++ b/drivers/tee/qcomtee/primordial_obj.c @@ -14,18 +14,31 @@ * for native kernel services or privileged operations. * * We support: + * - %QCOMTEE_OBJECT_OP_MAP_REGION to map a memory object and return mapp= ing + * object and mapping information (see qcomtee_mem_object_map()). * - %QCOMTEE_OBJECT_OP_YIELD to yield by the thread running in QTEE. * - %QCOMTEE_OBJECT_OP_SLEEP to wait for a period of time. */ =20 +#define QCOMTEE_OBJECT_OP_MAP_REGION 0 #define QCOMTEE_OBJECT_OP_YIELD 1 #define QCOMTEE_OBJECT_OP_SLEEP 2 =20 +/* Mapping information format as expected by QTEE. */ +struct qcomtee_mapping_info { + u64 paddr; + u64 len; + u32 perms; +} __packed; + static int qcomtee_primordial_obj_dispatch(struct qcomtee_object_invoke_ctx *oic, struct qcomtee_object *primordial_object_unused, u32 op, struct qcomtee_arg *args) { + struct qcomtee_mapping_info *map_info; + struct qcomtee_object *mem_object; + struct qcomtee_object *map_object; int err =3D 0; =20 switch (op) { @@ -33,6 +46,7 @@ qcomtee_primordial_obj_dispatch(struct qcomtee_object_inv= oke_ctx *oic, cond_resched(); /* No output object. */ oic->data =3D NULL; + break; case QCOMTEE_OBJECT_OP_SLEEP: /* Check message format matched QCOMTEE_OBJECT_OP_SLEEP op. */ @@ -44,6 +58,29 @@ qcomtee_primordial_obj_dispatch(struct qcomtee_object_in= voke_ctx *oic, msleep(*(u32 *)(args[0].b.addr)); /* No output object. */ oic->data =3D NULL; + + break; + case QCOMTEE_OBJECT_OP_MAP_REGION: + if (qcomtee_args_len(args) !=3D 3 || + args[0].type !=3D QCOMTEE_ARG_TYPE_OB || + args[1].type !=3D QCOMTEE_ARG_TYPE_IO || + args[2].type !=3D QCOMTEE_ARG_TYPE_OO || + args[0].b.size < sizeof(struct qcomtee_mapping_info)) + return -EINVAL; + + map_info =3D args[0].b.addr; + mem_object =3D args[1].o; + + qcomtee_mem_object_map(mem_object, &map_object, + &map_info->paddr, &map_info->len, + &map_info->perms); + + args[2].o =3D map_object; + /* One output object; pass it for cleanup to notify. */ + oic->data =3D map_object; + + qcomtee_object_put(mem_object); + break; default: err =3D -EINVAL; @@ -52,8 +89,21 @@ qcomtee_primordial_obj_dispatch(struct qcomtee_object_in= voke_ctx *oic, return err; } =20 +/* Called after submitting the callback response. */ +static void qcomtee_primordial_obj_notify(struct qcomtee_object_invoke_ctx= *oic, + struct qcomtee_object *unused, + int err) +{ + struct qcomtee_object *object =3D oic->data; + + /* If err, QTEE did not obtain mapping object. Drop it. */ + if (object && err) + qcomtee_object_put(object); +} + static struct qcomtee_object_operations qcomtee_primordial_obj_ops =3D { .dispatch =3D qcomtee_primordial_obj_dispatch, + .notify =3D qcomtee_primordial_obj_notify, }; =20 struct qcomtee_object qcomtee_primordial_object =3D { diff --git a/drivers/tee/qcomtee/qcomtee.h b/drivers/tee/qcomtee/qcomtee.h index 084b3882017e..f39bf63fd1c2 100644 --- a/drivers/tee/qcomtee/qcomtee.h +++ b/drivers/tee/qcomtee/qcomtee.h @@ -15,6 +15,7 @@ /* Flags relating to object reference. */ #define QCOMTEE_OBJREF_FLAG_TEE BIT(0) #define QCOMTEE_OBJREF_FLAG_USER BIT(1) +#define QCOMTEE_OBJREF_FLAG_MEM BIT(2) =20 /** * struct qcomtee - Main service struct. @@ -143,4 +144,42 @@ int qcomtee_user_object_submit(struct tee_context *ctx, /* (2) Primordial Object. */ extern struct qcomtee_object qcomtee_primordial_object; =20 +/* (3) Memory Object API. */ + +/* Is it a memory object using tee_shm? */ +int is_qcomtee_memobj_object(struct qcomtee_object *object); + +/** + * qcomtee_memobj_param_to_object() - OBJREF parameter to &struct qcomtee_= object. + * @object: object returned. + * @param: TEE parameter. + * @ctx: context in which the conversion should happen. + * + * @param is an OBJREF with %QCOMTEE_OBJREF_FLAG_MEM flags. + * + * Return: On success return 0 or <0 on failure. + */ +int qcomtee_memobj_param_to_object(struct qcomtee_object **object, + struct tee_param *param, + struct tee_context *ctx); + +/* Reverse what qcomtee_memobj_param_to_object() does. */ +int qcomtee_memobj_param_from_object(struct tee_param *param, + struct qcomtee_object *object, + struct tee_context *ctx); + +/** + * qcomtee_mem_object_map() - Map a memory object. + * @object: memory object. + * @map_object: created mapping object. + * @mem_paddr: physical address of the memory. + * @mem_size: size of the memory. + * @perms: QTEE access permissions. + * + * Return: On success return 0 or <0 on failure. + */ +int qcomtee_mem_object_map(struct qcomtee_object *object, + struct qcomtee_object **map_object, u64 *mem_paddr, + u64 *mem_size, u32 *perms); + #endif /* QCOMTEE_H */ diff --git a/drivers/tee/qcomtee/shm.c b/drivers/tee/qcomtee/shm.c index 2aea76487372..580bd25f98ed 100644 --- a/drivers/tee/qcomtee/shm.c +++ b/drivers/tee/qcomtee/shm.c @@ -117,9 +117,6 @@ static int qcomtee_shm_unregister(struct tee_context *c= tx, struct tee_shm *shm) static int pool_op_alloc(struct tee_shm_pool *pool, struct tee_shm *shm, size_t size, size_t align) { - if (!(shm->flags & TEE_SHM_PRIV)) - return -ENOMEM; - return tee_dyn_shm_alloc_helper(shm, size, align, qcomtee_shm_register); } =20 --=20 2.34.1 From nobody Thu Oct 2 20:38:43 2025 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 E88B2271448 for ; Thu, 11 Sep 2025 03:41:44 +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=1757562106; cv=none; b=fAw0EdRoitlAoFaTkrSPuK8dHz0aJIsYvdOqG060EugYlT2QLaduMaT0nUlxOTGAG6Ps+zVpj87v7+lFUwMk5tYdbOMUtC/eze1f/jh9dNbGartkiNUhH+N7+HA5gLHDyXtTxY8/IYczWIubp90mzCFxtkDIeLGWxxL3yKMx+i8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757562106; c=relaxed/simple; bh=RN0nKuxToKAQ9VOhyNYte58FvHuKeDhMEOShy3rUoJE=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=kKAH9vdmv4ChuMy02gjgJZbUdmzD9H5tJa0pr1p3h1BUz2UoZdQVwdHocT3JvVdNIwRxH53p6xnwNOBy55Td1KdZKFOTHa4cm7HTpoVKVC3ZRwWjU6HFnhaDjCvdYoXRPzOBmkjX+it/MMBbcKFcVfJ82g5OjTRz8PvDAMTqv+A= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=oss.qualcomm.com; spf=pass smtp.mailfrom=oss.qualcomm.com; dkim=pass (2048-bit key) header.d=qualcomm.com header.i=@qualcomm.com header.b=KZ3JPY7d; arc=none smtp.client-ip=205.220.168.131 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=oss.qualcomm.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=oss.qualcomm.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=qualcomm.com header.i=@qualcomm.com header.b="KZ3JPY7d" Received: from pps.filterd (m0279862.ppops.net [127.0.0.1]) by mx0a-0031df01.pphosted.com (8.18.1.2/8.18.1.2) with ESMTP id 58B2IjgJ031026 for ; Thu, 11 Sep 2025 03:41:44 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=qualcomm.com; h= cc:content-transfer-encoding:content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to; s=qcppdkim1; bh= OdVTKF925ssMm3cQuiq+O1uNYUiJEhXOdcH2WTZnulA=; b=KZ3JPY7dAs5KGUTq HFUFea0XTIvJXWVY1Q7H74X0N+OosjBE4pxWKXcpJEMGJobLna+RmCS+VAAMe3Re fJxsMZmoXjDwkVeQorNjFAFklvxhRt6n5xzyqM2TUE1XieTmRnI1zT0RaUuntbhG iQoj5Q6AzwCRT0kjJUq9atRUqT+/R2UTWwoM0vFgFcpEZYOYgU+OUATZthZw6zps xDEaOu4LmRnGtPsYhC+IJ9gTX/iUqzqh0hjIdncQ6jj/1s0j1q4MryROkmM68SFW aaJKpoZAH/CkoRL9AefPCL9pSBnSvervqrh+GgbqTfMQQOXrXxBMJuNb7EWEALkH ar9Tiw== Received: from mail-pl1-f198.google.com (mail-pl1-f198.google.com [209.85.214.198]) by mx0a-0031df01.pphosted.com (PPS) with ESMTPS id 490dqg5x5d-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128 verify=NOT) for ; Thu, 11 Sep 2025 03:41:44 +0000 (GMT) Received: by mail-pl1-f198.google.com with SMTP id d9443c01a7336-24caf28cce0so6395615ad.0 for ; Wed, 10 Sep 2025 20:41:43 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1757562103; x=1758166903; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=OdVTKF925ssMm3cQuiq+O1uNYUiJEhXOdcH2WTZnulA=; b=VRo+Bq09741zliSw6v9on86ZJ2YW3X2aOiOBR4PgxpuCcdw0TldYSeXoWL5JuQinXH WND7/yEvOB4RpSPLy7mk2IC3YBze/AYMQTpII8schzbswlVFb1/WrD1iSser91PxnXSF u29Nw+ZlzJe0lyTs3lACwvtovXjuE1c6g+BIDPgSEn3kaMLtIk5qBrLCKahdd35B73MW TzQk8fYpMYzdliR4AYo9FyFtuRzymCQOcQH3JdElenWnX9PsmJjPrsQ9WwuZBeM0DmlH Ba7iVq8B+rkuA+IzGkX3ZEmBB5hCatlESYzBBm8hsDouTLy1P488KgSzY/mtyAXNZRol UYuA== X-Forwarded-Encrypted: i=1; AJvYcCWxTYDQSnLaqs1P5/x37Bi1rAgRP/OsktTxBRWCat5FYs+L5xH8QdbvMiFzTlrK0teo1i4wmNXE5cmSwLw=@vger.kernel.org X-Gm-Message-State: AOJu0YyG1fM9dlFw7mMuhOwuFsS+Xt9glgGh9WnZsOIuErK1huUHYawU PyWnjagHqnKx8fPewdpuQFC4Zp9hhjvbwicLvUtoB6N2D5iySqDvM71IrjraT9KYY9Icn6bGr4c AtRISIV9F9Biu9rRlEKBT0J+jxPNt9psJTsnwykDwZOLFH2oOcqYv45AyoCI/csgSxA== X-Gm-Gg: ASbGncvNgeT7aOE+PZBjpdy32QOJozWzcGSd6sYJ7M1G7dsocUpx7P7K2CeYzj23Vj2 iUlNp8+3iuT7YlHmKh6sMgQiWGkYyho9HdCXx0Ec0/1c2e9pBb7TddrzDJPRm1AoPCj8IUsBffi 0heh9+8MDyYtf4wYAGEBW+sFQqr/GTsDVlA7VwgC6nIb80IoKkOxLEfMBM5jtEyQ5OQyvMwEqrN 1WiuB+vj3pW2snBGJNERdq4xJXB+89XPIAkoaeh9vykYM5SJtljmZM5iB3qSPJcqOLGTB9TpopC y4/wTlncwGBBVdtJTvF92hjdBEG53eOsSmtrOj9ZOoTBTcQvCAsW1SPBxVUUmuMleOmbkYCSEa5 OuzVXdVVum5RNKsik5rOBJ7w= X-Received: by 2002:a17:903:138a:b0:24c:9e2d:9a13 with SMTP id d9443c01a7336-25170772b3amr227810425ad.27.1757562103025; Wed, 10 Sep 2025 20:41:43 -0700 (PDT) X-Google-Smtp-Source: AGHT+IGtd17Vhg+RzVHZGU8BB/FT8CYxosIKHklKDWfs0WsmhvNxis8G3SdePgjppVkj5JOpI57GYA== X-Received: by 2002:a17:903:138a:b0:24c:9e2d:9a13 with SMTP id d9443c01a7336-25170772b3amr227810115ad.27.1757562102478; Wed, 10 Sep 2025 20:41:42 -0700 (PDT) Received: from hu-azarrabi-lv.qualcomm.com (Global_NAT1.qualcomm.com. [129.46.96.20]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-25c3b304f76sm2962275ad.130.2025.09.10.20.41.40 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 10 Sep 2025 20:41:41 -0700 (PDT) From: Amirreza Zarrabi Date: Wed, 10 Sep 2025 20:41:24 -0700 Subject: [PATCH v11 11/11] Documentation: tee: Add Qualcomm TEE driver Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20250910-qcom-tee-using-tee-ss-without-mem-obj-v11-11-520e867b3d74@oss.qualcomm.com> References: <20250910-qcom-tee-using-tee-ss-without-mem-obj-v11-0-520e867b3d74@oss.qualcomm.com> In-Reply-To: <20250910-qcom-tee-using-tee-ss-without-mem-obj-v11-0-520e867b3d74@oss.qualcomm.com> To: Jens Wiklander , Sumit Garg , Bjorn Andersson , Konrad Dybcio , Bartosz Golaszewski , Apurupa Pattapu , Kees Cook , "Gustavo A. R. Silva" , Sumit Semwal , =?utf-8?q?Christian_K=C3=B6nig?= Cc: Harshal Dev , linux-arm-msm@vger.kernel.org, op-tee@lists.trustedfirmware.org, linux-kernel@vger.kernel.org, linux-hardening@vger.kernel.org, dri-devel@lists.freedesktop.org, linaro-mm-sig@lists.linaro.org, linux-doc@vger.kernel.org, Amirreza Zarrabi , Sumit Garg X-Mailer: b4 0.13.0 X-Proofpoint-ORIG-GUID: syVMBdSXsxt9yI7dqHwHLcaRtkbh13d3 X-Proofpoint-Spam-Details-Enc: AW1haW4tMjUwOTA2MDAzNSBTYWx0ZWRfXw5+zWkJ9n318 WKIS4UudrtLawfW52ZywVU+58nwmBzWAVPOoKyHij4gNFzHOMNwpqdyKwFjxX27mPAoVZRyLs2/ cDyaxp7Epgn4bcidrWHJmtiCA501zmrhJlpOuzg7NP4DC4SOdMXDgy8j6vm2EdkMgx+YbdULPrk Ny179rgIyKtBiS84zuueCh8t8m7szVNELsd/y7j/KxaUqO8iTnJcjBsUPnX74s5XnleMBCsjQQ7 dihf16ul/ntWPEa1URsjoCxckHPeOrnHOkmJnSogmi72Jdiix6EETQYuFoWkF13kgfhVOB5C0qR TdkSubfUJgfBU8wvkn6w4GuPkXGS13ecsIrdq53fYNKWe7x7uOuxQO0Sm42R3pjetWLq1uGmFyf kxe9nHfE X-Proofpoint-GUID: syVMBdSXsxt9yI7dqHwHLcaRtkbh13d3 X-Authority-Analysis: v=2.4 cv=N8UpF39B c=1 sm=1 tr=0 ts=68c244f8 cx=c_pps a=MTSHoo12Qbhz2p7MsH1ifg==:117 a=ouPCqIW2jiPt+lZRy3xVPw==:17 a=IkcTkHD0fZMA:10 a=yJojWOMRYYMA:10 a=EUspDBNiAAAA:8 a=7CQSdrXTAAAA:8 a=NEAV23lmAAAA:8 a=VwQbUJbxAAAA:8 a=vCTlBN6rBY5pDr9NrAkA:9 a=QEXdDO2ut3YA:10 a=M0EVDjxxv-UA:10 a=GvdueXVYPmCkWapjIL-Q:22 a=a-qgeE7W1pNrGK8U0ZQC:22 X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1117,Hydra:6.1.9,FMLib:17.12.80.40 definitions=2025-09-10_04,2025-09-10_01,2025-03-28_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 adultscore=0 spamscore=0 malwarescore=0 clxscore=1015 bulkscore=0 suspectscore=0 priorityscore=1501 impostorscore=0 phishscore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.19.0-2507300000 definitions=main-2509060035 Add documentation for the Qualcomm TEE driver. Acked-by: Sumit Garg Signed-off-by: Amirreza Zarrabi --- Documentation/tee/index.rst | 1 + Documentation/tee/qtee.rst | 96 +++++++++++++++++++++++++++++++++++++++++= ++++ MAINTAINERS | 1 + 3 files changed, 98 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 =20 .. only:: subproject and html =20 diff --git a/Documentation/tee/qtee.rst b/Documentation/tee/qtee.rst new file mode 100644 index 000000000000..2fa2c1bf6384 --- /dev/null +++ b/Documentation/tee/qtee.rst @@ -0,0 +1,96 @@ +.. SPDX-License-Identifier: GPL-2.0 + +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D +QTEE (Qualcomm Trusted Execution Environment) +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +The QTEE driver handles communication with Qualcomm TEE [1]. + +The lowest level of communication with QTEE builds on the ARM SMC Calling +Convention (SMCCC) [2], which is the foundation for QTEE's Secure Channel +Manager (SCM) [3] used internally by the driver. + +In a QTEE-based system, services are represented as objects with a 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 also invoke objects hosted in the non-= secure +world using a method known as "callback request". + +The SCM provides two functions to support direct invocation and callback r= equests: + +- QCOM_SCM_SMCINVOKE_INVOKE: Used for direct invocation. It can return eit= her + a result or initiate a callback request. +- QCOM_SCM_SMCINVOKE_CB_RSP: Used to submit a response to a callback reque= st + triggered by a previous direct invocation. + +The QTEE Transport Message [4] is stacked on top of the SCM driver functio= ns. + +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 requests. This picture shows the contents = of +a QTEE transport message:: + + +---------------------+ + | v + +-----------------+-------+-------+------+--------------------------+ + | qcomtee_msg_ |object | buffer | | + | object_invoke | id | offset, size | | = (inbound buffer) + +-----------------+-------+--------------+--------------------------+ + <---- header -----><---- arguments ------><- in/out buffer payload -> + + +-----------+ + | v + +-----------------+-------+-------+------+----------------------+ + | qcomtee_msg_ |object | buffer | | + | callback | id | offset, size | | (out= bound buffer) + +-----------------+-------+--------------+----------------------+ + +Each buffer is started with a header and array of arguments. + +QTEE Transport Message supports four types of arguments: + +- Input Object (IO) is an object parameter to the current invocation + or callback request. +- Output Object (OO) is an object parameter from the current invocation + or callback request. +- Input Buffer (IB) is (offset, size) pair to the inbound or outbound regi= on + to store parameter to the current invocation or callback request. +- Output Buffer (OB) is (offset, size) pair to the inbound or outbound reg= ion + to store parameter from the current invocation or callback request. + +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 | QTEE | | QTEE = | + | libqcomtee [5] | | subsys | driver | | Trusted OS = | + +-------+-------------+--+----+-------+----+-------------+-------------= -+ + | Generic TEE API | | QTEE MSG = | + | IOCTL (TEE_IOC_*) | | SMCCC (QCOM_SCM_SMCINVOKE_*) = | + +-----------------------------+ +--------------------------------= -+ + +References +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +[1] https://docs.qualcomm.com/bundle/publicresource/topics/80-70015-11/qua= lcomm-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] drivers/tee/qcomtee/qcomtee_msg.h + +[5] https://github.com/quic/quic-teec diff --git a/MAINTAINERS b/MAINTAINERS index bde449308736..589f8ea62bcf 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -20860,6 +20860,7 @@ QUALCOMM TEE (QCOMTEE) DRIVER M: Amirreza Zarrabi L: linux-arm-msm@vger.kernel.org S: Maintained +F: Documentation/tee/qtee.rst F: drivers/tee/qcomtee/ =20 QUALCOMM TRUST ZONE MEMORY ALLOCATOR --=20 2.34.1