xref: /optee_os/core/kernel/msg_param.c (revision 1bb929836182ecb96d2d9d268daa807c67596396)
1*1bb92983SJerome 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 
2950f24313SVolodymyr Babchuk #include <optee_msg.h>
3050f24313SVolodymyr Babchuk #include <stdio.h>
3150f24313SVolodymyr Babchuk #include <types_ext.h>
3250f24313SVolodymyr Babchuk #include <kernel/msg_param.h>
3350f24313SVolodymyr Babchuk #include <mm/mobj.h>
3450f24313SVolodymyr Babchuk 
35e7a8839bSVolodymyr Babchuk /**
36e7a8839bSVolodymyr Babchuk  * msg_param_extract_pages() - extract list of pages from
37e7a8839bSVolodymyr Babchuk  * OPTEE_MSG_ATTR_NONCONTIG buffer.
38e7a8839bSVolodymyr Babchuk  *
39e7a8839bSVolodymyr Babchuk  * @buffer:	pointer to parameters array
40e7a8839bSVolodymyr Babchuk  * @pages:	output array of page addresses
41e7a8839bSVolodymyr Babchuk  * @num_pages:  number of pages in array
42e7a8839bSVolodymyr Babchuk  *
43e7a8839bSVolodymyr Babchuk  * return:
44e7a8839bSVolodymyr Babchuk  *	true on success, false otherwise
45e7a8839bSVolodymyr Babchuk  *
46e7a8839bSVolodymyr Babchuk  * @buffer points to the physical address of a structure that can be viewed as
47e7a8839bSVolodymyr Babchuk  *
48e7a8839bSVolodymyr Babchuk  * struct page_data {
49e7a8839bSVolodymyr Babchuk  *   uint64_t pages_array[OPTEE_MSG_NONCONTIG_PAGE_SIZE/sizeof(uint64_t) - 1];
50e7a8839bSVolodymyr Babchuk  *   uint64_t next_page_data;
51e7a8839bSVolodymyr Babchuk  * };
52e7a8839bSVolodymyr Babchuk  *
53e7a8839bSVolodymyr Babchuk  * So, it is a linked list of arrays, where each element of linked list fits
54e7a8839bSVolodymyr Babchuk  * exactly into one 4K page.
55e7a8839bSVolodymyr Babchuk  *
56e7a8839bSVolodymyr Babchuk  * This function extracts data from arrays into one array pointed by @pages
57e7a8839bSVolodymyr Babchuk  *
58e7a8839bSVolodymyr Babchuk  * @buffer points to data shared with normal world, so some precautions
59e7a8839bSVolodymyr Babchuk  * should be taken.
60e7a8839bSVolodymyr Babchuk  */
61e7a8839bSVolodymyr Babchuk static bool msg_param_extract_pages(paddr_t buffer, paddr_t *pages,
62e7a8839bSVolodymyr Babchuk 				       size_t num_pages)
63e7a8839bSVolodymyr Babchuk {
64e7a8839bSVolodymyr Babchuk 	size_t cnt;
65e7a8839bSVolodymyr Babchuk 	struct mobj *mobj;
66e7a8839bSVolodymyr Babchuk 	paddr_t page;
67e7a8839bSVolodymyr Babchuk 	uint64_t *va;
68e7a8839bSVolodymyr Babchuk 	bool ret = false;
69e7a8839bSVolodymyr Babchuk 
70e7a8839bSVolodymyr Babchuk 	if (buffer & SMALL_PAGE_MASK)
71e7a8839bSVolodymyr Babchuk 		return false;
72e7a8839bSVolodymyr Babchuk 
73e7a8839bSVolodymyr Babchuk 	/*
74e7a8839bSVolodymyr Babchuk 	 * There we map first page of array.
75e7a8839bSVolodymyr Babchuk 	 * mobj_mapped_shm_alloc() will check if page resides in nonsec ddr
76e7a8839bSVolodymyr Babchuk 	 */
77e7a8839bSVolodymyr Babchuk 	mobj = mobj_mapped_shm_alloc(&buffer, 1, 0, 0);
78e7a8839bSVolodymyr Babchuk 	if (!mobj)
79e7a8839bSVolodymyr Babchuk 		return false;
80e7a8839bSVolodymyr Babchuk 
81e7a8839bSVolodymyr Babchuk 	va = mobj_get_va(mobj, 0);
82e7a8839bSVolodymyr Babchuk 	assert(va);
83e7a8839bSVolodymyr Babchuk 
84e7a8839bSVolodymyr Babchuk 	for (cnt = 0; cnt < num_pages; cnt++, va++) {
85e7a8839bSVolodymyr Babchuk 		/*
86e7a8839bSVolodymyr Babchuk 		 * If we about to roll over page boundary, then last entry holds
87e7a8839bSVolodymyr Babchuk 		 * address of next page of array. Unmap current page and map
88e7a8839bSVolodymyr Babchuk 		 * next one
89e7a8839bSVolodymyr Babchuk 		 */
90e7a8839bSVolodymyr Babchuk 		if (!((vaddr_t)(va + 1) & SMALL_PAGE_MASK)) {
91e7a8839bSVolodymyr Babchuk 			page = *va;
92e7a8839bSVolodymyr Babchuk 			if (page & SMALL_PAGE_MASK)
93e7a8839bSVolodymyr Babchuk 				goto out;
94e7a8839bSVolodymyr Babchuk 
95e7a8839bSVolodymyr Babchuk 			mobj_free(mobj);
96e7a8839bSVolodymyr Babchuk 			mobj = mobj_mapped_shm_alloc(&page, 1, 0, 0);
97e7a8839bSVolodymyr Babchuk 			if (!mobj)
98e7a8839bSVolodymyr Babchuk 				goto out;
99e7a8839bSVolodymyr Babchuk 
100e7a8839bSVolodymyr Babchuk 			va = mobj_get_va(mobj, 0);
101e7a8839bSVolodymyr Babchuk 			assert(va);
102e7a8839bSVolodymyr Babchuk 		}
103e7a8839bSVolodymyr Babchuk 		pages[cnt] = *va;
104e7a8839bSVolodymyr Babchuk 		if (pages[cnt] & SMALL_PAGE_MASK)
105e7a8839bSVolodymyr Babchuk 			goto out;
106e7a8839bSVolodymyr Babchuk 	}
107e7a8839bSVolodymyr Babchuk 
108e7a8839bSVolodymyr Babchuk 	ret = true;
109e7a8839bSVolodymyr Babchuk out:
110e7a8839bSVolodymyr Babchuk 	mobj_free(mobj);
111e7a8839bSVolodymyr Babchuk 	return ret;
112e7a8839bSVolodymyr Babchuk }
113e7a8839bSVolodymyr Babchuk 
114b05cd886SVolodymyr Babchuk struct mobj *msg_param_mobj_from_noncontig(paddr_t buf_ptr, size_t size,
115b05cd886SVolodymyr Babchuk 					   uint64_t shm_ref, bool map_buffer)
116e7a8839bSVolodymyr Babchuk {
117e7a8839bSVolodymyr Babchuk 	struct mobj *mobj = NULL;
118e7a8839bSVolodymyr Babchuk 	paddr_t *pages;
119e7a8839bSVolodymyr Babchuk 	paddr_t page_offset;
120e7a8839bSVolodymyr Babchuk 	size_t num_pages;
121e7a8839bSVolodymyr Babchuk 
122e7a8839bSVolodymyr Babchuk 	page_offset = buf_ptr & SMALL_PAGE_MASK;
123b05cd886SVolodymyr Babchuk 	num_pages = (size + page_offset - 1) / SMALL_PAGE_SIZE + 1;
124e7a8839bSVolodymyr Babchuk 
125e7a8839bSVolodymyr Babchuk 	pages = malloc(num_pages * sizeof(paddr_t));
126e7a8839bSVolodymyr Babchuk 	if (!pages)
127e7a8839bSVolodymyr Babchuk 		return NULL;
128e7a8839bSVolodymyr Babchuk 
129e7a8839bSVolodymyr Babchuk 	if (!msg_param_extract_pages(buf_ptr & ~SMALL_PAGE_MASK,
130e7a8839bSVolodymyr Babchuk 				     pages, num_pages))
131e7a8839bSVolodymyr Babchuk 		goto out;
132e7a8839bSVolodymyr Babchuk 
133e7a8839bSVolodymyr Babchuk 	if (map_buffer)
134e7a8839bSVolodymyr Babchuk 		mobj = mobj_mapped_shm_alloc(pages, num_pages, page_offset,
135b05cd886SVolodymyr Babchuk 					     shm_ref);
136e7a8839bSVolodymyr Babchuk 	else
137e7a8839bSVolodymyr Babchuk 		mobj = mobj_reg_shm_alloc(pages, num_pages, page_offset,
138b05cd886SVolodymyr Babchuk 					  shm_ref);
139e7a8839bSVolodymyr Babchuk out:
140e7a8839bSVolodymyr Babchuk 	free(pages);
141e7a8839bSVolodymyr Babchuk 	return mobj;
142e7a8839bSVolodymyr Babchuk }
143e7a8839bSVolodymyr Babchuk 
14450f24313SVolodymyr Babchuk bool msg_param_init_memparam(struct optee_msg_param *param, struct mobj *mobj,
14550f24313SVolodymyr Babchuk 			     size_t offset, size_t size,
14650f24313SVolodymyr Babchuk 			     uint64_t cookie, enum msg_param_mem_dir dir)
14750f24313SVolodymyr Babchuk {
14850f24313SVolodymyr Babchuk 	if (mobj_matches(mobj, CORE_MEM_REG_SHM)) {
14950f24313SVolodymyr Babchuk 		/* Registered SHM mobj */
15050f24313SVolodymyr Babchuk 		switch (dir) {
15150f24313SVolodymyr Babchuk 		case MSG_PARAM_MEM_DIR_IN:
15250f24313SVolodymyr Babchuk 			param->attr = OPTEE_MSG_ATTR_TYPE_RMEM_INPUT;
15350f24313SVolodymyr Babchuk 			break;
15450f24313SVolodymyr Babchuk 		case MSG_PARAM_MEM_DIR_OUT:
15550f24313SVolodymyr Babchuk 			param->attr = OPTEE_MSG_ATTR_TYPE_RMEM_OUTPUT;
15650f24313SVolodymyr Babchuk 			break;
15750f24313SVolodymyr Babchuk 		case MSG_PARAM_MEM_DIR_INOUT:
15850f24313SVolodymyr Babchuk 			param->attr = OPTEE_MSG_ATTR_TYPE_RMEM_INOUT;
15950f24313SVolodymyr Babchuk 			break;
16050f24313SVolodymyr Babchuk 		default:
16150f24313SVolodymyr Babchuk 			return false;
16250f24313SVolodymyr Babchuk 		}
16350f24313SVolodymyr Babchuk 
16450f24313SVolodymyr Babchuk 		param->u.rmem.size = size;
16550f24313SVolodymyr Babchuk 		param->u.rmem.offs = offset;
16650f24313SVolodymyr Babchuk 		param->u.rmem.shm_ref = cookie;
16750f24313SVolodymyr Babchuk 	} else if (mobj_matches(mobj, CORE_MEM_NSEC_SHM)) {
16850f24313SVolodymyr Babchuk 		/* MOBJ from from predefined pool */
16950f24313SVolodymyr Babchuk 		paddr_t pa;
17050f24313SVolodymyr Babchuk 
17150f24313SVolodymyr Babchuk 		if (mobj_get_pa(mobj, 0, 0, &pa) != TEE_SUCCESS)
17250f24313SVolodymyr Babchuk 			return false;
17350f24313SVolodymyr Babchuk 
17450f24313SVolodymyr Babchuk 		switch (dir) {
17550f24313SVolodymyr Babchuk 		case MSG_PARAM_MEM_DIR_IN:
17650f24313SVolodymyr Babchuk 			param->attr = OPTEE_MSG_ATTR_TYPE_TMEM_INPUT;
17750f24313SVolodymyr Babchuk 			break;
17850f24313SVolodymyr Babchuk 		case MSG_PARAM_MEM_DIR_OUT:
17950f24313SVolodymyr Babchuk 			param->attr = OPTEE_MSG_ATTR_TYPE_TMEM_OUTPUT;
18050f24313SVolodymyr Babchuk 			break;
18150f24313SVolodymyr Babchuk 		case MSG_PARAM_MEM_DIR_INOUT:
18250f24313SVolodymyr Babchuk 			param->attr = OPTEE_MSG_ATTR_TYPE_TMEM_INOUT;
18350f24313SVolodymyr Babchuk 			break;
18450f24313SVolodymyr Babchuk 		default:
18550f24313SVolodymyr Babchuk 			return false;
18650f24313SVolodymyr Babchuk 		}
18750f24313SVolodymyr Babchuk 
18850f24313SVolodymyr Babchuk 		param->u.tmem.buf_ptr = pa + offset;
18950f24313SVolodymyr Babchuk 		param->u.tmem.shm_ref = cookie;
19050f24313SVolodymyr Babchuk 		param->u.tmem.size = size;
19150f24313SVolodymyr Babchuk 	} else
19250f24313SVolodymyr Babchuk 		return false;
19350f24313SVolodymyr Babchuk 	return true;
19450f24313SVolodymyr Babchuk }
195