1 /*
2 * Copyright (C) 2010-2017 ARM Limited. All rights reserved.
3 *
4 * This program is free software and is provided to you under the terms of the GNU General Public License version 2
5 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
6 *
7 * A copy of the licence is included with the program, and can also be obtained from Free Software
8 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
9 */
10 #include <linux/fs.h> /* file system operations */
11 #include <linux/uaccess.h> /* user space access */
12
13 #include "mali_ukk.h"
14 #include "mali_osk.h"
15 #include "mali_kernel_common.h"
16 #include "mali_session.h"
17 #include "mali_ukk_wrappers.h"
18
mem_alloc_wrapper(struct mali_session_data * session_data,_mali_uk_alloc_mem_s __user * uargs)19 int mem_alloc_wrapper(struct mali_session_data *session_data, _mali_uk_alloc_mem_s __user *uargs)
20 {
21 _mali_uk_alloc_mem_s kargs;
22 _mali_osk_errcode_t err;
23
24 MALI_CHECK_NON_NULL(uargs, -EINVAL);
25 MALI_CHECK_NON_NULL(session_data, -EINVAL);
26
27 if (0 != copy_from_user(&kargs, uargs, sizeof(_mali_uk_alloc_mem_s))) {
28 return -EFAULT;
29 }
30 kargs.ctx = (uintptr_t)session_data;
31
32 err = _mali_ukk_mem_allocate(&kargs);
33
34 if (_MALI_OSK_ERR_OK != err) {
35 return map_errcode(err);
36 }
37
38 if (0 != put_user(kargs.backend_handle, &uargs->backend_handle)) {
39 return -EFAULT;
40 }
41
42 return 0;
43 }
44
mem_free_wrapper(struct mali_session_data * session_data,_mali_uk_free_mem_s __user * uargs)45 int mem_free_wrapper(struct mali_session_data *session_data, _mali_uk_free_mem_s __user *uargs)
46 {
47 _mali_uk_free_mem_s kargs;
48 _mali_osk_errcode_t err;
49
50 MALI_CHECK_NON_NULL(uargs, -EINVAL);
51 MALI_CHECK_NON_NULL(session_data, -EINVAL);
52
53 if (0 != copy_from_user(&kargs, uargs, sizeof(_mali_uk_free_mem_s))) {
54 return -EFAULT;
55 }
56 kargs.ctx = (uintptr_t)session_data;
57
58 err = _mali_ukk_mem_free(&kargs);
59
60 if (_MALI_OSK_ERR_OK != err) {
61 return map_errcode(err);
62 }
63
64 if (0 != put_user(kargs.free_pages_nr, &uargs->free_pages_nr)) {
65 return -EFAULT;
66 }
67
68 return 0;
69 }
70
mem_bind_wrapper(struct mali_session_data * session_data,_mali_uk_bind_mem_s __user * uargs)71 int mem_bind_wrapper(struct mali_session_data *session_data, _mali_uk_bind_mem_s __user *uargs)
72 {
73 _mali_uk_bind_mem_s kargs;
74 _mali_osk_errcode_t err;
75
76 MALI_CHECK_NON_NULL(uargs, -EINVAL);
77 MALI_CHECK_NON_NULL(session_data, -EINVAL);
78
79 if (0 != copy_from_user(&kargs, uargs, sizeof(_mali_uk_bind_mem_s))) {
80 return -EFAULT;
81 }
82 kargs.ctx = (uintptr_t)session_data;
83
84 err = _mali_ukk_mem_bind(&kargs);
85
86 if (_MALI_OSK_ERR_OK != err) {
87 return map_errcode(err);
88 }
89
90 return 0;
91 }
92
mem_unbind_wrapper(struct mali_session_data * session_data,_mali_uk_unbind_mem_s __user * uargs)93 int mem_unbind_wrapper(struct mali_session_data *session_data, _mali_uk_unbind_mem_s __user *uargs)
94 {
95 _mali_uk_unbind_mem_s kargs;
96 _mali_osk_errcode_t err;
97
98 MALI_CHECK_NON_NULL(uargs, -EINVAL);
99 MALI_CHECK_NON_NULL(session_data, -EINVAL);
100
101 if (0 != copy_from_user(&kargs, uargs, sizeof(_mali_uk_unbind_mem_s))) {
102 return -EFAULT;
103 }
104 kargs.ctx = (uintptr_t)session_data;
105
106 err = _mali_ukk_mem_unbind(&kargs);
107
108 if (_MALI_OSK_ERR_OK != err) {
109 return map_errcode(err);
110 }
111
112 return 0;
113 }
114
115
mem_cow_wrapper(struct mali_session_data * session_data,_mali_uk_cow_mem_s __user * uargs)116 int mem_cow_wrapper(struct mali_session_data *session_data, _mali_uk_cow_mem_s __user *uargs)
117 {
118 _mali_uk_cow_mem_s kargs;
119 _mali_osk_errcode_t err;
120
121 MALI_CHECK_NON_NULL(uargs, -EINVAL);
122 MALI_CHECK_NON_NULL(session_data, -EINVAL);
123
124 if (0 != copy_from_user(&kargs, uargs, sizeof(_mali_uk_cow_mem_s))) {
125 return -EFAULT;
126 }
127 kargs.ctx = (uintptr_t)session_data;
128
129 err = _mali_ukk_mem_cow(&kargs);
130
131 if (_MALI_OSK_ERR_OK != err) {
132 return map_errcode(err);
133 }
134
135 if (0 != put_user(kargs.backend_handle, &uargs->backend_handle)) {
136 return -EFAULT;
137 }
138
139 return 0;
140 }
141
mem_cow_modify_range_wrapper(struct mali_session_data * session_data,_mali_uk_cow_modify_range_s __user * uargs)142 int mem_cow_modify_range_wrapper(struct mali_session_data *session_data, _mali_uk_cow_modify_range_s __user *uargs)
143 {
144 _mali_uk_cow_modify_range_s kargs;
145 _mali_osk_errcode_t err;
146
147 MALI_CHECK_NON_NULL(uargs, -EINVAL);
148 MALI_CHECK_NON_NULL(session_data, -EINVAL);
149
150 if (0 != copy_from_user(&kargs, uargs, sizeof(_mali_uk_cow_modify_range_s))) {
151 return -EFAULT;
152 }
153 kargs.ctx = (uintptr_t)session_data;
154
155 err = _mali_ukk_mem_cow_modify_range(&kargs);
156
157 if (_MALI_OSK_ERR_OK != err) {
158 return map_errcode(err);
159 }
160
161 if (0 != put_user(kargs.change_pages_nr, &uargs->change_pages_nr)) {
162 return -EFAULT;
163 }
164 return 0;
165 }
166
167
mem_resize_mem_wrapper(struct mali_session_data * session_data,_mali_uk_mem_resize_s __user * uargs)168 int mem_resize_mem_wrapper(struct mali_session_data *session_data, _mali_uk_mem_resize_s __user *uargs)
169 {
170 _mali_uk_mem_resize_s kargs;
171 _mali_osk_errcode_t err;
172
173 MALI_CHECK_NON_NULL(uargs, -EINVAL);
174 MALI_CHECK_NON_NULL(session_data, -EINVAL);
175
176 if (0 != copy_from_user(&kargs, uargs, sizeof(_mali_uk_mem_resize_s))) {
177 return -EFAULT;
178 }
179 kargs.ctx = (uintptr_t)session_data;
180
181 err = _mali_ukk_mem_resize(&kargs);
182
183 if (_MALI_OSK_ERR_OK != err) {
184 return map_errcode(err);
185 }
186
187 return 0;
188 }
189
mem_write_safe_wrapper(struct mali_session_data * session_data,_mali_uk_mem_write_safe_s __user * uargs)190 int mem_write_safe_wrapper(struct mali_session_data *session_data, _mali_uk_mem_write_safe_s __user *uargs)
191 {
192 _mali_uk_mem_write_safe_s kargs;
193 _mali_osk_errcode_t err;
194
195 MALI_CHECK_NON_NULL(uargs, -EINVAL);
196 MALI_CHECK_NON_NULL(session_data, -EINVAL);
197
198 if (0 != copy_from_user(&kargs, uargs, sizeof(_mali_uk_mem_write_safe_s))) {
199 return -EFAULT;
200 }
201
202 kargs.ctx = (uintptr_t)session_data;
203
204 /* Check if we can access the buffers */
205 if (!access_ok((const void *)(uintptr_t)kargs.dest, kargs.size) ||
206 !access_ok((const void *)(uintptr_t)kargs.src, kargs.size)) {
207 return -EINVAL;
208 }
209
210 /* Check if size wraps */
211 if ((kargs.size + kargs.dest) <= kargs.dest
212 || (kargs.size + kargs.src) <= kargs.src) {
213 return -EINVAL;
214 }
215
216 err = _mali_ukk_mem_write_safe(&kargs);
217 if (_MALI_OSK_ERR_OK != err) {
218 return map_errcode(err);
219 }
220
221 if (0 != put_user(kargs.size, &uargs->size)) {
222 return -EFAULT;
223 }
224
225 return 0;
226 }
227
228
229
mem_query_mmu_page_table_dump_size_wrapper(struct mali_session_data * session_data,_mali_uk_query_mmu_page_table_dump_size_s __user * uargs)230 int mem_query_mmu_page_table_dump_size_wrapper(struct mali_session_data *session_data, _mali_uk_query_mmu_page_table_dump_size_s __user *uargs)
231 {
232 _mali_uk_query_mmu_page_table_dump_size_s kargs;
233 _mali_osk_errcode_t err;
234
235 MALI_CHECK_NON_NULL(uargs, -EINVAL);
236 MALI_CHECK_NON_NULL(session_data, -EINVAL);
237
238 kargs.ctx = (uintptr_t)session_data;
239
240 err = _mali_ukk_query_mmu_page_table_dump_size(&kargs);
241 if (_MALI_OSK_ERR_OK != err) return map_errcode(err);
242
243 if (0 != put_user(kargs.size, &uargs->size)) return -EFAULT;
244
245 return 0;
246 }
247
mem_dump_mmu_page_table_wrapper(struct mali_session_data * session_data,_mali_uk_dump_mmu_page_table_s __user * uargs)248 int mem_dump_mmu_page_table_wrapper(struct mali_session_data *session_data, _mali_uk_dump_mmu_page_table_s __user *uargs)
249 {
250 _mali_uk_dump_mmu_page_table_s kargs;
251 _mali_osk_errcode_t err;
252 void __user *user_buffer;
253 void *buffer = NULL;
254 int rc = -EFAULT;
255
256 /* validate input */
257 MALI_CHECK_NON_NULL(uargs, -EINVAL);
258 /* the session_data pointer was validated by caller */
259
260 if (0 != copy_from_user(&kargs, uargs, sizeof(_mali_uk_dump_mmu_page_table_s)))
261 goto err_exit;
262
263 user_buffer = (void __user *)(uintptr_t)kargs.buffer;
264 if (!access_ok(user_buffer, kargs.size))
265 goto err_exit;
266
267 /* allocate temporary buffer (kernel side) to store mmu page table info */
268 if (kargs.size <= 0)
269 return -EINVAL;
270 /* Allow at most 8MiB buffers, this is more than enough to dump a fully
271 * populated page table. */
272 if (kargs.size > SZ_8M)
273 return -EINVAL;
274
275 buffer = (void *)(uintptr_t)_mali_osk_valloc(kargs.size);
276 if (NULL == buffer) {
277 rc = -ENOMEM;
278 goto err_exit;
279 }
280
281 kargs.ctx = (uintptr_t)session_data;
282 kargs.buffer = (uintptr_t)buffer;
283 err = _mali_ukk_dump_mmu_page_table(&kargs);
284 if (_MALI_OSK_ERR_OK != err) {
285 rc = map_errcode(err);
286 goto err_exit;
287 }
288
289 /* copy mmu page table info back to user space and update pointers */
290 if (0 != copy_to_user(user_buffer, buffer, kargs.size))
291 goto err_exit;
292
293 kargs.register_writes = kargs.register_writes -
294 (uintptr_t)buffer + (uintptr_t)user_buffer;
295 kargs.page_table_dump = kargs.page_table_dump -
296 (uintptr_t)buffer + (uintptr_t)user_buffer;
297
298 if (0 != copy_to_user(uargs, &kargs, sizeof(kargs)))
299 goto err_exit;
300
301 rc = 0;
302
303 err_exit:
304 if (buffer) _mali_osk_vfree(buffer);
305 return rc;
306 }
307
mem_usage_get_wrapper(struct mali_session_data * session_data,_mali_uk_profiling_memory_usage_get_s __user * uargs)308 int mem_usage_get_wrapper(struct mali_session_data *session_data, _mali_uk_profiling_memory_usage_get_s __user *uargs)
309 {
310 _mali_osk_errcode_t err;
311 _mali_uk_profiling_memory_usage_get_s kargs;
312
313 MALI_CHECK_NON_NULL(uargs, -EINVAL);
314 MALI_CHECK_NON_NULL(session_data, -EINVAL);
315
316 if (0 != copy_from_user(&kargs, uargs, sizeof(_mali_uk_profiling_memory_usage_get_s))) {
317 return -EFAULT;
318 }
319
320 kargs.ctx = (uintptr_t)session_data;
321 err = _mali_ukk_mem_usage_get(&kargs);
322 if (_MALI_OSK_ERR_OK != err) {
323 return map_errcode(err);
324 }
325
326 kargs.ctx = (uintptr_t)NULL; /* prevent kernel address to be returned to user space */
327 if (0 != copy_to_user(uargs, &kargs, sizeof(_mali_uk_profiling_memory_usage_get_s))) {
328 return -EFAULT;
329 }
330
331 return 0;
332 }
333
334