150f24313SVolodymyr Babchuk /* 250f24313SVolodymyr Babchuk * Copyright (c) 2017, EPAM Systems 350f24313SVolodymyr Babchuk * All rights reserved. 450f24313SVolodymyr Babchuk * 550f24313SVolodymyr Babchuk * Redistribution and use in source and binary forms, with or without 650f24313SVolodymyr Babchuk * modification, are permitted provided that the following conditions are met: 750f24313SVolodymyr Babchuk * 850f24313SVolodymyr Babchuk * 1. Redistributions of source code must retain the above copyright notice, 950f24313SVolodymyr Babchuk * this list of conditions and the following disclaimer. 1050f24313SVolodymyr Babchuk * 1150f24313SVolodymyr Babchuk * 2. Redistributions in binary form must reproduce the above copyright notice, 1250f24313SVolodymyr Babchuk * this list of conditions and the following disclaimer in the documentation 1350f24313SVolodymyr Babchuk * and/or other materials provided with the distribution. 1450f24313SVolodymyr Babchuk * 1550f24313SVolodymyr Babchuk * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 1650f24313SVolodymyr Babchuk * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1750f24313SVolodymyr Babchuk * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1850f24313SVolodymyr Babchuk * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 1950f24313SVolodymyr Babchuk * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 2050f24313SVolodymyr Babchuk * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 2150f24313SVolodymyr Babchuk * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 2250f24313SVolodymyr Babchuk * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 2350f24313SVolodymyr Babchuk * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 2450f24313SVolodymyr Babchuk * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 2550f24313SVolodymyr Babchuk * POSSIBILITY OF SUCH DAMAGE. 2650f24313SVolodymyr Babchuk */ 2750f24313SVolodymyr Babchuk 2850f24313SVolodymyr Babchuk #include <optee_msg.h> 2950f24313SVolodymyr Babchuk #include <stdio.h> 3050f24313SVolodymyr Babchuk #include <types_ext.h> 3150f24313SVolodymyr Babchuk #include <kernel/msg_param.h> 3250f24313SVolodymyr Babchuk #include <mm/mobj.h> 3350f24313SVolodymyr Babchuk 34e7a8839bSVolodymyr Babchuk /** 35e7a8839bSVolodymyr Babchuk * msg_param_extract_pages() - extract list of pages from 36e7a8839bSVolodymyr Babchuk * OPTEE_MSG_ATTR_NONCONTIG buffer. 37e7a8839bSVolodymyr Babchuk * 38e7a8839bSVolodymyr Babchuk * @buffer: pointer to parameters array 39e7a8839bSVolodymyr Babchuk * @pages: output array of page addresses 40e7a8839bSVolodymyr Babchuk * @num_pages: number of pages in array 41e7a8839bSVolodymyr Babchuk * 42e7a8839bSVolodymyr Babchuk * return: 43e7a8839bSVolodymyr Babchuk * true on success, false otherwise 44e7a8839bSVolodymyr Babchuk * 45e7a8839bSVolodymyr Babchuk * @buffer points to the physical address of a structure that can be viewed as 46e7a8839bSVolodymyr Babchuk * 47e7a8839bSVolodymyr Babchuk * struct page_data { 48e7a8839bSVolodymyr Babchuk * uint64_t pages_array[OPTEE_MSG_NONCONTIG_PAGE_SIZE/sizeof(uint64_t) - 1]; 49e7a8839bSVolodymyr Babchuk * uint64_t next_page_data; 50e7a8839bSVolodymyr Babchuk * }; 51e7a8839bSVolodymyr Babchuk * 52e7a8839bSVolodymyr Babchuk * So, it is a linked list of arrays, where each element of linked list fits 53e7a8839bSVolodymyr Babchuk * exactly into one 4K page. 54e7a8839bSVolodymyr Babchuk * 55e7a8839bSVolodymyr Babchuk * This function extracts data from arrays into one array pointed by @pages 56e7a8839bSVolodymyr Babchuk * 57e7a8839bSVolodymyr Babchuk * @buffer points to data shared with normal world, so some precautions 58e7a8839bSVolodymyr Babchuk * should be taken. 59e7a8839bSVolodymyr Babchuk */ 60e7a8839bSVolodymyr Babchuk static bool msg_param_extract_pages(paddr_t buffer, paddr_t *pages, 61e7a8839bSVolodymyr Babchuk size_t num_pages) 62e7a8839bSVolodymyr Babchuk { 63e7a8839bSVolodymyr Babchuk size_t cnt; 64e7a8839bSVolodymyr Babchuk struct mobj *mobj; 65e7a8839bSVolodymyr Babchuk paddr_t page; 66e7a8839bSVolodymyr Babchuk uint64_t *va; 67e7a8839bSVolodymyr Babchuk bool ret = false; 68e7a8839bSVolodymyr Babchuk 69e7a8839bSVolodymyr Babchuk if (buffer & SMALL_PAGE_MASK) 70e7a8839bSVolodymyr Babchuk return false; 71e7a8839bSVolodymyr Babchuk 72e7a8839bSVolodymyr Babchuk /* 73e7a8839bSVolodymyr Babchuk * There we map first page of array. 74e7a8839bSVolodymyr Babchuk * mobj_mapped_shm_alloc() will check if page resides in nonsec ddr 75e7a8839bSVolodymyr Babchuk */ 76e7a8839bSVolodymyr Babchuk mobj = mobj_mapped_shm_alloc(&buffer, 1, 0, 0); 77e7a8839bSVolodymyr Babchuk if (!mobj) 78e7a8839bSVolodymyr Babchuk return false; 79e7a8839bSVolodymyr Babchuk 80e7a8839bSVolodymyr Babchuk va = mobj_get_va(mobj, 0); 81e7a8839bSVolodymyr Babchuk assert(va); 82e7a8839bSVolodymyr Babchuk 83e7a8839bSVolodymyr Babchuk for (cnt = 0; cnt < num_pages; cnt++, va++) { 84e7a8839bSVolodymyr Babchuk /* 85e7a8839bSVolodymyr Babchuk * If we about to roll over page boundary, then last entry holds 86e7a8839bSVolodymyr Babchuk * address of next page of array. Unmap current page and map 87e7a8839bSVolodymyr Babchuk * next one 88e7a8839bSVolodymyr Babchuk */ 89e7a8839bSVolodymyr Babchuk if (!((vaddr_t)(va + 1) & SMALL_PAGE_MASK)) { 90e7a8839bSVolodymyr Babchuk page = *va; 91e7a8839bSVolodymyr Babchuk if (page & SMALL_PAGE_MASK) 92e7a8839bSVolodymyr Babchuk goto out; 93e7a8839bSVolodymyr Babchuk 94e7a8839bSVolodymyr Babchuk mobj_free(mobj); 95e7a8839bSVolodymyr Babchuk mobj = mobj_mapped_shm_alloc(&page, 1, 0, 0); 96e7a8839bSVolodymyr Babchuk if (!mobj) 97e7a8839bSVolodymyr Babchuk goto out; 98e7a8839bSVolodymyr Babchuk 99e7a8839bSVolodymyr Babchuk va = mobj_get_va(mobj, 0); 100e7a8839bSVolodymyr Babchuk assert(va); 101e7a8839bSVolodymyr Babchuk } 102e7a8839bSVolodymyr Babchuk pages[cnt] = *va; 103e7a8839bSVolodymyr Babchuk if (pages[cnt] & SMALL_PAGE_MASK) 104e7a8839bSVolodymyr Babchuk goto out; 105e7a8839bSVolodymyr Babchuk } 106e7a8839bSVolodymyr Babchuk 107e7a8839bSVolodymyr Babchuk ret = true; 108e7a8839bSVolodymyr Babchuk out: 109e7a8839bSVolodymyr Babchuk mobj_free(mobj); 110e7a8839bSVolodymyr Babchuk return ret; 111e7a8839bSVolodymyr Babchuk } 112e7a8839bSVolodymyr Babchuk 113*b05cd886SVolodymyr Babchuk struct mobj *msg_param_mobj_from_noncontig(paddr_t buf_ptr, size_t size, 114*b05cd886SVolodymyr Babchuk uint64_t shm_ref, bool map_buffer) 115e7a8839bSVolodymyr Babchuk { 116e7a8839bSVolodymyr Babchuk struct mobj *mobj = NULL; 117e7a8839bSVolodymyr Babchuk paddr_t *pages; 118e7a8839bSVolodymyr Babchuk paddr_t page_offset; 119e7a8839bSVolodymyr Babchuk size_t num_pages; 120e7a8839bSVolodymyr Babchuk 121e7a8839bSVolodymyr Babchuk page_offset = buf_ptr & SMALL_PAGE_MASK; 122*b05cd886SVolodymyr Babchuk num_pages = (size + page_offset - 1) / SMALL_PAGE_SIZE + 1; 123e7a8839bSVolodymyr Babchuk 124e7a8839bSVolodymyr Babchuk pages = malloc(num_pages * sizeof(paddr_t)); 125e7a8839bSVolodymyr Babchuk if (!pages) 126e7a8839bSVolodymyr Babchuk return NULL; 127e7a8839bSVolodymyr Babchuk 128e7a8839bSVolodymyr Babchuk if (!msg_param_extract_pages(buf_ptr & ~SMALL_PAGE_MASK, 129e7a8839bSVolodymyr Babchuk pages, num_pages)) 130e7a8839bSVolodymyr Babchuk goto out; 131e7a8839bSVolodymyr Babchuk 132e7a8839bSVolodymyr Babchuk if (map_buffer) 133e7a8839bSVolodymyr Babchuk mobj = mobj_mapped_shm_alloc(pages, num_pages, page_offset, 134*b05cd886SVolodymyr Babchuk shm_ref); 135e7a8839bSVolodymyr Babchuk else 136e7a8839bSVolodymyr Babchuk mobj = mobj_reg_shm_alloc(pages, num_pages, page_offset, 137*b05cd886SVolodymyr Babchuk shm_ref); 138e7a8839bSVolodymyr Babchuk out: 139e7a8839bSVolodymyr Babchuk free(pages); 140e7a8839bSVolodymyr Babchuk return mobj; 141e7a8839bSVolodymyr Babchuk } 142e7a8839bSVolodymyr Babchuk 14350f24313SVolodymyr Babchuk bool msg_param_init_memparam(struct optee_msg_param *param, struct mobj *mobj, 14450f24313SVolodymyr Babchuk size_t offset, size_t size, 14550f24313SVolodymyr Babchuk uint64_t cookie, enum msg_param_mem_dir dir) 14650f24313SVolodymyr Babchuk { 14750f24313SVolodymyr Babchuk if (mobj_matches(mobj, CORE_MEM_REG_SHM)) { 14850f24313SVolodymyr Babchuk /* Registered SHM mobj */ 14950f24313SVolodymyr Babchuk switch (dir) { 15050f24313SVolodymyr Babchuk case MSG_PARAM_MEM_DIR_IN: 15150f24313SVolodymyr Babchuk param->attr = OPTEE_MSG_ATTR_TYPE_RMEM_INPUT; 15250f24313SVolodymyr Babchuk break; 15350f24313SVolodymyr Babchuk case MSG_PARAM_MEM_DIR_OUT: 15450f24313SVolodymyr Babchuk param->attr = OPTEE_MSG_ATTR_TYPE_RMEM_OUTPUT; 15550f24313SVolodymyr Babchuk break; 15650f24313SVolodymyr Babchuk case MSG_PARAM_MEM_DIR_INOUT: 15750f24313SVolodymyr Babchuk param->attr = OPTEE_MSG_ATTR_TYPE_RMEM_INOUT; 15850f24313SVolodymyr Babchuk break; 15950f24313SVolodymyr Babchuk default: 16050f24313SVolodymyr Babchuk return false; 16150f24313SVolodymyr Babchuk } 16250f24313SVolodymyr Babchuk 16350f24313SVolodymyr Babchuk param->u.rmem.size = size; 16450f24313SVolodymyr Babchuk param->u.rmem.offs = offset; 16550f24313SVolodymyr Babchuk param->u.rmem.shm_ref = cookie; 16650f24313SVolodymyr Babchuk } else if (mobj_matches(mobj, CORE_MEM_NSEC_SHM)) { 16750f24313SVolodymyr Babchuk /* MOBJ from from predefined pool */ 16850f24313SVolodymyr Babchuk paddr_t pa; 16950f24313SVolodymyr Babchuk 17050f24313SVolodymyr Babchuk if (mobj_get_pa(mobj, 0, 0, &pa) != TEE_SUCCESS) 17150f24313SVolodymyr Babchuk return false; 17250f24313SVolodymyr Babchuk 17350f24313SVolodymyr Babchuk switch (dir) { 17450f24313SVolodymyr Babchuk case MSG_PARAM_MEM_DIR_IN: 17550f24313SVolodymyr Babchuk param->attr = OPTEE_MSG_ATTR_TYPE_TMEM_INPUT; 17650f24313SVolodymyr Babchuk break; 17750f24313SVolodymyr Babchuk case MSG_PARAM_MEM_DIR_OUT: 17850f24313SVolodymyr Babchuk param->attr = OPTEE_MSG_ATTR_TYPE_TMEM_OUTPUT; 17950f24313SVolodymyr Babchuk break; 18050f24313SVolodymyr Babchuk case MSG_PARAM_MEM_DIR_INOUT: 18150f24313SVolodymyr Babchuk param->attr = OPTEE_MSG_ATTR_TYPE_TMEM_INOUT; 18250f24313SVolodymyr Babchuk break; 18350f24313SVolodymyr Babchuk default: 18450f24313SVolodymyr Babchuk return false; 18550f24313SVolodymyr Babchuk } 18650f24313SVolodymyr Babchuk 18750f24313SVolodymyr Babchuk param->u.tmem.buf_ptr = pa + offset; 18850f24313SVolodymyr Babchuk param->u.tmem.shm_ref = cookie; 18950f24313SVolodymyr Babchuk param->u.tmem.size = size; 19050f24313SVolodymyr Babchuk } else 19150f24313SVolodymyr Babchuk return false; 19250f24313SVolodymyr Babchuk return true; 19350f24313SVolodymyr Babchuk } 194