Commit d88e0493 authored by Jens Wiklander's avatar Jens Wiklander
Browse files

tee: simplify shm pool handling



Replaces the shared memory pool based on two pools with a single pool.
The alloc() function pointer in struct tee_shm_pool_ops gets another
parameter, align. This makes it possible to make less than page aligned
allocations from the optional reserved shared memory pool while still
making user space allocations page aligned. With in practice unchanged
behaviour using only a single pool for bookkeeping.

The allocation algorithm in the static OP-TEE shared memory pool is
changed from best-fit to first-fit since only the latter supports an
alignment parameter. The best-fit algorithm was previously the default
choice and not a conscious one.

The optee and amdtee drivers are updated as needed to work with this
changed pool handling.

This also removes OPTEE_SHM_NUM_PRIV_PAGES which becomes obsolete with
this change as the private pages can be mixed with the payload pages.

The OP-TEE driver changes minimum alignment for argument struct from 8
bytes to 512 bytes. A typical OP-TEE private shm allocation is 224 bytes
(argument struct with 6 parameters, needed for open session). So with an
alignment of 512 well waste a bit more than 50%. Before this we had a
single page reserved for this so worst case usage compared to that would
be 3 pages instead of 1 page. However, this worst case only occurs if
there is a high pressure from multiple threads on secure world. All in
all this should scale up and down better than fixed boundaries.

Reviewed-by: default avatarSumit Garg <sumit.garg@linaro.org>
Signed-off-by: default avatarJens Wiklander <jens.wiklander@linaro.org>
parent 71cc47d4
Loading
Loading
Loading
Loading
+16 −39
Original line number Original line Diff line number Diff line
@@ -8,13 +8,17 @@
#include <linux/psp-sev.h>
#include <linux/psp-sev.h>
#include "amdtee_private.h"
#include "amdtee_private.h"


static int pool_op_alloc(struct tee_shm_pool_mgr *poolm, struct tee_shm *shm,
static int pool_op_alloc(struct tee_shm_pool *pool, struct tee_shm *shm,
			 size_t size)
			 size_t size, size_t align)
{
{
	unsigned int order = get_order(size);
	unsigned int order = get_order(size);
	unsigned long va;
	unsigned long va;
	int rc;
	int rc;


	/*
	 * Ignore alignment since this is already going to be page aligned
	 * and there's no need for any larger alignment.
	 */
	va = __get_free_pages(GFP_KERNEL | __GFP_ZERO, order);
	va = __get_free_pages(GFP_KERNEL | __GFP_ZERO, order);
	if (!va)
	if (!va)
		return -ENOMEM;
		return -ENOMEM;
@@ -34,7 +38,7 @@ static int pool_op_alloc(struct tee_shm_pool_mgr *poolm, struct tee_shm *shm,
	return 0;
	return 0;
}
}


static void pool_op_free(struct tee_shm_pool_mgr *poolm, struct tee_shm *shm)
static void pool_op_free(struct tee_shm_pool *pool, struct tee_shm *shm)
{
{
	/* Unmap the shared memory from TEE */
	/* Unmap the shared memory from TEE */
	amdtee_unmap_shmem(shm);
	amdtee_unmap_shmem(shm);
@@ -42,52 +46,25 @@ static void pool_op_free(struct tee_shm_pool_mgr *poolm, struct tee_shm *shm)
	shm->kaddr = NULL;
	shm->kaddr = NULL;
}
}


static void pool_op_destroy_poolmgr(struct tee_shm_pool_mgr *poolm)
static void pool_op_destroy_pool(struct tee_shm_pool *pool)
{
{
	kfree(poolm);
	kfree(pool);
}
}


static const struct tee_shm_pool_mgr_ops pool_ops = {
static const struct tee_shm_pool_ops pool_ops = {
	.alloc = pool_op_alloc,
	.alloc = pool_op_alloc,
	.free = pool_op_free,
	.free = pool_op_free,
	.destroy_poolmgr = pool_op_destroy_poolmgr,
	.destroy_pool = pool_op_destroy_pool,
};
};


static struct tee_shm_pool_mgr *pool_mem_mgr_alloc(void)
{
	struct tee_shm_pool_mgr *mgr = kzalloc(sizeof(*mgr), GFP_KERNEL);

	if (!mgr)
		return ERR_PTR(-ENOMEM);

	mgr->ops = &pool_ops;

	return mgr;
}

struct tee_shm_pool *amdtee_config_shm(void)
struct tee_shm_pool *amdtee_config_shm(void)
{
{
	struct tee_shm_pool_mgr *priv_mgr;
	struct tee_shm_pool *pool = kzalloc(sizeof(*pool), GFP_KERNEL);
	struct tee_shm_pool_mgr *dmabuf_mgr;
	void *rc;

	rc = pool_mem_mgr_alloc();
	if (IS_ERR(rc))
		return rc;
	priv_mgr = rc;


	rc = pool_mem_mgr_alloc();
	if (!pool)
	if (IS_ERR(rc)) {
		return ERR_PTR(-ENOMEM);
		tee_shm_pool_mgr_destroy(priv_mgr);
		return rc;
	}
	dmabuf_mgr = rc;


	rc = tee_shm_pool_alloc(priv_mgr, dmabuf_mgr);
	pool->ops = &pool_ops;
	if (IS_ERR(rc)) {
		tee_shm_pool_mgr_destroy(priv_mgr);
		tee_shm_pool_mgr_destroy(dmabuf_mgr);
	}


	return rc;
	return pool;
}
}
+0 −8
Original line number Original line Diff line number Diff line
@@ -7,11 +7,3 @@ config OPTEE
	help
	help
	  This implements the OP-TEE Trusted Execution Environment (TEE)
	  This implements the OP-TEE Trusted Execution Environment (TEE)
	  driver.
	  driver.

config OPTEE_SHM_NUM_PRIV_PAGES
	int "Private Shared Memory Pages"
	default 1
	depends on OPTEE
	help
	  This sets the number of private shared memory pages to be
	  used by OP-TEE TEE driver.
+7 −4
Original line number Original line Diff line number Diff line
@@ -18,8 +18,8 @@
#include <linux/workqueue.h>
#include <linux/workqueue.h>
#include "optee_private.h"
#include "optee_private.h"


int optee_pool_op_alloc_helper(struct tee_shm_pool_mgr *poolm,
int optee_pool_op_alloc_helper(struct tee_shm_pool *pool, struct tee_shm *shm,
			       struct tee_shm *shm, size_t size,
			       size_t size, size_t align,
			       int (*shm_register)(struct tee_context *ctx,
			       int (*shm_register)(struct tee_context *ctx,
						   struct tee_shm *shm,
						   struct tee_shm *shm,
						   struct page **pages,
						   struct page **pages,
@@ -30,6 +30,10 @@ int optee_pool_op_alloc_helper(struct tee_shm_pool_mgr *poolm,
	struct page *page;
	struct page *page;
	int rc = 0;
	int rc = 0;


	/*
	 * Ignore alignment since this is already going to be page aligned
	 * and there's no need for any larger alignment.
	 */
	page = alloc_pages(GFP_KERNEL | __GFP_ZERO, order);
	page = alloc_pages(GFP_KERNEL | __GFP_ZERO, order);
	if (!page)
	if (!page)
		return -ENOMEM;
		return -ENOMEM;
@@ -51,7 +55,6 @@ int optee_pool_op_alloc_helper(struct tee_shm_pool_mgr *poolm,
		for (i = 0; i < nr_pages; i++)
		for (i = 0; i < nr_pages; i++)
			pages[i] = page + i;
			pages[i] = page + i;


		shm->flags |= TEE_SHM_REGISTER;
		rc = shm_register(shm->ctx, shm, pages, nr_pages,
		rc = shm_register(shm->ctx, shm, pages, nr_pages,
				  (unsigned long)shm->kaddr);
				  (unsigned long)shm->kaddr);
		kfree(pages);
		kfree(pages);
@@ -62,7 +65,7 @@ int optee_pool_op_alloc_helper(struct tee_shm_pool_mgr *poolm,
	return 0;
	return 0;


err:
err:
	__free_pages(page, order);
	free_pages((unsigned long)shm->kaddr, order);
	return rc;
	return rc;
}
}


+14 −41
Original line number Original line Diff line number Diff line
@@ -369,14 +369,14 @@ static int optee_ffa_shm_unregister_supp(struct tee_context *ctx,
 * The main function is optee_ffa_shm_pool_alloc_pages().
 * The main function is optee_ffa_shm_pool_alloc_pages().
 */
 */


static int pool_ffa_op_alloc(struct tee_shm_pool_mgr *poolm,
static int pool_ffa_op_alloc(struct tee_shm_pool *pool,
			     struct tee_shm *shm, size_t size)
			     struct tee_shm *shm, size_t size, size_t align)
{
{
	return optee_pool_op_alloc_helper(poolm, shm, size,
	return optee_pool_op_alloc_helper(pool, shm, size, align,
					  optee_ffa_shm_register);
					  optee_ffa_shm_register);
}
}


static void pool_ffa_op_free(struct tee_shm_pool_mgr *poolm,
static void pool_ffa_op_free(struct tee_shm_pool *pool,
			     struct tee_shm *shm)
			     struct tee_shm *shm)
{
{
	optee_ffa_shm_unregister(shm->ctx, shm);
	optee_ffa_shm_unregister(shm->ctx, shm);
@@ -384,15 +384,15 @@ static void pool_ffa_op_free(struct tee_shm_pool_mgr *poolm,
	shm->kaddr = NULL;
	shm->kaddr = NULL;
}
}


static void pool_ffa_op_destroy_poolmgr(struct tee_shm_pool_mgr *poolm)
static void pool_ffa_op_destroy_pool(struct tee_shm_pool *pool)
{
{
	kfree(poolm);
	kfree(pool);
}
}


static const struct tee_shm_pool_mgr_ops pool_ffa_ops = {
static const struct tee_shm_pool_ops pool_ffa_ops = {
	.alloc = pool_ffa_op_alloc,
	.alloc = pool_ffa_op_alloc,
	.free = pool_ffa_op_free,
	.free = pool_ffa_op_free,
	.destroy_poolmgr = pool_ffa_op_destroy_poolmgr,
	.destroy_pool = pool_ffa_op_destroy_pool,
};
};


/**
/**
@@ -401,16 +401,16 @@ static const struct tee_shm_pool_mgr_ops pool_ffa_ops = {
 * This pool is used with OP-TEE over FF-A. In this case command buffers
 * This pool is used with OP-TEE over FF-A. In this case command buffers
 * and such are allocated from kernel's own memory.
 * and such are allocated from kernel's own memory.
 */
 */
static struct tee_shm_pool_mgr *optee_ffa_shm_pool_alloc_pages(void)
static struct tee_shm_pool *optee_ffa_shm_pool_alloc_pages(void)
{
{
	struct tee_shm_pool_mgr *mgr = kzalloc(sizeof(*mgr), GFP_KERNEL);
	struct tee_shm_pool *pool = kzalloc(sizeof(*pool), GFP_KERNEL);


	if (!mgr)
	if (!pool)
		return ERR_PTR(-ENOMEM);
		return ERR_PTR(-ENOMEM);


	mgr->ops = &pool_ffa_ops;
	pool->ops = &pool_ffa_ops;


	return mgr;
	return pool;
}
}


/*
/*
@@ -691,33 +691,6 @@ static bool optee_ffa_exchange_caps(struct ffa_device *ffa_dev,
	return true;
	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,
static void optee_ffa_get_version(struct tee_device *teedev,
				  struct tee_ioctl_version_data *vers)
				  struct tee_ioctl_version_data *vers)
{
{
@@ -815,7 +788,7 @@ static int optee_ffa_probe(struct ffa_device *ffa_dev)
	if (!optee)
	if (!optee)
		return -ENOMEM;
		return -ENOMEM;


	pool = optee_ffa_config_dyn_shm();
	pool = optee_ffa_shm_pool_alloc_pages();
	if (IS_ERR(pool)) {
	if (IS_ERR(pool)) {
		rc = PTR_ERR(pool);
		rc = PTR_ERR(pool);
		goto err_free_optee;
		goto err_free_optee;
+2 −2
Original line number Original line Diff line number Diff line
@@ -229,8 +229,8 @@ int optee_cancel_req(struct tee_context *ctx, u32 cancel_id, u32 session);
int optee_enumerate_devices(u32 func);
int optee_enumerate_devices(u32 func);
void optee_unregister_devices(void);
void optee_unregister_devices(void);


int optee_pool_op_alloc_helper(struct tee_shm_pool_mgr *poolm,
int optee_pool_op_alloc_helper(struct tee_shm_pool *pool, struct tee_shm *shm,
			       struct tee_shm *shm, size_t size,
			       size_t size, size_t align,
			       int (*shm_register)(struct tee_context *ctx,
			       int (*shm_register)(struct tee_context *ctx,
						   struct tee_shm *shm,
						   struct tee_shm *shm,
						   struct page **pages,
						   struct page **pages,
Loading