xref: /optee_os/core/tee/tee_fs_rpc.c (revision 2ffdd194063da02d2e82a5f671893fb19ba7846c)
1 /*
2  * Copyright (c) 2016, Linaro Limited
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 <assert.h>
29 #include <kernel/thread.h>
30 #include <mm/core_memprot.h>
31 #include <optee_msg_fs.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <string_ext.h>
35 #include <tee/tee_fs.h>
36 #include <tee/tee_fs_rpc.h>
37 #include <trace.h>
38 #include <util.h>
39 
40 #define RPC_FAILED -1
41 
42 /* TEE FS operation */
43 #define TEE_FS_OPEN       1
44 #define TEE_FS_CLOSE      2
45 #define TEE_FS_READ       3
46 #define TEE_FS_WRITE      4
47 #define TEE_FS_SEEK       5
48 #define TEE_FS_UNLINK     6
49 #define TEE_FS_RENAME     7
50 #define TEE_FS_TRUNC      8
51 #define TEE_FS_MKDIR      9
52 #define TEE_FS_OPENDIR   10
53 #define TEE_FS_CLOSEDIR  11
54 #define TEE_FS_READDIR   12
55 #define TEE_FS_RMDIR     13
56 #define TEE_FS_ACCESS    14
57 #define TEE_FS_LINK      15
58 #define TEE_FS_BEGIN     16 /* SQL FS: begin transaction */
59 #define TEE_FS_END       17 /* SQL FS: end transaction */
60 
61 #define TEE_FS_MODE_NONE 0
62 #define TEE_FS_MODE_IN   1
63 #define TEE_FS_MODE_OUT  2
64 
65 struct tee_fs_rpc {
66 	int op;
67 	int flags;
68 	int arg;
69 	int fd;
70 	uint32_t len;
71 	int res;
72 };
73 
74 struct tee_fs_dir {
75 	int nw_dir;
76 	struct tee_fs_dirent d;
77 };
78 
79 static TEE_Result tee_fs_rpc_send_cmd(int cmd_id, struct tee_fs_rpc *bf_cmd,
80 				      void *data, uint32_t len, uint32_t mode)
81 {
82 	TEE_Result ret;
83 	struct optee_msg_param params;
84 	paddr_t phpayload = 0;
85 	uint64_t cpayload = 0;
86 	struct tee_fs_rpc *bf;
87 	int res = TEE_ERROR_GENERIC;
88 
89 	assert(cmd_id == OPTEE_MSG_RPC_CMD_FS ||
90 	       cmd_id == OPTEE_MSG_RPC_CMD_SQL_FS);
91 
92 	bf = tee_fs_rpc_cache_alloc(sizeof(struct tee_fs_rpc) + len,
93 				    &phpayload, &cpayload);
94 	if (!bf)
95 		goto exit;
96 
97 	memset(&params, 0, sizeof(params));
98 	params.attr = OPTEE_MSG_ATTR_TYPE_TMEM_INOUT;
99 	params.u.tmem.buf_ptr = phpayload;
100 	params.u.tmem.size = sizeof(struct tee_fs_rpc) + len;
101 	params.u.tmem.shm_ref = cpayload;
102 
103 	/* fill in parameters */
104 	*bf = *bf_cmd;
105 
106 	if (mode & TEE_FS_MODE_IN)
107 		memcpy((void *)(bf + 1), data, len);
108 
109 	ret = thread_rpc_cmd(cmd_id, 1, &params);
110 	/* update result */
111 	*bf_cmd = *bf;
112 	if (ret != TEE_SUCCESS)
113 		goto exit;
114 
115 	if (mode & TEE_FS_MODE_OUT) {
116 		uint32_t olen = MIN(len, bf->len);
117 
118 		memcpy(data, (void *)(bf + 1), olen);
119 	}
120 
121 	res = TEE_SUCCESS;
122 
123 exit:
124 	return res;
125 }
126 
127 int tee_fs_rpc_access(int id, const char *name, int mode)
128 {
129 	struct tee_fs_rpc head = { 0 };
130 	TEE_Result res;
131 	int rc = RPC_FAILED;
132 	size_t len;
133 
134 	DMSG("(id: %d, name: %s, mode: %d)...", id, name, mode);
135 
136 	if (!name)
137 		goto exit;
138 
139 	len = strlen(name) + 1;
140 	if (len <= 1)
141 		goto exit;
142 
143 	head.op = TEE_FS_ACCESS;
144 	head.flags = mode;
145 
146 	res = tee_fs_rpc_send_cmd(id, &head, (void *)name, len, TEE_FS_MODE_IN);
147 	if (res != TEE_SUCCESS)
148 		goto exit;
149 
150 	rc = head.res;
151 exit:
152 	DMSG("...%d", rc);
153 	return rc;
154 }
155 
156 int tee_fs_rpc_begin_transaction(int id)
157 {
158 	struct tee_fs_rpc head = { 0 };
159 	TEE_Result res;
160 	int rc = RPC_FAILED;
161 
162 	assert(id == OPTEE_MSG_RPC_CMD_SQL_FS);
163 
164 	DMSG("(id: %d)...", id);
165 
166 	/* fill in parameters */
167 	head.op = TEE_FS_BEGIN;
168 	head.fd = -1;
169 
170 	res = tee_fs_rpc_send_cmd(id, &head, NULL, 0,
171 				  TEE_FS_MODE_NONE);
172 	if (res != TEE_SUCCESS)
173 		goto exit;
174 
175 	rc = head.res;
176 exit:
177 	DMSG("...%d", rc);
178 	return rc;
179 }
180 
181 int tee_fs_rpc_end_transaction(int id, bool rollback)
182 {
183 	struct tee_fs_rpc head = { 0 };
184 	TEE_Result res;
185 	int rc = RPC_FAILED;
186 
187 	assert(id == OPTEE_MSG_RPC_CMD_SQL_FS);
188 
189 	DMSG("(id: %d, rollback: %d)...", id, rollback);
190 
191 	head.op = TEE_FS_END;
192 	head.arg = rollback;
193 	head.fd = -1;
194 
195 	res = tee_fs_rpc_send_cmd(id, &head, NULL, 0, TEE_FS_MODE_NONE);
196 	if (res != TEE_SUCCESS)
197 		goto exit;
198 
199 	rc = head.res;
200 exit:
201 	DMSG("...%d", rc);
202 	return rc;
203 }
204 
205 int tee_fs_rpc_link(int id, const char *old, const char *nw)
206 {
207 	size_t len_old;
208 	size_t len_new;
209 	size_t len;
210 	struct tee_fs_rpc head = { 0 };
211 	char *tmp = NULL;
212 	TEE_Result res;
213 	int rc = RPC_FAILED;
214 
215 	DMSG("(id: %d, old: %s, nw: %s)...", id, old, nw);
216 
217 	if (!old || !nw)
218 		goto exit;
219 
220 	len_old = strlen(old) + 1;
221 	len_new = strlen(nw) + 1;
222 	len = len_old + len_new;
223 
224 	tmp = malloc(len);
225 	if (!tmp)
226 		goto exit;
227 	memcpy(tmp, old, len_old);
228 	memcpy(tmp + len_old, nw, len_new);
229 
230 	head.op = TEE_FS_LINK;
231 
232 	res = tee_fs_rpc_send_cmd(id, &head, tmp, len, TEE_FS_MODE_IN);
233 	if (res != TEE_SUCCESS)
234 		goto exit;
235 
236 	rc = head.res;
237 exit:
238 	free(tmp);
239 	DMSG("...%d", rc);
240 	return rc;
241 }
242 
243 int tee_fs_rpc_mkdir(int id, const char *path, tee_fs_mode_t mode)
244 {
245 	struct tee_fs_rpc head = { 0 };
246 	TEE_Result res;
247 	uint32_t len;
248 	int rc = RPC_FAILED;
249 
250 	DMSG("(id: %d, path: %s, mode: %d)...", id, path, mode);
251 
252 	if (!path)
253 		goto exit;
254 
255 	len = strlen(path) + 1;
256 	if (len <= 1)
257 		goto exit;
258 
259 	head.op = TEE_FS_MKDIR;
260 	head.flags = mode;
261 
262 	res = tee_fs_rpc_send_cmd(id, &head, (void *)path, len,
263 				  TEE_FS_MODE_IN);
264 	if (res != TEE_SUCCESS)
265 		goto exit;
266 
267 	rc = head.res;
268 exit:
269 	DMSG("...%d", rc);
270 	return rc;
271 }
272 
273 struct tee_fs_dir *tee_fs_rpc_opendir(int id, const char *name)
274 {
275 	struct tee_fs_rpc head = { 0 };
276 	struct tee_fs_dir *dir = NULL;
277 	size_t len;
278 	TEE_Result res = TEE_SUCCESS;
279 
280 	DMSG("(id: %d, name: %s)...", id, name);
281 
282 	if (!name)
283 		goto exit;
284 
285 	len = strlen(name) + 1;
286 	if (len <= 1)
287 		goto exit;
288 
289 	dir = malloc(sizeof(struct tee_fs_dir));
290 	if (!dir)
291 		goto exit;
292 
293 	head.op = TEE_FS_OPENDIR;
294 
295 	res = tee_fs_rpc_send_cmd(id, &head, (void *)name, len,
296 				  TEE_FS_MODE_IN);
297 	if (res != TEE_SUCCESS)
298 		goto free_and_exit;
299 	if (head.res < 0)
300 		goto free_and_exit;
301 
302 	dir->nw_dir = head.res;
303 	dir->d.d_name = NULL;
304 
305 	goto exit;
306 
307 free_and_exit:
308 	free(dir);
309 	dir = NULL;
310 exit:
311 	DMSG("...%p", (void *)dir);
312 	return dir;
313 }
314 
315 struct tee_fs_dirent *tee_fs_rpc_readdir(int id, struct tee_fs_dir *d)
316 {
317 	struct tee_fs_dirent *rc = NULL;
318 	char fname[TEE_FS_NAME_MAX + 1];
319 	struct tee_fs_rpc head = { 0 };
320 	TEE_Result res;
321 
322 	DMSG("(id: %d, d: %p)...", id, (void *)d);
323 
324 	if (!d)
325 		goto exit;
326 
327 	head.op = TEE_FS_READDIR;
328 	head.arg = (int)d->nw_dir;
329 	head.len = sizeof(fname);
330 
331 	res = tee_fs_rpc_send_cmd(id, &head, fname, sizeof(fname),
332 				  TEE_FS_MODE_OUT);
333 	if (res != TEE_SUCCESS)
334 		goto exit;
335 
336 	if (head.res < 0)
337 		goto exit;
338 
339 	if (!head.len || head.len > sizeof(fname))
340 		goto exit;
341 
342 	fname[head.len - 1] = '\0'; /* make sure it's zero terminated */
343 	free(d->d.d_name);
344 	d->d.d_name = strdup(fname);
345 	if (!d->d.d_name)
346 		goto exit;
347 
348 	rc = &d->d;
349 exit:
350 	DMSG("...%p", (void *)rc);
351 	return rc;
352 }
353 
354 int tee_fs_rpc_rename(int id, const char *old, const char *nw)
355 {
356 	size_t len_old;
357 	size_t len_new;
358 	size_t len;
359 	struct tee_fs_rpc head = { 0 };
360 	char *tmp = NULL;
361 	TEE_Result res;
362 	int rc = RPC_FAILED;
363 
364 	DMSG("(id: %d, old: %s, nw: %s)...", id, old, nw);
365 
366 	if (!old || !nw)
367 		goto exit;
368 
369 	len_old = strlen(old) + 1;
370 	len_new = strlen(nw) + 1;
371 	len = len_old + len_new;
372 
373 	tmp = malloc(len);
374 	if (!tmp)
375 		goto exit;
376 
377 	memcpy(tmp, old, len_old);
378 	memcpy(tmp + len_old, nw, len_new);
379 
380 	head.op = TEE_FS_RENAME;
381 
382 	res = tee_fs_rpc_send_cmd(id, &head, tmp, len, TEE_FS_MODE_IN);
383 	if (res != TEE_SUCCESS)
384 		goto exit;
385 
386 	rc = head.res;
387 exit:
388 	free(tmp);
389 	DMSG("...%d", rc);
390 	return rc;
391 }
392 
393 int tee_fs_rpc_closedir(int id, struct tee_fs_dir *d)
394 {
395 	struct tee_fs_rpc head = { 0 };
396 	TEE_Result res;
397 	int rc = RPC_FAILED;
398 
399 	DMSG("(id: %d, d: %p)...", id, (void *)d);
400 
401 	if (!d) {
402 		rc = 0;
403 		goto exit;
404 	}
405 
406 	head.op = TEE_FS_CLOSEDIR;
407 	head.arg = (int)d->nw_dir;
408 
409 	res = tee_fs_rpc_send_cmd(id, &head, NULL, 0, TEE_FS_MODE_NONE);
410 	if (res != TEE_SUCCESS)
411 		goto exit;
412 
413 	rc = head.res;
414 exit:
415 	if (d)
416 		free(d->d.d_name);
417 	free(d);
418 
419 	DMSG("...%d", rc);
420 	return rc;
421 }
422 
423 int tee_fs_rpc_rmdir(int id, const char *name)
424 {
425 	struct tee_fs_rpc head = { 0 };
426 	TEE_Result res;
427 	int rc = RPC_FAILED;
428 	size_t len;
429 
430 	DMSG("(id: %d, name: %s)...", id, name);
431 
432 	if (!name)
433 		goto exit;
434 
435 	len = strlen(name) + 1;
436 	if (len <= 1)
437 		goto exit;
438 
439 	head.op = TEE_FS_RMDIR;
440 
441 	res = tee_fs_rpc_send_cmd(id, &head, (void *)name, len,
442 				  TEE_FS_MODE_IN);
443 	if (res != TEE_SUCCESS)
444 		goto exit;
445 
446 	rc = head.res;
447 exit:
448 	DMSG("...%d", rc);
449 	return rc;
450 }
451 
452 static TEE_Result operation_commit(struct tee_fs_rpc_operation *op)
453 {
454 	return thread_rpc_cmd(op->id, op->num_params, op->params);
455 }
456 
457 static TEE_Result operation_open(uint32_t id, unsigned int cmd,
458 				 const char *fname, int *fd)
459 {
460 	struct tee_fs_rpc_operation op = { .id = id, .num_params = 3 };
461 	TEE_Result res;
462 	void *va;
463 	paddr_t pa;
464 	uint64_t cookie;
465 	size_t fname_size = strlen(fname) + 1;
466 
467 	va = tee_fs_rpc_cache_alloc(fname_size, &pa, &cookie);
468 	if (!va)
469 		return TEE_ERROR_OUT_OF_MEMORY;
470 
471 	op.params[0].attr = OPTEE_MSG_ATTR_TYPE_VALUE_INPUT;
472 	op.params[0].u.value.a = cmd;
473 
474 	op.params[1].attr = OPTEE_MSG_ATTR_TYPE_TMEM_INPUT;
475 	op.params[1].u.tmem.buf_ptr = pa;
476 	op.params[1].u.tmem.size = fname_size;
477 	op.params[1].u.tmem.shm_ref = cookie;
478 	strlcpy(va, fname, fname_size);
479 
480 	op.params[2].attr = OPTEE_MSG_ATTR_TYPE_VALUE_OUTPUT;
481 
482 	res = operation_commit(&op);
483 	if (res == TEE_SUCCESS)
484 		*fd = op.params[2].u.value.a;
485 
486 	return res;
487 }
488 
489 TEE_Result tee_fs_rpc_new_open(uint32_t id, const char *fname, int *fd)
490 {
491 	return operation_open(id, OPTEE_MRF_OPEN, fname, fd);
492 }
493 
494 TEE_Result tee_fs_rpc_new_create(uint32_t id, const char *fname, int *fd)
495 {
496 	return operation_open(id, OPTEE_MRF_CREATE, fname, fd);
497 }
498 
499 TEE_Result tee_fs_rpc_new_close(uint32_t id, int fd)
500 {
501 	struct tee_fs_rpc_operation op = { .id = id, .num_params = 1 };
502 
503 	op.params[0].attr = OPTEE_MSG_ATTR_TYPE_VALUE_INPUT;
504 	op.params[0].u.value.a = OPTEE_MRF_CLOSE;
505 	op.params[0].u.value.b = fd;
506 
507 	return operation_commit(&op);
508 }
509 
510 TEE_Result tee_fs_rpc_new_read_init(struct tee_fs_rpc_operation *op,
511 				    uint32_t id, int fd, tee_fs_off_t offset,
512 				    size_t data_len, void **out_data)
513 {
514 	uint8_t *va;
515 	paddr_t pa;
516 	uint64_t cookie;
517 
518 	if (offset < 0)
519 		return TEE_ERROR_BAD_PARAMETERS;
520 
521 	va = tee_fs_rpc_cache_alloc(data_len, &pa, &cookie);
522 	if (!va)
523 		return TEE_ERROR_OUT_OF_MEMORY;
524 
525 	memset(op, 0, sizeof(*op));
526 	op->id = id;
527 	op->num_params = 2;
528 
529 	op->params[0].attr = OPTEE_MSG_ATTR_TYPE_VALUE_INPUT;
530 	op->params[0].u.value.a = OPTEE_MRF_READ;
531 	op->params[0].u.value.b = fd;
532 	op->params[0].u.value.c = offset;
533 
534 	op->params[1].attr = OPTEE_MSG_ATTR_TYPE_TMEM_OUTPUT;
535 	op->params[1].u.tmem.buf_ptr = pa;
536 	op->params[1].u.tmem.size = data_len;
537 	op->params[1].u.tmem.shm_ref = cookie;
538 
539 	*out_data = va;
540 
541 	return TEE_SUCCESS;
542 }
543 
544 TEE_Result tee_fs_rpc_new_read_final(struct tee_fs_rpc_operation *op,
545 				     size_t *data_len)
546 {
547 	TEE_Result res = operation_commit(op);
548 
549 	if (res == TEE_SUCCESS)
550 		*data_len = op->params[1].u.tmem.size;
551 	return res;
552 }
553 
554 TEE_Result tee_fs_rpc_new_write_init(struct tee_fs_rpc_operation *op,
555 				     uint32_t id, int fd, tee_fs_off_t offset,
556 				     size_t data_len, void **data)
557 {
558 	uint8_t *va;
559 	paddr_t pa;
560 	uint64_t cookie;
561 
562 	if (offset < 0)
563 		return TEE_ERROR_BAD_PARAMETERS;
564 
565 	va = tee_fs_rpc_cache_alloc(data_len, &pa, &cookie);
566 	if (!va)
567 		return TEE_ERROR_OUT_OF_MEMORY;
568 
569 	memset(op, 0, sizeof(*op));
570 	op->id = id;
571 	op->num_params = 2;
572 
573 
574 	op->params[0].attr = OPTEE_MSG_ATTR_TYPE_VALUE_INPUT;
575 	op->params[0].u.value.a = OPTEE_MRF_WRITE;
576 	op->params[0].u.value.b = fd;
577 	op->params[0].u.value.c = offset;
578 
579 	op->params[1].attr = OPTEE_MSG_ATTR_TYPE_TMEM_INPUT;
580 	op->params[1].u.tmem.buf_ptr = pa;
581 	op->params[1].u.tmem.size = data_len;
582 	op->params[1].u.tmem.shm_ref = cookie;
583 
584 	*data = va;
585 
586 	return TEE_SUCCESS;
587 }
588 
589 TEE_Result tee_fs_rpc_new_write_final(struct tee_fs_rpc_operation *op)
590 {
591 	return operation_commit(op);
592 }
593 
594 TEE_Result tee_fs_rpc_new_truncate(uint32_t id, int fd, size_t len)
595 {
596 	struct tee_fs_rpc_operation op = { .id = id, .num_params = 1 };
597 
598 	op.params[0].attr = OPTEE_MSG_ATTR_TYPE_VALUE_INPUT;
599 	op.params[0].u.value.a = OPTEE_MRF_TRUNCATE;
600 	op.params[0].u.value.b = fd;
601 	op.params[0].u.value.c = len;
602 
603 	return operation_commit(&op);
604 }
605 
606 TEE_Result tee_fs_rpc_new_remove(uint32_t id, const char *fname)
607 {
608 	struct tee_fs_rpc_operation op = { .id = id, .num_params = 2 };
609 	void *va;
610 	paddr_t pa;
611 	uint64_t cookie;
612 	size_t name_len = strlen(fname) + 1;
613 
614 	va = tee_fs_rpc_cache_alloc(name_len, &pa, &cookie);
615 	if (!va)
616 		return TEE_ERROR_OUT_OF_MEMORY;
617 
618 	op.params[0].attr = OPTEE_MSG_ATTR_TYPE_VALUE_INPUT;
619 	op.params[0].u.value.a = OPTEE_MRF_REMOVE;
620 
621 	op.params[1].attr = OPTEE_MSG_ATTR_TYPE_TMEM_INPUT;
622 	op.params[1].u.tmem.buf_ptr = pa;
623 	op.params[1].u.tmem.size = name_len;
624 	op.params[1].u.tmem.shm_ref = cookie;
625 	strlcpy(va, fname, name_len);
626 
627 	return operation_commit(&op);
628 }
629 
630 TEE_Result tee_fs_rpc_new_rename(uint32_t id, const char *old_fname,
631 				 const char *new_fname, bool overwrite)
632 {
633 	struct tee_fs_rpc_operation op = { .id = id, .num_params = 3 };
634 	char *va;
635 	paddr_t pa;
636 	uint64_t cookie;
637 	size_t old_fname_size = strlen(old_fname) + 1;
638 	size_t new_fname_size = strlen(new_fname) + 1;
639 
640 	va = tee_fs_rpc_cache_alloc(old_fname_size + new_fname_size,
641 				    &pa, &cookie);
642 	if (!va)
643 		return TEE_ERROR_OUT_OF_MEMORY;
644 
645 	op.params[0].attr = OPTEE_MSG_ATTR_TYPE_VALUE_INPUT;
646 	op.params[0].u.value.a = OPTEE_MRF_RENAME;
647 	op.params[0].u.value.b = overwrite;
648 
649 	op.params[1].attr = OPTEE_MSG_ATTR_TYPE_TMEM_INPUT;
650 	op.params[1].u.tmem.buf_ptr = pa;
651 	op.params[1].u.tmem.size = old_fname_size;
652 	op.params[1].u.tmem.shm_ref = cookie;
653 	strlcpy(va, old_fname, old_fname_size);
654 
655 	op.params[2].attr = OPTEE_MSG_ATTR_TYPE_TMEM_INPUT;
656 	op.params[2].u.tmem.buf_ptr = pa + old_fname_size;
657 	op.params[2].u.tmem.size = new_fname_size;
658 	op.params[2].u.tmem.shm_ref = cookie;
659 	strlcpy(va + old_fname_size, new_fname, new_fname_size);
660 
661 	return operation_commit(&op);
662 }
663 
664 TEE_Result tee_fs_rpc_new_opendir(uint32_t id, const char *name,
665 				  struct tee_fs_dir **d)
666 {
667 	TEE_Result res;
668 	struct tee_fs_rpc_operation op = { .id = id, .num_params = 3 };
669 	void *va;
670 	paddr_t pa;
671 	uint64_t cookie;
672 	size_t name_len = strlen(name) + 1;
673 	struct tee_fs_dir *dir = calloc(1, sizeof(*dir));
674 
675 	if (!dir)
676 		return TEE_ERROR_OUT_OF_MEMORY;
677 
678 	va = tee_fs_rpc_cache_alloc(name_len, &pa, &cookie);
679 	if (!va) {
680 		res = TEE_ERROR_OUT_OF_MEMORY;
681 		goto err_exit;
682 	}
683 
684 	op.params[0].attr = OPTEE_MSG_ATTR_TYPE_VALUE_INPUT;
685 	op.params[0].u.value.a = OPTEE_MRF_OPENDIR;
686 
687 	op.params[1].attr = OPTEE_MSG_ATTR_TYPE_TMEM_INPUT;
688 	op.params[1].u.tmem.buf_ptr = pa;
689 	op.params[1].u.tmem.size = name_len;
690 	op.params[1].u.tmem.shm_ref = cookie;
691 	strlcpy(va, name, name_len);
692 
693 	op.params[2].attr = OPTEE_MSG_ATTR_TYPE_VALUE_OUTPUT;
694 
695 	res = operation_commit(&op);
696 
697 	if (res != TEE_SUCCESS)
698 		goto err_exit;
699 
700 	dir->nw_dir = op.params[2].u.value.a;
701 	*d = dir;
702 
703 	return TEE_SUCCESS;
704 err_exit:
705 	free(dir);
706 
707 	return res;
708 }
709 
710 TEE_Result tee_fs_rpc_new_closedir(uint32_t id, struct tee_fs_dir *d)
711 {
712 	struct tee_fs_rpc_operation op = { .id = id, .num_params = 1 };
713 
714 	op.params[0].attr = OPTEE_MSG_ATTR_TYPE_VALUE_INPUT;
715 	op.params[0].u.value.a = OPTEE_MRF_CLOSEDIR;
716 	op.params[0].u.value.b = d->nw_dir;
717 
718 	if (d)
719 		free(d->d.d_name);
720 	free(d);
721 	return operation_commit(&op);
722 }
723 
724 TEE_Result tee_fs_rpc_new_readdir(uint32_t id, struct tee_fs_dir *d,
725 				  struct tee_fs_dirent **ent)
726 {
727 	TEE_Result res;
728 	struct tee_fs_rpc_operation op = { .id = id, .num_params = 2 };
729 	void *va;
730 	paddr_t pa;
731 	uint64_t cookie;
732 	const size_t max_name_len = TEE_FS_NAME_MAX + 1;
733 
734 	if (!d)
735 		return TEE_ERROR_ITEM_NOT_FOUND;
736 
737 	va = tee_fs_rpc_cache_alloc(max_name_len, &pa, &cookie);
738 	if (!va)
739 		return TEE_ERROR_OUT_OF_MEMORY;
740 
741 	op.params[0].attr = OPTEE_MSG_ATTR_TYPE_VALUE_INPUT;
742 	op.params[0].u.value.a = OPTEE_MRF_READDIR;
743 	op.params[0].u.value.b = d->nw_dir;
744 
745 	op.params[1].attr = OPTEE_MSG_ATTR_TYPE_TMEM_OUTPUT;
746 	op.params[1].u.tmem.buf_ptr = pa;
747 	op.params[1].u.tmem.size = max_name_len;
748 	op.params[1].u.tmem.shm_ref = cookie;
749 
750 	res = operation_commit(&op);
751 	if (res != TEE_SUCCESS)
752 		return res;
753 
754 	free(d->d.d_name);
755 	d->d.d_name = strndup(va, max_name_len);
756 	if (!d->d.d_name)
757 		return TEE_ERROR_OUT_OF_MEMORY;
758 
759 	*ent = &d->d;
760 	return TEE_SUCCESS;
761 }
762 
763 TEE_Result tee_fs_rpc_new_begin_transaction(uint32_t id)
764 {
765 	struct tee_fs_rpc_operation op = { .id = id, .num_params = 1 };
766 
767 	op.params[0].attr = OPTEE_MSG_ATTR_TYPE_VALUE_INPUT;
768 	op.params[0].u.value.a = OPTEE_MRF_BEGIN_TRANSACTION;
769 
770 	return operation_commit(&op);
771 }
772 
773 TEE_Result tee_fs_rpc_new_end_transaction(uint32_t id, bool rollback)
774 {
775 	struct tee_fs_rpc_operation op = { .id = id, .num_params = 1 };
776 
777 	op.params[0].attr = OPTEE_MSG_ATTR_TYPE_VALUE_INPUT;
778 	op.params[0].u.value.a = OPTEE_MRF_END_TRANSACTION;
779 	op.params[0].u.value.b = rollback;
780 
781 	return operation_commit(&op);
782 }
783