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 <kernel/msg_param.h> 30 #include <mm/mobj.h> 31 #include <optee_msg.h> 32 #include <stdio.h> 33 #include <types_ext.h> 34 #include <util.h> 35 36 /** 37 * msg_param_extract_pages() - extract list of pages from 38 * OPTEE_MSG_ATTR_NONCONTIG buffer. 39 * 40 * @buffer: pointer to parameters array 41 * @pages: output array of page addresses 42 * @num_pages: number of pages in array 43 * 44 * return: 45 * true on success, false otherwise 46 * 47 * @buffer points to the physical address of a structure that can be viewed as 48 * 49 * struct page_data { 50 * uint64_t pages_array[OPTEE_MSG_NONCONTIG_PAGE_SIZE/sizeof(uint64_t) - 1]; 51 * uint64_t next_page_data; 52 * }; 53 * 54 * So, it is a linked list of arrays, where each element of linked list fits 55 * exactly into one 4K page. 56 * 57 * This function extracts data from arrays into one array pointed by @pages 58 * 59 * @buffer points to data shared with normal world, so some precautions 60 * should be taken. 61 */ 62 static bool msg_param_extract_pages(paddr_t buffer, paddr_t *pages, 63 size_t num_pages) 64 { 65 size_t cnt; 66 struct mobj *mobj; 67 paddr_t page; 68 uint64_t *va; 69 bool ret = false; 70 71 if (buffer & SMALL_PAGE_MASK) 72 return false; 73 74 /* 75 * There we map first page of array. 76 * mobj_mapped_shm_alloc() will check if page resides in nonsec ddr 77 */ 78 mobj = mobj_mapped_shm_alloc(&buffer, 1, 0, 0); 79 if (!mobj) 80 return false; 81 82 va = mobj_get_va(mobj, 0); 83 assert(va); 84 85 for (cnt = 0; cnt < num_pages; cnt++, va++) { 86 /* 87 * If we about to roll over page boundary, then last entry holds 88 * address of next page of array. Unmap current page and map 89 * next one 90 */ 91 if (!((vaddr_t)(va + 1) & SMALL_PAGE_MASK)) { 92 page = *va; 93 if (page & SMALL_PAGE_MASK) 94 goto out; 95 96 mobj_free(mobj); 97 mobj = mobj_mapped_shm_alloc(&page, 1, 0, 0); 98 if (!mobj) 99 goto out; 100 101 va = mobj_get_va(mobj, 0); 102 assert(va); 103 } 104 pages[cnt] = *va; 105 if (pages[cnt] & SMALL_PAGE_MASK) 106 goto out; 107 } 108 109 ret = true; 110 out: 111 mobj_free(mobj); 112 return ret; 113 } 114 115 struct mobj *msg_param_mobj_from_noncontig(paddr_t buf_ptr, size_t size, 116 uint64_t shm_ref, bool map_buffer) 117 { 118 struct mobj *mobj = NULL; 119 paddr_t *pages = NULL; 120 paddr_t page_offset = 0; 121 size_t num_pages = 0; 122 size_t size_plus_offs = 0; 123 size_t msize = 0; 124 125 page_offset = buf_ptr & SMALL_PAGE_MASK; 126 if (ADD_OVERFLOW(size, page_offset, &size_plus_offs)) 127 return NULL; 128 num_pages = (size_plus_offs - 1) / SMALL_PAGE_SIZE + 1; 129 if (MUL_OVERFLOW(num_pages, sizeof(paddr_t), &msize)) 130 return NULL; 131 132 pages = malloc(msize); 133 if (!pages) 134 return NULL; 135 136 if (!msg_param_extract_pages(buf_ptr & ~SMALL_PAGE_MASK, 137 pages, num_pages)) 138 goto out; 139 140 if (map_buffer) 141 mobj = mobj_mapped_shm_alloc(pages, num_pages, page_offset, 142 shm_ref); 143 else 144 mobj = mobj_reg_shm_alloc(pages, num_pages, page_offset, 145 shm_ref); 146 out: 147 free(pages); 148 return mobj; 149 } 150