1 /* 2 * Copyright (c) 2017, EPAM Systems 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, 9 * this list of conditions and the following disclaimer. 10 * 11 * 2. Redistributions in binary form must reproduce the above copyright notice, 12 * this list of conditions and the following disclaimer in the documentation 13 * and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 19 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 24 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 * POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28 #include <optee_msg.h> 29 #include <stdio.h> 30 #include <types_ext.h> 31 #include <kernel/msg_param.h> 32 #include <mm/mobj.h> 33 34 /** 35 * msg_param_extract_pages() - extract list of pages from 36 * OPTEE_MSG_ATTR_NONCONTIG buffer. 37 * 38 * @buffer: pointer to parameters array 39 * @pages: output array of page addresses 40 * @num_pages: number of pages in array 41 * 42 * return: 43 * true on success, false otherwise 44 * 45 * @buffer points to the physical address of a structure that can be viewed as 46 * 47 * struct page_data { 48 * uint64_t pages_array[OPTEE_MSG_NONCONTIG_PAGE_SIZE/sizeof(uint64_t) - 1]; 49 * uint64_t next_page_data; 50 * }; 51 * 52 * So, it is a linked list of arrays, where each element of linked list fits 53 * exactly into one 4K page. 54 * 55 * This function extracts data from arrays into one array pointed by @pages 56 * 57 * @buffer points to data shared with normal world, so some precautions 58 * should be taken. 59 */ 60 static bool msg_param_extract_pages(paddr_t buffer, paddr_t *pages, 61 size_t num_pages) 62 { 63 size_t cnt; 64 struct mobj *mobj; 65 paddr_t page; 66 uint64_t *va; 67 bool ret = false; 68 69 if (buffer & SMALL_PAGE_MASK) 70 return false; 71 72 /* 73 * There we map first page of array. 74 * mobj_mapped_shm_alloc() will check if page resides in nonsec ddr 75 */ 76 mobj = mobj_mapped_shm_alloc(&buffer, 1, 0, 0); 77 if (!mobj) 78 return false; 79 80 va = mobj_get_va(mobj, 0); 81 assert(va); 82 83 for (cnt = 0; cnt < num_pages; cnt++, va++) { 84 /* 85 * If we about to roll over page boundary, then last entry holds 86 * address of next page of array. Unmap current page and map 87 * next one 88 */ 89 if (!((vaddr_t)(va + 1) & SMALL_PAGE_MASK)) { 90 page = *va; 91 if (page & SMALL_PAGE_MASK) 92 goto out; 93 94 mobj_free(mobj); 95 mobj = mobj_mapped_shm_alloc(&page, 1, 0, 0); 96 if (!mobj) 97 goto out; 98 99 va = mobj_get_va(mobj, 0); 100 assert(va); 101 } 102 pages[cnt] = *va; 103 if (pages[cnt] & SMALL_PAGE_MASK) 104 goto out; 105 } 106 107 ret = true; 108 out: 109 mobj_free(mobj); 110 return ret; 111 } 112 113 struct mobj *msg_param_mobj_from_noncontig(const struct optee_msg_param *param, 114 bool map_buffer) 115 { 116 struct mobj *mobj = NULL; 117 paddr_t *pages; 118 paddr_t page_offset; 119 size_t num_pages; 120 uint64_t buf_ptr; 121 122 assert(param->attr & OPTEE_MSG_ATTR_NONCONTIG); 123 124 /* Make sure that NW will not change value in SHM */ 125 buf_ptr = param->u.tmem.buf_ptr; 126 127 page_offset = buf_ptr & SMALL_PAGE_MASK; 128 num_pages = (param->u.tmem.size + page_offset - 1) / 129 SMALL_PAGE_SIZE + 1; 130 131 pages = malloc(num_pages * sizeof(paddr_t)); 132 if (!pages) 133 return NULL; 134 135 if (!msg_param_extract_pages(buf_ptr & ~SMALL_PAGE_MASK, 136 pages, num_pages)) 137 goto out; 138 139 if (map_buffer) 140 mobj = mobj_mapped_shm_alloc(pages, num_pages, page_offset, 141 param->u.tmem.shm_ref); 142 else 143 mobj = mobj_reg_shm_alloc(pages, num_pages, page_offset, 144 param->u.tmem.shm_ref); 145 out: 146 free(pages); 147 return mobj; 148 } 149 150 bool msg_param_init_memparam(struct optee_msg_param *param, struct mobj *mobj, 151 size_t offset, size_t size, 152 uint64_t cookie, enum msg_param_mem_dir dir) 153 { 154 if (mobj_matches(mobj, CORE_MEM_REG_SHM)) { 155 /* Registered SHM mobj */ 156 switch (dir) { 157 case MSG_PARAM_MEM_DIR_IN: 158 param->attr = OPTEE_MSG_ATTR_TYPE_RMEM_INPUT; 159 break; 160 case MSG_PARAM_MEM_DIR_OUT: 161 param->attr = OPTEE_MSG_ATTR_TYPE_RMEM_OUTPUT; 162 break; 163 case MSG_PARAM_MEM_DIR_INOUT: 164 param->attr = OPTEE_MSG_ATTR_TYPE_RMEM_INOUT; 165 break; 166 default: 167 return false; 168 } 169 170 param->u.rmem.size = size; 171 param->u.rmem.offs = offset; 172 param->u.rmem.shm_ref = cookie; 173 } else if (mobj_matches(mobj, CORE_MEM_NSEC_SHM)) { 174 /* MOBJ from from predefined pool */ 175 paddr_t pa; 176 177 if (mobj_get_pa(mobj, 0, 0, &pa) != TEE_SUCCESS) 178 return false; 179 180 switch (dir) { 181 case MSG_PARAM_MEM_DIR_IN: 182 param->attr = OPTEE_MSG_ATTR_TYPE_TMEM_INPUT; 183 break; 184 case MSG_PARAM_MEM_DIR_OUT: 185 param->attr = OPTEE_MSG_ATTR_TYPE_TMEM_OUTPUT; 186 break; 187 case MSG_PARAM_MEM_DIR_INOUT: 188 param->attr = OPTEE_MSG_ATTR_TYPE_TMEM_INOUT; 189 break; 190 default: 191 return false; 192 } 193 194 param->u.tmem.buf_ptr = pa + offset; 195 param->u.tmem.shm_ref = cookie; 196 param->u.tmem.size = size; 197 } else 198 return false; 199 return true; 200 } 201