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