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