xref: /optee_os/core/kernel/msg_param.c (revision b05cd886e06dce9516b6434d3f1e0bd0029be1ac)
150f24313SVolodymyr Babchuk /*
250f24313SVolodymyr Babchuk  * Copyright (c) 2017, EPAM Systems
350f24313SVolodymyr Babchuk  * All rights reserved.
450f24313SVolodymyr Babchuk  *
550f24313SVolodymyr Babchuk  * Redistribution and use in source and binary forms, with or without
650f24313SVolodymyr Babchuk  * modification, are permitted provided that the following conditions are met:
750f24313SVolodymyr Babchuk  *
850f24313SVolodymyr Babchuk  * 1. Redistributions of source code must retain the above copyright notice,
950f24313SVolodymyr Babchuk  * this list of conditions and the following disclaimer.
1050f24313SVolodymyr Babchuk  *
1150f24313SVolodymyr Babchuk  * 2. Redistributions in binary form must reproduce the above copyright notice,
1250f24313SVolodymyr Babchuk  * this list of conditions and the following disclaimer in the documentation
1350f24313SVolodymyr Babchuk  * and/or other materials provided with the distribution.
1450f24313SVolodymyr Babchuk  *
1550f24313SVolodymyr Babchuk  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
1650f24313SVolodymyr Babchuk  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1750f24313SVolodymyr Babchuk  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1850f24313SVolodymyr Babchuk  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
1950f24313SVolodymyr Babchuk  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2050f24313SVolodymyr Babchuk  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2150f24313SVolodymyr Babchuk  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2250f24313SVolodymyr Babchuk  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2350f24313SVolodymyr Babchuk  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2450f24313SVolodymyr Babchuk  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2550f24313SVolodymyr Babchuk  * POSSIBILITY OF SUCH DAMAGE.
2650f24313SVolodymyr Babchuk  */
2750f24313SVolodymyr Babchuk 
2850f24313SVolodymyr Babchuk #include <optee_msg.h>
2950f24313SVolodymyr Babchuk #include <stdio.h>
3050f24313SVolodymyr Babchuk #include <types_ext.h>
3150f24313SVolodymyr Babchuk #include <kernel/msg_param.h>
3250f24313SVolodymyr Babchuk #include <mm/mobj.h>
3350f24313SVolodymyr Babchuk 
34e7a8839bSVolodymyr Babchuk /**
35e7a8839bSVolodymyr Babchuk  * msg_param_extract_pages() - extract list of pages from
36e7a8839bSVolodymyr Babchuk  * OPTEE_MSG_ATTR_NONCONTIG buffer.
37e7a8839bSVolodymyr Babchuk  *
38e7a8839bSVolodymyr Babchuk  * @buffer:	pointer to parameters array
39e7a8839bSVolodymyr Babchuk  * @pages:	output array of page addresses
40e7a8839bSVolodymyr Babchuk  * @num_pages:  number of pages in array
41e7a8839bSVolodymyr Babchuk  *
42e7a8839bSVolodymyr Babchuk  * return:
43e7a8839bSVolodymyr Babchuk  *	true on success, false otherwise
44e7a8839bSVolodymyr Babchuk  *
45e7a8839bSVolodymyr Babchuk  * @buffer points to the physical address of a structure that can be viewed as
46e7a8839bSVolodymyr Babchuk  *
47e7a8839bSVolodymyr Babchuk  * struct page_data {
48e7a8839bSVolodymyr Babchuk  *   uint64_t pages_array[OPTEE_MSG_NONCONTIG_PAGE_SIZE/sizeof(uint64_t) - 1];
49e7a8839bSVolodymyr Babchuk  *   uint64_t next_page_data;
50e7a8839bSVolodymyr Babchuk  * };
51e7a8839bSVolodymyr Babchuk  *
52e7a8839bSVolodymyr Babchuk  * So, it is a linked list of arrays, where each element of linked list fits
53e7a8839bSVolodymyr Babchuk  * exactly into one 4K page.
54e7a8839bSVolodymyr Babchuk  *
55e7a8839bSVolodymyr Babchuk  * This function extracts data from arrays into one array pointed by @pages
56e7a8839bSVolodymyr Babchuk  *
57e7a8839bSVolodymyr Babchuk  * @buffer points to data shared with normal world, so some precautions
58e7a8839bSVolodymyr Babchuk  * should be taken.
59e7a8839bSVolodymyr Babchuk  */
60e7a8839bSVolodymyr Babchuk static bool msg_param_extract_pages(paddr_t buffer, paddr_t *pages,
61e7a8839bSVolodymyr Babchuk 				       size_t num_pages)
62e7a8839bSVolodymyr Babchuk {
63e7a8839bSVolodymyr Babchuk 	size_t cnt;
64e7a8839bSVolodymyr Babchuk 	struct mobj *mobj;
65e7a8839bSVolodymyr Babchuk 	paddr_t page;
66e7a8839bSVolodymyr Babchuk 	uint64_t *va;
67e7a8839bSVolodymyr Babchuk 	bool ret = false;
68e7a8839bSVolodymyr Babchuk 
69e7a8839bSVolodymyr Babchuk 	if (buffer & SMALL_PAGE_MASK)
70e7a8839bSVolodymyr Babchuk 		return false;
71e7a8839bSVolodymyr Babchuk 
72e7a8839bSVolodymyr Babchuk 	/*
73e7a8839bSVolodymyr Babchuk 	 * There we map first page of array.
74e7a8839bSVolodymyr Babchuk 	 * mobj_mapped_shm_alloc() will check if page resides in nonsec ddr
75e7a8839bSVolodymyr Babchuk 	 */
76e7a8839bSVolodymyr Babchuk 	mobj = mobj_mapped_shm_alloc(&buffer, 1, 0, 0);
77e7a8839bSVolodymyr Babchuk 	if (!mobj)
78e7a8839bSVolodymyr Babchuk 		return false;
79e7a8839bSVolodymyr Babchuk 
80e7a8839bSVolodymyr Babchuk 	va = mobj_get_va(mobj, 0);
81e7a8839bSVolodymyr Babchuk 	assert(va);
82e7a8839bSVolodymyr Babchuk 
83e7a8839bSVolodymyr Babchuk 	for (cnt = 0; cnt < num_pages; cnt++, va++) {
84e7a8839bSVolodymyr Babchuk 		/*
85e7a8839bSVolodymyr Babchuk 		 * If we about to roll over page boundary, then last entry holds
86e7a8839bSVolodymyr Babchuk 		 * address of next page of array. Unmap current page and map
87e7a8839bSVolodymyr Babchuk 		 * next one
88e7a8839bSVolodymyr Babchuk 		 */
89e7a8839bSVolodymyr Babchuk 		if (!((vaddr_t)(va + 1) & SMALL_PAGE_MASK)) {
90e7a8839bSVolodymyr Babchuk 			page = *va;
91e7a8839bSVolodymyr Babchuk 			if (page & SMALL_PAGE_MASK)
92e7a8839bSVolodymyr Babchuk 				goto out;
93e7a8839bSVolodymyr Babchuk 
94e7a8839bSVolodymyr Babchuk 			mobj_free(mobj);
95e7a8839bSVolodymyr Babchuk 			mobj = mobj_mapped_shm_alloc(&page, 1, 0, 0);
96e7a8839bSVolodymyr Babchuk 			if (!mobj)
97e7a8839bSVolodymyr Babchuk 				goto out;
98e7a8839bSVolodymyr Babchuk 
99e7a8839bSVolodymyr Babchuk 			va = mobj_get_va(mobj, 0);
100e7a8839bSVolodymyr Babchuk 			assert(va);
101e7a8839bSVolodymyr Babchuk 		}
102e7a8839bSVolodymyr Babchuk 		pages[cnt] = *va;
103e7a8839bSVolodymyr Babchuk 		if (pages[cnt] & SMALL_PAGE_MASK)
104e7a8839bSVolodymyr Babchuk 			goto out;
105e7a8839bSVolodymyr Babchuk 	}
106e7a8839bSVolodymyr Babchuk 
107e7a8839bSVolodymyr Babchuk 	ret = true;
108e7a8839bSVolodymyr Babchuk out:
109e7a8839bSVolodymyr Babchuk 	mobj_free(mobj);
110e7a8839bSVolodymyr Babchuk 	return ret;
111e7a8839bSVolodymyr Babchuk }
112e7a8839bSVolodymyr Babchuk 
113*b05cd886SVolodymyr Babchuk struct mobj *msg_param_mobj_from_noncontig(paddr_t buf_ptr, size_t size,
114*b05cd886SVolodymyr Babchuk 					   uint64_t shm_ref, bool map_buffer)
115e7a8839bSVolodymyr Babchuk {
116e7a8839bSVolodymyr Babchuk 	struct mobj *mobj = NULL;
117e7a8839bSVolodymyr Babchuk 	paddr_t *pages;
118e7a8839bSVolodymyr Babchuk 	paddr_t page_offset;
119e7a8839bSVolodymyr Babchuk 	size_t num_pages;
120e7a8839bSVolodymyr Babchuk 
121e7a8839bSVolodymyr Babchuk 	page_offset = buf_ptr & SMALL_PAGE_MASK;
122*b05cd886SVolodymyr Babchuk 	num_pages = (size + page_offset - 1) / SMALL_PAGE_SIZE + 1;
123e7a8839bSVolodymyr Babchuk 
124e7a8839bSVolodymyr Babchuk 	pages = malloc(num_pages * sizeof(paddr_t));
125e7a8839bSVolodymyr Babchuk 	if (!pages)
126e7a8839bSVolodymyr Babchuk 		return NULL;
127e7a8839bSVolodymyr Babchuk 
128e7a8839bSVolodymyr Babchuk 	if (!msg_param_extract_pages(buf_ptr & ~SMALL_PAGE_MASK,
129e7a8839bSVolodymyr Babchuk 				     pages, num_pages))
130e7a8839bSVolodymyr Babchuk 		goto out;
131e7a8839bSVolodymyr Babchuk 
132e7a8839bSVolodymyr Babchuk 	if (map_buffer)
133e7a8839bSVolodymyr Babchuk 		mobj = mobj_mapped_shm_alloc(pages, num_pages, page_offset,
134*b05cd886SVolodymyr Babchuk 					     shm_ref);
135e7a8839bSVolodymyr Babchuk 	else
136e7a8839bSVolodymyr Babchuk 		mobj = mobj_reg_shm_alloc(pages, num_pages, page_offset,
137*b05cd886SVolodymyr Babchuk 					  shm_ref);
138e7a8839bSVolodymyr Babchuk out:
139e7a8839bSVolodymyr Babchuk 	free(pages);
140e7a8839bSVolodymyr Babchuk 	return mobj;
141e7a8839bSVolodymyr Babchuk }
142e7a8839bSVolodymyr Babchuk 
14350f24313SVolodymyr Babchuk bool msg_param_init_memparam(struct optee_msg_param *param, struct mobj *mobj,
14450f24313SVolodymyr Babchuk 			     size_t offset, size_t size,
14550f24313SVolodymyr Babchuk 			     uint64_t cookie, enum msg_param_mem_dir dir)
14650f24313SVolodymyr Babchuk {
14750f24313SVolodymyr Babchuk 	if (mobj_matches(mobj, CORE_MEM_REG_SHM)) {
14850f24313SVolodymyr Babchuk 		/* Registered SHM mobj */
14950f24313SVolodymyr Babchuk 		switch (dir) {
15050f24313SVolodymyr Babchuk 		case MSG_PARAM_MEM_DIR_IN:
15150f24313SVolodymyr Babchuk 			param->attr = OPTEE_MSG_ATTR_TYPE_RMEM_INPUT;
15250f24313SVolodymyr Babchuk 			break;
15350f24313SVolodymyr Babchuk 		case MSG_PARAM_MEM_DIR_OUT:
15450f24313SVolodymyr Babchuk 			param->attr = OPTEE_MSG_ATTR_TYPE_RMEM_OUTPUT;
15550f24313SVolodymyr Babchuk 			break;
15650f24313SVolodymyr Babchuk 		case MSG_PARAM_MEM_DIR_INOUT:
15750f24313SVolodymyr Babchuk 			param->attr = OPTEE_MSG_ATTR_TYPE_RMEM_INOUT;
15850f24313SVolodymyr Babchuk 			break;
15950f24313SVolodymyr Babchuk 		default:
16050f24313SVolodymyr Babchuk 			return false;
16150f24313SVolodymyr Babchuk 		}
16250f24313SVolodymyr Babchuk 
16350f24313SVolodymyr Babchuk 		param->u.rmem.size = size;
16450f24313SVolodymyr Babchuk 		param->u.rmem.offs = offset;
16550f24313SVolodymyr Babchuk 		param->u.rmem.shm_ref = cookie;
16650f24313SVolodymyr Babchuk 	} else if (mobj_matches(mobj, CORE_MEM_NSEC_SHM)) {
16750f24313SVolodymyr Babchuk 		/* MOBJ from from predefined pool */
16850f24313SVolodymyr Babchuk 		paddr_t pa;
16950f24313SVolodymyr Babchuk 
17050f24313SVolodymyr Babchuk 		if (mobj_get_pa(mobj, 0, 0, &pa) != TEE_SUCCESS)
17150f24313SVolodymyr Babchuk 			return false;
17250f24313SVolodymyr Babchuk 
17350f24313SVolodymyr Babchuk 		switch (dir) {
17450f24313SVolodymyr Babchuk 		case MSG_PARAM_MEM_DIR_IN:
17550f24313SVolodymyr Babchuk 			param->attr = OPTEE_MSG_ATTR_TYPE_TMEM_INPUT;
17650f24313SVolodymyr Babchuk 			break;
17750f24313SVolodymyr Babchuk 		case MSG_PARAM_MEM_DIR_OUT:
17850f24313SVolodymyr Babchuk 			param->attr = OPTEE_MSG_ATTR_TYPE_TMEM_OUTPUT;
17950f24313SVolodymyr Babchuk 			break;
18050f24313SVolodymyr Babchuk 		case MSG_PARAM_MEM_DIR_INOUT:
18150f24313SVolodymyr Babchuk 			param->attr = OPTEE_MSG_ATTR_TYPE_TMEM_INOUT;
18250f24313SVolodymyr Babchuk 			break;
18350f24313SVolodymyr Babchuk 		default:
18450f24313SVolodymyr Babchuk 			return false;
18550f24313SVolodymyr Babchuk 		}
18650f24313SVolodymyr Babchuk 
18750f24313SVolodymyr Babchuk 		param->u.tmem.buf_ptr = pa + offset;
18850f24313SVolodymyr Babchuk 		param->u.tmem.shm_ref = cookie;
18950f24313SVolodymyr Babchuk 		param->u.tmem.size = size;
19050f24313SVolodymyr Babchuk 	} else
19150f24313SVolodymyr Babchuk 		return false;
19250f24313SVolodymyr Babchuk 	return true;
19350f24313SVolodymyr Babchuk }
194