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