* Re: [PATCH v6 09/10] optee: FF-A: dynamic restricted memory allocation
[not found] ` <CAHUa44H1MzBLBM+Oeawca52C8PF3uAT0ggbL-zRdnBqj4LYrZg@mail.gmail.com>
@ 2025-04-01 10:13 ` Sumit Garg
2025-04-01 12:26 ` Jens Wiklander
2025-04-09 10:01 ` David Hildenbrand
0 siblings, 2 replies; 6+ messages in thread
From: Sumit Garg @ 2025-04-01 10:13 UTC (permalink / raw)
To: Jens Wiklander, akpm, david, rppt
Cc: linux-kernel, linux-media, dri-devel, linaro-mm-sig, op-tee,
linux-arm-kernel, Olivier Masse, Thierry Reding, Yong Wu,
Sumit Semwal, Benjamin Gaignard, Brian Starkey, John Stultz,
T . J . Mercier, Christian König, Matthias Brugger,
AngeloGioacchino Del Regno, azarrabi, Simona Vetter, Daniel Stone,
linux-mm
+ MM folks to seek guidance here.
On Thu, Mar 27, 2025 at 09:07:34AM +0100, Jens Wiklander wrote:
> Hi Sumit,
>
> On Tue, Mar 25, 2025 at 8:42 AM Sumit Garg <sumit.garg@kernel.org> wrote:
> >
> > On Wed, Mar 05, 2025 at 02:04:15PM +0100, Jens Wiklander wrote:
> > > Add support in the OP-TEE backend driver dynamic restricted memory
> > > allocation with FF-A.
> > >
> > > The restricted memory pools for dynamically allocated restrict memory
> > > are instantiated when requested by user-space. This instantiation can
> > > fail if OP-TEE doesn't support the requested use-case of restricted
> > > memory.
> > >
> > > Restricted memory pools based on a static carveout or dynamic allocation
> > > can coexist for different use-cases. We use only dynamic allocation with
> > > FF-A.
> > >
> > > Signed-off-by: Jens Wiklander <jens.wiklander@linaro.org>
> > > ---
> > > drivers/tee/optee/Makefile | 1 +
> > > drivers/tee/optee/ffa_abi.c | 143 ++++++++++++-
> > > drivers/tee/optee/optee_private.h | 13 +-
> > > drivers/tee/optee/rstmem.c | 329 ++++++++++++++++++++++++++++++
> > > 4 files changed, 483 insertions(+), 3 deletions(-)
> > > create mode 100644 drivers/tee/optee/rstmem.c
> > >
<snip>
> > > diff --git a/drivers/tee/optee/rstmem.c b/drivers/tee/optee/rstmem.c
> > > new file mode 100644
> > > index 000000000000..ea27769934d4
> > > --- /dev/null
> > > +++ b/drivers/tee/optee/rstmem.c
> > > @@ -0,0 +1,329 @@
> > > +// SPDX-License-Identifier: GPL-2.0-only
> > > +/*
> > > + * Copyright (c) 2025, Linaro Limited
> > > + */
> > > +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
> > > +
> > > +#include <linux/errno.h>
> > > +#include <linux/genalloc.h>
> > > +#include <linux/slab.h>
> > > +#include <linux/string.h>
> > > +#include <linux/tee_core.h>
> > > +#include <linux/types.h>
> > > +#include "optee_private.h"
> > > +
> > > +struct optee_rstmem_cma_pool {
> > > + struct tee_rstmem_pool pool;
> > > + struct gen_pool *gen_pool;
> > > + struct optee *optee;
> > > + size_t page_count;
> > > + u16 *end_points;
> > > + u_int end_point_count;
> > > + u_int align;
> > > + refcount_t refcount;
> > > + u32 use_case;
> > > + struct tee_shm *rstmem;
> > > + /* Protects when initializing and tearing down this struct */
> > > + struct mutex mutex;
> > > +};
> > > +
> > > +static struct optee_rstmem_cma_pool *
> > > +to_rstmem_cma_pool(struct tee_rstmem_pool *pool)
> > > +{
> > > + return container_of(pool, struct optee_rstmem_cma_pool, pool);
> > > +}
> > > +
> > > +static int init_cma_rstmem(struct optee_rstmem_cma_pool *rp)
> > > +{
> > > + int rc;
> > > +
> > > + rp->rstmem = tee_shm_alloc_cma_phys_mem(rp->optee->ctx, rp->page_count,
> > > + rp->align);
> > > + if (IS_ERR(rp->rstmem)) {
> > > + rc = PTR_ERR(rp->rstmem);
> > > + goto err_null_rstmem;
> > > + }
> > > +
> > > + /*
> > > + * TODO unmap the memory range since the physical memory will
> > > + * become inaccesible after the lend_rstmem() call.
> > > + */
> >
> > What's your plan for this TODO? I think we need a CMA allocator here
> > which can allocate un-mapped memory such that any cache speculation
> > won't lead to CPU hangs once the memory restriction comes into picture.
>
> What happens is platform-specific. For some platforms, it might be
> enough to avoid explicit access. Yes, a CMA allocator with unmapped
> memory or where memory can be unmapped is one option.
Did you get a chance to enable real memory protection on RockPi board?
This will atleast ensure that mapped restricted memory without explicit
access works fine. Since otherwise once people start to enable real
memory restriction in OP-TEE, there can be chances of random hang ups
due to cache speculation.
MM folks,
Basically what we are trying to achieve here is a "no-map" DT behaviour
[1] which is rather dynamic in nature. The use-case here is that a memory
block allocated from CMA can be marked restricted at runtime where we
would like the Linux not being able to directly or indirectly (cache
speculation) access it. Once memory restriction use-case has been
completed, the memory block can be marked as normal and freed for
further CMA allocation.
It will be apprciated if you can guide us regarding the appropriate APIs
to use for un-mapping/mamping CMA allocations for this use-case.
[1] https://github.com/devicetree-org/dt-schema/blob/main/dtschema/schemas/reserved-memory/reserved-memory.yaml#L79
-Sumit
>
> >
> > > + rc = rp->optee->ops->lend_rstmem(rp->optee, rp->rstmem, rp->end_points,
> > > + rp->end_point_count, rp->use_case);
> > > + if (rc)
> > > + goto err_put_shm;
> > > + rp->rstmem->flags |= TEE_SHM_DYNAMIC;
> > > +
> > > + rp->gen_pool = gen_pool_create(PAGE_SHIFT, -1);
> > > + if (!rp->gen_pool) {
> > > + rc = -ENOMEM;
> > > + goto err_reclaim;
> > > + }
> > > +
> > > + rc = gen_pool_add(rp->gen_pool, rp->rstmem->paddr,
> > > + rp->rstmem->size, -1);
> > > + if (rc)
> > > + goto err_free_pool;
> > > +
> > > + refcount_set(&rp->refcount, 1);
> > > + return 0;
> > > +
> > > +err_free_pool:
> > > + gen_pool_destroy(rp->gen_pool);
> > > + rp->gen_pool = NULL;
> > > +err_reclaim:
> > > + rp->optee->ops->reclaim_rstmem(rp->optee, rp->rstmem);
> > > +err_put_shm:
> > > + tee_shm_put(rp->rstmem);
> > > +err_null_rstmem:
> > > + rp->rstmem = NULL;
> > > + return rc;
> > > +}
> > > +
> > > +static int get_cma_rstmem(struct optee_rstmem_cma_pool *rp)
> > > +{
> > > + int rc = 0;
> > > +
> > > + if (!refcount_inc_not_zero(&rp->refcount)) {
> > > + mutex_lock(&rp->mutex);
> > > + if (rp->gen_pool) {
> > > + /*
> > > + * Another thread has already initialized the pool
> > > + * before us, or the pool was just about to be torn
> > > + * down. Either way we only need to increase the
> > > + * refcount and we're done.
> > > + */
> > > + refcount_inc(&rp->refcount);
> > > + } else {
> > > + rc = init_cma_rstmem(rp);
> > > + }
> > > + mutex_unlock(&rp->mutex);
> > > + }
> > > +
> > > + return rc;
> > > +}
> > > +
> > > +static void release_cma_rstmem(struct optee_rstmem_cma_pool *rp)
> > > +{
> > > + gen_pool_destroy(rp->gen_pool);
> > > + rp->gen_pool = NULL;
> > > +
> > > + rp->optee->ops->reclaim_rstmem(rp->optee, rp->rstmem);
> > > + rp->rstmem->flags &= ~TEE_SHM_DYNAMIC;
> > > +
> > > + WARN(refcount_read(&rp->rstmem->refcount) != 1, "Unexpected refcount");
> > > + tee_shm_put(rp->rstmem);
> > > + rp->rstmem = NULL;
> > > +}
> > > +
> > > +static void put_cma_rstmem(struct optee_rstmem_cma_pool *rp)
> > > +{
> > > + if (refcount_dec_and_test(&rp->refcount)) {
> > > + mutex_lock(&rp->mutex);
> > > + if (rp->gen_pool)
> > > + release_cma_rstmem(rp);
> > > + mutex_unlock(&rp->mutex);
> > > + }
> > > +}
> > > +
> > > +static int rstmem_pool_op_cma_alloc(struct tee_rstmem_pool *pool,
> > > + struct sg_table *sgt, size_t size,
> > > + size_t *offs)
> > > +{
> > > + struct optee_rstmem_cma_pool *rp = to_rstmem_cma_pool(pool);
> > > + size_t sz = ALIGN(size, PAGE_SIZE);
> > > + phys_addr_t pa;
> > > + int rc;
> > > +
> > > + rc = get_cma_rstmem(rp);
> > > + if (rc)
> > > + return rc;
> > > +
> > > + pa = gen_pool_alloc(rp->gen_pool, sz);
> > > + if (!pa) {
> > > + rc = -ENOMEM;
> > > + goto err_put;
> > > + }
> > > +
> > > + rc = sg_alloc_table(sgt, 1, GFP_KERNEL);
> > > + if (rc)
> > > + goto err_free;
> > > +
> > > + sg_set_page(sgt->sgl, phys_to_page(pa), size, 0);
> > > + *offs = pa - rp->rstmem->paddr;
> > > +
> > > + return 0;
> > > +err_free:
> > > + gen_pool_free(rp->gen_pool, pa, size);
> > > +err_put:
> > > + put_cma_rstmem(rp);
> > > +
> > > + return rc;
> > > +}
> > > +
> > > +static void rstmem_pool_op_cma_free(struct tee_rstmem_pool *pool,
> > > + struct sg_table *sgt)
> > > +{
> > > + struct optee_rstmem_cma_pool *rp = to_rstmem_cma_pool(pool);
> > > + struct scatterlist *sg;
> > > + int i;
> > > +
> > > + for_each_sgtable_sg(sgt, sg, i)
> > > + gen_pool_free(rp->gen_pool, sg_phys(sg), sg->length);
> > > + sg_free_table(sgt);
> > > + put_cma_rstmem(rp);
> > > +}
> > > +
> > > +static int rstmem_pool_op_cma_update_shm(struct tee_rstmem_pool *pool,
> > > + struct sg_table *sgt, size_t offs,
> > > + struct tee_shm *shm,
> > > + struct tee_shm **parent_shm)
> > > +{
> > > + struct optee_rstmem_cma_pool *rp = to_rstmem_cma_pool(pool);
> > > +
> > > + *parent_shm = rp->rstmem;
> > > +
> > > + return 0;
> > > +}
> > > +
> > > +static void pool_op_cma_destroy_pool(struct tee_rstmem_pool *pool)
> > > +{
> > > + struct optee_rstmem_cma_pool *rp = to_rstmem_cma_pool(pool);
> > > +
> > > + mutex_destroy(&rp->mutex);
> > > + kfree(rp);
> > > +}
> > > +
> > > +static struct tee_rstmem_pool_ops rstmem_pool_ops_cma = {
> > > + .alloc = rstmem_pool_op_cma_alloc,
> > > + .free = rstmem_pool_op_cma_free,
> > > + .update_shm = rstmem_pool_op_cma_update_shm,
> > > + .destroy_pool = pool_op_cma_destroy_pool,
> > > +};
> > > +
> > > +static int get_rstmem_config(struct optee *optee, u32 use_case,
> > > + size_t *min_size, u_int *min_align,
> > > + u16 *end_points, u_int *ep_count)
> >
> > I guess this end points terminology is specific to FF-A ABI. Is there
> > any relevance for this in the common APIs?
>
> Yes, endpoints are specific to FF-A ABI. The list of end-points must
> be presented to FFA_MEM_LEND. We're relying on the secure world to
> know which endpoints are needed for a specific use case.
>
> Cheers,
> Jens
>
> >
> > -Sumit
> >
> > > +{
> > > + struct tee_param params[2] = {
> > > + [0] = {
> > > + .attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT,
> > > + .u.value.a = use_case,
> > > + },
> > > + [1] = {
> > > + .attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT,
> > > + },
> > > + };
> > > + struct optee_shm_arg_entry *entry;
> > > + struct tee_shm *shm_param = NULL;
> > > + struct optee_msg_arg *msg_arg;
> > > + struct tee_shm *shm;
> > > + u_int offs;
> > > + int rc;
> > > +
> > > + if (end_points && *ep_count) {
> > > + params[1].u.memref.size = *ep_count * sizeof(*end_points);
> > > + shm_param = tee_shm_alloc_priv_buf(optee->ctx,
> > > + params[1].u.memref.size);
> > > + if (IS_ERR(shm_param))
> > > + return PTR_ERR(shm_param);
> > > + params[1].u.memref.shm = shm_param;
> > > + }
> > > +
> > > + msg_arg = optee_get_msg_arg(optee->ctx, ARRAY_SIZE(params), &entry,
> > > + &shm, &offs);
> > > + if (IS_ERR(msg_arg)) {
> > > + rc = PTR_ERR(msg_arg);
> > > + goto out_free_shm;
> > > + }
> > > + msg_arg->cmd = OPTEE_MSG_CMD_GET_RSTMEM_CONFIG;
> > > +
> > > + rc = optee->ops->to_msg_param(optee, msg_arg->params,
> > > + ARRAY_SIZE(params), params,
> > > + false /*!update_out*/);
> > > + if (rc)
> > > + goto out_free_msg;
> > > +
> > > + rc = optee->ops->do_call_with_arg(optee->ctx, shm, offs, false);
> > > + if (rc)
> > > + goto out_free_msg;
> > > + if (msg_arg->ret && msg_arg->ret != TEEC_ERROR_SHORT_BUFFER) {
> > > + rc = -EINVAL;
> > > + goto out_free_msg;
> > > + }
> > > +
> > > + rc = optee->ops->from_msg_param(optee, params, ARRAY_SIZE(params),
> > > + msg_arg->params, true /*update_out*/);
> > > + if (rc)
> > > + goto out_free_msg;
> > > +
> > > + if (!msg_arg->ret && end_points &&
> > > + *ep_count < params[1].u.memref.size / sizeof(u16)) {
> > > + rc = -EINVAL;
> > > + goto out_free_msg;
> > > + }
> > > +
> > > + *min_size = params[0].u.value.a;
> > > + *min_align = params[0].u.value.b;
> > > + *ep_count = params[1].u.memref.size / sizeof(u16);
> > > +
> > > + if (msg_arg->ret == TEEC_ERROR_SHORT_BUFFER) {
> > > + rc = -ENOSPC;
> > > + goto out_free_msg;
> > > + }
> > > +
> > > + if (end_points)
> > > + memcpy(end_points, tee_shm_get_va(shm_param, 0),
> > > + params[1].u.memref.size);
> > > +
> > > +out_free_msg:
> > > + optee_free_msg_arg(optee->ctx, entry, offs);
> > > +out_free_shm:
> > > + if (shm_param)
> > > + tee_shm_free(shm_param);
> > > + return rc;
> > > +}
> > > +
> > > +struct tee_rstmem_pool *optee_rstmem_alloc_cma_pool(struct optee *optee,
> > > + enum tee_dma_heap_id id)
> > > +{
> > > + struct optee_rstmem_cma_pool *rp;
> > > + u32 use_case = id;
> > > + size_t min_size;
> > > + int rc;
> > > +
> > > + rp = kzalloc(sizeof(*rp), GFP_KERNEL);
> > > + if (!rp)
> > > + return ERR_PTR(-ENOMEM);
> > > + rp->use_case = use_case;
> > > +
> > > + rc = get_rstmem_config(optee, use_case, &min_size, &rp->align, NULL,
> > > + &rp->end_point_count);
> > > + if (rc) {
> > > + if (rc != -ENOSPC)
> > > + goto err;
> > > + rp->end_points = kcalloc(rp->end_point_count,
> > > + sizeof(*rp->end_points), GFP_KERNEL);
> > > + if (!rp->end_points) {
> > > + rc = -ENOMEM;
> > > + goto err;
> > > + }
> > > + rc = get_rstmem_config(optee, use_case, &min_size, &rp->align,
> > > + rp->end_points, &rp->end_point_count);
> > > + if (rc)
> > > + goto err_kfree_eps;
> > > + }
> > > +
> > > + rp->pool.ops = &rstmem_pool_ops_cma;
> > > + rp->optee = optee;
> > > + rp->page_count = min_size / PAGE_SIZE;
> > > + mutex_init(&rp->mutex);
> > > +
> > > + return &rp->pool;
> > > +
> > > +err_kfree_eps:
> > > + kfree(rp->end_points);
> > > +err:
> > > + kfree(rp);
> > > + return ERR_PTR(rc);
> > > +}
> > > --
> > > 2.43.0
> > >
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH v6 09/10] optee: FF-A: dynamic restricted memory allocation
2025-04-01 10:13 ` [PATCH v6 09/10] optee: FF-A: dynamic restricted memory allocation Sumit Garg
@ 2025-04-01 12:26 ` Jens Wiklander
2025-04-08 9:20 ` Sumit Garg
2025-04-09 10:01 ` David Hildenbrand
1 sibling, 1 reply; 6+ messages in thread
From: Jens Wiklander @ 2025-04-01 12:26 UTC (permalink / raw)
To: Sumit Garg
Cc: akpm, david, rppt, linux-kernel, linux-media, dri-devel,
linaro-mm-sig, op-tee, linux-arm-kernel, Olivier Masse,
Thierry Reding, Yong Wu, Sumit Semwal, Benjamin Gaignard,
Brian Starkey, John Stultz, T . J . Mercier, Christian König,
Matthias Brugger, AngeloGioacchino Del Regno, azarrabi,
Simona Vetter, Daniel Stone, linux-mm
On Tue, Apr 1, 2025 at 12:13 PM Sumit Garg <sumit.garg@kernel.org> wrote:
>
> + MM folks to seek guidance here.
>
> On Thu, Mar 27, 2025 at 09:07:34AM +0100, Jens Wiklander wrote:
> > Hi Sumit,
> >
> > On Tue, Mar 25, 2025 at 8:42 AM Sumit Garg <sumit.garg@kernel.org> wrote:
> > >
> > > On Wed, Mar 05, 2025 at 02:04:15PM +0100, Jens Wiklander wrote:
> > > > Add support in the OP-TEE backend driver dynamic restricted memory
> > > > allocation with FF-A.
> > > >
> > > > The restricted memory pools for dynamically allocated restrict memory
> > > > are instantiated when requested by user-space. This instantiation can
> > > > fail if OP-TEE doesn't support the requested use-case of restricted
> > > > memory.
> > > >
> > > > Restricted memory pools based on a static carveout or dynamic allocation
> > > > can coexist for different use-cases. We use only dynamic allocation with
> > > > FF-A.
> > > >
> > > > Signed-off-by: Jens Wiklander <jens.wiklander@linaro.org>
> > > > ---
> > > > drivers/tee/optee/Makefile | 1 +
> > > > drivers/tee/optee/ffa_abi.c | 143 ++++++++++++-
> > > > drivers/tee/optee/optee_private.h | 13 +-
> > > > drivers/tee/optee/rstmem.c | 329 ++++++++++++++++++++++++++++++
> > > > 4 files changed, 483 insertions(+), 3 deletions(-)
> > > > create mode 100644 drivers/tee/optee/rstmem.c
> > > >
>
> <snip>
>
> > > > diff --git a/drivers/tee/optee/rstmem.c b/drivers/tee/optee/rstmem.c
> > > > new file mode 100644
> > > > index 000000000000..ea27769934d4
> > > > --- /dev/null
> > > > +++ b/drivers/tee/optee/rstmem.c
> > > > @@ -0,0 +1,329 @@
> > > > +// SPDX-License-Identifier: GPL-2.0-only
> > > > +/*
> > > > + * Copyright (c) 2025, Linaro Limited
> > > > + */
> > > > +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
> > > > +
> > > > +#include <linux/errno.h>
> > > > +#include <linux/genalloc.h>
> > > > +#include <linux/slab.h>
> > > > +#include <linux/string.h>
> > > > +#include <linux/tee_core.h>
> > > > +#include <linux/types.h>
> > > > +#include "optee_private.h"
> > > > +
> > > > +struct optee_rstmem_cma_pool {
> > > > + struct tee_rstmem_pool pool;
> > > > + struct gen_pool *gen_pool;
> > > > + struct optee *optee;
> > > > + size_t page_count;
> > > > + u16 *end_points;
> > > > + u_int end_point_count;
> > > > + u_int align;
> > > > + refcount_t refcount;
> > > > + u32 use_case;
> > > > + struct tee_shm *rstmem;
> > > > + /* Protects when initializing and tearing down this struct */
> > > > + struct mutex mutex;
> > > > +};
> > > > +
> > > > +static struct optee_rstmem_cma_pool *
> > > > +to_rstmem_cma_pool(struct tee_rstmem_pool *pool)
> > > > +{
> > > > + return container_of(pool, struct optee_rstmem_cma_pool, pool);
> > > > +}
> > > > +
> > > > +static int init_cma_rstmem(struct optee_rstmem_cma_pool *rp)
> > > > +{
> > > > + int rc;
> > > > +
> > > > + rp->rstmem = tee_shm_alloc_cma_phys_mem(rp->optee->ctx, rp->page_count,
> > > > + rp->align);
> > > > + if (IS_ERR(rp->rstmem)) {
> > > > + rc = PTR_ERR(rp->rstmem);
> > > > + goto err_null_rstmem;
> > > > + }
> > > > +
> > > > + /*
> > > > + * TODO unmap the memory range since the physical memory will
> > > > + * become inaccesible after the lend_rstmem() call.
> > > > + */
> > >
> > > What's your plan for this TODO? I think we need a CMA allocator here
> > > which can allocate un-mapped memory such that any cache speculation
> > > won't lead to CPU hangs once the memory restriction comes into picture.
> >
> > What happens is platform-specific. For some platforms, it might be
> > enough to avoid explicit access. Yes, a CMA allocator with unmapped
> > memory or where memory can be unmapped is one option.
>
> Did you get a chance to enable real memory protection on RockPi board?
No, I don't think I have access to the needed documentation for the
board to set it up for relevant peripherals.
> This will atleast ensure that mapped restricted memory without explicit
> access works fine. Since otherwise once people start to enable real
> memory restriction in OP-TEE, there can be chances of random hang ups
> due to cache speculation.
A hypervisor in the normal world can also make the memory inaccessible
to the kernel. That shouldn't cause any hangups due to cache
speculation.
Cheers,
Jens
>
> MM folks,
>
> Basically what we are trying to achieve here is a "no-map" DT behaviour
> [1] which is rather dynamic in nature. The use-case here is that a memory
> block allocated from CMA can be marked restricted at runtime where we
> would like the Linux not being able to directly or indirectly (cache
> speculation) access it. Once memory restriction use-case has been
> completed, the memory block can be marked as normal and freed for
> further CMA allocation.
>
> It will be apprciated if you can guide us regarding the appropriate APIs
> to use for un-mapping/mamping CMA allocations for this use-case.
>
> [1] https://github.com/devicetree-org/dt-schema/blob/main/dtschema/schemas/reserved-memory/reserved-memory.yaml#L79
>
> -Sumit
>
> >
> > >
> > > > + rc = rp->optee->ops->lend_rstmem(rp->optee, rp->rstmem, rp->end_points,
> > > > + rp->end_point_count, rp->use_case);
> > > > + if (rc)
> > > > + goto err_put_shm;
> > > > + rp->rstmem->flags |= TEE_SHM_DYNAMIC;
> > > > +
> > > > + rp->gen_pool = gen_pool_create(PAGE_SHIFT, -1);
> > > > + if (!rp->gen_pool) {
> > > > + rc = -ENOMEM;
> > > > + goto err_reclaim;
> > > > + }
> > > > +
> > > > + rc = gen_pool_add(rp->gen_pool, rp->rstmem->paddr,
> > > > + rp->rstmem->size, -1);
> > > > + if (rc)
> > > > + goto err_free_pool;
> > > > +
> > > > + refcount_set(&rp->refcount, 1);
> > > > + return 0;
> > > > +
> > > > +err_free_pool:
> > > > + gen_pool_destroy(rp->gen_pool);
> > > > + rp->gen_pool = NULL;
> > > > +err_reclaim:
> > > > + rp->optee->ops->reclaim_rstmem(rp->optee, rp->rstmem);
> > > > +err_put_shm:
> > > > + tee_shm_put(rp->rstmem);
> > > > +err_null_rstmem:
> > > > + rp->rstmem = NULL;
> > > > + return rc;
> > > > +}
> > > > +
> > > > +static int get_cma_rstmem(struct optee_rstmem_cma_pool *rp)
> > > > +{
> > > > + int rc = 0;
> > > > +
> > > > + if (!refcount_inc_not_zero(&rp->refcount)) {
> > > > + mutex_lock(&rp->mutex);
> > > > + if (rp->gen_pool) {
> > > > + /*
> > > > + * Another thread has already initialized the pool
> > > > + * before us, or the pool was just about to be torn
> > > > + * down. Either way we only need to increase the
> > > > + * refcount and we're done.
> > > > + */
> > > > + refcount_inc(&rp->refcount);
> > > > + } else {
> > > > + rc = init_cma_rstmem(rp);
> > > > + }
> > > > + mutex_unlock(&rp->mutex);
> > > > + }
> > > > +
> > > > + return rc;
> > > > +}
> > > > +
> > > > +static void release_cma_rstmem(struct optee_rstmem_cma_pool *rp)
> > > > +{
> > > > + gen_pool_destroy(rp->gen_pool);
> > > > + rp->gen_pool = NULL;
> > > > +
> > > > + rp->optee->ops->reclaim_rstmem(rp->optee, rp->rstmem);
> > > > + rp->rstmem->flags &= ~TEE_SHM_DYNAMIC;
> > > > +
> > > > + WARN(refcount_read(&rp->rstmem->refcount) != 1, "Unexpected refcount");
> > > > + tee_shm_put(rp->rstmem);
> > > > + rp->rstmem = NULL;
> > > > +}
> > > > +
> > > > +static void put_cma_rstmem(struct optee_rstmem_cma_pool *rp)
> > > > +{
> > > > + if (refcount_dec_and_test(&rp->refcount)) {
> > > > + mutex_lock(&rp->mutex);
> > > > + if (rp->gen_pool)
> > > > + release_cma_rstmem(rp);
> > > > + mutex_unlock(&rp->mutex);
> > > > + }
> > > > +}
> > > > +
> > > > +static int rstmem_pool_op_cma_alloc(struct tee_rstmem_pool *pool,
> > > > + struct sg_table *sgt, size_t size,
> > > > + size_t *offs)
> > > > +{
> > > > + struct optee_rstmem_cma_pool *rp = to_rstmem_cma_pool(pool);
> > > > + size_t sz = ALIGN(size, PAGE_SIZE);
> > > > + phys_addr_t pa;
> > > > + int rc;
> > > > +
> > > > + rc = get_cma_rstmem(rp);
> > > > + if (rc)
> > > > + return rc;
> > > > +
> > > > + pa = gen_pool_alloc(rp->gen_pool, sz);
> > > > + if (!pa) {
> > > > + rc = -ENOMEM;
> > > > + goto err_put;
> > > > + }
> > > > +
> > > > + rc = sg_alloc_table(sgt, 1, GFP_KERNEL);
> > > > + if (rc)
> > > > + goto err_free;
> > > > +
> > > > + sg_set_page(sgt->sgl, phys_to_page(pa), size, 0);
> > > > + *offs = pa - rp->rstmem->paddr;
> > > > +
> > > > + return 0;
> > > > +err_free:
> > > > + gen_pool_free(rp->gen_pool, pa, size);
> > > > +err_put:
> > > > + put_cma_rstmem(rp);
> > > > +
> > > > + return rc;
> > > > +}
> > > > +
> > > > +static void rstmem_pool_op_cma_free(struct tee_rstmem_pool *pool,
> > > > + struct sg_table *sgt)
> > > > +{
> > > > + struct optee_rstmem_cma_pool *rp = to_rstmem_cma_pool(pool);
> > > > + struct scatterlist *sg;
> > > > + int i;
> > > > +
> > > > + for_each_sgtable_sg(sgt, sg, i)
> > > > + gen_pool_free(rp->gen_pool, sg_phys(sg), sg->length);
> > > > + sg_free_table(sgt);
> > > > + put_cma_rstmem(rp);
> > > > +}
> > > > +
> > > > +static int rstmem_pool_op_cma_update_shm(struct tee_rstmem_pool *pool,
> > > > + struct sg_table *sgt, size_t offs,
> > > > + struct tee_shm *shm,
> > > > + struct tee_shm **parent_shm)
> > > > +{
> > > > + struct optee_rstmem_cma_pool *rp = to_rstmem_cma_pool(pool);
> > > > +
> > > > + *parent_shm = rp->rstmem;
> > > > +
> > > > + return 0;
> > > > +}
> > > > +
> > > > +static void pool_op_cma_destroy_pool(struct tee_rstmem_pool *pool)
> > > > +{
> > > > + struct optee_rstmem_cma_pool *rp = to_rstmem_cma_pool(pool);
> > > > +
> > > > + mutex_destroy(&rp->mutex);
> > > > + kfree(rp);
> > > > +}
> > > > +
> > > > +static struct tee_rstmem_pool_ops rstmem_pool_ops_cma = {
> > > > + .alloc = rstmem_pool_op_cma_alloc,
> > > > + .free = rstmem_pool_op_cma_free,
> > > > + .update_shm = rstmem_pool_op_cma_update_shm,
> > > > + .destroy_pool = pool_op_cma_destroy_pool,
> > > > +};
> > > > +
> > > > +static int get_rstmem_config(struct optee *optee, u32 use_case,
> > > > + size_t *min_size, u_int *min_align,
> > > > + u16 *end_points, u_int *ep_count)
> > >
> > > I guess this end points terminology is specific to FF-A ABI. Is there
> > > any relevance for this in the common APIs?
> >
> > Yes, endpoints are specific to FF-A ABI. The list of end-points must
> > be presented to FFA_MEM_LEND. We're relying on the secure world to
> > know which endpoints are needed for a specific use case.
> >
> > Cheers,
> > Jens
> >
> > >
> > > -Sumit
> > >
> > > > +{
> > > > + struct tee_param params[2] = {
> > > > + [0] = {
> > > > + .attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT,
> > > > + .u.value.a = use_case,
> > > > + },
> > > > + [1] = {
> > > > + .attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT,
> > > > + },
> > > > + };
> > > > + struct optee_shm_arg_entry *entry;
> > > > + struct tee_shm *shm_param = NULL;
> > > > + struct optee_msg_arg *msg_arg;
> > > > + struct tee_shm *shm;
> > > > + u_int offs;
> > > > + int rc;
> > > > +
> > > > + if (end_points && *ep_count) {
> > > > + params[1].u.memref.size = *ep_count * sizeof(*end_points);
> > > > + shm_param = tee_shm_alloc_priv_buf(optee->ctx,
> > > > + params[1].u.memref.size);
> > > > + if (IS_ERR(shm_param))
> > > > + return PTR_ERR(shm_param);
> > > > + params[1].u.memref.shm = shm_param;
> > > > + }
> > > > +
> > > > + msg_arg = optee_get_msg_arg(optee->ctx, ARRAY_SIZE(params), &entry,
> > > > + &shm, &offs);
> > > > + if (IS_ERR(msg_arg)) {
> > > > + rc = PTR_ERR(msg_arg);
> > > > + goto out_free_shm;
> > > > + }
> > > > + msg_arg->cmd = OPTEE_MSG_CMD_GET_RSTMEM_CONFIG;
> > > > +
> > > > + rc = optee->ops->to_msg_param(optee, msg_arg->params,
> > > > + ARRAY_SIZE(params), params,
> > > > + false /*!update_out*/);
> > > > + if (rc)
> > > > + goto out_free_msg;
> > > > +
> > > > + rc = optee->ops->do_call_with_arg(optee->ctx, shm, offs, false);
> > > > + if (rc)
> > > > + goto out_free_msg;
> > > > + if (msg_arg->ret && msg_arg->ret != TEEC_ERROR_SHORT_BUFFER) {
> > > > + rc = -EINVAL;
> > > > + goto out_free_msg;
> > > > + }
> > > > +
> > > > + rc = optee->ops->from_msg_param(optee, params, ARRAY_SIZE(params),
> > > > + msg_arg->params, true /*update_out*/);
> > > > + if (rc)
> > > > + goto out_free_msg;
> > > > +
> > > > + if (!msg_arg->ret && end_points &&
> > > > + *ep_count < params[1].u.memref.size / sizeof(u16)) {
> > > > + rc = -EINVAL;
> > > > + goto out_free_msg;
> > > > + }
> > > > +
> > > > + *min_size = params[0].u.value.a;
> > > > + *min_align = params[0].u.value.b;
> > > > + *ep_count = params[1].u.memref.size / sizeof(u16);
> > > > +
> > > > + if (msg_arg->ret == TEEC_ERROR_SHORT_BUFFER) {
> > > > + rc = -ENOSPC;
> > > > + goto out_free_msg;
> > > > + }
> > > > +
> > > > + if (end_points)
> > > > + memcpy(end_points, tee_shm_get_va(shm_param, 0),
> > > > + params[1].u.memref.size);
> > > > +
> > > > +out_free_msg:
> > > > + optee_free_msg_arg(optee->ctx, entry, offs);
> > > > +out_free_shm:
> > > > + if (shm_param)
> > > > + tee_shm_free(shm_param);
> > > > + return rc;
> > > > +}
> > > > +
> > > > +struct tee_rstmem_pool *optee_rstmem_alloc_cma_pool(struct optee *optee,
> > > > + enum tee_dma_heap_id id)
> > > > +{
> > > > + struct optee_rstmem_cma_pool *rp;
> > > > + u32 use_case = id;
> > > > + size_t min_size;
> > > > + int rc;
> > > > +
> > > > + rp = kzalloc(sizeof(*rp), GFP_KERNEL);
> > > > + if (!rp)
> > > > + return ERR_PTR(-ENOMEM);
> > > > + rp->use_case = use_case;
> > > > +
> > > > + rc = get_rstmem_config(optee, use_case, &min_size, &rp->align, NULL,
> > > > + &rp->end_point_count);
> > > > + if (rc) {
> > > > + if (rc != -ENOSPC)
> > > > + goto err;
> > > > + rp->end_points = kcalloc(rp->end_point_count,
> > > > + sizeof(*rp->end_points), GFP_KERNEL);
> > > > + if (!rp->end_points) {
> > > > + rc = -ENOMEM;
> > > > + goto err;
> > > > + }
> > > > + rc = get_rstmem_config(optee, use_case, &min_size, &rp->align,
> > > > + rp->end_points, &rp->end_point_count);
> > > > + if (rc)
> > > > + goto err_kfree_eps;
> > > > + }
> > > > +
> > > > + rp->pool.ops = &rstmem_pool_ops_cma;
> > > > + rp->optee = optee;
> > > > + rp->page_count = min_size / PAGE_SIZE;
> > > > + mutex_init(&rp->mutex);
> > > > +
> > > > + return &rp->pool;
> > > > +
> > > > +err_kfree_eps:
> > > > + kfree(rp->end_points);
> > > > +err:
> > > > + kfree(rp);
> > > > + return ERR_PTR(rc);
> > > > +}
> > > > --
> > > > 2.43.0
> > > >
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH v6 09/10] optee: FF-A: dynamic restricted memory allocation
2025-04-01 12:26 ` Jens Wiklander
@ 2025-04-08 9:20 ` Sumit Garg
2025-04-08 13:39 ` Jens Wiklander
0 siblings, 1 reply; 6+ messages in thread
From: Sumit Garg @ 2025-04-08 9:20 UTC (permalink / raw)
To: Jens Wiklander
Cc: akpm, david, rppt, linux-kernel, linux-media, dri-devel,
linaro-mm-sig, op-tee, linux-arm-kernel, Olivier Masse,
Thierry Reding, Yong Wu, Sumit Semwal, Benjamin Gaignard,
Brian Starkey, John Stultz, T . J . Mercier, Christian König,
Matthias Brugger, AngeloGioacchino Del Regno, azarrabi,
Simona Vetter, Daniel Stone, linux-mm
On Tue, Apr 01, 2025 at 02:26:59PM +0200, Jens Wiklander wrote:
> On Tue, Apr 1, 2025 at 12:13 PM Sumit Garg <sumit.garg@kernel.org> wrote:
> >
> > + MM folks to seek guidance here.
> >
> > On Thu, Mar 27, 2025 at 09:07:34AM +0100, Jens Wiklander wrote:
> > > Hi Sumit,
> > >
> > > On Tue, Mar 25, 2025 at 8:42 AM Sumit Garg <sumit.garg@kernel.org> wrote:
> > > >
> > > > On Wed, Mar 05, 2025 at 02:04:15PM +0100, Jens Wiklander wrote:
> > > > > Add support in the OP-TEE backend driver dynamic restricted memory
> > > > > allocation with FF-A.
> > > > >
> > > > > The restricted memory pools for dynamically allocated restrict memory
> > > > > are instantiated when requested by user-space. This instantiation can
> > > > > fail if OP-TEE doesn't support the requested use-case of restricted
> > > > > memory.
> > > > >
> > > > > Restricted memory pools based on a static carveout or dynamic allocation
> > > > > can coexist for different use-cases. We use only dynamic allocation with
> > > > > FF-A.
> > > > >
> > > > > Signed-off-by: Jens Wiklander <jens.wiklander@linaro.org>
> > > > > ---
> > > > > drivers/tee/optee/Makefile | 1 +
> > > > > drivers/tee/optee/ffa_abi.c | 143 ++++++++++++-
> > > > > drivers/tee/optee/optee_private.h | 13 +-
> > > > > drivers/tee/optee/rstmem.c | 329 ++++++++++++++++++++++++++++++
> > > > > 4 files changed, 483 insertions(+), 3 deletions(-)
> > > > > create mode 100644 drivers/tee/optee/rstmem.c
> > > > >
> >
> > <snip>
> >
> > > > > diff --git a/drivers/tee/optee/rstmem.c b/drivers/tee/optee/rstmem.c
> > > > > new file mode 100644
> > > > > index 000000000000..ea27769934d4
> > > > > --- /dev/null
> > > > > +++ b/drivers/tee/optee/rstmem.c
> > > > > @@ -0,0 +1,329 @@
> > > > > +// SPDX-License-Identifier: GPL-2.0-only
> > > > > +/*
> > > > > + * Copyright (c) 2025, Linaro Limited
> > > > > + */
> > > > > +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
> > > > > +
> > > > > +#include <linux/errno.h>
> > > > > +#include <linux/genalloc.h>
> > > > > +#include <linux/slab.h>
> > > > > +#include <linux/string.h>
> > > > > +#include <linux/tee_core.h>
> > > > > +#include <linux/types.h>
> > > > > +#include "optee_private.h"
> > > > > +
> > > > > +struct optee_rstmem_cma_pool {
> > > > > + struct tee_rstmem_pool pool;
> > > > > + struct gen_pool *gen_pool;
> > > > > + struct optee *optee;
> > > > > + size_t page_count;
> > > > > + u16 *end_points;
> > > > > + u_int end_point_count;
> > > > > + u_int align;
> > > > > + refcount_t refcount;
> > > > > + u32 use_case;
> > > > > + struct tee_shm *rstmem;
> > > > > + /* Protects when initializing and tearing down this struct */
> > > > > + struct mutex mutex;
> > > > > +};
> > > > > +
> > > > > +static struct optee_rstmem_cma_pool *
> > > > > +to_rstmem_cma_pool(struct tee_rstmem_pool *pool)
> > > > > +{
> > > > > + return container_of(pool, struct optee_rstmem_cma_pool, pool);
> > > > > +}
> > > > > +
> > > > > +static int init_cma_rstmem(struct optee_rstmem_cma_pool *rp)
> > > > > +{
> > > > > + int rc;
> > > > > +
> > > > > + rp->rstmem = tee_shm_alloc_cma_phys_mem(rp->optee->ctx, rp->page_count,
> > > > > + rp->align);
> > > > > + if (IS_ERR(rp->rstmem)) {
> > > > > + rc = PTR_ERR(rp->rstmem);
> > > > > + goto err_null_rstmem;
> > > > > + }
> > > > > +
> > > > > + /*
> > > > > + * TODO unmap the memory range since the physical memory will
> > > > > + * become inaccesible after the lend_rstmem() call.
> > > > > + */
> > > >
> > > > What's your plan for this TODO? I think we need a CMA allocator here
> > > > which can allocate un-mapped memory such that any cache speculation
> > > > won't lead to CPU hangs once the memory restriction comes into picture.
> > >
> > > What happens is platform-specific. For some platforms, it might be
> > > enough to avoid explicit access. Yes, a CMA allocator with unmapped
> > > memory or where memory can be unmapped is one option.
> >
> > Did you get a chance to enable real memory protection on RockPi board?
>
> No, I don't think I have access to the needed documentation for the
> board to set it up for relevant peripherals.
>
> > This will atleast ensure that mapped restricted memory without explicit
> > access works fine. Since otherwise once people start to enable real
> > memory restriction in OP-TEE, there can be chances of random hang ups
> > due to cache speculation.
>
> A hypervisor in the normal world can also make the memory inaccessible
> to the kernel. That shouldn't cause any hangups due to cache
> speculation.
The hypervisor should unmap the memory from EL2 translation tables which
I think should disallow the cache speculation to take place. However,
without hypervisor here the memory remains mapped in normal world which
can lead to cache speculation for restricted buffers. That's why we
should atleast test on one platform with real memory protection enabled
to rule out any assumptions we make.
-Sumit
>
> Cheers,
> Jens
>
> >
> > MM folks,
> >
> > Basically what we are trying to achieve here is a "no-map" DT behaviour
> > [1] which is rather dynamic in nature. The use-case here is that a memory
> > block allocated from CMA can be marked restricted at runtime where we
> > would like the Linux not being able to directly or indirectly (cache
> > speculation) access it. Once memory restriction use-case has been
> > completed, the memory block can be marked as normal and freed for
> > further CMA allocation.
> >
> > It will be apprciated if you can guide us regarding the appropriate APIs
> > to use for un-mapping/mamping CMA allocations for this use-case.
> >
> > [1] https://github.com/devicetree-org/dt-schema/blob/main/dtschema/schemas/reserved-memory/reserved-memory.yaml#L79
> >
> > -Sumit
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH v6 09/10] optee: FF-A: dynamic restricted memory allocation
2025-04-08 9:20 ` Sumit Garg
@ 2025-04-08 13:39 ` Jens Wiklander
0 siblings, 0 replies; 6+ messages in thread
From: Jens Wiklander @ 2025-04-08 13:39 UTC (permalink / raw)
To: Sumit Garg
Cc: akpm, david, rppt, linux-kernel, linux-media, dri-devel,
linaro-mm-sig, op-tee, linux-arm-kernel, Olivier Masse,
Thierry Reding, Yong Wu, Sumit Semwal, Benjamin Gaignard,
Brian Starkey, John Stultz, T . J . Mercier, Christian König,
Matthias Brugger, AngeloGioacchino Del Regno, azarrabi,
Simona Vetter, Daniel Stone, linux-mm
On Tue, Apr 8, 2025 at 11:20 AM Sumit Garg <sumit.garg@kernel.org> wrote:
>
> On Tue, Apr 01, 2025 at 02:26:59PM +0200, Jens Wiklander wrote:
> > On Tue, Apr 1, 2025 at 12:13 PM Sumit Garg <sumit.garg@kernel.org> wrote:
> > >
> > > + MM folks to seek guidance here.
> > >
> > > On Thu, Mar 27, 2025 at 09:07:34AM +0100, Jens Wiklander wrote:
> > > > Hi Sumit,
> > > >
> > > > On Tue, Mar 25, 2025 at 8:42 AM Sumit Garg <sumit.garg@kernel.org> wrote:
> > > > >
> > > > > On Wed, Mar 05, 2025 at 02:04:15PM +0100, Jens Wiklander wrote:
> > > > > > Add support in the OP-TEE backend driver dynamic restricted memory
> > > > > > allocation with FF-A.
> > > > > >
> > > > > > The restricted memory pools for dynamically allocated restrict memory
> > > > > > are instantiated when requested by user-space. This instantiation can
> > > > > > fail if OP-TEE doesn't support the requested use-case of restricted
> > > > > > memory.
> > > > > >
> > > > > > Restricted memory pools based on a static carveout or dynamic allocation
> > > > > > can coexist for different use-cases. We use only dynamic allocation with
> > > > > > FF-A.
> > > > > >
> > > > > > Signed-off-by: Jens Wiklander <jens.wiklander@linaro.org>
> > > > > > ---
> > > > > > drivers/tee/optee/Makefile | 1 +
> > > > > > drivers/tee/optee/ffa_abi.c | 143 ++++++++++++-
> > > > > > drivers/tee/optee/optee_private.h | 13 +-
> > > > > > drivers/tee/optee/rstmem.c | 329 ++++++++++++++++++++++++++++++
> > > > > > 4 files changed, 483 insertions(+), 3 deletions(-)
> > > > > > create mode 100644 drivers/tee/optee/rstmem.c
> > > > > >
> > >
> > > <snip>
> > >
> > > > > > diff --git a/drivers/tee/optee/rstmem.c b/drivers/tee/optee/rstmem.c
> > > > > > new file mode 100644
> > > > > > index 000000000000..ea27769934d4
> > > > > > --- /dev/null
> > > > > > +++ b/drivers/tee/optee/rstmem.c
> > > > > > @@ -0,0 +1,329 @@
> > > > > > +// SPDX-License-Identifier: GPL-2.0-only
> > > > > > +/*
> > > > > > + * Copyright (c) 2025, Linaro Limited
> > > > > > + */
> > > > > > +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
> > > > > > +
> > > > > > +#include <linux/errno.h>
> > > > > > +#include <linux/genalloc.h>
> > > > > > +#include <linux/slab.h>
> > > > > > +#include <linux/string.h>
> > > > > > +#include <linux/tee_core.h>
> > > > > > +#include <linux/types.h>
> > > > > > +#include "optee_private.h"
> > > > > > +
> > > > > > +struct optee_rstmem_cma_pool {
> > > > > > + struct tee_rstmem_pool pool;
> > > > > > + struct gen_pool *gen_pool;
> > > > > > + struct optee *optee;
> > > > > > + size_t page_count;
> > > > > > + u16 *end_points;
> > > > > > + u_int end_point_count;
> > > > > > + u_int align;
> > > > > > + refcount_t refcount;
> > > > > > + u32 use_case;
> > > > > > + struct tee_shm *rstmem;
> > > > > > + /* Protects when initializing and tearing down this struct */
> > > > > > + struct mutex mutex;
> > > > > > +};
> > > > > > +
> > > > > > +static struct optee_rstmem_cma_pool *
> > > > > > +to_rstmem_cma_pool(struct tee_rstmem_pool *pool)
> > > > > > +{
> > > > > > + return container_of(pool, struct optee_rstmem_cma_pool, pool);
> > > > > > +}
> > > > > > +
> > > > > > +static int init_cma_rstmem(struct optee_rstmem_cma_pool *rp)
> > > > > > +{
> > > > > > + int rc;
> > > > > > +
> > > > > > + rp->rstmem = tee_shm_alloc_cma_phys_mem(rp->optee->ctx, rp->page_count,
> > > > > > + rp->align);
> > > > > > + if (IS_ERR(rp->rstmem)) {
> > > > > > + rc = PTR_ERR(rp->rstmem);
> > > > > > + goto err_null_rstmem;
> > > > > > + }
> > > > > > +
> > > > > > + /*
> > > > > > + * TODO unmap the memory range since the physical memory will
> > > > > > + * become inaccesible after the lend_rstmem() call.
> > > > > > + */
> > > > >
> > > > > What's your plan for this TODO? I think we need a CMA allocator here
> > > > > which can allocate un-mapped memory such that any cache speculation
> > > > > won't lead to CPU hangs once the memory restriction comes into picture.
> > > >
> > > > What happens is platform-specific. For some platforms, it might be
> > > > enough to avoid explicit access. Yes, a CMA allocator with unmapped
> > > > memory or where memory can be unmapped is one option.
> > >
> > > Did you get a chance to enable real memory protection on RockPi board?
> >
> > No, I don't think I have access to the needed documentation for the
> > board to set it up for relevant peripherals.
> >
> > > This will atleast ensure that mapped restricted memory without explicit
> > > access works fine. Since otherwise once people start to enable real
> > > memory restriction in OP-TEE, there can be chances of random hang ups
> > > due to cache speculation.
> >
> > A hypervisor in the normal world can also make the memory inaccessible
> > to the kernel. That shouldn't cause any hangups due to cache
> > speculation.
>
> The hypervisor should unmap the memory from EL2 translation tables which
> I think should disallow the cache speculation to take place. However,
> without hypervisor here the memory remains mapped in normal world which
> can lead to cache speculation for restricted buffers. That's why we
> should atleast test on one platform with real memory protection enabled
> to rule out any assumptions we make.
Do I hear a volunteer? ;-)
Anyway, this isn't something that can be enabled in the kernel alone.
Only platforms where the firmware has been updated will be affected.
If this can't be supported on a particular platform, there's still the
option with a static carveout.
Cheers,
Jens
>
> -Sumit
>
> >
> > Cheers,
> > Jens
> >
> > >
> > > MM folks,
> > >
> > > Basically what we are trying to achieve here is a "no-map" DT behaviour
> > > [1] which is rather dynamic in nature. The use-case here is that a memory
> > > block allocated from CMA can be marked restricted at runtime where we
> > > would like the Linux not being able to directly or indirectly (cache
> > > speculation) access it. Once memory restriction use-case has been
> > > completed, the memory block can be marked as normal and freed for
> > > further CMA allocation.
> > >
> > > It will be apprciated if you can guide us regarding the appropriate APIs
> > > to use for un-mapping/mamping CMA allocations for this use-case.
> > >
> > > [1] https://github.com/devicetree-org/dt-schema/blob/main/dtschema/schemas/reserved-memory/reserved-memory.yaml#L79
> > >
> > > -Sumit
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH v6 09/10] optee: FF-A: dynamic restricted memory allocation
2025-04-01 10:13 ` [PATCH v6 09/10] optee: FF-A: dynamic restricted memory allocation Sumit Garg
2025-04-01 12:26 ` Jens Wiklander
@ 2025-04-09 10:01 ` David Hildenbrand
2025-04-09 13:19 ` Sumit Garg
1 sibling, 1 reply; 6+ messages in thread
From: David Hildenbrand @ 2025-04-09 10:01 UTC (permalink / raw)
To: Sumit Garg, Jens Wiklander, akpm, rppt
Cc: linux-kernel, linux-media, dri-devel, linaro-mm-sig, op-tee,
linux-arm-kernel, Olivier Masse, Thierry Reding, Yong Wu,
Sumit Semwal, Benjamin Gaignard, Brian Starkey, John Stultz,
T . J . Mercier, Christian König, Matthias Brugger,
AngeloGioacchino Del Regno, azarrabi, Simona Vetter, Daniel Stone,
linux-mm
On 01.04.25 12:13, Sumit Garg wrote:
> + MM folks to seek guidance here.
>
> On Thu, Mar 27, 2025 at 09:07:34AM +0100, Jens Wiklander wrote:
>> Hi Sumit,
>>
>> On Tue, Mar 25, 2025 at 8:42 AM Sumit Garg <sumit.garg@kernel.org> wrote:
>>>
>>> On Wed, Mar 05, 2025 at 02:04:15PM +0100, Jens Wiklander wrote:
>>>> Add support in the OP-TEE backend driver dynamic restricted memory
>>>> allocation with FF-A.
>>>>
>>>> The restricted memory pools for dynamically allocated restrict memory
>>>> are instantiated when requested by user-space. This instantiation can
>>>> fail if OP-TEE doesn't support the requested use-case of restricted
>>>> memory.
>>>>
>>>> Restricted memory pools based on a static carveout or dynamic allocation
>>>> can coexist for different use-cases. We use only dynamic allocation with
>>>> FF-A.
>>>>
>>>> Signed-off-by: Jens Wiklander <jens.wiklander@linaro.org>
>>>> ---
>>>> drivers/tee/optee/Makefile | 1 +
>>>> drivers/tee/optee/ffa_abi.c | 143 ++++++++++++-
>>>> drivers/tee/optee/optee_private.h | 13 +-
>>>> drivers/tee/optee/rstmem.c | 329 ++++++++++++++++++++++++++++++
>>>> 4 files changed, 483 insertions(+), 3 deletions(-)
>>>> create mode 100644 drivers/tee/optee/rstmem.c
>>>>
>
> <snip>
>
>>>> diff --git a/drivers/tee/optee/rstmem.c b/drivers/tee/optee/rstmem.c
>>>> new file mode 100644
>>>> index 000000000000..ea27769934d4
>>>> --- /dev/null
>>>> +++ b/drivers/tee/optee/rstmem.c
>>>> @@ -0,0 +1,329 @@
>>>> +// SPDX-License-Identifier: GPL-2.0-only
>>>> +/*
>>>> + * Copyright (c) 2025, Linaro Limited
>>>> + */
>>>> +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
>>>> +
>>>> +#include <linux/errno.h>
>>>> +#include <linux/genalloc.h>
>>>> +#include <linux/slab.h>
>>>> +#include <linux/string.h>
>>>> +#include <linux/tee_core.h>
>>>> +#include <linux/types.h>
>>>> +#include "optee_private.h"
>>>> +
>>>> +struct optee_rstmem_cma_pool {
>>>> + struct tee_rstmem_pool pool;
>>>> + struct gen_pool *gen_pool;
>>>> + struct optee *optee;
>>>> + size_t page_count;
>>>> + u16 *end_points;
>>>> + u_int end_point_count;
>>>> + u_int align;
>>>> + refcount_t refcount;
>>>> + u32 use_case;
>>>> + struct tee_shm *rstmem;
>>>> + /* Protects when initializing and tearing down this struct */
>>>> + struct mutex mutex;
>>>> +};
>>>> +
>>>> +static struct optee_rstmem_cma_pool *
>>>> +to_rstmem_cma_pool(struct tee_rstmem_pool *pool)
>>>> +{
>>>> + return container_of(pool, struct optee_rstmem_cma_pool, pool);
>>>> +}
>>>> +
>>>> +static int init_cma_rstmem(struct optee_rstmem_cma_pool *rp)
>>>> +{
>>>> + int rc;
>>>> +
>>>> + rp->rstmem = tee_shm_alloc_cma_phys_mem(rp->optee->ctx, rp->page_count,
>>>> + rp->align);
>>>> + if (IS_ERR(rp->rstmem)) {
>>>> + rc = PTR_ERR(rp->rstmem);
>>>> + goto err_null_rstmem;
>>>> + }
>>>> +
>>>> + /*
>>>> + * TODO unmap the memory range since the physical memory will
>>>> + * become inaccesible after the lend_rstmem() call.
>>>> + */
>>>
>>> What's your plan for this TODO? I think we need a CMA allocator here
>>> which can allocate un-mapped memory such that any cache speculation
>>> won't lead to CPU hangs once the memory restriction comes into picture.
>>
>> What happens is platform-specific. For some platforms, it might be
>> enough to avoid explicit access. Yes, a CMA allocator with unmapped
>> memory or where memory can be unmapped is one option.
>
> Did you get a chance to enable real memory protection on RockPi board?
> This will atleast ensure that mapped restricted memory without explicit
> access works fine. Since otherwise once people start to enable real
> memory restriction in OP-TEE, there can be chances of random hang ups
> due to cache speculation.
>
> MM folks,
>
> Basically what we are trying to achieve here is a "no-map" DT behaviour
> [1] which is rather dynamic in nature. The use-case here is that a memory
> block allocated from CMA can be marked restricted at runtime where we
> would like the Linux not being able to directly or indirectly (cache
> speculation) access it. Once memory restriction use-case has been
> completed, the memory block can be marked as normal and freed for
> further CMA allocation.
>
> It will be apprciated if you can guide us regarding the appropriate APIs
> to use for un-mapping/mamping CMA allocations for this use-case.
Can we get some more information why that is even required, so we can
decide if that is even the right thing to do? :)
Who would mark the memory block as restricted and for which purpose?
In arch/powerpc/platforms/powernv/memtrace.c we have some arch-specific
code to remove the directmap after alloc_contig_pages(). See
memtrace_alloc_node(). But it's very arch-specific ...
--
Cheers,
David / dhildenb
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH v6 09/10] optee: FF-A: dynamic restricted memory allocation
2025-04-09 10:01 ` David Hildenbrand
@ 2025-04-09 13:19 ` Sumit Garg
0 siblings, 0 replies; 6+ messages in thread
From: Sumit Garg @ 2025-04-09 13:19 UTC (permalink / raw)
To: David Hildenbrand
Cc: Jens Wiklander, akpm, rppt, linux-kernel, linux-media, dri-devel,
linaro-mm-sig, op-tee, linux-arm-kernel, Olivier Masse,
Thierry Reding, Yong Wu, Sumit Semwal, Benjamin Gaignard,
Brian Starkey, John Stultz, T . J . Mercier, Christian König,
Matthias Brugger, AngeloGioacchino Del Regno, azarrabi,
Simona Vetter, Daniel Stone, linux-mm
Thanks David for your response.
On Wed, Apr 09, 2025 at 12:01:21PM +0200, David Hildenbrand wrote:
> On 01.04.25 12:13, Sumit Garg wrote:
> > + MM folks to seek guidance here.
> >
> > On Thu, Mar 27, 2025 at 09:07:34AM +0100, Jens Wiklander wrote:
> > > Hi Sumit,
> > >
> > > On Tue, Mar 25, 2025 at 8:42 AM Sumit Garg <sumit.garg@kernel.org> wrote:
> > > >
> > > > On Wed, Mar 05, 2025 at 02:04:15PM +0100, Jens Wiklander wrote:
> > > > > Add support in the OP-TEE backend driver dynamic restricted memory
> > > > > allocation with FF-A.
> > > > >
> > > > > The restricted memory pools for dynamically allocated restrict memory
> > > > > are instantiated when requested by user-space. This instantiation can
> > > > > fail if OP-TEE doesn't support the requested use-case of restricted
> > > > > memory.
> > > > >
> > > > > Restricted memory pools based on a static carveout or dynamic allocation
> > > > > can coexist for different use-cases. We use only dynamic allocation with
> > > > > FF-A.
> > > > >
> > > > > Signed-off-by: Jens Wiklander <jens.wiklander@linaro.org>
> > > > > ---
> > > > > drivers/tee/optee/Makefile | 1 +
> > > > > drivers/tee/optee/ffa_abi.c | 143 ++++++++++++-
> > > > > drivers/tee/optee/optee_private.h | 13 +-
> > > > > drivers/tee/optee/rstmem.c | 329 ++++++++++++++++++++++++++++++
> > > > > 4 files changed, 483 insertions(+), 3 deletions(-)
> > > > > create mode 100644 drivers/tee/optee/rstmem.c
> > > > >
> >
> > <snip>
> >
> > > > > diff --git a/drivers/tee/optee/rstmem.c b/drivers/tee/optee/rstmem.c
> > > > > new file mode 100644
> > > > > index 000000000000..ea27769934d4
> > > > > --- /dev/null
> > > > > +++ b/drivers/tee/optee/rstmem.c
> > > > > @@ -0,0 +1,329 @@
> > > > > +// SPDX-License-Identifier: GPL-2.0-only
> > > > > +/*
> > > > > + * Copyright (c) 2025, Linaro Limited
> > > > > + */
> > > > > +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
> > > > > +
> > > > > +#include <linux/errno.h>
> > > > > +#include <linux/genalloc.h>
> > > > > +#include <linux/slab.h>
> > > > > +#include <linux/string.h>
> > > > > +#include <linux/tee_core.h>
> > > > > +#include <linux/types.h>
> > > > > +#include "optee_private.h"
> > > > > +
> > > > > +struct optee_rstmem_cma_pool {
> > > > > + struct tee_rstmem_pool pool;
> > > > > + struct gen_pool *gen_pool;
> > > > > + struct optee *optee;
> > > > > + size_t page_count;
> > > > > + u16 *end_points;
> > > > > + u_int end_point_count;
> > > > > + u_int align;
> > > > > + refcount_t refcount;
> > > > > + u32 use_case;
> > > > > + struct tee_shm *rstmem;
> > > > > + /* Protects when initializing and tearing down this struct */
> > > > > + struct mutex mutex;
> > > > > +};
> > > > > +
> > > > > +static struct optee_rstmem_cma_pool *
> > > > > +to_rstmem_cma_pool(struct tee_rstmem_pool *pool)
> > > > > +{
> > > > > + return container_of(pool, struct optee_rstmem_cma_pool, pool);
> > > > > +}
> > > > > +
> > > > > +static int init_cma_rstmem(struct optee_rstmem_cma_pool *rp)
> > > > > +{
> > > > > + int rc;
> > > > > +
> > > > > + rp->rstmem = tee_shm_alloc_cma_phys_mem(rp->optee->ctx, rp->page_count,
> > > > > + rp->align);
> > > > > + if (IS_ERR(rp->rstmem)) {
> > > > > + rc = PTR_ERR(rp->rstmem);
> > > > > + goto err_null_rstmem;
> > > > > + }
> > > > > +
> > > > > + /*
> > > > > + * TODO unmap the memory range since the physical memory will
> > > > > + * become inaccesible after the lend_rstmem() call.
> > > > > + */
> > > >
> > > > What's your plan for this TODO? I think we need a CMA allocator here
> > > > which can allocate un-mapped memory such that any cache speculation
> > > > won't lead to CPU hangs once the memory restriction comes into picture.
> > >
> > > What happens is platform-specific. For some platforms, it might be
> > > enough to avoid explicit access. Yes, a CMA allocator with unmapped
> > > memory or where memory can be unmapped is one option.
> >
> > Did you get a chance to enable real memory protection on RockPi board?
> > This will atleast ensure that mapped restricted memory without explicit
> > access works fine. Since otherwise once people start to enable real
> > memory restriction in OP-TEE, there can be chances of random hang ups
> > due to cache speculation.
> >
> > MM folks,
> >
> > Basically what we are trying to achieve here is a "no-map" DT behaviour
> > [1] which is rather dynamic in nature. The use-case here is that a memory
> > block allocated from CMA can be marked restricted at runtime where we
> > would like the Linux not being able to directly or indirectly (cache
> > speculation) access it. Once memory restriction use-case has been
> > completed, the memory block can be marked as normal and freed for
> > further CMA allocation.
> >
> > It will be apprciated if you can guide us regarding the appropriate APIs
> > to use for un-mapping/mamping CMA allocations for this use-case.
>
> Can we get some more information why that is even required, so we can decide
> if that is even the right thing to do? :)
The main reason which I can see is for memory re-use. Although we should
be able to carve out memory during boot and then mark it restricted for
the entire boot cycle but without re-use. Especially for secure media
pipeline use-case where the video buffers can be sufficiently large
enough which will benefit from memory re-use.
>
> Who would mark the memory block as restricted and for which purpose?
It will be the higher privileged firmware/Trusted OS which can either be
the running on same CPU with higher privileges like Arm TrustZone or a
separate co-processor like AMD-TEE etc. The purpose is for secure media
pipeline, trusted UI or secure crypto use-cases where essentially the
motivation is that the Linux kernel shouldn't be able to access
decrypted content or key material in plain format but rather only the
allowed peripherals like media pipeline, crypto accelerators etc. able to
access them.
>
> In arch/powerpc/platforms/powernv/memtrace.c we have some arch-specific code
> to remove the directmap after alloc_contig_pages(). See
> memtrace_alloc_node(). But it's very arch-specific ...
Thanks for the reference, we are looking for something like that but
with generic code along with capability to remap when the restricted
memory block is freed and available for normal kernel usage.
-Sumit
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2025-04-09 13:19 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[not found] <20250305130634.1850178-1-jens.wiklander@linaro.org>
[not found] ` <20250305130634.1850178-10-jens.wiklander@linaro.org>
[not found] ` <Z-JePo6yGlUgrZkw@sumit-X1>
[not found] ` <CAHUa44H1MzBLBM+Oeawca52C8PF3uAT0ggbL-zRdnBqj4LYrZg@mail.gmail.com>
2025-04-01 10:13 ` [PATCH v6 09/10] optee: FF-A: dynamic restricted memory allocation Sumit Garg
2025-04-01 12:26 ` Jens Wiklander
2025-04-08 9:20 ` Sumit Garg
2025-04-08 13:39 ` Jens Wiklander
2025-04-09 10:01 ` David Hildenbrand
2025-04-09 13:19 ` Sumit Garg
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).