xref: /optee_os/core/kernel/msg_param.c (revision b96514926b8ec7d98c36c4943df452b73bcc04a4)
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