From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 082AFE7AD72 for ; Tue, 3 Oct 2023 15:31:25 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:In-Reply-To:MIME-Version:References: Message-ID:Subject:Cc:To:From:Date:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=XnYQp/8Ix3dUwu5K3WNOntqtHAgvEZgK+trT5TuG/Fs=; b=aZ34gmBi7wOy05 3dGw2h+vWxlVhc9W0iy7GGjnadJRItKPn1SoFgsms5saxkFUffeUFz0Es/ry72aYxNkNupVHmo5ro 8jzdznPeHvQUlM7ltyBRe3KYfq12Hn2q5svqwgGHLh9UAlDPa8NhM75h2uwMagrwLw1znv3NBhNa1 UIRu0KDIZQiQLPS+pM8InYnCq4qKD4mTIfL6Yy/Epm7FpyZ+ERaU50W+VonnmDT5OORwp/ys+bIUM MIq9QE49VCnbkk3WuR2Yg9fh5K8DJ1hotIrySeP6SQ713aGZ17xFcWUpI0bKJryFn3DvP8STnpP8h nUOXpHp6ptV/eSgq0SMQ==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.96 #2 (Red Hat Linux)) id 1qnhMQ-00EskJ-22; Tue, 03 Oct 2023 15:30:58 +0000 Received: from mail-pg1-x52e.google.com ([2607:f8b0:4864:20::52e]) by bombadil.infradead.org with esmtps (Exim 4.96 #2 (Red Hat Linux)) id 1qnhML-00Esjp-37 for linux-arm-kernel@lists.infradead.org; Tue, 03 Oct 2023 15:30:57 +0000 Received: by mail-pg1-x52e.google.com with SMTP id 41be03b00d2f7-5789ffc8ae0so689628a12.0 for ; Tue, 03 Oct 2023 08:30:52 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1696347052; x=1696951852; darn=lists.infradead.org; h=in-reply-to:content-disposition:mime-version:references:message-id :subject:cc:to:from:date:from:to:cc:subject:date:message-id:reply-to; bh=lYp5yCIDGT/fm50kxbjV/5sJTKWSTh4IiZ+UcJC4PC4=; b=tR2olY09LeOwAzL8mSTK0JrTdnR5F+8+R502DbEi/6RDZJjOtdWOhe9s9HdjvptkHD g6+n0IQ2pzMHe+kdGAq4rXoBuahztiFo9S9acTzmp5kwNgM/hQGEAVGEGwFyBTk4SS/c 7z+6ZjAH7h+cn5thSwpboETzhxPIbgBqpMVLEJBscrjFRdEG+338y9STX/7O61AhxupR qnQK3T+w9mstrPUfr2mAlBr9GU0dqrK5kVK/JnZsMKFluawQeR23MeCOUbQ3yD287pww 7HcW0D5I5Beh4uZuO4NtLDuGMIlRNdZLnMB/9SBmP1CAdo2otZCYmTOSTNQ51cHWgXhH vJxg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1696347052; x=1696951852; h=in-reply-to:content-disposition:mime-version:references:message-id :subject:cc:to:from:date:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=lYp5yCIDGT/fm50kxbjV/5sJTKWSTh4IiZ+UcJC4PC4=; b=DrxAZwqNG7eMLPbAevHbWnMh6CD+41R9Wg6AUkv4qO9h2l6jyrMkW2Pv2Jcllo9pow QEzmxNhRW7KklRzbXX5QTVecAt4h0ZQdxLVdQ96/gYinb9RvILE54fSLbOerGgHapkqk M5gWTPVXp0Gs7eaTHjZtpmETxWKGYRwcmxFxxdVCp3FBtiLmUyGn2eL4Rh7dn+OdnBPt Yu58Ok2jmrmc5zXf7K9HXHO4c2/NjQFj+jUNpvPHzEBB88+ZgHYv+H4qNZNJ1dpVQ03l +gxMrY33iX7/lkHlgcn9FPmMAKS2PmbPGKYh+7Y3qYQPd8112Us/DcjKtME9MbtKx6Nz DWng== X-Gm-Message-State: AOJu0YwB0kdhh2LtOBKNhEnXiCnXeZKhyo0bkeojzz7MX6/zqRtEe2JB 3ruuYsQijt37LVEDSydpmj2u/w== X-Google-Smtp-Source: AGHT+IHhSG7Bntl0r34lK0M291VfTwROB76qcr6PGxa+SckYGhyFfOhlurveX4QnxWFM88BUKp9uOw== X-Received: by 2002:a05:6a20:144f:b0:14e:b4d5:782d with SMTP id a15-20020a056a20144f00b0014eb4d5782dmr13895744pzi.2.1696347051992; Tue, 03 Oct 2023 08:30:51 -0700 (PDT) Received: from rayden (h-46-59-78-111.A175.priv.bahnhof.se. [46.59.78.111]) by smtp.gmail.com with ESMTPSA id c20-20020aa78c14000000b006934350c3absm1492080pfd.109.2023.10.03.08.30.46 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 03 Oct 2023 08:30:51 -0700 (PDT) Date: Tue, 3 Oct 2023 17:30:41 +0200 From: Jens Wiklander To: Balint Dobszay Cc: linux-arm-kernel@lists.infradead.org, op-tee@lists.trustedfirmware.org, sumit.garg@linaro.org, sudeep.holla@arm.com, marc.bonnici@arm.com, olivier.deprez@arm.com, achin.gupta@arm.com, gyorgy.szing@arm.com Subject: Re: [RFC PATCH] tee: tstee: Add initial Trusted Services TEE driver Message-ID: <20231003153041.GA568632@rayden> References: <20230927152145.111777-1-balint.dobszay@arm.com> MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: <20230927152145.111777-1-balint.dobszay@arm.com> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20231003_083054_017029_5D734074 X-CRM114-Status: GOOD ( 44.43 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org Hi Balint, On Wed, Sep 27, 2023 at 05:21:46PM +0200, Balint Dobszay wrote: > The Trusted Services project provides a framework for developing and > deploying device Root Of Trust services in FF-A Secure Partitions. The > FF-A SPs are accessible through the FF-A driver, but this doesn't > provide a user space interface. The goal of this TEE driver is to make > Trusted Services SPs accessible for user space clients. > > All TS SPs have the same FF-A UUID, it identifies the RPC protocol used > by TS. A TS SP can host one or more services, a service is identified by > its service UUID. The same type of service cannot be present twice in > the same SP. During SP boot each service in the SP gets assigned an > interface ID, this is just a short ID to simplify message addressing. > There is 1:1 mapping between TS SPs and TEE devices, i.e. a TEE device > gets registered for each Trusted Services compatible FF-A device found > on the FF-A bus. Opening the SP corresponds to opening the TEE dev and > creating a TEE context. A TS SP hosts one or more services, opening a > service corresponds to opening a session in the given tee_context. > > Signed-off-by: Balint Dobszay > --- > > Hi All, > > This is an initial TEE driver implementation for Trusted Services [1]. > Trusted Services is a TrustedFirmware.org project that provides a > framework for developing and deploying device Root Of Trust services in > FF-A Secure Partitions. The project hosts the reference implementation > of Arm Platform Security Architecture [2] for Arm A-profile devices. > > The FF-A Secure Partitions (SPs) are accessible through the FF-A driver > in Linux. However, the FF-A driver doesn't have a user space interface > so user space clients currently cannot access Trusted Services. The goal > of this TEE driver is to bridge this gap and make Trusted Services > functionality accessible from user space. > > The predecessor of this driver is an out-of-tree kernel module that we > have been using for prototyping [3]. An integration of Trusted Services, > OP-TEE as a S-EL1 SPMC, TF-A, Linux and this out-of-tree module is > available as part of the OP-TEE project, please find the manifest file > at [4]. > > Some key points about the structure of Trusted Services (for more > details please see the documentation at [5]): > - A Trusted Services SP can host one or multiple services. All TS SPs > have the same FF-A UUID, it identifies the RPC protocol used by TS. > The protocol's register ABI definition is available at [6] and is > implemented in tstee_private.h. > - A service hosted by an SP is identified by its service UUID. The > same type of service can be present in multiple SPs, but not twice in > the same SP. During SP boot each service in the SP gets assigned an > interface ID, this is just a short ID to simplify message addressing. > - There is 1:1 mapping between TS SPs and TEE devices, i.e. a TEE device > gets registered for each Trusted Services compatible FF-A device found > on the FF-A bus. > - Opening the SP corresponds to opening the TEE dev and creating a TEE > context. A TS SP hosts one or more services, opening a service > corresponds to opening a session in the given tee_context. > > Regards, > Balint > > [1] https://www.trustedfirmware.org/projects/trusted-services/ > [2] https://www.arm.com/architecture/security-features/platform-security > [3] https://gitlab.arm.com/linux-arm/linux-trusted-services > [4] https://github.com/OP-TEE/manifest/blob/master/fvp-ts.xml > [5] https://trusted-services.readthedocs.io > [6] https://trusted-services.readthedocs.io/en/integration/developer/service-access-protocols.html#abi > > drivers/tee/Kconfig | 1 + > drivers/tee/Makefile | 1 + > drivers/tee/tstee/Kconfig | 11 + > drivers/tee/tstee/Makefile | 3 + > drivers/tee/tstee/core.c | 473 ++++++++++++++++++++++++++++++ > drivers/tee/tstee/shm_pool.c | 91 ++++++ > drivers/tee/tstee/tstee_private.h | 97 ++++++ > include/uapi/linux/tee.h | 1 + > 8 files changed, 678 insertions(+) > create mode 100644 drivers/tee/tstee/Kconfig > create mode 100644 drivers/tee/tstee/Makefile > create mode 100644 drivers/tee/tstee/core.c > create mode 100644 drivers/tee/tstee/shm_pool.c > create mode 100644 drivers/tee/tstee/tstee_private.h > > diff --git a/drivers/tee/Kconfig b/drivers/tee/Kconfig > index 73a147202e88..61b507c18780 100644 > --- a/drivers/tee/Kconfig > +++ b/drivers/tee/Kconfig > @@ -15,5 +15,6 @@ if TEE > > source "drivers/tee/optee/Kconfig" > source "drivers/tee/amdtee/Kconfig" > +source "drivers/tee/tstee/Kconfig" > > endif > diff --git a/drivers/tee/Makefile b/drivers/tee/Makefile > index 68da044afbfa..5488cba30bd2 100644 > --- a/drivers/tee/Makefile > +++ b/drivers/tee/Makefile > @@ -5,3 +5,4 @@ tee-objs += tee_shm.o > tee-objs += tee_shm_pool.o > obj-$(CONFIG_OPTEE) += optee/ > obj-$(CONFIG_AMDTEE) += amdtee/ > +obj-$(CONFIG_ARM_TSTEE) += tstee/ > diff --git a/drivers/tee/tstee/Kconfig b/drivers/tee/tstee/Kconfig > new file mode 100644 > index 000000000000..cd8d32586a77 > --- /dev/null > +++ b/drivers/tee/tstee/Kconfig > @@ -0,0 +1,11 @@ > +# SPDX-License-Identifier: GPL-2.0-only > +config ARM_TSTEE > + tristate "Arm Trusted Services TEE driver" > + depends on ARM_FFA_TRANSPORT > + default n > + help > + The Trusted Services project provides a framework for developing and > + deploying device Root Of Trust services in FF-A Secure Partitions. > + This driver provides an interface to make Trusted Services Secure > + Partitions accessible for user space clients, since the FF-A driver > + doesn't implement a user space interface directly. > diff --git a/drivers/tee/tstee/Makefile b/drivers/tee/tstee/Makefile > new file mode 100644 > index 000000000000..dd54b1f88652 > --- /dev/null > +++ b/drivers/tee/tstee/Makefile > @@ -0,0 +1,3 @@ > +# SPDX-License-Identifier: GPL-2.0-only > +arm-tstee-objs := core.o shm_pool.o > +obj-$(CONFIG_ARM_TSTEE) = arm-tstee.o > diff --git a/drivers/tee/tstee/core.c b/drivers/tee/tstee/core.c > new file mode 100644 > index 000000000000..c0194638b7da > --- /dev/null > +++ b/drivers/tee/tstee/core.c > @@ -0,0 +1,473 @@ > +// SPDX-License-Identifier: GPL-2.0-only > +/* > + * Copyright (c) 2023, Arm Limited > + */ > + > +#define DRIVER_NAME "Arm TSTEE" > +#define pr_fmt(fmt) DRIVER_NAME ": " fmt > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include "tstee_private.h" > + > +#define FFA_INVALID_MEM_HANDLE U64_MAX > + > +static void arg_list_to_ffa_data(const u32 *args, struct ffa_send_direct_data *data) > +{ > + data->data0 = args[0]; > + data->data1 = args[1]; > + data->data2 = args[2]; > + data->data3 = args[3]; > + data->data4 = args[4]; > +} > + > +static void arg_list_from_ffa_data(const struct ffa_send_direct_data *data, u32 *args) > +{ > + args[0] = lower_32_bits(data->data0); > + args[1] = lower_32_bits(data->data1); > + args[2] = lower_32_bits(data->data2); > + args[3] = lower_32_bits(data->data3); > + args[4] = lower_32_bits(data->data4); > +} > + > +static void tstee_get_version(struct tee_device *teedev, struct tee_ioctl_version_data *vers) > +{ > + struct tstee *tstee = tee_get_drvdata(teedev); > + struct tee_ioctl_version_data v = { > + .impl_id = TEE_IMPL_ID_TSTEE, > + .impl_caps = tstee->ffa_dev->vm_id, > + .gen_caps = 0, > + }; > + > + *vers = v; > +} > + > +static int tstee_open(struct tee_context *ctx) > +{ > + struct ts_context_data *ctxdata; > + > + ctxdata = kzalloc(sizeof(*ctxdata), GFP_KERNEL); > + if (!ctxdata) > + return -ENOMEM; > + > + mutex_init(&ctxdata->mutex); > + idr_init(&ctxdata->sess_ids); > + INIT_LIST_HEAD(&ctxdata->sess_list); > + > + ctx->data = ctxdata; > + > + return 0; > +} > + > +static void tstee_release(struct tee_context *ctx) > +{ > + struct ts_context_data *ctxdata = ctx->data; > + struct ts_session *sess, *sess_tmp; > + > + if (!ctxdata) > + return; > + > + list_for_each_entry_safe(sess, sess_tmp, &ctxdata->sess_list, list_node) { > + list_del(&sess->list_node); > + idr_remove(&ctxdata->sess_ids, sess->session_id); > + kfree(sess); > + } > + > + idr_destroy(&ctxdata->sess_ids); > + mutex_destroy(&ctxdata->mutex); > + > + kfree(ctxdata); > + ctx->data = NULL; > +} > + > +static struct ts_session *find_session(struct ts_context_data *ctxdata, u32 session_id) > +{ > + struct ts_session *sess; > + > + list_for_each_entry(sess, &ctxdata->sess_list, list_node) > + if (sess->session_id == session_id) > + return sess; > + > + return NULL; > +} > + > +static int tstee_open_session(struct tee_context *ctx, struct tee_ioctl_open_session_arg *arg, > + struct tee_param *param __always_unused) > +{ > + struct tstee *tstee = tee_get_drvdata(ctx->teedev); > + struct ffa_device *ffa_dev = tstee->ffa_dev; > + struct ts_context_data *ctxdata = ctx->data; > + struct ffa_send_direct_data ffa_data; > + struct ts_session *sess = NULL; > + u32 ffa_args[5] = {}; > + int sess_id; > + int rc; > + > + ffa_args[TS_RPC_CTRL_REG] = TS_RPC_CTRL_PACK_IFACE_OPCODE(TS_RPC_MGMT_IFACE_ID, > + TS_RPC_OP_SERVICE_INFO); > + > + memcpy((u8 *)(ffa_args + TS_RPC_SERVICE_INFO_UUID0), arg->uuid, UUID_SIZE); > + > + arg_list_to_ffa_data(ffa_args, &ffa_data); > + rc = ffa_dev->ops->msg_ops->sync_send_receive(ffa_dev, &ffa_data); > + if (rc) > + return rc; > + > + arg_list_from_ffa_data(&ffa_data, ffa_args); > + > + if (ffa_args[TS_RPC_SERVICE_INFO_RPC_STATUS] != TS_RPC_OK) > + return -ENODEV; > + > + if (ffa_args[TS_RPC_SERVICE_INFO_IFACE] > U8_MAX) > + return -EINVAL; > + > + sess = kzalloc(sizeof(*sess), GFP_KERNEL); > + if (!sess) > + return -ENOMEM; > + > + sess_id = idr_alloc(&ctxdata->sess_ids, sess, 1, 0, GFP_KERNEL); > + if (sess_id < 0) { > + kfree(sess); > + return sess_id; > + } > + > + sess->session_id = sess_id; > + sess->iface_id = ffa_args[TS_RPC_SERVICE_INFO_IFACE]; > + > + mutex_lock(&ctxdata->mutex); > + list_add(&sess->list_node, &ctxdata->sess_list); > + mutex_unlock(&ctxdata->mutex); > + > + arg->session = sess_id; > + arg->ret = 0; > + > + return 0; > +} > + > +static int tstee_close_session(struct tee_context *ctx, u32 session) > +{ > + struct ts_context_data *ctxdata = ctx->data; > + struct ts_session *sess; > + > + mutex_lock(&ctxdata->mutex); > + sess = find_session(ctxdata, session); > + if (sess) > + list_del(&sess->list_node); > + > + mutex_unlock(&ctxdata->mutex); > + > + if (!sess) > + return -EINVAL; > + > + idr_remove(&ctxdata->sess_ids, sess->session_id); > + kfree(sess); > + > + return 0; > +} > + > +static int tstee_invoke_func(struct tee_context *ctx, struct tee_ioctl_invoke_arg *arg, > + struct tee_param *param) > +{ > + struct tstee *tstee = tee_get_drvdata(ctx->teedev); > + struct ffa_device *ffa_dev = tstee->ffa_dev; > + struct ts_context_data *ctxdata = ctx->data; > + struct ffa_send_direct_data ffa_data; > + struct tee_shm *shm = NULL; > + struct ts_session *sess; > + u32 req_len, ffa_args[5] = {}; > + int shm_id, rc; > + u8 iface_id; > + u64 handle; > + u16 opcode; > + > + mutex_lock(&ctxdata->mutex); > + sess = find_session(ctxdata, arg->session); > + > + /* Do this while holding the mutex to make sure that the session wasn't closed meanwhile */ > + if (sess) > + iface_id = sess->iface_id; > + > + mutex_unlock(&ctxdata->mutex); > + if (!sess) > + return -EINVAL; > + > + opcode = lower_16_bits(arg->func); > + shm_id = lower_32_bits(param[0].u.value.a); > + req_len = lower_32_bits(param[0].u.value.b); > + > + if (shm_id != 0) { > + shm = tee_shm_get_from_id(ctx, shm_id); > + if (IS_ERR(shm)) > + return PTR_ERR(shm); > + > + if (shm->size < req_len) { > + pr_err("request doesn't fit into shared memory buffer\n"); > + rc = -EINVAL; > + goto out; > + } > + > + handle = shm->sec_world_id; > + } else { > + handle = FFA_INVALID_MEM_HANDLE; > + } > + > + ffa_args[TS_RPC_CTRL_REG] = TS_RPC_CTRL_PACK_IFACE_OPCODE(iface_id, opcode); > + ffa_args[TS_RPC_SERVICE_MEM_HANDLE_LSW] = lower_32_bits(handle); > + ffa_args[TS_RPC_SERVICE_MEM_HANDLE_MSW] = upper_32_bits(handle); > + ffa_args[TS_RPC_SERVICE_REQ_LEN] = req_len; > + ffa_args[TS_RPC_SERVICE_CLIENT_ID] = 0; > + > + arg_list_to_ffa_data(ffa_args, &ffa_data); > + rc = ffa_dev->ops->msg_ops->sync_send_receive(ffa_dev, &ffa_data); > + if (rc) > + goto out; > + > + arg_list_from_ffa_data(&ffa_data, ffa_args); > + > + if (ffa_args[TS_RPC_SERVICE_RPC_STATUS] != TS_RPC_OK) { > + pr_err("invoke_func rpc status: %d\n", ffa_args[TS_RPC_SERVICE_RPC_STATUS]); > + rc = -EINVAL; > + goto out; > + } > + > + arg->ret = ffa_args[TS_RPC_SERVICE_STATUS]; > + if (shm && shm->size >= ffa_args[TS_RPC_SERVICE_RESP_LEN]) > + param[0].u.value.a = ffa_args[TS_RPC_SERVICE_RESP_LEN]; > + > +out: > + if (shm) > + tee_shm_put(shm); > + > + return rc; > +} > + > +static int tstee_cancel_req(struct tee_context *ctx __always_unused, u32 cancel_id __always_unused, > + u32 session __always_unused) > +{ > + return -EINVAL; > +} > + > +int tstee_shm_register(struct tee_context *ctx, struct tee_shm *shm, struct page **pages, > + size_t num_pages, unsigned long start __always_unused) > +{ > + struct tstee *tstee = tee_get_drvdata(ctx->teedev); > + struct ffa_device *ffa_dev = tstee->ffa_dev; > + struct ffa_mem_region_attributes mem_attr = { > + .receiver = tstee->ffa_dev->vm_id, > + .attrs = FFA_MEM_RW, > + .flag = 0, > + }; > + struct ffa_mem_ops_args mem_args = { > + .attrs = &mem_attr, > + .use_txbuf = true, > + .nattrs = 1, > + .flags = 0, > + }; > + struct ffa_send_direct_data ffa_data; > + struct sg_table sgt; > + u32 ffa_args[5] = {}; > + int rc; > + > + rc = sg_alloc_table_from_pages(&sgt, pages, num_pages, 0, num_pages * PAGE_SIZE, > + GFP_KERNEL); > + if (rc) > + return rc; > + > + mem_args.sg = sgt.sgl; > + rc = ffa_dev->ops->mem_ops->memory_share(&mem_args); > + sg_free_table(&sgt); > + if (rc) > + return rc; > + > + shm->sec_world_id = mem_args.g_handle; > + > + ffa_args[TS_RPC_CTRL_REG] = TS_RPC_CTRL_PACK_IFACE_OPCODE(TS_RPC_MGMT_IFACE_ID, > + TS_RPC_OP_RETRIEVE_MEM); > + ffa_args[TS_RPC_RETRIEVE_MEM_HANDLE_LSW] = lower_32_bits(shm->sec_world_id); > + ffa_args[TS_RPC_RETRIEVE_MEM_HANDLE_MSW] = upper_32_bits(shm->sec_world_id); > + ffa_args[TS_RPC_RETRIEVE_MEM_TAG_LSW] = 0; > + ffa_args[TS_RPC_RETRIEVE_MEM_TAG_MSW] = 0; > + > + arg_list_to_ffa_data(ffa_args, &ffa_data); > + rc = ffa_dev->ops->msg_ops->sync_send_receive(ffa_dev, &ffa_data); > + if (rc) { > + (void)ffa_dev->ops->mem_ops->memory_reclaim(shm->sec_world_id, 0); > + return rc; > + } > + > + arg_list_from_ffa_data(&ffa_data, ffa_args); > + > + if (ffa_args[TS_RPC_RETRIEVE_MEM_RPC_STATUS] != TS_RPC_OK) { > + pr_err("shm_register rpc status: %d\n", ffa_args[TS_RPC_RETRIEVE_MEM_RPC_STATUS]); > + ffa_dev->ops->mem_ops->memory_reclaim(shm->sec_world_id, 0); > + return -EINVAL; > + } > + > + return 0; > +} > + > +int tstee_shm_unregister(struct tee_context *ctx, struct tee_shm *shm) > +{ > + struct tstee *tstee = tee_get_drvdata(ctx->teedev); > + struct ffa_device *ffa_dev = tstee->ffa_dev; > + struct ffa_send_direct_data ffa_data; > + u32 ffa_args[5] = {}; > + int rc; > + > + ffa_args[TS_RPC_CTRL_REG] = TS_RPC_CTRL_PACK_IFACE_OPCODE(TS_RPC_MGMT_IFACE_ID, > + TS_RPC_OP_RELINQ_MEM); > + ffa_args[TS_RPC_RELINQ_MEM_HANDLE_LSW] = lower_32_bits(shm->sec_world_id); > + ffa_args[TS_RPC_RELINQ_MEM_HANDLE_MSW] = upper_32_bits(shm->sec_world_id); > + > + arg_list_to_ffa_data(ffa_args, &ffa_data); > + rc = ffa_dev->ops->msg_ops->sync_send_receive(ffa_dev, &ffa_data); > + if (rc) > + return rc; > + arg_list_from_ffa_data(&ffa_data, ffa_args); > + > + if (ffa_args[TS_RPC_RELINQ_MEM_RPC_STATUS] != TS_RPC_OK) { > + pr_err("shm_unregister rpc status: %d\n", ffa_args[TS_RPC_RELINQ_MEM_RPC_STATUS]); > + return -EINVAL; > + } > + > + rc = ffa_dev->ops->mem_ops->memory_reclaim(shm->sec_world_id, 0); > + > + return rc; > +} > + > +static const struct tee_driver_ops tstee_ops = { > + .get_version = tstee_get_version, > + .open = tstee_open, > + .release = tstee_release, > + .open_session = tstee_open_session, > + .close_session = tstee_close_session, > + .invoke_func = tstee_invoke_func, > + .cancel_req = tstee_cancel_req, > + .shm_register = tstee_shm_register, > + .shm_unregister = tstee_shm_unregister, > +}; > + > +static const struct tee_desc tstee_desc = { > + .name = "tstee-clnt", > + .ops = &tstee_ops, > + .owner = THIS_MODULE, > +}; > + > +static bool tstee_check_rpc_compatible(struct ffa_device *ffa_dev) > +{ > + struct ffa_send_direct_data ffa_data; > + u32 ffa_args[5] = {}; > + > + ffa_args[TS_RPC_CTRL_REG] = TS_RPC_CTRL_PACK_IFACE_OPCODE(TS_RPC_MGMT_IFACE_ID, > + TS_RPC_OP_GET_VERSION); > + > + arg_list_to_ffa_data(ffa_args, &ffa_data); > + if (ffa_dev->ops->msg_ops->sync_send_receive(ffa_dev, &ffa_data)) > + return false; > + > + arg_list_from_ffa_data(&ffa_data, ffa_args); > + > + return ffa_args[TS_RPC_GET_VERSION_RESP] == TS_RPC_PROTOCOL_VERSION; > +} > + > +static void tstee_deinit_common(struct tstee *tstee) > +{ > + tee_device_unregister(tstee->teedev); > + if (tstee->pool) > + tee_shm_pool_free(tstee->pool); > + > + kfree(tstee); > +} > + > +static int tstee_probe(struct ffa_device *ffa_dev) > +{ > + struct tstee *tstee; > + int rc; > + > + ffa_dev->ops->msg_ops->mode_32bit_set(ffa_dev); > + > + if (!tstee_check_rpc_compatible(ffa_dev)) > + return -EINVAL; > + > + tstee = kzalloc(sizeof(*tstee), GFP_KERNEL); > + if (!tstee) > + return -ENOMEM; > + > + tstee->ffa_dev = ffa_dev; > + > + tstee->pool = tstee_create_shm_pool(); > + if (IS_ERR(tstee->pool)) { > + rc = PTR_ERR(tstee->pool); > + tstee->pool = NULL; > + goto err; > + } > + > + tstee->teedev = tee_device_alloc(&tstee_desc, NULL, tstee->pool, tstee); > + if (IS_ERR(tstee->teedev)) { > + rc = PTR_ERR(tstee->teedev); > + tstee->teedev = NULL; > + goto err; > + } > + > + rc = tee_device_register(tstee->teedev); > + if (rc) > + goto err; > + > + ffa_dev_set_drvdata(ffa_dev, tstee); > + > + pr_info("driver initialized for endpoint 0x%x\n", ffa_dev->vm_id); > + > + return 0; > + > +err: > + tstee_deinit_common(tstee); > + return rc; > +} > + > +static void tstee_remove(struct ffa_device *ffa_dev) > +{ > + tstee_deinit_common(ffa_dev->dev.driver_data); > +} > + > +static const struct ffa_device_id tstee_device_ids[] = { > + /* TS RPC protocol UUID: bdcd76d7-825e-4751-963b-86d4f84943ac */ > + { TS_RPC_UUID }, > + {} > +}; > + > +static struct ffa_driver tstee_driver = { > + .name = "arm_tstee", > + .probe = tstee_probe, > + .remove = tstee_remove, > + .id_table = tstee_device_ids, > +}; > + > +static int __init mod_init(void) > +{ > + return ffa_register(&tstee_driver); > +} > +module_init(mod_init) > + > +static void __exit mod_exit(void) > +{ > + ffa_unregister(&tstee_driver); > +} > +module_exit(mod_exit) > + > +MODULE_ALIAS("arm-tstee"); > +MODULE_AUTHOR("Balint Dobszay "); > +MODULE_DESCRIPTION("Arm Trusted Services TEE driver"); > +MODULE_LICENSE("GPL"); > diff --git a/drivers/tee/tstee/shm_pool.c b/drivers/tee/tstee/shm_pool.c > new file mode 100644 > index 000000000000..518c10dd0735 > --- /dev/null > +++ b/drivers/tee/tstee/shm_pool.c > @@ -0,0 +1,91 @@ > +// SPDX-License-Identifier: GPL-2.0-only > +/* > + * Copyright (c) 2023, Arm Limited > + */ > + > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include "tstee_private.h" > + > +static int pool_op_alloc(struct tee_shm_pool *pool __always_unused, struct tee_shm *shm, > + size_t size, size_t align __always_unused) > +{ > + unsigned int order, nr_pages, i; > + struct page *page, **pages; > + int rc; > + > + if (size == 0) > + return -EINVAL; > + > + order = get_order(size); > + nr_pages = 1 << order; > + > + page = alloc_pages(GFP_KERNEL | __GFP_ZERO, order); > + if (!page) > + return -ENOMEM; > + > + shm->kaddr = page_address(page); > + shm->paddr = page_to_phys(page); > + shm->size = PAGE_SIZE << order; > + > + pages = kcalloc(nr_pages, sizeof(*pages), GFP_KERNEL); > + if (!pages) { > + rc = -ENOMEM; > + goto err; > + } > + > + for (i = 0; i < nr_pages; i++) > + pages[i] = page + i; > + > + rc = tstee_shm_register(shm->ctx, shm, pages, nr_pages, (unsigned long)shm->kaddr); > + kfree(pages); > + if (rc) > + goto err; > + > + return 0; > + > +err: > + __free_pages(page, order); > + return rc; > +} > + > +static void pool_op_free(struct tee_shm_pool *pool __always_unused, struct tee_shm *shm) > +{ > + int rc; > + > + rc = tstee_shm_unregister(shm->ctx, shm); > + if (rc) > + pr_err("shm id 0x%llx unregister rc %d\n", shm->sec_world_id, rc); > + > + free_pages((unsigned long)shm->kaddr, get_order(shm->size)); > + shm->kaddr = NULL; > +} > + > +static void pool_op_destroy_pool(struct tee_shm_pool *pool) > +{ > + kfree(pool); > +} These pool_op functions look very much like the optee_pool_op functions. Compare this with how the pool_ffa_ops is implemented in the OP-TEE driver. We should consider factoring out the optee_pool_op functions into the TEE subsystem instead so we can avoid reimplementing the same thing. Cheers, Jens > + > +static const struct tee_shm_pool_ops pool_ops = { > + .alloc = pool_op_alloc, > + .free = pool_op_free, > + .destroy_pool = pool_op_destroy_pool, > +}; > + > +struct tee_shm_pool *tstee_create_shm_pool(void) > +{ > + struct tee_shm_pool *pool; > + > + pool = kzalloc(sizeof(*pool), GFP_KERNEL); > + if (!pool) > + return ERR_PTR(-ENOMEM); > + > + pool->ops = &pool_ops; > + > + return pool; > +} > diff --git a/drivers/tee/tstee/tstee_private.h b/drivers/tee/tstee/tstee_private.h > new file mode 100644 > index 000000000000..2ea266804ccf > --- /dev/null > +++ b/drivers/tee/tstee/tstee_private.h > @@ -0,0 +1,97 @@ > +/* SPDX-License-Identifier: GPL-2.0-only */ > +/* > + * Copyright (c) 2023, Arm Limited > + */ > + > +#ifndef TSTEE_PRIVATE_H > +#define TSTEE_PRIVATE_H > + > +#include > +#include > +#include > +#include > +#include > +#include > + > +/* UUID of this protocol */ > +#define TS_RPC_UUID UUID_INIT(0xbdcd76d7, 0x825e, 0x4751, \ > + 0x96, 0x3b, 0x86, 0xd4, 0xf8, 0x49, 0x43, 0xac) > + > +/* Protocol version*/ > +#define TS_RPC_PROTOCOL_VERSION (1) > + > +/* Status codes */ > +#define TS_RPC_OK (0) > + > +/* RPC control register */ > +#define TS_RPC_CTRL_REG (0) > +#define OPCODE_MASK GENMASK(15, 0) > +#define IFACE_ID_MASK GENMASK(23, 16) > +#define TS_RPC_CTRL_OPCODE(x) ((u16)(FIELD_GET(OPCODE_MASK, (x)))) > +#define TS_RPC_CTRL_IFACE_ID(x) ((u8)(FIELD_GET(IFACE_ID_MASK, (x)))) > +#define TS_RPC_CTRL_PACK_IFACE_OPCODE(i, o) \ > + (FIELD_PREP(IFACE_ID_MASK, (i)) | FIELD_PREP(OPCODE_MASK, (o))) > +#define TS_RPC_CTRL_SAP_RC BIT(30) > +#define TS_RPC_CTRL_SAP_ERR BIT(31) > + > +/* Interface ID for RPC management operations */ > +#define TS_RPC_MGMT_IFACE_ID (0xff) > + > +/* Management calls */ > +#define TS_RPC_OP_GET_VERSION (0x0000) > +#define TS_RPC_GET_VERSION_RESP (1) > + > +#define TS_RPC_OP_RETRIEVE_MEM (0x0001) > +#define TS_RPC_RETRIEVE_MEM_HANDLE_LSW (1) > +#define TS_RPC_RETRIEVE_MEM_HANDLE_MSW (2) > +#define TS_RPC_RETRIEVE_MEM_TAG_LSW (3) > +#define TS_RPC_RETRIEVE_MEM_TAG_MSW (4) > +#define TS_RPC_RETRIEVE_MEM_RPC_STATUS (1) > + > +#define TS_RPC_OP_RELINQ_MEM (0x0002) > +#define TS_RPC_RELINQ_MEM_HANDLE_LSW (1) > +#define TS_RPC_RELINQ_MEM_HANDLE_MSW (2) > +#define TS_RPC_RELINQ_MEM_RPC_STATUS (1) > + > +#define TS_RPC_OP_SERVICE_INFO (0x0003) > +#define TS_RPC_SERVICE_INFO_UUID0 (1) > +#define TS_RPC_SERVICE_INFO_UUID1 (2) > +#define TS_RPC_SERVICE_INFO_UUID2 (3) > +#define TS_RPC_SERVICE_INFO_UUID3 (4) > +#define TS_RPC_SERVICE_INFO_RPC_STATUS (1) > +#define TS_RPC_SERVICE_INFO_IFACE (2) > + > +/* Service call */ > +#define TS_RPC_SERVICE_MEM_HANDLE_LSW (1) > +#define TS_RPC_SERVICE_MEM_HANDLE_MSW (2) > +#define TS_RPC_SERVICE_REQ_LEN (3) > +#define TS_RPC_SERVICE_CLIENT_ID (4) > +#define TS_RPC_SERVICE_RPC_STATUS (1) > +#define TS_RPC_SERVICE_STATUS (2) > +#define TS_RPC_SERVICE_RESP_LEN (3) > + > +struct tstee { > + struct ffa_device *ffa_dev; > + struct tee_device *teedev; > + struct tee_shm_pool *pool; > +}; > + > +struct ts_session { > + struct list_head list_node; > + u32 session_id; > + u8 iface_id; > +}; > + > +struct ts_context_data { > + struct list_head sess_list; > + struct idr sess_ids; > + /* Serializes access to this struct */ > + struct mutex mutex; > +}; > + > +struct tee_shm_pool *tstee_create_shm_pool(void); > +int tstee_shm_register(struct tee_context *ctx, struct tee_shm *shm, struct page **pages, > + size_t num_pages, unsigned long start); > +int tstee_shm_unregister(struct tee_context *ctx, struct tee_shm *shm); > + > +#endif /* TSTEE_PRIVATE_H */ > diff --git a/include/uapi/linux/tee.h b/include/uapi/linux/tee.h > index 23e57164693c..d0430bee8292 100644 > --- a/include/uapi/linux/tee.h > +++ b/include/uapi/linux/tee.h > @@ -56,6 +56,7 @@ > */ > #define TEE_IMPL_ID_OPTEE 1 > #define TEE_IMPL_ID_AMDTEE 2 > +#define TEE_IMPL_ID_TSTEE 3 > > /* > * OP-TEE specific capabilities > -- > 2.34.1 _______________________________________________ linux-arm-kernel mailing list linux-arm-kernel@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-arm-kernel