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 34*e7a8839bSVolodymyr Babchuk /** 35*e7a8839bSVolodymyr Babchuk * msg_param_extract_pages() - extract list of pages from 36*e7a8839bSVolodymyr Babchuk * OPTEE_MSG_ATTR_NONCONTIG buffer. 37*e7a8839bSVolodymyr Babchuk * 38*e7a8839bSVolodymyr Babchuk * @buffer: pointer to parameters array 39*e7a8839bSVolodymyr Babchuk * @pages: output array of page addresses 40*e7a8839bSVolodymyr Babchuk * @num_pages: number of pages in array 41*e7a8839bSVolodymyr Babchuk * 42*e7a8839bSVolodymyr Babchuk * return: 43*e7a8839bSVolodymyr Babchuk * true on success, false otherwise 44*e7a8839bSVolodymyr Babchuk * 45*e7a8839bSVolodymyr Babchuk * @buffer points to the physical address of a structure that can be viewed as 46*e7a8839bSVolodymyr Babchuk * 47*e7a8839bSVolodymyr Babchuk * struct page_data { 48*e7a8839bSVolodymyr Babchuk * uint64_t pages_array[OPTEE_MSG_NONCONTIG_PAGE_SIZE/sizeof(uint64_t) - 1]; 49*e7a8839bSVolodymyr Babchuk * uint64_t next_page_data; 50*e7a8839bSVolodymyr Babchuk * }; 51*e7a8839bSVolodymyr Babchuk * 52*e7a8839bSVolodymyr Babchuk * So, it is a linked list of arrays, where each element of linked list fits 53*e7a8839bSVolodymyr Babchuk * exactly into one 4K page. 54*e7a8839bSVolodymyr Babchuk * 55*e7a8839bSVolodymyr Babchuk * This function extracts data from arrays into one array pointed by @pages 56*e7a8839bSVolodymyr Babchuk * 57*e7a8839bSVolodymyr Babchuk * @buffer points to data shared with normal world, so some precautions 58*e7a8839bSVolodymyr Babchuk * should be taken. 59*e7a8839bSVolodymyr Babchuk */ 60*e7a8839bSVolodymyr Babchuk static bool msg_param_extract_pages(paddr_t buffer, paddr_t *pages, 61*e7a8839bSVolodymyr Babchuk size_t num_pages) 62*e7a8839bSVolodymyr Babchuk { 63*e7a8839bSVolodymyr Babchuk size_t cnt; 64*e7a8839bSVolodymyr Babchuk struct mobj *mobj; 65*e7a8839bSVolodymyr Babchuk paddr_t page; 66*e7a8839bSVolodymyr Babchuk uint64_t *va; 67*e7a8839bSVolodymyr Babchuk bool ret = false; 68*e7a8839bSVolodymyr Babchuk 69*e7a8839bSVolodymyr Babchuk if (buffer & SMALL_PAGE_MASK) 70*e7a8839bSVolodymyr Babchuk return false; 71*e7a8839bSVolodymyr Babchuk 72*e7a8839bSVolodymyr Babchuk /* 73*e7a8839bSVolodymyr Babchuk * There we map first page of array. 74*e7a8839bSVolodymyr Babchuk * mobj_mapped_shm_alloc() will check if page resides in nonsec ddr 75*e7a8839bSVolodymyr Babchuk */ 76*e7a8839bSVolodymyr Babchuk mobj = mobj_mapped_shm_alloc(&buffer, 1, 0, 0); 77*e7a8839bSVolodymyr Babchuk if (!mobj) 78*e7a8839bSVolodymyr Babchuk return false; 79*e7a8839bSVolodymyr Babchuk 80*e7a8839bSVolodymyr Babchuk va = mobj_get_va(mobj, 0); 81*e7a8839bSVolodymyr Babchuk assert(va); 82*e7a8839bSVolodymyr Babchuk 83*e7a8839bSVolodymyr Babchuk for (cnt = 0; cnt < num_pages; cnt++, va++) { 84*e7a8839bSVolodymyr Babchuk /* 85*e7a8839bSVolodymyr Babchuk * If we about to roll over page boundary, then last entry holds 86*e7a8839bSVolodymyr Babchuk * address of next page of array. Unmap current page and map 87*e7a8839bSVolodymyr Babchuk * next one 88*e7a8839bSVolodymyr Babchuk */ 89*e7a8839bSVolodymyr Babchuk if (!((vaddr_t)(va + 1) & SMALL_PAGE_MASK)) { 90*e7a8839bSVolodymyr Babchuk page = *va; 91*e7a8839bSVolodymyr Babchuk if (page & SMALL_PAGE_MASK) 92*e7a8839bSVolodymyr Babchuk goto out; 93*e7a8839bSVolodymyr Babchuk 94*e7a8839bSVolodymyr Babchuk mobj_free(mobj); 95*e7a8839bSVolodymyr Babchuk mobj = mobj_mapped_shm_alloc(&page, 1, 0, 0); 96*e7a8839bSVolodymyr Babchuk if (!mobj) 97*e7a8839bSVolodymyr Babchuk goto out; 98*e7a8839bSVolodymyr Babchuk 99*e7a8839bSVolodymyr Babchuk va = mobj_get_va(mobj, 0); 100*e7a8839bSVolodymyr Babchuk assert(va); 101*e7a8839bSVolodymyr Babchuk } 102*e7a8839bSVolodymyr Babchuk pages[cnt] = *va; 103*e7a8839bSVolodymyr Babchuk if (pages[cnt] & SMALL_PAGE_MASK) 104*e7a8839bSVolodymyr Babchuk goto out; 105*e7a8839bSVolodymyr Babchuk } 106*e7a8839bSVolodymyr Babchuk 107*e7a8839bSVolodymyr Babchuk ret = true; 108*e7a8839bSVolodymyr Babchuk out: 109*e7a8839bSVolodymyr Babchuk mobj_free(mobj); 110*e7a8839bSVolodymyr Babchuk return ret; 111*e7a8839bSVolodymyr Babchuk } 112*e7a8839bSVolodymyr Babchuk 113*e7a8839bSVolodymyr Babchuk struct mobj *msg_param_mobj_from_noncontig(const struct optee_msg_param *param, 114*e7a8839bSVolodymyr Babchuk bool map_buffer) 115*e7a8839bSVolodymyr Babchuk { 116*e7a8839bSVolodymyr Babchuk struct mobj *mobj = NULL; 117*e7a8839bSVolodymyr Babchuk paddr_t *pages; 118*e7a8839bSVolodymyr Babchuk paddr_t page_offset; 119*e7a8839bSVolodymyr Babchuk size_t num_pages; 120*e7a8839bSVolodymyr Babchuk uint64_t buf_ptr; 121*e7a8839bSVolodymyr Babchuk 122*e7a8839bSVolodymyr Babchuk assert(param->attr & OPTEE_MSG_ATTR_NONCONTIG); 123*e7a8839bSVolodymyr Babchuk 124*e7a8839bSVolodymyr Babchuk /* Make sure that NW will not change value in SHM */ 125*e7a8839bSVolodymyr Babchuk buf_ptr = param->u.tmem.buf_ptr; 126*e7a8839bSVolodymyr Babchuk 127*e7a8839bSVolodymyr Babchuk page_offset = buf_ptr & SMALL_PAGE_MASK; 128*e7a8839bSVolodymyr Babchuk num_pages = (param->u.tmem.size + page_offset - 1) / 129*e7a8839bSVolodymyr Babchuk SMALL_PAGE_SIZE + 1; 130*e7a8839bSVolodymyr Babchuk 131*e7a8839bSVolodymyr Babchuk pages = malloc(num_pages * sizeof(paddr_t)); 132*e7a8839bSVolodymyr Babchuk if (!pages) 133*e7a8839bSVolodymyr Babchuk return NULL; 134*e7a8839bSVolodymyr Babchuk 135*e7a8839bSVolodymyr Babchuk if (!msg_param_extract_pages(buf_ptr & ~SMALL_PAGE_MASK, 136*e7a8839bSVolodymyr Babchuk pages, num_pages)) 137*e7a8839bSVolodymyr Babchuk goto out; 138*e7a8839bSVolodymyr Babchuk 139*e7a8839bSVolodymyr Babchuk if (map_buffer) 140*e7a8839bSVolodymyr Babchuk mobj = mobj_mapped_shm_alloc(pages, num_pages, page_offset, 141*e7a8839bSVolodymyr Babchuk param->u.tmem.shm_ref); 142*e7a8839bSVolodymyr Babchuk else 143*e7a8839bSVolodymyr Babchuk mobj = mobj_reg_shm_alloc(pages, num_pages, page_offset, 144*e7a8839bSVolodymyr Babchuk param->u.tmem.shm_ref); 145*e7a8839bSVolodymyr Babchuk out: 146*e7a8839bSVolodymyr Babchuk free(pages); 147*e7a8839bSVolodymyr Babchuk return mobj; 148*e7a8839bSVolodymyr Babchuk } 149*e7a8839bSVolodymyr Babchuk 15050f24313SVolodymyr Babchuk bool msg_param_init_memparam(struct optee_msg_param *param, struct mobj *mobj, 15150f24313SVolodymyr Babchuk size_t offset, size_t size, 15250f24313SVolodymyr Babchuk uint64_t cookie, enum msg_param_mem_dir dir) 15350f24313SVolodymyr Babchuk { 15450f24313SVolodymyr Babchuk if (mobj_matches(mobj, CORE_MEM_REG_SHM)) { 15550f24313SVolodymyr Babchuk /* Registered SHM mobj */ 15650f24313SVolodymyr Babchuk switch (dir) { 15750f24313SVolodymyr Babchuk case MSG_PARAM_MEM_DIR_IN: 15850f24313SVolodymyr Babchuk param->attr = OPTEE_MSG_ATTR_TYPE_RMEM_INPUT; 15950f24313SVolodymyr Babchuk break; 16050f24313SVolodymyr Babchuk case MSG_PARAM_MEM_DIR_OUT: 16150f24313SVolodymyr Babchuk param->attr = OPTEE_MSG_ATTR_TYPE_RMEM_OUTPUT; 16250f24313SVolodymyr Babchuk break; 16350f24313SVolodymyr Babchuk case MSG_PARAM_MEM_DIR_INOUT: 16450f24313SVolodymyr Babchuk param->attr = OPTEE_MSG_ATTR_TYPE_RMEM_INOUT; 16550f24313SVolodymyr Babchuk break; 16650f24313SVolodymyr Babchuk default: 16750f24313SVolodymyr Babchuk return false; 16850f24313SVolodymyr Babchuk } 16950f24313SVolodymyr Babchuk 17050f24313SVolodymyr Babchuk param->u.rmem.size = size; 17150f24313SVolodymyr Babchuk param->u.rmem.offs = offset; 17250f24313SVolodymyr Babchuk param->u.rmem.shm_ref = cookie; 17350f24313SVolodymyr Babchuk } else if (mobj_matches(mobj, CORE_MEM_NSEC_SHM)) { 17450f24313SVolodymyr Babchuk /* MOBJ from from predefined pool */ 17550f24313SVolodymyr Babchuk paddr_t pa; 17650f24313SVolodymyr Babchuk 17750f24313SVolodymyr Babchuk if (mobj_get_pa(mobj, 0, 0, &pa) != TEE_SUCCESS) 17850f24313SVolodymyr Babchuk return false; 17950f24313SVolodymyr Babchuk 18050f24313SVolodymyr Babchuk switch (dir) { 18150f24313SVolodymyr Babchuk case MSG_PARAM_MEM_DIR_IN: 18250f24313SVolodymyr Babchuk param->attr = OPTEE_MSG_ATTR_TYPE_TMEM_INPUT; 18350f24313SVolodymyr Babchuk break; 18450f24313SVolodymyr Babchuk case MSG_PARAM_MEM_DIR_OUT: 18550f24313SVolodymyr Babchuk param->attr = OPTEE_MSG_ATTR_TYPE_TMEM_OUTPUT; 18650f24313SVolodymyr Babchuk break; 18750f24313SVolodymyr Babchuk case MSG_PARAM_MEM_DIR_INOUT: 18850f24313SVolodymyr Babchuk param->attr = OPTEE_MSG_ATTR_TYPE_TMEM_INOUT; 18950f24313SVolodymyr Babchuk break; 19050f24313SVolodymyr Babchuk default: 19150f24313SVolodymyr Babchuk return false; 19250f24313SVolodymyr Babchuk } 19350f24313SVolodymyr Babchuk 19450f24313SVolodymyr Babchuk param->u.tmem.buf_ptr = pa + offset; 19550f24313SVolodymyr Babchuk param->u.tmem.shm_ref = cookie; 19650f24313SVolodymyr Babchuk param->u.tmem.size = size; 19750f24313SVolodymyr Babchuk } else 19850f24313SVolodymyr Babchuk return false; 19950f24313SVolodymyr Babchuk return true; 20050f24313SVolodymyr Babchuk } 201