gpoulios commented on code in PR #16309: URL: https://github.com/apache/nuttx/pull/16309#discussion_r2074777223
########## drivers/misc/optee.c: ########## @@ -145,10 +207,398 @@ static bool optee_safe_va_range(FAR void *va, size_t size) return false; } -#else +#else /* !CONFIG_ARCH_ADDRENV */ +static uintptr_t optee_va_to_pa(FAR void *va) +{ + return (uintptr_t)va; +} + #define optee_safe_va_range(addr, size) (true) #endif +/**************************************************************************** + * Name: optee_shm_to_page_list + * + * Description: + * Provide a page list of a shared memory buffer. Secure world doesn't + * know about the address environment mapping of NuttX, so physical + * pointers are needed when sharing memory. This implementation enables + * sharing of physically non-contiguous buffers according to + * optee_msg.h#OPTEE_MSG_ATTR_NONCONTIG. + * Each entry in the generated page list is an array of the physical, + * potentially non-contiguous pages making up the actual buffer to + * represent. Note that this representation does not account for the page + * offset of the shared memory buffer. The offset is encoded in the + * physical address returned in `list_pa_p`. + * + * Parameters: + * shme - Shared memory entry to create a page list for. + * list_pa_p - If not NULL, will be set to the page list's physical + * address (which is aligned to + * OPTEE_MSG_NONCONTIG_PAGE_SIZE) added with shared memory + * page offset. + * + * Returned Values: + * A pointer to the kernel virtual address of the page list on success. + * NULL on failure. Caller responsible to free the returned list using + * `kmm_free()`. + * + ****************************************************************************/ + +FAR void *optee_shm_to_page_list(FAR struct optee_shm_entry *shme, + FAR uintptr_t *list_pa_p) +{ + const size_t pgsize = OPTEE_MSG_NONCONTIG_PAGE_SIZE; + uintptr_t shm_pgoff; + uintptr_t shm_page; + uint32_t shm_total_pages; + uint32_t list_size; + FAR void *list; + FAR struct page_list_entry *list_entry; + uint32_t i; + + shm_pgoff = shme->shm.addr & (pgsize - 1); + shm_total_pages = (uint32_t) + (ALIGN_UP(shm_pgoff + shme->shm.length, pgsize) / pgsize); + list_size = div_round_up(shm_total_pages, PAGES_ARRAY_LEN) * pgsize; + + /* Page list's address should be page aligned, conveniently leaving + * log2(<page size>) zero least-significant bits to use as the page + * offset of the shm buffer (added last before return below). + */ + + list = kmm_memalign(pgsize, list_size); + if (!list) + { + return NULL; + } + + list_entry = (FAR struct page_list_entry *)list; + shm_page = ALIGN_DOWN(shme->shm.addr, pgsize); + i = 0; + while (shm_total_pages) + { + list_entry->pages_array[i++] = optee_va_to_pa((FAR void *)shm_page); + shm_page += pgsize; + shm_total_pages--; + + if (i == PAGES_ARRAY_LEN) + { + list_entry->next_page_data = optee_va_to_pa(list_entry + 1); + list_entry++; + i = 0; + } + } + + if (list_pa_p) + { + *list_pa_p = optee_va_to_pa(list) | shm_pgoff; + } + + return list; +} + +/**************************************************************************** + * Name: optee_shm_sec_register + * + * Description: + * Register specified shared memory entry with OP-TEE. + * + * Parameters: + * priv - The driver's private data structure + * shme - Pointer to shared memory entry to register. The entry, the + * contained shared memory object, or the referenced shared buffer + * cannot be NULL. + * + * Returned Values: + * 0 on success, negative error code otherwise. + * + ****************************************************************************/ + +static int optee_shm_sec_register(FAR struct optee_priv_data *priv, + FAR struct optee_shm_entry *shme) +{ + FAR struct optee_shm_entry *msg_shme; + FAR struct optee_msg_arg *msg; + FAR void *page_list; + uintptr_t page_list_pa; + int ret = 0; + + msg = optee_shm_alloc_msg(priv, 1, &msg_shme); + if (msg == NULL) + { + return -ENOMEM; + } + + page_list = optee_shm_to_page_list(shme, &page_list_pa); + if (page_list == NULL) + { + ret = -ENOMEM; + goto errout_with_msg; + } + + msg->cmd = OPTEE_MSG_CMD_REGISTER_SHM; + msg->params[0].attr = OPTEE_MSG_ATTR_TYPE_TMEM_OUTPUT | + OPTEE_MSG_ATTR_NONCONTIG; + msg->params[0].u.tmem.buf_ptr = page_list_pa; + msg->params[0].u.tmem.shm_ref = shme->shm.addr; + msg->params[0].u.tmem.size = shme->shm.length; + + if (optee_transport_call(priv, msg) || msg->ret) + { + ret = -EINVAL; + } + + kmm_free(page_list); + +errout_with_msg: + optee_shm_free(msg_shme); + + return ret; +} + +/**************************************************************************** + * Name: optee_shm_sec_unregister + * + * Description: + * Unregister specified shared memory entry with OP-TEE. + * + * Parameters: + * priv - the driver's private data structure + * shme - Pointer to shared memory entry to unregister. The shared + * memory entry must have been previously registered previously + * with the OP-TEE and cannot be NULL. + * + * Returned Values: + * 0 on success, negative error code otherwise. + * + ****************************************************************************/ + +static int optee_shm_sec_unregister(FAR struct optee_priv_data *priv, + FAR struct optee_shm_entry *shme) +{ + FAR struct optee_shm_entry *msg_shme; + FAR struct optee_msg_arg *msg; + int ret = 0; + + msg = optee_shm_alloc_msg(priv, 1, &msg_shme); + if (msg == NULL) + { + return -ENOMEM; + } + + msg->cmd = OPTEE_MSG_CMD_UNREGISTER_SHM; + msg->params[0].attr = OPTEE_MSG_ATTR_TYPE_RMEM_INPUT; + msg->params[0].u.rmem.shm_ref = shme->shm.addr; + + if (optee_transport_call(priv, msg) || msg->ret) + { + ret = -EINVAL; + } + + optee_shm_free(msg_shme); + + return ret; +} + +/**************************************************************************** + * Name: optee_shm_alloc + * + * Description: + * Allocate, register and/or add shared memory for use with OP-TEE calls. + * Shared memory entry suitable for use in shared memory linked list + * returned in pass-by-reference `shmep` pointer. This function always + * allocates a shared memory entry, regardless of flags. The rest of this + * function's behaviour is largely determined by `flags`: + * - If `TEE_SHM_ALLOC` is specified, then a buffer of length `size` and + * alignment `align` will be allocated. In this case `addr` will be + * ignored. This flag is reserved for kernel use only. + * - If `TEE_SHM_SEC_REGISTER` is specified, then the memory specified by + * `addr` or allocated through `TEE_SHM_ALLOC`, will be registered with + * OP-TEE as dynamic shared memory. + * - If `TEE_SHM_REGISTER` is specified, then the memory specified by + * `addr` or allocated through `TEE_SHM_ALLOC`, will be added to the + * driver's private data structure linked list of shared memory chunks. + * + * Use `optee_shm_free()` to undo this operation, i.e. to free, + * unregister, and/or remove from the list the entry returned in `shmep` + * and the contained buffer. + * + * Parameters: + * priv - the driver's private data structure + * align - the desired alignment for the shared memory to allocate. + * Ignored when `flags` do not specify `TEE_SHM_ALLOC`. + * addr - the address of the shared memory to register with OP-TEE and/or + * add to the driver's linked list of shared memory chunks. + * size - the size of the shared memory buffer to allocate/add/register. + * flags - flags specifying the behaviour of this function. Supports + * combinations of `TEE_SHM_{ALLOC,REGISTER,SEC_REGISTER}`. + * shmep - Pass-by-reference pointer to return the shared memory entry + * allocated. Cannot be NULL. + * + * Returned Values: + * 0 on success, negative error code otherwise. + * + ****************************************************************************/ + +static int optee_shm_alloc(FAR struct optee_priv_data *priv, uintptr_t align, + FAR void *addr, size_t size, uint32_t flags, + FAR struct optee_shm_entry **shmep) +{ + FAR struct optee_shm_entry *shme; + FAR void *ptr; + int ret; + + shme = (FAR struct optee_shm_entry *) + kmm_zalloc(sizeof(struct optee_shm_entry)); + if (shme == NULL) + { + return -ENOMEM; + } + + if (flags & TEE_SHM_ALLOC) + { + if (align) + { + ptr = kmm_memalign(align, size); + } + else + { + ptr = kmm_malloc(size); + } + } + else + { + ptr = addr; + } + + if (ptr == NULL) + { + ret = -ENOMEM; + goto err; + } + + shme->priv = priv; Review Comment: Only for being able to call `optee_shm_free()` without it. I will remove it. -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: commits-unsubscr...@nuttx.apache.org For queries about this service, please contact Infrastructure at: us...@infra.apache.org