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