aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVolodymyr Babchuk <vlad.babchuk@gmail.com>2017-06-15 23:28:44 +0300
committerJérôme Forissier <jerome.forissier@linaro.org>2017-06-22 13:51:38 +0200
commite7a8839b3e0658a7deb6f980c8d73f3355533054 (patch)
treef1884202c791468c75fd0b036c808b24ec48deb6
parent13f187f4c19a1b4c1c8f2028c8aed4bb11bb5e69 (diff)
ABI change: add OPTEE_MSG_ATTR_NONCONTIG handling
This patch introduces new attribute OPTEE_MSG_ATTR_NONCONTIG to allow Normal World pass arbitrary list of physical pages as a shared buffer. To read this list of page address two new functions are added: - msg_param_extract_pages() is a helper function that read pages list into provided array - msg_param_mobj_from_noncontig_param() constructs mobj from provided struct optee_msg_param parameter. This mobj then can be used in various parts of OP-TEE Signed-off-by: Volodymyr Babchuk <vlad.babchuk@gmail.com> Reviewed-by: Jens Wiklander <jens.wiklander@linaro.org> Reviewed-by: Etienne Carriere <etienne.carriere@linaro.org>
-rw-r--r--core/arch/arm/tee/entry_std.c2
-rw-r--r--core/include/kernel/msg_param.h13
-rw-r--r--core/include/optee_msg.h34
-rw-r--r--core/kernel/msg_param.c116
4 files changed, 160 insertions, 5 deletions
diff --git a/core/arch/arm/tee/entry_std.c b/core/arch/arm/tee/entry_std.c
index 615cf58d..08d11677 100644
--- a/core/arch/arm/tee/entry_std.c
+++ b/core/arch/arm/tee/entry_std.c
@@ -111,7 +111,7 @@ static TEE_Result copy_in_params(const struct optee_msg_param *params,
if (params[n].attr & OPTEE_MSG_ATTR_META)
return TEE_ERROR_BAD_PARAMETERS;
- if (params[n].attr & OPTEE_MSG_ATTR_FRAGMENT)
+ if (params[n].attr & OPTEE_MSG_ATTR_NONCONTIG)
return TEE_ERROR_BAD_PARAMETERS;
attr = params[n].attr & OPTEE_MSG_ATTR_TYPE_MASK;
diff --git a/core/include/kernel/msg_param.h b/core/include/kernel/msg_param.h
index feef4ae2..99051676 100644
--- a/core/include/kernel/msg_param.h
+++ b/core/include/kernel/msg_param.h
@@ -45,6 +45,19 @@ enum msg_param_mem_dir {
};
/**
+ * msg_param_mobj_from_noncontig() - construct mobj from non-contiguous
+ * list of pages.
+ *
+ * @param - pointer to msg_param with OPTEE_MSG_ATTR_NONCONTIG flag set
+ * @map_buffer - true if buffer needs to be mapped into OP-TEE address space
+ *
+ * return:
+ * mobj or NULL on error
+ */
+struct mobj *msg_param_mobj_from_noncontig(const struct optee_msg_param *param,
+ bool map_buffer);
+
+/**
* msg_param_init_memparam() - fill memory reference parameter for RPC call
* @param - parameter to fill
* @mobj - mobj describing the shared memory buffer
diff --git a/core/include/optee_msg.h b/core/include/optee_msg.h
index ddc3110c..30ec0bbf 100644
--- a/core/include/optee_msg.h
+++ b/core/include/optee_msg.h
@@ -68,11 +68,32 @@
#define OPTEE_MSG_ATTR_META BIT(8)
/*
- * The temporary shared memory object is not physically contiguous and this
- * temp memref is followed by another fragment until the last temp memref
- * that doesn't have this bit set.
+ * Pointer to a list of pages used to register user-defined SHM buffer.
+ * Used with OPTEE_MSG_ATTR_TYPE_TMEM_*.
+ * buf_ptr should point to the beginning of the buffer. Buffer will contain
+ * list of page addresses. OP-TEE core can reconstruct contiguous buffer from
+ * that page addresses list. Page addresses are stored as 64 bit values.
+ * Last entry on a page should point to the next page of buffer.
+ * Every entry in buffer should point to a 4k page beginning (12 least
+ * significant bits must be equal to zero).
+ *
+ * 12 least significant of optee_msg_param.u.tmem.buf_ptr should hold page
+ * offset of user buffer.
+ *
+ * So, entries should be placed like members of this structure:
+ *
+ * struct page_data {
+ * uint64_t pages_array[OPTEE_MSG_NONCONTIG_PAGE_SIZE/sizeof(uint64_t) - 1];
+ * uint64_t next_page_data;
+ * };
+ *
+ * Structure is designed to exactly fit into the page size
+ * OPTEE_MSG_NONCONTIG_PAGE_SIZE which is a standard 4KB page.
+ *
+ * The size of 4KB is chosen because this is the smallest page size for ARM
+ * architectures. If REE uses larger pages, it should divide them to 4KB ones.
*/
-#define OPTEE_MSG_ATTR_FRAGMENT BIT(9)
+#define OPTEE_MSG_ATTR_NONCONTIG BIT(9)
/*
* Memory attributes for caching passed with temp memrefs. The actual value
@@ -95,6 +116,11 @@
#define OPTEE_MSG_LOGIN_APPLICATION_USER 0x00000005
#define OPTEE_MSG_LOGIN_APPLICATION_GROUP 0x00000006
+/*
+ * Page size used in non-contiguous buffer entries
+ */
+#define OPTEE_MSG_NONCONTIG_PAGE_SIZE 4096
+
#ifndef ASM
/**
* struct optee_msg_param_tmem - temporary memory reference parameter
diff --git a/core/kernel/msg_param.c b/core/kernel/msg_param.c
index 71b9f22a..bc4683f7 100644
--- a/core/kernel/msg_param.c
+++ b/core/kernel/msg_param.c
@@ -31,6 +31,122 @@
#include <kernel/msg_param.h>
#include <mm/mobj.h>
+/**
+ * msg_param_extract_pages() - extract list of pages from
+ * OPTEE_MSG_ATTR_NONCONTIG buffer.
+ *
+ * @buffer: pointer to parameters array
+ * @pages: output array of page addresses
+ * @num_pages: number of pages in array
+ *
+ * return:
+ * true on success, false otherwise
+ *
+ * @buffer points to the physical address of a structure that can be viewed as
+ *
+ * struct page_data {
+ * uint64_t pages_array[OPTEE_MSG_NONCONTIG_PAGE_SIZE/sizeof(uint64_t) - 1];
+ * uint64_t next_page_data;
+ * };
+ *
+ * So, it is a linked list of arrays, where each element of linked list fits
+ * exactly into one 4K page.
+ *
+ * This function extracts data from arrays into one array pointed by @pages
+ *
+ * @buffer points to data shared with normal world, so some precautions
+ * should be taken.
+ */
+static bool msg_param_extract_pages(paddr_t buffer, paddr_t *pages,
+ size_t num_pages)
+{
+ size_t cnt;
+ struct mobj *mobj;
+ paddr_t page;
+ uint64_t *va;
+ bool ret = false;
+
+ if (buffer & SMALL_PAGE_MASK)
+ return false;
+
+ /*
+ * There we map first page of array.
+ * mobj_mapped_shm_alloc() will check if page resides in nonsec ddr
+ */
+ mobj = mobj_mapped_shm_alloc(&buffer, 1, 0, 0);
+ if (!mobj)
+ return false;
+
+ va = mobj_get_va(mobj, 0);
+ assert(va);
+
+ for (cnt = 0; cnt < num_pages; cnt++, va++) {
+ /*
+ * If we about to roll over page boundary, then last entry holds
+ * address of next page of array. Unmap current page and map
+ * next one
+ */
+ if (!((vaddr_t)(va + 1) & SMALL_PAGE_MASK)) {
+ page = *va;
+ if (page & SMALL_PAGE_MASK)
+ goto out;
+
+ mobj_free(mobj);
+ mobj = mobj_mapped_shm_alloc(&page, 1, 0, 0);
+ if (!mobj)
+ goto out;
+
+ va = mobj_get_va(mobj, 0);
+ assert(va);
+ }
+ pages[cnt] = *va;
+ if (pages[cnt] & SMALL_PAGE_MASK)
+ goto out;
+ }
+
+ ret = true;
+out:
+ mobj_free(mobj);
+ return ret;
+}
+
+struct mobj *msg_param_mobj_from_noncontig(const struct optee_msg_param *param,
+ bool map_buffer)
+{
+ struct mobj *mobj = NULL;
+ paddr_t *pages;
+ paddr_t page_offset;
+ size_t num_pages;
+ uint64_t buf_ptr;
+
+ assert(param->attr & OPTEE_MSG_ATTR_NONCONTIG);
+
+ /* Make sure that NW will not change value in SHM */
+ buf_ptr = param->u.tmem.buf_ptr;
+
+ page_offset = buf_ptr & SMALL_PAGE_MASK;
+ num_pages = (param->u.tmem.size + page_offset - 1) /
+ SMALL_PAGE_SIZE + 1;
+
+ pages = malloc(num_pages * sizeof(paddr_t));
+ if (!pages)
+ return NULL;
+
+ if (!msg_param_extract_pages(buf_ptr & ~SMALL_PAGE_MASK,
+ pages, num_pages))
+ goto out;
+
+ if (map_buffer)
+ mobj = mobj_mapped_shm_alloc(pages, num_pages, page_offset,
+ param->u.tmem.shm_ref);
+ else
+ mobj = mobj_reg_shm_alloc(pages, num_pages, page_offset,
+ param->u.tmem.shm_ref);
+out:
+ free(pages);
+ return mobj;
+}
+
bool msg_param_init_memparam(struct optee_msg_param *param, struct mobj *mobj,
size_t offset, size_t size,
uint64_t cookie, enum msg_param_mem_dir dir)