xref: /optee_os/core/kernel/msg_param.c (revision b05cd886e06dce9516b6434d3f1e0bd0029be1ac)
1 /*
2  * Copyright (c) 2017, EPAM Systems
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice,
9  * this list of conditions and the following disclaimer.
10  *
11  * 2. Redistributions in binary form must reproduce the above copyright notice,
12  * this list of conditions and the following disclaimer in the documentation
13  * and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
19  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25  * POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 #include <optee_msg.h>
29 #include <stdio.h>
30 #include <types_ext.h>
31 #include <kernel/msg_param.h>
32 #include <mm/mobj.h>
33 
34 /**
35  * msg_param_extract_pages() - extract list of pages from
36  * OPTEE_MSG_ATTR_NONCONTIG buffer.
37  *
38  * @buffer:	pointer to parameters array
39  * @pages:	output array of page addresses
40  * @num_pages:  number of pages in array
41  *
42  * return:
43  *	true on success, false otherwise
44  *
45  * @buffer points to the physical address of a structure that can be viewed as
46  *
47  * struct page_data {
48  *   uint64_t pages_array[OPTEE_MSG_NONCONTIG_PAGE_SIZE/sizeof(uint64_t) - 1];
49  *   uint64_t next_page_data;
50  * };
51  *
52  * So, it is a linked list of arrays, where each element of linked list fits
53  * exactly into one 4K page.
54  *
55  * This function extracts data from arrays into one array pointed by @pages
56  *
57  * @buffer points to data shared with normal world, so some precautions
58  * should be taken.
59  */
60 static bool msg_param_extract_pages(paddr_t buffer, paddr_t *pages,
61 				       size_t num_pages)
62 {
63 	size_t cnt;
64 	struct mobj *mobj;
65 	paddr_t page;
66 	uint64_t *va;
67 	bool ret = false;
68 
69 	if (buffer & SMALL_PAGE_MASK)
70 		return false;
71 
72 	/*
73 	 * There we map first page of array.
74 	 * mobj_mapped_shm_alloc() will check if page resides in nonsec ddr
75 	 */
76 	mobj = mobj_mapped_shm_alloc(&buffer, 1, 0, 0);
77 	if (!mobj)
78 		return false;
79 
80 	va = mobj_get_va(mobj, 0);
81 	assert(va);
82 
83 	for (cnt = 0; cnt < num_pages; cnt++, va++) {
84 		/*
85 		 * If we about to roll over page boundary, then last entry holds
86 		 * address of next page of array. Unmap current page and map
87 		 * next one
88 		 */
89 		if (!((vaddr_t)(va + 1) & SMALL_PAGE_MASK)) {
90 			page = *va;
91 			if (page & SMALL_PAGE_MASK)
92 				goto out;
93 
94 			mobj_free(mobj);
95 			mobj = mobj_mapped_shm_alloc(&page, 1, 0, 0);
96 			if (!mobj)
97 				goto out;
98 
99 			va = mobj_get_va(mobj, 0);
100 			assert(va);
101 		}
102 		pages[cnt] = *va;
103 		if (pages[cnt] & SMALL_PAGE_MASK)
104 			goto out;
105 	}
106 
107 	ret = true;
108 out:
109 	mobj_free(mobj);
110 	return ret;
111 }
112 
113 struct mobj *msg_param_mobj_from_noncontig(paddr_t buf_ptr, size_t size,
114 					   uint64_t shm_ref, bool map_buffer)
115 {
116 	struct mobj *mobj = NULL;
117 	paddr_t *pages;
118 	paddr_t page_offset;
119 	size_t num_pages;
120 
121 	page_offset = buf_ptr & SMALL_PAGE_MASK;
122 	num_pages = (size + page_offset - 1) / SMALL_PAGE_SIZE + 1;
123 
124 	pages = malloc(num_pages * sizeof(paddr_t));
125 	if (!pages)
126 		return NULL;
127 
128 	if (!msg_param_extract_pages(buf_ptr & ~SMALL_PAGE_MASK,
129 				     pages, num_pages))
130 		goto out;
131 
132 	if (map_buffer)
133 		mobj = mobj_mapped_shm_alloc(pages, num_pages, page_offset,
134 					     shm_ref);
135 	else
136 		mobj = mobj_reg_shm_alloc(pages, num_pages, page_offset,
137 					  shm_ref);
138 out:
139 	free(pages);
140 	return mobj;
141 }
142 
143 bool msg_param_init_memparam(struct optee_msg_param *param, struct mobj *mobj,
144 			     size_t offset, size_t size,
145 			     uint64_t cookie, enum msg_param_mem_dir dir)
146 {
147 	if (mobj_matches(mobj, CORE_MEM_REG_SHM)) {
148 		/* Registered SHM mobj */
149 		switch (dir) {
150 		case MSG_PARAM_MEM_DIR_IN:
151 			param->attr = OPTEE_MSG_ATTR_TYPE_RMEM_INPUT;
152 			break;
153 		case MSG_PARAM_MEM_DIR_OUT:
154 			param->attr = OPTEE_MSG_ATTR_TYPE_RMEM_OUTPUT;
155 			break;
156 		case MSG_PARAM_MEM_DIR_INOUT:
157 			param->attr = OPTEE_MSG_ATTR_TYPE_RMEM_INOUT;
158 			break;
159 		default:
160 			return false;
161 		}
162 
163 		param->u.rmem.size = size;
164 		param->u.rmem.offs = offset;
165 		param->u.rmem.shm_ref = cookie;
166 	} else if (mobj_matches(mobj, CORE_MEM_NSEC_SHM)) {
167 		/* MOBJ from from predefined pool */
168 		paddr_t pa;
169 
170 		if (mobj_get_pa(mobj, 0, 0, &pa) != TEE_SUCCESS)
171 			return false;
172 
173 		switch (dir) {
174 		case MSG_PARAM_MEM_DIR_IN:
175 			param->attr = OPTEE_MSG_ATTR_TYPE_TMEM_INPUT;
176 			break;
177 		case MSG_PARAM_MEM_DIR_OUT:
178 			param->attr = OPTEE_MSG_ATTR_TYPE_TMEM_OUTPUT;
179 			break;
180 		case MSG_PARAM_MEM_DIR_INOUT:
181 			param->attr = OPTEE_MSG_ATTR_TYPE_TMEM_INOUT;
182 			break;
183 		default:
184 			return false;
185 		}
186 
187 		param->u.tmem.buf_ptr = pa + offset;
188 		param->u.tmem.shm_ref = cookie;
189 		param->u.tmem.size = size;
190 	} else
191 		return false;
192 	return true;
193 }
194