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 X-Spam-Level: X-Spam-Status: No, score=-14.5 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER, INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 5982BC4338F for ; Wed, 25 Aug 2021 11:44:49 +0000 (UTC) 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 mail.kernel.org (Postfix) with ESMTPS id 0CB4A61176 for ; Wed, 25 Aug 2021 11:44:49 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.4.1 mail.kernel.org 0CB4A61176 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=linaro.org Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=lists.infradead.org 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:Cc:To:Subject:Message-ID:Date:From: In-Reply-To:References:MIME-Version:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=vhkGKyEdEfNapLS5qkJGNCTFakyMbWpnxZQ6YZjsnCI=; b=jmod/uG/s6ow33 j/ObJGLSTp0CTZuTpjj2HEGDq8xY84mdlSh2WGGaGFXkzvJom21W0ZEsUkDGWyPe1pSC4XaMQEmGi /aQiH7DQ13T+fgSeW7Tu1XPv7RWTvbjoWctBH2aRNylXLrj8Nu4PqphTgaoHaWFlxGybmadGgPTnZ xYJRSEXXsz48oln2hcDLtVppdQGdIn9pzGUzJDsrOtVlCsJBDl5uiRes71OHx06+cBWBXQyIEPzph vM0El4v3YdOXKwJKqJ+d/4AjPoK4WoBMRJ+xsgveCem8OEP99u7yzPwS+yhkHvvF9/nfRH4diCCd4 T17fTubxUonanA8Bxj9Q==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1mIrJB-006rdZ-W5; Wed, 25 Aug 2021 11:43:06 +0000 Received: from mail-lj1-x22f.google.com ([2a00:1450:4864:20::22f]) by bombadil.infradead.org with esmtps (Exim 4.94.2 #2 (Red Hat Linux)) id 1mIrJ4-006rc7-KB for linux-arm-kernel@lists.infradead.org; Wed, 25 Aug 2021 11:43:03 +0000 Received: by mail-lj1-x22f.google.com with SMTP id f2so43135315ljn.1 for ; Wed, 25 Aug 2021 04:42:58 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=mime-version:references:in-reply-to:from:date:message-id:subject:to :cc; bh=3kTC0YbpltlYVu44kCbHAD0qvrDWo+lveWesaqq9p18=; b=VJ9K4nDwquVAfzMgLrPBvIbtdeVCQbPhWqQaZX2u7bt6Eodb6MEL5Ej7Wr32lp2FUF tKQHP07COnrO4iS4OBBLOxjhSIg+0eH+geYDbzW1weaeN82RN0u/fcLKKpR8fHjOwCg6 kyUWippfDVjOh+6ZZf9cHQOIdu3n9VogwpAegHjFA4E0FZFtaST9fXSP+8Mx6TLKhUm9 WrRffESPt5ihLg+ffkhnvOH2KGOtcS9IeWif8tkvbwzTqN8V3OMUZasYYIsPUFVg/LUT uc6UkFDYnOOxUacLv28A2kJoo3zpS+J8xLm+D7jcIcBdZ8li8SuuYhGl25Mzi+bRuLJ1 hg5g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:references:in-reply-to:from:date :message-id:subject:to:cc; bh=3kTC0YbpltlYVu44kCbHAD0qvrDWo+lveWesaqq9p18=; b=rG7hXOIbBVhxVghzps209FQqQOF0Ud3jIfpLyLq6jen3co/kPLZaeITyMog7sDhfWR 3HryyUTOraxC2QWcu9AcQYY6t+m2RZVQdfNFg9KtKUb7hHi3WEa6IPrv6CxgnHEVdarK L+YmDhHhr0+WBz6H1bSeNpaKIBGp7YXU5mueDHWsbne6osx8s+C7uEClB+V2kyPHRNhh 1Thk8HehBSXh3tUraEkm5mivKP7zoIWvf58BRpC9bbSN9UZhU/5IUuhLUmyZ6RnOQMfQ gROReheK6vL7jk3twjDegYBSdagNTk1hjy5fBUGXLojUEnJ4AxlKQHRGA/mbC6vFjqZt XkZQ== X-Gm-Message-State: AOAM532ivVQ5cZQnyEddwoyeDaDs9OnN56Jbz2ue0RF4/I+EVewz1qsU 0Ip4NMNhWVMJlSwLeFXyuPloWL+Xl3mvFp+9erlzag== X-Google-Smtp-Source: ABdhPJwPDkDAGqRbbea5e1tkFJk/pCTc+r9vtZeEq4pcFmfI6X/9ag1TSC7adXKpQUeFxd3CO0UrDVbvzuDLp6sWogY= X-Received: by 2002:a2e:a794:: with SMTP id c20mr21485854ljf.442.1629891776962; Wed, 25 Aug 2021 04:42:56 -0700 (PDT) MIME-Version: 1.0 References: <20210819110655.739318-1-jens.wiklander@linaro.org> <20210819110655.739318-6-jens.wiklander@linaro.org> In-Reply-To: <20210819110655.739318-6-jens.wiklander@linaro.org> From: Sumit Garg Date: Wed, 25 Aug 2021 17:12:45 +0530 Message-ID: Subject: Re: [PATCH v4 5/5] optee: add FF-A support To: Jens Wiklander Cc: Linux Kernel Mailing List , linux-arm-kernel , OP-TEE TrustedFirmware , Sudeep Holla , Marc Bonnici , Jerome Forissier , Sughosh Ganu X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20210825_044259_056053_112E5467 X-CRM114-Status: GOOD ( 39.42 ) 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 On Thu, 19 Aug 2021 at 16:37, Jens Wiklander wrote: > > Adds support for using FF-A [1] as transport to the OP-TEE driver. > > Introduces struct optee_msg_param_fmem which carries all information > needed when OP-TEE is calling FFA_MEM_RETRIEVE_REQ to get the shared > memory reference mapped by the hypervisor in S-EL2. Register usage is > also updated to include the information needed. > > The FF-A part of this driver is enabled if CONFIG_ARM_FFA_TRANSPORT is > enabled. > > [1] https://developer.arm.com/documentation/den0077/latest > Signed-off-by: Jens Wiklander > --- > drivers/tee/optee/Makefile | 3 +- > drivers/tee/optee/call.c | 13 +- > drivers/tee/optee/core.c | 16 +- > drivers/tee/optee/ffa_abi.c | 907 ++++++++++++++++++++++++++++++ > drivers/tee/optee/optee_ffa.h | 153 +++++ > drivers/tee/optee/optee_msg.h | 27 +- > drivers/tee/optee/optee_private.h | 43 +- > 7 files changed, 1148 insertions(+), 14 deletions(-) > create mode 100644 drivers/tee/optee/ffa_abi.c > create mode 100644 drivers/tee/optee/optee_ffa.h > > diff --git a/drivers/tee/optee/Makefile b/drivers/tee/optee/Makefile > index e92f77462f40..dbfd83d3c4ae 100644 > --- a/drivers/tee/optee/Makefile > +++ b/drivers/tee/optee/Makefile > @@ -7,7 +7,8 @@ optee-objs += supp.o > optee-objs += device.o > > optee-smc-abi-y = smc_abi.o > -optee-objs += $(optee-ffa-abi-y) > +optee-ffa-abi-$(CONFIG_ARM_FFA_TRANSPORT) = ffa_abi.o > +optee-objs += $(optee-smc-abi-y) $(optee-ffa-abi-y) > > # for tracing framework to find optee_trace.h > CFLAGS_smc_abi.o := -I$(src) > diff --git a/drivers/tee/optee/call.c b/drivers/tee/optee/call.c > index 3f81c168ed3f..87d739091055 100644 > --- a/drivers/tee/optee/call.c > +++ b/drivers/tee/optee/call.c > @@ -107,11 +107,20 @@ static struct optee_session *find_session(struct optee_context_data *ctxdata, > struct tee_shm *optee_get_msg_arg(struct tee_context *ctx, size_t num_params, > struct optee_msg_arg **msg_arg) > { > + struct optee *optee = tee_get_drvdata(ctx->teedev); > + size_t sz = OPTEE_MSG_GET_ARG_SIZE(num_params); > struct tee_shm *shm; > struct optee_msg_arg *ma; > > - shm = tee_shm_alloc(ctx, OPTEE_MSG_GET_ARG_SIZE(num_params), > - TEE_SHM_MAPPED); > + /* > + * rpc_arg_count is set to the number of allocated parameters in > + * the RPC argument struct if a second MSG arg struct is expected. > + * The second arg struct will then be used for RPC. > + */ > + if (optee->rpc_arg_count) > + sz += OPTEE_MSG_GET_ARG_SIZE(optee->rpc_arg_count); > + > + shm = tee_shm_alloc(ctx, sz, TEE_SHM_MAPPED); > if (IS_ERR(shm)) > return shm; > > diff --git a/drivers/tee/optee/core.c b/drivers/tee/optee/core.c > index e372ebaff5d6..c22cdf65451b 100644 > --- a/drivers/tee/optee/core.c > +++ b/drivers/tee/optee/core.c > @@ -160,15 +160,27 @@ void optee_remove_common(struct optee *optee) > mutex_destroy(&optee->call_queue.mutex); > } > > +static int smc_abi_rc; > +static int ffa_abi_rc; > + > static int optee_core_init(void) > { > - return optee_smc_abi_register(); > + smc_abi_rc = optee_smc_abi_register(); > + ffa_abi_rc = optee_ffa_abi_register(); > + > + /* If both failed there's no point with this module */ > + if (smc_abi_rc && ffa_abi_rc) > + return smc_abi_rc; > + return 0; > } > module_init(optee_core_init); > > static void optee_core_exit(void) > { > - optee_smc_abi_unregister(); > + if (!smc_abi_rc) > + optee_smc_abi_unregister(); > + if (!ffa_abi_rc) > + optee_ffa_abi_unregister(); > } > module_exit(optee_core_exit); > > diff --git a/drivers/tee/optee/ffa_abi.c b/drivers/tee/optee/ffa_abi.c > new file mode 100644 > index 000000000000..85dca49ac2ce > --- /dev/null > +++ b/drivers/tee/optee/ffa_abi.c > @@ -0,0 +1,907 @@ > +// SPDX-License-Identifier: GPL-2.0-only > +/* > + * Copyright (c) 2021, Linaro Limited > + */ > + > +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include "optee_private.h" > +#include "optee_ffa.h" > +#include "optee_rpc_cmd.h" > + > +/* > + * This file implement the FF-A ABI used when communicating with secure world > + * OP-TEE OS via FF-A. > + * This file is divided into the follow sections: s/follow/following/ > + * 1. Maintain a hash table for lookup of a global FF-A memory handle > + * 2. Convert between struct tee_param and struct optee_msg_param > + * 3. Low level support functions to register shared memory in secure world > + * 4. Dynamic shared memory pool based on alloc_pages() > + * 5. Do a normal scheduled call into secure world > + * 6. Driver initialization. > + */ > + > +/* > + * 1. Maintain a hash table for lookup of a global FF-A memory handle > + * > + * FF-A assigns a global memory handle for each piece shared memory. > + * This handle is then used when communicating with secure world. > + * > + * Main functions are optee_shm_add_ffa_handle() and optee_shm_rem_ffa_handle() > + */ > +struct shm_rhash { > + struct tee_shm *shm; > + u64 global_id; > + struct rhash_head linkage; > +}; > + > +static void rh_free_fn(void *ptr, void *arg) > +{ > + kfree(ptr); > +} > + > +static const struct rhashtable_params shm_rhash_params = { > + .head_offset = offsetof(struct shm_rhash, linkage), > + .key_len = sizeof(u64), > + .key_offset = offsetof(struct shm_rhash, global_id), > + .automatic_shrinking = true, > +}; > + > +static struct tee_shm *optee_shm_from_ffa_handle(struct optee *optee, > + u64 global_id) > +{ > + struct tee_shm *shm = NULL; > + struct shm_rhash *r; > + > + mutex_lock(&optee->ffa.mutex); > + r = rhashtable_lookup_fast(&optee->ffa.global_ids, &global_id, > + shm_rhash_params); > + if (r) > + shm = r->shm; > + mutex_unlock(&optee->ffa.mutex); > + > + return shm; > +} > + > +static int optee_shm_add_ffa_handle(struct optee *optee, struct tee_shm *shm, > + u64 global_id) > +{ > + struct shm_rhash *r; > + int rc; > + > + r = kmalloc(sizeof(*r), GFP_KERNEL); > + if (!r) > + return -ENOMEM; > + r->shm = shm; > + r->global_id = global_id; > + > + mutex_lock(&optee->ffa.mutex); > + rc = rhashtable_lookup_insert_fast(&optee->ffa.global_ids, &r->linkage, > + shm_rhash_params); > + mutex_unlock(&optee->ffa.mutex); > + > + if (rc) > + kfree(r); > + > + return rc; > +} > + > +static int optee_shm_rem_ffa_handle(struct optee *optee, u64 global_id) > +{ > + struct shm_rhash *r; > + int rc = -ENOENT; > + > + mutex_lock(&optee->ffa.mutex); > + r = rhashtable_lookup_fast(&optee->ffa.global_ids, &global_id, > + shm_rhash_params); > + if (r) > + rc = rhashtable_remove_fast(&optee->ffa.global_ids, > + &r->linkage, shm_rhash_params); > + mutex_unlock(&optee->ffa.mutex); > + > + if (!rc) > + kfree(r); > + > + return rc; > +} > + > +/* > + * 2. Convert between struct tee_param and struct optee_msg_param > + * > + * optee_ffa_from_msg_param() and optee_ffa_to_msg_param() are the main > + * functions. > + */ > + > +static void from_msg_param_ffa_mem(struct optee *optee, struct tee_param *p, > + u32 attr, const struct optee_msg_param *mp) > +{ > + struct tee_shm *shm = NULL; > + u64 offs_high = 0; > + u64 offs_low = 0; > + > + p->attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT + > + attr - OPTEE_MSG_ATTR_TYPE_FMEM_INPUT; > + p->u.memref.size = mp->u.fmem.size; > + > + if (mp->u.fmem.global_id != OPTEE_MSG_FMEM_INVALID_GLOBAL_ID) > + shm = optee_shm_from_ffa_handle(optee, mp->u.fmem.global_id); > + p->u.memref.shm = shm; > + > + if (shm) { > + offs_low = mp->u.fmem.offs_low; > + offs_high = mp->u.fmem.offs_high; > + } > + p->u.memref.shm_offs = offs_low | offs_high << 32; > +} > + > +/** > + * optee_ffa_from_msg_param() - convert from OPTEE_MSG parameters to > + * struct tee_param > + * @optee: main service struct > + * @params: subsystem internal parameter representation > + * @num_params: number of elements in the parameter arrays > + * @msg_params: OPTEE_MSG parameters > + * > + * Returns 0 on success or <0 on failure > + */ > +static int optee_ffa_from_msg_param(struct optee *optee, > + struct tee_param *params, size_t num_params, > + const struct optee_msg_param *msg_params) > +{ > + size_t n; > + > + for (n = 0; n < num_params; n++) { > + struct tee_param *p = params + n; > + const struct optee_msg_param *mp = msg_params + n; > + u32 attr = mp->attr & OPTEE_MSG_ATTR_TYPE_MASK; > + > + switch (attr) { > + case OPTEE_MSG_ATTR_TYPE_NONE: > + p->attr = TEE_IOCTL_PARAM_ATTR_TYPE_NONE; > + memset(&p->u, 0, sizeof(p->u)); > + break; > + case OPTEE_MSG_ATTR_TYPE_VALUE_INPUT: > + case OPTEE_MSG_ATTR_TYPE_VALUE_OUTPUT: > + case OPTEE_MSG_ATTR_TYPE_VALUE_INOUT: > + optee_from_msg_param_value(p, attr, mp); > + break; > + case OPTEE_MSG_ATTR_TYPE_FMEM_INPUT: > + case OPTEE_MSG_ATTR_TYPE_FMEM_OUTPUT: > + case OPTEE_MSG_ATTR_TYPE_FMEM_INOUT: > + from_msg_param_ffa_mem(optee, p, attr, mp); > + break; > + default: > + return -EINVAL; > + } > + } > + > + return 0; > +} > + > +static int to_msg_param_ffa_mem(struct optee_msg_param *mp, > + const struct tee_param *p) > +{ > + struct tee_shm *shm = p->u.memref.shm; > + > + mp->attr = OPTEE_MSG_ATTR_TYPE_FMEM_INPUT + p->attr - > + TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT; > + > + if (shm) { > + u64 shm_offs = p->u.memref.shm_offs; > + > + mp->u.fmem.internal_offs = shm->offset; > + > + mp->u.fmem.offs_low = shm_offs; > + mp->u.fmem.offs_high = shm_offs >> 32; > + /* Check that the entire offset could be stored. */ > + if (mp->u.fmem.offs_high != shm_offs >> 32) > + return -EINVAL; > + > + mp->u.fmem.global_id = shm->sec_world_id; > + } else { > + memset(&mp->u, 0, sizeof(mp->u)); > + mp->u.fmem.global_id = OPTEE_MSG_FMEM_INVALID_GLOBAL_ID; > + } > + mp->u.fmem.size = p->u.memref.size; > + > + return 0; > +} > + > +/** > + * optee_ffa_to_msg_param() - convert from struct tee_params to OPTEE_MSG > + * parameters > + * @optee: main service struct > + * @msg_params: OPTEE_MSG parameters > + * @num_params: number of elements in the parameter arrays > + * @params: subsystem itnernal parameter representation > + * Returns 0 on success or <0 on failure > + */ > +static int optee_ffa_to_msg_param(struct optee *optee, > + struct optee_msg_param *msg_params, > + size_t num_params, > + const struct tee_param *params) > +{ > + size_t n; > + > + for (n = 0; n < num_params; n++) { > + const struct tee_param *p = params + n; > + struct optee_msg_param *mp = msg_params + n; > + > + switch (p->attr) { > + case TEE_IOCTL_PARAM_ATTR_TYPE_NONE: > + mp->attr = TEE_IOCTL_PARAM_ATTR_TYPE_NONE; > + memset(&mp->u, 0, sizeof(mp->u)); > + break; > + case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT: > + case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT: > + case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT: > + optee_to_msg_param_value(mp, p); > + 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: > + if (to_msg_param_ffa_mem(mp, p)) > + return -EINVAL; > + break; > + default: > + return -EINVAL; > + } > + } > + > + return 0; > +} > + > +/* > + * 3. Low level support functions to register shared memory in secure world > + * > + * Functions to register and unregister shared memory both for normal > + * clients and for tee-supplicant. > + */ > + > +static int optee_ffa_shm_register(struct tee_context *ctx, struct tee_shm *shm, > + struct page **pages, size_t num_pages, > + unsigned long start) > +{ > + struct optee *optee = tee_get_drvdata(ctx->teedev); > + const struct ffa_dev_ops *ffa_ops = optee->ffa.ffa_ops; > + struct ffa_device *ffa_dev = optee->ffa.ffa_dev; > + struct ffa_mem_region_attributes mem_attr = { > + .receiver = ffa_dev->vm_id, > + .attrs = FFA_MEM_RW, > + }; > + struct ffa_mem_ops_args args = { > + .use_txbuf = true, > + .attrs = &mem_attr, > + .nattrs = 1, > + }; > + struct sg_table sgt; > + int rc; > + > + rc = optee_check_mem_type(start, num_pages); > + if (rc) > + return rc; > + > + rc = sg_alloc_table_from_pages(&sgt, pages, num_pages, 0, > + num_pages * PAGE_SIZE, GFP_KERNEL); > + if (rc) > + return rc; > + args.sg = sgt.sgl; > + rc = ffa_ops->memory_share(ffa_dev, &args); > + sg_free_table(&sgt); > + if (rc) > + return rc; > + > + rc = optee_shm_add_ffa_handle(optee, shm, args.g_handle); > + if (rc) { > + ffa_ops->memory_reclaim(args.g_handle, 0); > + return rc; > + } > + > + shm->sec_world_id = args.g_handle; > + > + return 0; > +} > + > +static int optee_ffa_shm_unregister(struct tee_context *ctx, > + struct tee_shm *shm) > +{ > + struct optee *optee = tee_get_drvdata(ctx->teedev); > + const struct ffa_dev_ops *ffa_ops = optee->ffa.ffa_ops; > + struct ffa_device *ffa_dev = optee->ffa.ffa_dev; > + u64 global_handle = shm->sec_world_id; > + struct ffa_send_direct_data data = { > + .data0 = OPTEE_FFA_UNREGISTER_SHM, > + .data1 = (u32)global_handle, > + .data2 = (u32)(global_handle >> 32) > + }; > + int rc; > + > + optee_shm_rem_ffa_handle(optee, global_handle); > + shm->sec_world_id = 0; > + > + rc = ffa_ops->sync_send_receive(ffa_dev, &data); > + if (rc) > + pr_err("Unregister SHM id 0x%llx rc %d\n", global_handle, rc); > + > + rc = ffa_ops->memory_reclaim(global_handle, 0); > + if (rc) > + pr_err("mem_reclain: 0x%llx %d", global_handle, rc); > + > + return rc; > +} > + > +static int optee_ffa_shm_unregister_supp(struct tee_context *ctx, > + struct tee_shm *shm) > +{ > + struct optee *optee = tee_get_drvdata(ctx->teedev); > + const struct ffa_dev_ops *ffa_ops = optee->ffa.ffa_ops; > + u64 global_handle = shm->sec_world_id; > + int rc; > + > + /* > + * We're skipping the OPTEE_FFA_YIELDING_CALL_UNREGISTER_SHM call > + * since this is OP-TEE freeing via RPC so it has already retired > + * this ID. > + */ > + > + optee_shm_rem_ffa_handle(optee, global_handle); > + rc = ffa_ops->memory_reclaim(global_handle, 0); > + if (rc) > + pr_err("mem_reclain: 0x%llx %d", global_handle, rc); > + > + shm->sec_world_id = 0; > + > + return rc; > +} > + > +/* > + * 4. Dynamic shared memory pool based on alloc_pages() > + * > + * Implements an OP-TEE specific shared memory pool. > + * The main function is optee_ffa_shm_pool_alloc_pages(). > + */ > + > +static int pool_ffa_op_alloc(struct tee_shm_pool_mgr *poolm, > + struct tee_shm *shm, size_t size) > +{ > + return optee_pool_op_alloc_helper(poolm, shm, size, > + optee_ffa_shm_register); > +} > + > +static void pool_ffa_op_free(struct tee_shm_pool_mgr *poolm, > + struct tee_shm *shm) > +{ > + optee_ffa_shm_unregister(shm->ctx, shm); > + free_pages((unsigned long)shm->kaddr, get_order(shm->size)); > + shm->kaddr = NULL; > +} > + > +static void pool_ffa_op_destroy_poolmgr(struct tee_shm_pool_mgr *poolm) > +{ > + kfree(poolm); > +} > + > +static const struct tee_shm_pool_mgr_ops pool_ffa_ops = { > + .alloc = pool_ffa_op_alloc, > + .free = pool_ffa_op_free, > + .destroy_poolmgr = pool_ffa_op_destroy_poolmgr, > +}; > + > +/** > + * optee_ffa_shm_pool_alloc_pages() - create page-based allocator pool > + * > + * This pool is used with OP-TEE over FF-A. In this case command buffers > + * and such are allocated from kernel's own memory. > + */ > +static struct tee_shm_pool_mgr *optee_ffa_shm_pool_alloc_pages(void) > +{ > + struct tee_shm_pool_mgr *mgr = kzalloc(sizeof(*mgr), GFP_KERNEL); > + > + if (!mgr) > + return ERR_PTR(-ENOMEM); > + > + mgr->ops = &pool_ffa_ops; > + > + return mgr; > +} > + > +/* > + * 5. Do a normal scheduled call into secure world > + * > + * The function optee_ffa_do_call_with_arg() performs a normal scheduled > + * call into secure world. During this call may normal world request help > + * from normal world using RPCs, Remote Procedure Calls. This includes > + * delivery of non-secure interrupts to for instance allow rescheduling of > + * the current task. > + */ > + > +static void handle_ffa_rpc_func_cmd_shm_alloc(struct tee_context *ctx, > + struct optee_msg_arg *arg) > +{ > + struct tee_shm *shm; > + > + if (arg->num_params != 1 || > + arg->params[0].attr != OPTEE_MSG_ATTR_TYPE_VALUE_INPUT) { > + arg->ret = TEEC_ERROR_BAD_PARAMETERS; > + return; > + } > + > + switch (arg->params[0].u.value.a) { > + case OPTEE_RPC_SHM_TYPE_APPL: > + shm = optee_rpc_cmd_alloc_suppl(ctx, arg->params[0].u.value.b); > + break; > + case OPTEE_RPC_SHM_TYPE_KERNEL: > + shm = tee_shm_alloc(ctx, arg->params[0].u.value.b, > + TEE_SHM_MAPPED); > + break; > + default: > + arg->ret = TEEC_ERROR_BAD_PARAMETERS; > + return; > + } > + > + if (IS_ERR(shm)) { > + arg->ret = TEEC_ERROR_OUT_OF_MEMORY; > + return; > + } > + > + arg->params[0] = (struct optee_msg_param){ > + .attr = OPTEE_MSG_ATTR_TYPE_FMEM_OUTPUT, > + .u.fmem.size = tee_shm_get_size(shm), > + .u.fmem.global_id = shm->sec_world_id, > + .u.fmem.internal_offs = shm->offset, > + }; > + > + arg->ret = TEEC_SUCCESS; > +} > + > +static void handle_ffa_rpc_func_cmd_shm_free(struct tee_context *ctx, > + struct optee *optee, > + struct optee_msg_arg *arg) > +{ > + struct tee_shm *shm; > + > + if (arg->num_params != 1 || > + arg->params[0].attr != OPTEE_MSG_ATTR_TYPE_VALUE_INPUT) > + goto err_bad_param; > + > + shm = optee_shm_from_ffa_handle(optee, arg->params[0].u.value.b); > + if (!shm) > + goto err_bad_param; > + switch (arg->params[0].u.value.a) { > + case OPTEE_RPC_SHM_TYPE_APPL: > + optee_rpc_cmd_free_suppl(ctx, shm); > + break; > + case OPTEE_RPC_SHM_TYPE_KERNEL: > + tee_shm_free(shm); > + break; > + default: > + goto err_bad_param; > + } > + arg->ret = TEEC_SUCCESS; > + return; > + > +err_bad_param: > + arg->ret = TEEC_ERROR_BAD_PARAMETERS; > +} > + > +static void handle_ffa_rpc_func_cmd(struct tee_context *ctx, > + struct optee_msg_arg *arg) > +{ > + struct optee *optee = tee_get_drvdata(ctx->teedev); > + > + arg->ret_origin = TEEC_ORIGIN_COMMS; > + switch (arg->cmd) { > + case OPTEE_RPC_CMD_SHM_ALLOC: > + handle_ffa_rpc_func_cmd_shm_alloc(ctx, arg); > + break; > + case OPTEE_RPC_CMD_SHM_FREE: > + handle_ffa_rpc_func_cmd_shm_free(ctx, optee, arg); > + break; > + default: > + optee_rpc_cmd(ctx, optee, arg); > + } > +} > + > +static void optee_handle_ffa_rpc(struct tee_context *ctx, u32 cmd, > + struct optee_msg_arg *arg) > +{ > + switch (cmd) { > + case OPTEE_FFA_YIELDING_CALL_RETURN_RPC_CMD: > + handle_ffa_rpc_func_cmd(ctx, arg); > + break; > + case OPTEE_FFA_YIELDING_CALL_RETURN_INTERRUPT: > + /* Interrupt delivered by now */ > + break; > + default: > + pr_warn("Unknown RPC func 0x%x\n", cmd); > + break; > + } > +} > + > +static int optee_ffa_yielding_call(struct tee_context *ctx, > + struct ffa_send_direct_data *data, > + struct optee_msg_arg *rpc_arg) > +{ > + struct optee *optee = tee_get_drvdata(ctx->teedev); > + const struct ffa_dev_ops *ffa_ops = optee->ffa.ffa_ops; > + struct ffa_device *ffa_dev = optee->ffa.ffa_dev; > + struct optee_call_waiter w; > + u32 cmd = data->data0; > + u32 w4 = data->data1; > + u32 w5 = data->data2; > + u32 w6 = data->data3; > + int rc; > + > + /* Initialize waiter */ > + optee_cq_wait_init(&optee->call_queue, &w); > + while (true) { > + rc = ffa_ops->sync_send_receive(ffa_dev, data); > + if (rc) > + goto done; > + > + switch ((int)data->data0) { > + case TEEC_SUCCESS: > + break; > + case TEEC_ERROR_BUSY: > + if (cmd == OPTEE_FFA_YIELDING_CALL_RESUME) { > + rc = -EIO; > + goto done; > + } > + > + /* > + * Out of threads in secure world, wait for a thread > + * become available. > + */ > + optee_cq_wait_for_completion(&optee->call_queue, &w); > + data->data0 = cmd; > + data->data1 = w4; > + data->data2 = w5; > + data->data3 = w6; > + continue; > + default: > + rc = -EIO; > + goto done; > + } > + > + if (data->data1 == OPTEE_FFA_YIELDING_CALL_RETURN_DONE) > + goto done; > + > + /* > + * OP-TEE has returned with a RPC request. > + * > + * Note that data->data4 (passed in register w7) is already > + * filled in by ffa_ops->sync_send_receive() returning > + * above. > + */ > + cond_resched(); > + optee_handle_ffa_rpc(ctx, data->data1, rpc_arg); > + cmd = OPTEE_FFA_YIELDING_CALL_RESUME; > + data->data0 = cmd; > + data->data1 = 0; > + data->data2 = 0; > + data->data3 = 0; > + } > +done: > + /* > + * We're done with our thread in secure world, if there's any > + * thread waiters wake up one. > + */ > + optee_cq_wait_final(&optee->call_queue, &w); > + > + return rc; > +} > + > +/** > + * optee_ffa_do_call_with_arg() - Do a FF-A call to enter OP-TEE in secure world > + * @ctx: calling context > + * @shm: shared memory holding the message to pass to secure world > + * > + * Does a FF-A call to OP-TEE in secure world and handles eventual resulting > + * Remote Procedure Calls (RPC) from OP-TEE. > + * > + * Returns return code from FF-A, 0 is OK > + */ > + > +static int optee_ffa_do_call_with_arg(struct tee_context *ctx, > + struct tee_shm *shm) > +{ > + struct ffa_send_direct_data data = { > + .data0 = OPTEE_FFA_YIELDING_CALL_WITH_ARG, > + .data1 = (u32)shm->sec_world_id, > + .data2 = (u32)(shm->sec_world_id >> 32), > + .data3 = shm->offset, > + }; > + struct optee_msg_arg *arg = tee_shm_get_va(shm, 0); > + unsigned int rpc_arg_offs = OPTEE_MSG_GET_ARG_SIZE(arg->num_params); > + struct optee_msg_arg *rpc_arg = tee_shm_get_va(shm, rpc_arg_offs); > + > + return optee_ffa_yielding_call(ctx, &data, rpc_arg); > +} > + > +/* > + * 6. Driver initialization > + * > + * During driver inititialization is the OP-TEE Secure Partition is probed > + * to find out which features it supports so the driver can be initialized > + * with a matching configuration. > + */ > + > +static bool optee_ffa_api_is_compatbile(struct ffa_device *ffa_dev, > + const struct ffa_dev_ops *ops) > +{ > + struct ffa_send_direct_data data = { OPTEE_FFA_GET_API_VERSION }; > + int rc; > + > + ops->mode_32bit_set(ffa_dev); > + > + rc = ops->sync_send_receive(ffa_dev, &data); > + if (rc) { > + pr_err("Unexpected error %d\n", rc); > + return false; > + } > + if (data.data0 != OPTEE_FFA_VERSION_MAJOR || > + data.data1 < OPTEE_FFA_VERSION_MINOR) { > + pr_err("Incompatible OP-TEE API version %lu.%lu", > + data.data0, data.data1); > + return false; > + } > + > + data = (struct ffa_send_direct_data){ OPTEE_FFA_GET_OS_VERSION }; > + rc = ops->sync_send_receive(ffa_dev, &data); > + if (rc) { > + pr_err("Unexpected error %d\n", rc); > + return false; > + } > + if (data.data2) > + pr_info("revision %lu.%lu (%08lx)", > + data.data0, data.data1, data.data2); > + else > + pr_info("revision %lu.%lu", data.data0, data.data1); > + > + return true; > +} > + > +static bool optee_ffa_exchange_caps(struct ffa_device *ffa_dev, > + const struct ffa_dev_ops *ops, > + unsigned int *rpc_arg_count) > +{ > + struct ffa_send_direct_data data = { OPTEE_FFA_EXCHANGE_CAPABILITIES }; > + int rc; > + > + rc = ops->sync_send_receive(ffa_dev, &data); > + if (rc) { > + pr_err("Unexpected error %d", rc); > + return false; > + } > + if (data.data0) { > + pr_err("Unexpected exchange error %lu", data.data0); > + return false; > + } > + > + *rpc_arg_count = (u8)data.data1; Why is this special capability required in case of FF-A? Is it true that RPC arguments count will be fixed for all RPC commands? > + > + return true; > +} > + > +static struct tee_shm_pool *optee_ffa_config_dyn_shm(void) > +{ > + struct tee_shm_pool_mgr *priv_mgr; > + struct tee_shm_pool_mgr *dmabuf_mgr; > + void *rc; > + > + rc = optee_ffa_shm_pool_alloc_pages(); > + if (IS_ERR(rc)) > + return rc; > + priv_mgr = rc; > + > + rc = optee_ffa_shm_pool_alloc_pages(); > + if (IS_ERR(rc)) { > + tee_shm_pool_mgr_destroy(priv_mgr); > + return rc; > + } > + dmabuf_mgr = rc; > + > + rc = tee_shm_pool_alloc(priv_mgr, dmabuf_mgr); > + if (IS_ERR(rc)) { > + tee_shm_pool_mgr_destroy(priv_mgr); > + tee_shm_pool_mgr_destroy(dmabuf_mgr); > + } > + > + return rc; > +} > + > +static void optee_ffa_get_version(struct tee_device *teedev, > + struct tee_ioctl_version_data *vers) > +{ > + struct tee_ioctl_version_data v = { > + .impl_id = TEE_IMPL_ID_OPTEE, > + .impl_caps = TEE_OPTEE_CAP_TZ, > + .gen_caps = TEE_GEN_CAP_GP | TEE_GEN_CAP_REG_MEM | > + TEE_GEN_CAP_MEMREF_NULL, > + }; > + > + *vers = v; > +} > + > +static int optee_ffa_open(struct tee_context *ctx) > +{ > + return optee_open(ctx, true); > +} > + > +static const struct tee_driver_ops optee_ffa_clnt_ops = { > + .get_version = optee_ffa_get_version, > + .open = optee_ffa_open, > + .release = optee_release, > + .open_session = optee_open_session, > + .close_session = optee_close_session, > + .invoke_func = optee_invoke_func, > + .cancel_req = optee_cancel_req, > + .shm_register = optee_ffa_shm_register, > + .shm_unregister = optee_ffa_shm_unregister, > +}; > + > +static const struct tee_desc optee_ffa_clnt_desc = { > + .name = DRIVER_NAME "-ffa-clnt", > + .ops = &optee_ffa_clnt_ops, > + .owner = THIS_MODULE, > +}; > + > +static const struct tee_driver_ops optee_ffa_supp_ops = { > + .get_version = optee_ffa_get_version, > + .open = optee_ffa_open, > + .release = optee_release_supp, > + .supp_recv = optee_supp_recv, > + .supp_send = optee_supp_send, > + .shm_register = optee_ffa_shm_register, /* same as for clnt ops */ > + .shm_unregister = optee_ffa_shm_unregister_supp, > +}; > + > +static const struct tee_desc optee_ffa_supp_desc = { > + .name = DRIVER_NAME "-ffa-supp", > + .ops = &optee_ffa_supp_ops, > + .owner = THIS_MODULE, > + .flags = TEE_DESC_PRIVILEGED, > +}; > + > +static const struct optee_ops optee_ffa_ops = { > + .do_call_with_arg = optee_ffa_do_call_with_arg, > + .to_msg_param = optee_ffa_to_msg_param, > + .from_msg_param = optee_ffa_from_msg_param, > +}; > + > +static void optee_ffa_remove(struct ffa_device *ffa_dev) > +{ > + struct optee *optee = ffa_dev->dev.driver_data; > + > + optee_remove_common(optee); > + > + mutex_destroy(&optee->ffa.mutex); > + rhashtable_free_and_destroy(&optee->ffa.global_ids, rh_free_fn, NULL); > + > + kfree(optee); > +} > + > +static int optee_ffa_probe(struct ffa_device *ffa_dev) > +{ > + const struct ffa_dev_ops *ffa_ops; > + unsigned int rpc_arg_count; > + struct tee_device *teedev; > + struct optee *optee; > + int rc; > + > + ffa_ops = ffa_dev_ops_get(ffa_dev); > + if (!ffa_ops) { > + pr_warn("failed \"method\" init: ffa\n"); > + return -ENOENT; > + } > + > + if (!optee_ffa_api_is_compatbile(ffa_dev, ffa_ops)) > + return -EINVAL; > + > + if (!optee_ffa_exchange_caps(ffa_dev, ffa_ops, &rpc_arg_count)) > + return -EINVAL; => + > + optee = kzalloc(sizeof(*optee), GFP_KERNEL); > + if (!optee) { > + rc = -ENOMEM; > + goto err; > + } > + optee->pool = optee_ffa_config_dyn_shm(); > + if (IS_ERR(optee->pool)) { > + rc = PTR_ERR(optee->pool); > + optee->pool = NULL; > + goto err; > + } IIUC, with FF-A we will only be supporting dynamic shared memory. So CFG_CORE_DYN_SHM=y should be enforced in OP-TEE OS when CFG_CORE_FFA=y, but I don't see that currently. Am I missing something? -Sumit > + > + optee->ops = &optee_ffa_ops; > + optee->ffa.ffa_dev = ffa_dev; > + optee->ffa.ffa_ops = ffa_ops; > + optee->rpc_arg_count = rpc_arg_count; > + > + teedev = tee_device_alloc(&optee_ffa_clnt_desc, NULL, optee->pool, > + optee); > + if (IS_ERR(teedev)) { > + rc = PTR_ERR(teedev); > + goto err; > + } > + optee->teedev = teedev; > + > + teedev = tee_device_alloc(&optee_ffa_supp_desc, NULL, optee->pool, > + optee); > + if (IS_ERR(teedev)) { > + rc = PTR_ERR(teedev); > + goto err; > + } > + optee->supp_teedev = teedev; > + > + rc = tee_device_register(optee->teedev); > + if (rc) > + goto err; > + > + rc = tee_device_register(optee->supp_teedev); > + if (rc) > + goto err; > + > + rc = rhashtable_init(&optee->ffa.global_ids, &shm_rhash_params); > + if (rc) > + goto err; > + mutex_init(&optee->ffa.mutex); > + mutex_init(&optee->call_queue.mutex); > + INIT_LIST_HEAD(&optee->call_queue.waiters); > + optee_wait_queue_init(&optee->wait_queue); > + optee_supp_init(&optee->supp); > + ffa_dev_set_drvdata(ffa_dev, optee); > + > + rc = optee_enumerate_devices(PTA_CMD_GET_DEVICES); > + if (rc) { > + optee_ffa_remove(ffa_dev); > + return rc; > + } > + > + pr_info("initialized driver\n"); > + return 0; > +err: > + /* > + * tee_device_unregister() is safe to call even if the > + * devices hasn't been registered with > + * tee_device_register() yet. > + */ > + tee_device_unregister(optee->supp_teedev); > + tee_device_unregister(optee->teedev); > + if (optee->pool) > + tee_shm_pool_free(optee->pool); > + kfree(optee); > + return rc; > +} > + > +static const struct ffa_device_id optee_ffa_device_id[] = { > + /* 486178e0-e7f8-11e3-bc5e0002a5d5c51b */ > + { UUID_INIT(0x486178e0, 0xe7f8, 0x11e3, > + 0xbc, 0x5e, 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b) }, > + {} > +}; > + > +static struct ffa_driver optee_ffa_driver = { > + .name = "optee", > + .probe = optee_ffa_probe, > + .remove = optee_ffa_remove, > + .id_table = optee_ffa_device_id, > +}; > + > +int optee_ffa_abi_register(void) > +{ > + return ffa_register(&optee_ffa_driver); > +} > + > +void optee_ffa_abi_unregister(void) > +{ > + ffa_unregister(&optee_ffa_driver); > +} > diff --git a/drivers/tee/optee/optee_ffa.h b/drivers/tee/optee/optee_ffa.h > new file mode 100644 > index 000000000000..ee3a03fc392c > --- /dev/null > +++ b/drivers/tee/optee/optee_ffa.h > @@ -0,0 +1,153 @@ > +/* SPDX-License-Identifier: BSD-2-Clause */ > +/* > + * Copyright (c) 2019-2021, Linaro Limited > + */ > + > +/* > + * This file is exported by OP-TEE and is kept in sync between secure world > + * and normal world drivers. We're using ARM FF-A 1.0 specification. > + */ > + > +#ifndef __OPTEE_FFA_H > +#define __OPTEE_FFA_H > + > +#include > + > +/* > + * Normal world sends requests with FFA_MSG_SEND_DIRECT_REQ and > + * responses are returned with FFA_MSG_SEND_DIRECT_RESP for normal > + * messages. > + * > + * All requests with FFA_MSG_SEND_DIRECT_REQ and FFA_MSG_SEND_DIRECT_RESP > + * are using the AArch32 SMC calling convention with register usage as > + * defined in FF-A specification: > + * w0: Function ID (0x8400006F or 0x84000070) > + * w1: Source/Destination IDs > + * w2: Reserved (MBZ) > + * w3-w7: Implementation defined, free to be used below > + */ > + > +#define OPTEE_FFA_VERSION_MAJOR 1 > +#define OPTEE_FFA_VERSION_MINOR 0 > + > +#define OPTEE_FFA_BLOCKING_CALL(id) (id) > +#define OPTEE_FFA_YIELDING_CALL_BIT 31 > +#define OPTEE_FFA_YIELDING_CALL(id) ((id) | BIT(OPTEE_FFA_YIELDING_CALL_BIT)) > + > +/* > + * Returns the API version implemented, currently follows the FF-A version. > + * Call register usage: > + * w3: Service ID, OPTEE_FFA_GET_API_VERSION > + * w4-w7: Not used (MBZ) > + * > + * Return register usage: > + * w3: OPTEE_FFA_VERSION_MAJOR > + * w4: OPTEE_FFA_VERSION_MINOR > + * w5-w7: Not used (MBZ) > + */ > +#define OPTEE_FFA_GET_API_VERSION OPTEE_FFA_BLOCKING_CALL(0) > + > +/* > + * Returns the revision of OP-TEE. > + * > + * Used by non-secure world to figure out which version of the Trusted OS > + * is installed. Note that the returned revision is the revision of the > + * Trusted OS, not of the API. > + * > + * Call register usage: > + * w3: Service ID, OPTEE_FFA_GET_OS_VERSION > + * w4-w7: Unused (MBZ) > + * > + * Return register usage: > + * w3: CFG_OPTEE_REVISION_MAJOR > + * w4: CFG_OPTEE_REVISION_MINOR > + * w5: TEE_IMPL_GIT_SHA1 (or zero if not supported) > + */ > +#define OPTEE_FFA_GET_OS_VERSION OPTEE_FFA_BLOCKING_CALL(1) > + > +/* > + * Exchange capabilities between normal world and secure world. > + * > + * Currently there are no defined capabilities. When features are added new > + * capabilities may be added. > + * > + * Call register usage: > + * w3: Service ID, OPTEE_FFA_EXCHANGE_CAPABILITIES > + * w4-w7: Note used (MBZ) > + * > + * Return register usage: > + * w3: Error code, 0 on success > + * w4: Bit[7:0]: Number of parameters needed for RPC to be supplied > + * as the second MSG arg struct for > + * OPTEE_FFA_YIELDING_CALL_WITH_ARG. > + * Bit[31:8]: Reserved (MBZ) > + * w5-w7: Note used (MBZ) > + */ > +#define OPTEE_FFA_EXCHANGE_CAPABILITIES OPTEE_FFA_BLOCKING_CALL(2) > + > +/* > + * Unregister shared memory > + * > + * Call register usage: > + * w3: Service ID, OPTEE_FFA_YIELDING_CALL_UNREGISTER_SHM > + * w4: Shared memory handle, lower bits > + * w5: Shared memory handle, higher bits > + * w6-w7: Not used (MBZ) > + * > + * Return register usage: > + * w3: Error code, 0 on success > + * w4-w7: Note used (MBZ) > + */ > +#define OPTEE_FFA_UNREGISTER_SHM OPTEE_FFA_BLOCKING_CALL(3) > + > +/* > + * Call with struct optee_msg_arg as argument in the supplied shared memory > + * with a zero internal offset and normal cached memory attributes. > + * Register usage: > + * w3: Service ID, OPTEE_FFA_YIELDING_CALL_WITH_ARG > + * w4: Lower 32 bits of a 64-bit Shared memory handle > + * w5: Upper 32 bits of a 64-bit Shared memory handle > + * w6: Offset into shared memory pointing to a struct optee_msg_arg > + * right after the parameters of this struct (at offset > + * OPTEE_MSG_GET_ARG_SIZE(num_params) follows a struct optee_msg_arg > + * for RPC, this struct has reserved space for the number of RPC > + * parameters as returned by OPTEE_FFA_EXCHANGE_CAPABILITIES. > + * w7: Not used (MBZ) > + * Resume from RPC. Register usage: > + * w3: Service ID, OPTEE_FFA_YIELDING_CALL_RESUME > + * w4-w6: Not used (MBZ) > + * w7: Resume info > + * > + * Normal return (yielding call is completed). Register usage: > + * w3: Error code, 0 on success > + * w4: OPTEE_FFA_YIELDING_CALL_RETURN_DONE > + * w5-w7: Not used (MBZ) > + * > + * RPC interrupt return (RPC from secure world). Register usage: > + * w3: Error code == 0 > + * w4: Any defined RPC code but OPTEE_FFA_YIELDING_CALL_RETURN_DONE > + * w5-w6: Not used (MBZ) > + * w7: Resume info > + * > + * Possible error codes in register w3: > + * 0: Success > + * FFA_DENIED: w4 isn't one of OPTEE_FFA_YIELDING_CALL_START > + * OPTEE_FFA_YIELDING_CALL_RESUME > + * > + * Possible error codes for OPTEE_FFA_YIELDING_CALL_START, > + * FFA_BUSY: Number of OP-TEE OS threads exceeded, > + * try again later > + * FFA_DENIED: RPC shared memory object not found > + * FFA_INVALID_PARAMETER: Bad shared memory handle or offset into the memory > + * > + * Possible error codes for OPTEE_FFA_YIELDING_CALL_RESUME > + * FFA_INVALID_PARAMETER: Bad resume info > + */ > +#define OPTEE_FFA_YIELDING_CALL_WITH_ARG OPTEE_FFA_YIELDING_CALL(0) > +#define OPTEE_FFA_YIELDING_CALL_RESUME OPTEE_FFA_YIELDING_CALL(1) > + > +#define OPTEE_FFA_YIELDING_CALL_RETURN_DONE 0 > +#define OPTEE_FFA_YIELDING_CALL_RETURN_RPC_CMD 1 > +#define OPTEE_FFA_YIELDING_CALL_RETURN_INTERRUPT 2 > + > +#endif /*__OPTEE_FFA_H*/ > diff --git a/drivers/tee/optee/optee_msg.h b/drivers/tee/optee/optee_msg.h > index e3d72d09c484..2422e185d400 100644 > --- a/drivers/tee/optee/optee_msg.h > +++ b/drivers/tee/optee/optee_msg.h > @@ -28,6 +28,9 @@ > #define OPTEE_MSG_ATTR_TYPE_RMEM_INPUT 0x5 > #define OPTEE_MSG_ATTR_TYPE_RMEM_OUTPUT 0x6 > #define OPTEE_MSG_ATTR_TYPE_RMEM_INOUT 0x7 > +#define OPTEE_MSG_ATTR_TYPE_FMEM_INPUT OPTEE_MSG_ATTR_TYPE_RMEM_INPUT > +#define OPTEE_MSG_ATTR_TYPE_FMEM_OUTPUT OPTEE_MSG_ATTR_TYPE_RMEM_OUTPUT > +#define OPTEE_MSG_ATTR_TYPE_FMEM_INOUT OPTEE_MSG_ATTR_TYPE_RMEM_INOUT > #define OPTEE_MSG_ATTR_TYPE_TMEM_INPUT 0x9 > #define OPTEE_MSG_ATTR_TYPE_TMEM_OUTPUT 0xa > #define OPTEE_MSG_ATTR_TYPE_TMEM_INOUT 0xb > @@ -96,6 +99,8 @@ > */ > #define OPTEE_MSG_NONCONTIG_PAGE_SIZE 4096 > > +#define OPTEE_MSG_FMEM_INVALID_GLOBAL_ID 0xffffffffffffffff > + > /** > * struct optee_msg_param_tmem - temporary memory reference parameter > * @buf_ptr: Address of the buffer > @@ -127,6 +132,23 @@ struct optee_msg_param_rmem { > u64 shm_ref; > }; > > +/** > + * struct optee_msg_param_fmem - ffa memory reference parameter > + * @offs_lower: Lower bits of offset into shared memory reference > + * @offs_upper: Upper bits of offset into shared memory reference > + * @internal_offs: Internal offset into the first page of shared memory > + * reference > + * @size: Size of the buffer > + * @global_id: Global identifier of Shared memory > + */ > +struct optee_msg_param_fmem { > + u32 offs_low; > + u16 offs_high; > + u16 internal_offs; > + u64 size; > + u64 global_id; > +}; > + > /** > * struct optee_msg_param_value - opaque value parameter > * > @@ -143,13 +165,15 @@ struct optee_msg_param_value { > * @attr: attributes > * @tmem: parameter by temporary memory reference > * @rmem: parameter by registered memory reference > + * @fmem: parameter by ffa registered memory reference > * @value: parameter by opaque value > * @octets: parameter by octet string > * > * @attr & OPTEE_MSG_ATTR_TYPE_MASK indicates if tmem, rmem or value is used in > * the union. OPTEE_MSG_ATTR_TYPE_VALUE_* indicates value or octets, > * OPTEE_MSG_ATTR_TYPE_TMEM_* indicates @tmem and > - * OPTEE_MSG_ATTR_TYPE_RMEM_* indicates @rmem, > + * OPTEE_MSG_ATTR_TYPE_RMEM_* or the alias PTEE_MSG_ATTR_TYPE_FMEM_* indicates > + * @rmem or @fmem depending on the conduit. > * OPTEE_MSG_ATTR_TYPE_NONE indicates that none of the members are used. > */ > struct optee_msg_param { > @@ -157,6 +181,7 @@ struct optee_msg_param { > union { > struct optee_msg_param_tmem tmem; > struct optee_msg_param_rmem rmem; > + struct optee_msg_param_fmem fmem; > struct optee_msg_param_value value; > u8 octets[24]; > } u; > diff --git a/drivers/tee/optee/optee_private.h b/drivers/tee/optee/optee_private.h > index ca0213e330b5..2593742364da 100644 > --- a/drivers/tee/optee/optee_private.h > +++ b/drivers/tee/optee/optee_private.h > @@ -7,6 +7,7 @@ > #define OPTEE_PRIVATE_H > > #include > +#include > #include > #include > #include > @@ -22,6 +23,7 @@ > #define TEEC_ERROR_NOT_SUPPORTED 0xFFFF000A > #define TEEC_ERROR_COMMUNICATION 0xFFFF000E > #define TEEC_ERROR_OUT_OF_MEMORY 0xFFFF000C > +#define TEEC_ERROR_BUSY 0xFFFF000D > #define TEEC_ERROR_SHORT_BUFFER 0xFFFF0010 > > #define TEEC_ORIGIN_COMMS 0x00000002 > @@ -73,19 +75,28 @@ struct optee_supp { > struct completion reqs_c; > }; > > -/** > - * struct optee_smc - SMC ABI specifics > - * @invoke_fn: function to issue smc or hvc > - * @memremaped_shm virtual address of memory in shared memory pool > - * @sec_caps: secure world capabilities defined by > - * OPTEE_SMC_SEC_CAP_* in optee_smc.h > - */ > struct optee_smc { > optee_invoke_fn *invoke_fn; > void *memremaped_shm; > u32 sec_caps; > }; > > +/** > + * struct optee_ffa_data - FFA communication struct > + * @ffa_dev FFA device, contains the destination id, the id of > + * OP-TEE in secure world > + * @ffa_ops FFA operations > + * @mutex Serializes access to @global_ids > + * @global_ids FF-A shared memory global handle translation > + */ > +struct optee_ffa { > + struct ffa_device *ffa_dev; > + const struct ffa_dev_ops *ffa_ops; > + /* Serializes access to @global_ids */ > + struct mutex mutex; > + struct rhashtable global_ids; > +}; > + > struct optee; > > /** > @@ -116,11 +127,13 @@ struct optee_ops { > * world > * @teedev: client device > * @smc: specific to SMC ABI > + * @ffa: specific to FF-A ABI > * @call_queue: queue of threads waiting to call @invoke_fn > * @wait_queue: queue of threads from secure world waiting for a > * secure world sync object > * @supp: supplicant synchronization struct for RPC to supplicant > * @pool: shared memory pool > + * @rpc_arg_count: If > 0 number of RPC parameters to make room for > * @scan_bus_done flag if device registation was already done. > * @scan_bus_wq workqueue to scan optee bus and register optee drivers > * @scan_bus_work workq to scan optee bus and register optee drivers > @@ -129,11 +142,17 @@ struct optee { > struct tee_device *supp_teedev; > struct tee_device *teedev; > const struct optee_ops *ops; > - struct optee_smc smc; > + union { > + struct optee_smc smc; > +#ifdef CONFIG_ARM_FFA_TRANSPORT > + struct optee_ffa ffa; > +#endif > + }; > struct optee_call_queue call_queue; > struct optee_wait_queue wait_queue; > struct optee_supp supp; > struct tee_shm_pool *pool; > + unsigned int rpc_arg_count; > bool scan_bus_done; > struct workqueue_struct *scan_bus_wq; > struct work_struct scan_bus_work; > @@ -266,4 +285,12 @@ static inline void reg_pair_from_64(u32 *reg0, u32 *reg1, u64 val) > int optee_smc_abi_register(void); > void optee_smc_abi_unregister(void); > > +#ifdef CONFIG_ARM_FFA_TRANSPORT > +int optee_ffa_abi_register(void); > +void optee_ffa_abi_unregister(void); > +#else > +static inline int optee_ffa_abi_register(void) { return -EOPNOTSUPP; } > +static inline void optee_ffa_abi_unregister(void) {} > +#endif > + > #endif /*OPTEE_PRIVATE_H*/ > -- > 2.31.1 > _______________________________________________ linux-arm-kernel mailing list linux-arm-kernel@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-arm-kernel