xref: /optee_os/core/tee/tee_rpmb_fs.c (revision 88e6e089bcabb6ed26a9ce200c61af09ad69a214)
1 /*
2  * Copyright (c) 2014, STMicroelectronics International N.V.
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 <kernel/tee_common.h>
29 #include <kernel/handle.h>
30 #include <tee/tee_rpmb_fs.h>
31 #include <tee/tee_rpmb.h>
32 #include <tee/tee_fs_defs.h>
33 #include <tee/tee_fs.h>
34 #include <mm/tee_mm.h>
35 #include <trace.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <string_ext.h>
39 #include <util.h>
40 #include <sys/queue.h>
41 
42 #define RPMB_STORAGE_START_ADDRESS      0
43 #define RPMB_FS_FAT_START_ADDRESS       512
44 #define RPMB_BLOCK_SIZE_SHIFT           8
45 
46 #define RPMB_FS_MAGIC                   0x52504D42
47 #define FS_VERSION                      2
48 #define N_ENTRIES                       8
49 
50 #define FILE_IS_ACTIVE                  (1u << 0)
51 #define FILE_IS_LAST_ENTRY              (1u << 1)
52 
53 /**
54  * FS parameters: Information often used by internal functions.
55  * fat_start_address will be set by rpmb_fs_setup().
56  * rpmb_fs_parameters can be read by any other function.
57  */
58 struct rpmb_fs_parameters {
59 	uint32_t fat_start_address;
60 	uint32_t max_rpmb_address;
61 };
62 
63 /**
64  * File entry for a single file in a RPMB_FS partition.
65  */
66 struct rpmb_fat_entry {
67 	uint32_t start_address;
68 	uint32_t data_size;
69 	uint32_t flags;
70 	uint32_t write_counter;
71 	char filename[TEE_RPMB_FS_FILENAME_LENGTH];
72 };
73 
74 /**
75  * FAT entry context with reference to a FAT entry and its
76  * location in RPMB.
77  */
78 struct rpmb_file_handle {
79 	/* Pointer to a fat_entry */
80 	struct rpmb_fat_entry fat_entry;
81 	/* Pointer to a filename */
82 	char filename[TEE_RPMB_FS_FILENAME_LENGTH];
83 	/* Adress for current entry in RPMB */
84 	uint32_t rpmb_fat_address;
85 	/* Current position */
86 	uint32_t pos;
87 };
88 
89 /**
90  * RPMB_FS partition data
91  */
92 struct rpmb_fs_partition {
93 	uint32_t rpmb_fs_magic;
94 	uint32_t fs_version;
95 	uint32_t write_counter;
96 	uint32_t fat_start_address;
97 	/* Do not use reserved[] for other purpose than partition data. */
98 	uint8_t reserved[112];
99 };
100 
101 /**
102  * A node in a list of directory entries. entry->name is a
103  * pointer to name here.
104  */
105 struct tee_rpmb_fs_dirent {
106 	struct tee_fs_dirent entry;
107 	char name[TEE_RPMB_FS_FILENAME_LENGTH];
108 	SIMPLEQ_ENTRY(tee_rpmb_fs_dirent) link;
109 };
110 
111 /**
112  * The RPMB directory representation. It contains a queue of
113  * RPMB directory entries: 'next'.
114  * The current pointer points to the last directory entry
115  * returned by readdir().
116  */
117 struct tee_fs_dir {
118 	struct tee_rpmb_fs_dirent *current;
119 	SIMPLEQ_HEAD(next_head, tee_rpmb_fs_dirent) next;
120 };
121 
122 static TEE_Result get_fat_start_address(uint32_t *addr);
123 
124 static struct rpmb_fs_parameters *fs_par;
125 
126 static struct handle_db fs_handle_db = HANDLE_DB_INITIALIZER;
127 
128 static void dump_fat(void)
129 {
130 	TEE_Result res = TEE_ERROR_GENERIC;
131 	struct rpmb_fat_entry *fat_entries = NULL;
132 	uint32_t fat_address;
133 	size_t size;
134 	int i;
135 	bool last_entry_found = false;
136 
137 	res = get_fat_start_address(&fat_address);
138 	if (res != TEE_SUCCESS)
139 		goto out;
140 
141 	size = N_ENTRIES * sizeof(struct rpmb_fat_entry);
142 	fat_entries = malloc(size);
143 	if (!fat_entries) {
144 		res = TEE_ERROR_OUT_OF_MEMORY;
145 		goto out;
146 	}
147 
148 	while (!last_entry_found) {
149 		res = tee_rpmb_read(CFG_RPMB_FS_DEV_ID, fat_address,
150 				    (uint8_t *)fat_entries, size);
151 		if (res != TEE_SUCCESS)
152 			goto out;
153 
154 		for (i = 0; i < N_ENTRIES; i++) {
155 
156 			FMSG("flags 0x%x, size %d, address 0x%x, filename '%s'",
157 				fat_entries[i].flags,
158 				fat_entries[i].data_size,
159 				fat_entries[i].start_address,
160 				fat_entries[i].filename);
161 
162 			if ((fat_entries[i].flags & FILE_IS_LAST_ENTRY) != 0) {
163 				last_entry_found = true;
164 				break;
165 			}
166 
167 			/* Move to next fat_entry. */
168 			fat_address += sizeof(struct rpmb_fat_entry);
169 		}
170 	}
171 
172 out:
173 	free(fat_entries);
174 }
175 
176 #if (TRACE_LEVEL >= TRACE_DEBUG)
177 static void dump_fh(struct rpmb_file_handle *fh)
178 {
179 	DMSG("fh->filename=%s", fh->filename);
180 	DMSG("fh->pos=%u", fh->pos);
181 	DMSG("fh->rpmb_fat_address=%u", fh->rpmb_fat_address);
182 	DMSG("fh->fat_entry.start_address=%u", fh->fat_entry.start_address);
183 	DMSG("fh->fat_entry.data_size=%u", fh->fat_entry.data_size);
184 }
185 #else
186 static void dump_fh(struct rpmb_file_handle *fh __unused)
187 {
188 }
189 #endif
190 
191 static struct rpmb_file_handle *alloc_file_handle(const char *filename)
192 {
193 	struct rpmb_file_handle *fh = NULL;
194 
195 	fh = calloc(1, sizeof(struct rpmb_file_handle));
196 	if (!fh)
197 		return NULL;
198 
199 	if (filename)
200 		strlcpy(fh->filename, filename, sizeof(fh->filename));
201 
202 	return fh;
203 }
204 
205 /**
206  * write_fat_entry: Store info in a fat_entry to RPMB.
207  */
208 static TEE_Result write_fat_entry(struct rpmb_file_handle *fh,
209 				  bool update_write_counter)
210 {
211 	TEE_Result res = TEE_ERROR_GENERIC;
212 
213 	/* Protect partition data. */
214 	if (fh->rpmb_fat_address < sizeof(struct rpmb_fs_partition)) {
215 		res = TEE_ERROR_ACCESS_CONFLICT;
216 		goto out;
217 	}
218 
219 	if (fh->rpmb_fat_address % sizeof(struct rpmb_fat_entry) != 0) {
220 		res = TEE_ERROR_BAD_PARAMETERS;
221 		goto out;
222 	}
223 
224 	if (update_write_counter) {
225 		res = tee_rpmb_get_write_counter(CFG_RPMB_FS_DEV_ID,
226 						 &fh->fat_entry.write_counter);
227 		if (res != TEE_SUCCESS)
228 			goto out;
229 	}
230 
231 	res = tee_rpmb_write(CFG_RPMB_FS_DEV_ID, fh->rpmb_fat_address,
232 			     (uint8_t *)&fh->fat_entry,
233 			     sizeof(struct rpmb_fat_entry));
234 
235 	dump_fat();
236 
237 out:
238 	return res;
239 }
240 
241 /**
242  * rpmb_fs_setup: Setup rpmb fs.
243  * Set initial partition and FS values and write to RPMB.
244  * Store frequently used data in RAM.
245  */
246 static TEE_Result rpmb_fs_setup(void)
247 {
248 	TEE_Result res = TEE_ERROR_GENERIC;
249 	struct rpmb_fs_partition *partition_data = NULL;
250 	struct rpmb_file_handle *fh = NULL;
251 	uint32_t max_rpmb_block = 0;
252 
253 	if (fs_par) {
254 		res = TEE_SUCCESS;
255 		goto out;
256 	}
257 
258 	res = tee_rpmb_get_max_block(CFG_RPMB_FS_DEV_ID, &max_rpmb_block);
259 	if (res != TEE_SUCCESS)
260 		goto out;
261 
262 	partition_data = calloc(1, sizeof(struct rpmb_fs_partition));
263 	if (!partition_data) {
264 		res = TEE_ERROR_OUT_OF_MEMORY;
265 		goto out;
266 	}
267 
268 	res = tee_rpmb_read(CFG_RPMB_FS_DEV_ID, RPMB_STORAGE_START_ADDRESS,
269 			    (uint8_t *)partition_data,
270 			    sizeof(struct rpmb_fs_partition));
271 	if (res != TEE_SUCCESS)
272 		goto out;
273 
274 #ifndef CFG_RPMB_RESET_FAT
275 	if (partition_data->rpmb_fs_magic == RPMB_FS_MAGIC) {
276 		if (partition_data->fs_version == FS_VERSION) {
277 			res = TEE_SUCCESS;
278 			goto store_fs_par;
279 		} else {
280 			/* Wrong software is in use. */
281 			res = TEE_ERROR_ACCESS_DENIED;
282 			goto out;
283 		}
284 	}
285 #else
286 	EMSG("**** Clearing Storage ****");
287 #endif
288 
289 	/* Setup new partition data. */
290 	partition_data->rpmb_fs_magic = RPMB_FS_MAGIC;
291 	partition_data->fs_version = FS_VERSION;
292 	partition_data->fat_start_address = RPMB_FS_FAT_START_ADDRESS;
293 
294 	/* Initial FAT entry with FILE_IS_LAST_ENTRY flag set. */
295 	fh = alloc_file_handle(NULL);
296 	if (!fh) {
297 		res = TEE_ERROR_OUT_OF_MEMORY;
298 		goto out;
299 	}
300 	fh->fat_entry.flags = FILE_IS_LAST_ENTRY;
301 	fh->rpmb_fat_address = partition_data->fat_start_address;
302 
303 	/* Write init FAT entry and partition data to RPMB. */
304 	res = write_fat_entry(fh, true);
305 	if (res != TEE_SUCCESS)
306 		goto out;
307 
308 	res =
309 	    tee_rpmb_get_write_counter(CFG_RPMB_FS_DEV_ID,
310 				       &partition_data->write_counter);
311 	if (res != TEE_SUCCESS)
312 		goto out;
313 	res = tee_rpmb_write(CFG_RPMB_FS_DEV_ID, RPMB_STORAGE_START_ADDRESS,
314 			     (uint8_t *)partition_data,
315 			     sizeof(struct rpmb_fs_partition));
316 
317 #ifndef CFG_RPMB_RESET_FAT
318 store_fs_par:
319 #endif
320 
321 	/* Store FAT start address. */
322 	fs_par = calloc(1, sizeof(struct rpmb_fs_parameters));
323 	if (!fs_par) {
324 		res = TEE_ERROR_OUT_OF_MEMORY;
325 		goto out;
326 	}
327 
328 	fs_par->fat_start_address = partition_data->fat_start_address;
329 	fs_par->max_rpmb_address = max_rpmb_block << RPMB_BLOCK_SIZE_SHIFT;
330 
331 	dump_fat();
332 
333 out:
334 	free(fh);
335 	free(partition_data);
336 	return res;
337 }
338 
339 /**
340  * get_fat_start_address:
341  * FAT start_address from fs_par.
342  */
343 static TEE_Result get_fat_start_address(uint32_t *addr)
344 {
345 	if (!fs_par)
346 		return TEE_ERROR_NO_DATA;
347 
348 	*addr = fs_par->fat_start_address;
349 
350 	return TEE_SUCCESS;
351 }
352 
353 /**
354  * read_fat: Read FAT entries
355  * Return matching FAT entry for read, rm rename and stat.
356  * Build up memory pool and return matching entry for write operation.
357  * "Last FAT entry" can be returned during write.
358  */
359 static TEE_Result read_fat(struct rpmb_file_handle *fh, tee_mm_pool_t *p)
360 {
361 	TEE_Result res = TEE_ERROR_GENERIC;
362 	tee_mm_entry_t *mm = NULL;
363 	struct rpmb_fat_entry *fat_entries = NULL;
364 	uint32_t fat_address;
365 	size_t size;
366 	int i;
367 	bool entry_found = false;
368 	bool last_entry_found = false;
369 	bool expand_fat = false;
370 	struct rpmb_file_handle last_fh;
371 
372 	DMSG("fat_address %d", fh->rpmb_fat_address);
373 
374 	res = rpmb_fs_setup();
375 	if (res != TEE_SUCCESS)
376 		goto out;
377 
378 	res = get_fat_start_address(&fat_address);
379 	if (res != TEE_SUCCESS)
380 		goto out;
381 
382 	size = N_ENTRIES * sizeof(struct rpmb_fat_entry);
383 	fat_entries = malloc(size);
384 	if (!fat_entries) {
385 		res = TEE_ERROR_OUT_OF_MEMORY;
386 		goto out;
387 	}
388 
389 	/*
390 	 * The pool is used to represent the current RPMB layout. To find
391 	 * a slot for the file tee_mm_alloc is called on the pool. Thus
392 	 * if it is not NULL the entire FAT must be traversed to fill in
393 	 * the pool.
394 	 */
395 	while (!last_entry_found && (!entry_found || p)) {
396 		res = tee_rpmb_read(CFG_RPMB_FS_DEV_ID, fat_address,
397 				    (uint8_t *)fat_entries, size);
398 		if (res != TEE_SUCCESS)
399 			goto out;
400 
401 		for (i = 0; i < N_ENTRIES; i++) {
402 			/*
403 			 * Look for an entry, matching filenames. (read, rm,
404 			 * rename and stat.). Only store first filename match.
405 			 */
406 			if (fh->filename &&
407 			    (strcmp(fh->filename,
408 				    fat_entries[i].filename) == 0) &&
409 			    (fat_entries[i].flags & FILE_IS_ACTIVE) &&
410 			    (!entry_found)) {
411 				entry_found = true;
412 				fh->rpmb_fat_address = fat_address;
413 				memcpy(&fh->fat_entry, &fat_entries[i],
414 				       sizeof(struct rpmb_fat_entry));
415 				if (!p)
416 					break;
417 			}
418 
419 			/* Add existing files to memory pool. (write) */
420 			if (p) {
421 				if ((fat_entries[i].flags & FILE_IS_ACTIVE) &&
422 				    (fat_entries[i].data_size > 0)) {
423 
424 					mm = tee_mm_alloc2
425 						(p,
426 						 fat_entries[i].start_address,
427 						 fat_entries[i].data_size);
428 					if (!mm) {
429 						res = TEE_ERROR_OUT_OF_MEMORY;
430 						goto out;
431 					}
432 				}
433 
434 				/* Unused FAT entries can be reused (write) */
435 				if (((fat_entries[i].flags & FILE_IS_ACTIVE) ==
436 				     0) && (fh->rpmb_fat_address == 0)) {
437 					fh->rpmb_fat_address = fat_address;
438 					memcpy(&fh->fat_entry, &fat_entries[i],
439 					       sizeof(struct rpmb_fat_entry));
440 				}
441 			}
442 
443 			if ((fat_entries[i].flags & FILE_IS_LAST_ENTRY) != 0) {
444 				last_entry_found = true;
445 
446 				/*
447 				 * If the last entry was reached and was chosen
448 				 * by the previous check, then the FAT needs to
449 				 * be expanded.
450 				 * fh->rpmb_fat_address is the address chosen
451 				 * to store the files FAT entry and fat_address
452 				 * is the current FAT entry address being
453 				 * compared.
454 				 */
455 				if (p && fh->rpmb_fat_address == fat_address)
456 					expand_fat = true;
457 				break;
458 			}
459 
460 			/* Move to next fat_entry. */
461 			fat_address += sizeof(struct rpmb_fat_entry);
462 		}
463 	}
464 
465 	/*
466 	 * Represent the FAT table in the pool.
467 	 */
468 	if (p) {
469 		/*
470 		 * Since fat_address is the start of the last entry it needs to
471 		 * be moved up by an entry.
472 		 */
473 		fat_address += sizeof(struct rpmb_fat_entry);
474 
475 		/* Make room for yet a FAT entry and add to memory pool. */
476 		if (expand_fat)
477 			fat_address += sizeof(struct rpmb_fat_entry);
478 
479 		mm = tee_mm_alloc2(p, RPMB_STORAGE_START_ADDRESS, fat_address);
480 		if (!mm) {
481 			res = TEE_ERROR_OUT_OF_MEMORY;
482 			goto out;
483 		}
484 
485 		if (expand_fat) {
486 			/*
487 			 * Point fat_address to the beginning of the new
488 			 * entry.
489 			 */
490 			fat_address -= sizeof(struct rpmb_fat_entry);
491 			memset(&last_fh, 0, sizeof(last_fh));
492 			last_fh.fat_entry.flags = FILE_IS_LAST_ENTRY;
493 			last_fh.rpmb_fat_address = fat_address;
494 			res = write_fat_entry(&last_fh, true);
495 			if (res != TEE_SUCCESS)
496 				goto out;
497 		}
498 	}
499 
500 	if (fh->filename && !fh->rpmb_fat_address)
501 		res = TEE_ERROR_FILE_NOT_FOUND;
502 
503 out:
504 	free(fat_entries);
505 	return res;
506 }
507 
508 int tee_rpmb_fs_open(const char *file, int flags, ...)
509 {
510 	int fd = -1;
511 	struct rpmb_file_handle *fh = NULL;
512 	size_t filelen;
513 	tee_mm_pool_t p;
514 	bool pool_result;
515 	TEE_Result res = TEE_ERROR_GENERIC;
516 
517 	if (!file) {
518 		res = TEE_ERROR_BAD_PARAMETERS;
519 		goto out;
520 	}
521 
522 	filelen = strlen(file);
523 	if (filelen >= TEE_RPMB_FS_FILENAME_LENGTH - 1 || filelen == 0) {
524 		res = TEE_ERROR_BAD_PARAMETERS;
525 		goto out;
526 	}
527 
528 	if (file[filelen - 1] == '/') {
529 		res = TEE_ERROR_BAD_PARAMETERS;
530 		goto out;
531 	}
532 
533 	fh = alloc_file_handle(file);
534 	if (!fh) {
535 		res = TEE_ERROR_OUT_OF_MEMORY;
536 		goto out;
537 	}
538 
539 	/* We need to do setup in order to make sure fs_par is filled in */
540 	res = rpmb_fs_setup();
541 	if (res != TEE_SUCCESS)
542 		goto out;
543 
544 	if (flags & TEE_FS_O_CREATE) {
545 		/* Upper memory allocation must be used for RPMB_FS. */
546 		pool_result = tee_mm_init(&p,
547 					  RPMB_STORAGE_START_ADDRESS,
548 					  fs_par->max_rpmb_address,
549 					  RPMB_BLOCK_SIZE_SHIFT,
550 					  TEE_MM_POOL_HI_ALLOC);
551 
552 		if (!pool_result) {
553 			res = TEE_ERROR_OUT_OF_MEMORY;
554 			goto out;
555 		}
556 
557 		res = read_fat(fh, &p);
558 		tee_mm_final(&p);
559 		if (res != TEE_SUCCESS)
560 			goto out;
561 
562 	} else {
563 		res = read_fat(fh, NULL);
564 		if (res != TEE_SUCCESS)
565 			goto out;
566 	}
567 
568 	/* Add the handle to the db */
569 	fd = handle_get(&fs_handle_db, fh);
570 	if (fd == -1) {
571 		res = TEE_ERROR_OUT_OF_MEMORY;
572 		goto out;
573 	}
574 
575 	/*
576 	 * If this is opened with create and the entry found was not active
577 	 * then this is a new file and the FAT entry must be written
578 	 */
579 	if (flags & TEE_FS_O_CREATE) {
580 		if ((fh->fat_entry.flags & FILE_IS_ACTIVE) == 0) {
581 			memset(&fh->fat_entry, 0,
582 				sizeof(struct rpmb_fat_entry));
583 			memcpy(fh->fat_entry.filename, file, strlen(file));
584 			/* Start address and size are 0 */
585 			fh->fat_entry.flags = FILE_IS_ACTIVE;
586 
587 			res = write_fat_entry(fh, true);
588 			if (res != TEE_SUCCESS) {
589 				handle_put(&fs_handle_db, fd);
590 				fd = -1;
591 				goto out;
592 			}
593 		}
594 	}
595 
596 	res = TEE_SUCCESS;
597 
598 out:
599 	if (res != TEE_SUCCESS) {
600 		if (fh)
601 			free(fh);
602 
603 		fd = -1;
604 	}
605 
606 	return fd;
607 }
608 
609 int tee_rpmb_fs_close(int fd)
610 {
611 	struct rpmb_file_handle *fh;
612 
613 	fh = handle_put(&fs_handle_db, fd);
614 	if (fh) {
615 		free(fh);
616 		return 0;
617 	}
618 
619 	return -1;
620 }
621 
622 int tee_rpmb_fs_read(int fd, uint8_t *buf, size_t size)
623 {
624 	TEE_Result res = TEE_ERROR_GENERIC;
625 	struct rpmb_file_handle *fh;
626 	int read_size = -1;
627 
628 	if (!size)
629 		return 0;
630 
631 	if (!buf) {
632 		res = TEE_ERROR_BAD_PARAMETERS;
633 		goto out;
634 	}
635 
636 	fh = handle_lookup(&fs_handle_db, fd);
637 	if (!fh) {
638 		res = TEE_ERROR_BAD_PARAMETERS;
639 		goto out;
640 	}
641 	dump_fh(fh);
642 
643 	res = read_fat(fh, NULL);
644 	if (res != TEE_SUCCESS)
645 		goto out;
646 
647 	size = MIN(size, fh->fat_entry.data_size - fh->pos);
648 	if (size > 0) {
649 		res = tee_rpmb_read(CFG_RPMB_FS_DEV_ID,
650 				    fh->fat_entry.start_address + fh->pos, buf,
651 				    size);
652 		if (res != TEE_SUCCESS)
653 			goto out;
654 	}
655 
656 	read_size = size;
657 	res = TEE_SUCCESS;
658 
659 out:
660 	if (res != TEE_SUCCESS)
661 		read_size = -1;
662 
663 	return read_size;
664 }
665 
666 int tee_rpmb_fs_write(int fd, uint8_t *buf, size_t size)
667 {
668 	TEE_Result res = TEE_ERROR_GENERIC;
669 	struct rpmb_file_handle *fh;
670 	tee_mm_pool_t p;
671 	bool pool_result = false;
672 	tee_mm_entry_t *mm;
673 	size_t end;
674 	size_t newsize;
675 	uint8_t *newbuf = NULL;
676 	uintptr_t newaddr;
677 	uint32_t start_addr;
678 
679 	if (!size)
680 		return 0;
681 
682 	if (!buf) {
683 		res = TEE_ERROR_BAD_PARAMETERS;
684 		goto out;
685 	}
686 
687 	if (!fs_par) {
688 		res = TEE_ERROR_GENERIC;
689 		goto out;
690 	}
691 
692 	fh = handle_lookup(&fs_handle_db, fd);
693 	if (!fh) {
694 		res = TEE_ERROR_BAD_PARAMETERS;
695 		goto out;
696 	}
697 	dump_fh(fh);
698 
699 	/* Upper memory allocation must be used for RPMB_FS. */
700 	pool_result = tee_mm_init(&p,
701 				  RPMB_STORAGE_START_ADDRESS,
702 				  fs_par->max_rpmb_address,
703 				  RPMB_BLOCK_SIZE_SHIFT,
704 				  TEE_MM_POOL_HI_ALLOC);
705 	if (!pool_result) {
706 		res = TEE_ERROR_OUT_OF_MEMORY;
707 		goto out;
708 	}
709 
710 	res = read_fat(fh, &p);
711 	if (res != TEE_SUCCESS)
712 		goto out;
713 
714 	TEE_ASSERT(!(fh->fat_entry.flags & FILE_IS_LAST_ENTRY));
715 
716 	end = fh->pos + size;
717 	start_addr = fh->fat_entry.start_address + fh->pos;
718 
719 	if (end <= fh->fat_entry.data_size &&
720 	    tee_rpmb_write_is_atomic(CFG_RPMB_FS_DEV_ID, start_addr, size)) {
721 
722 		DMSG("Updating data in-place");
723 		res = tee_rpmb_write(CFG_RPMB_FS_DEV_ID, start_addr, buf,
724 				     size);
725 		if (res != TEE_SUCCESS)
726 			goto out;
727 	} else {
728 		/*
729 		 * File must be extended, or update cannot be atomic: allocate,
730 		 * read, update, write.
731 		 */
732 
733 		DMSG("Need to re-allocate");
734 		newsize = MAX(end, fh->fat_entry.data_size);
735 		mm = tee_mm_alloc(&p, newsize);
736 		newbuf = calloc(newsize, 1);
737 		if (!mm || !newbuf) {
738 			res = TEE_ERROR_OUT_OF_MEMORY;
739 			goto out;
740 		}
741 
742 		if (fh->fat_entry.data_size) {
743 			res = tee_rpmb_read(CFG_RPMB_FS_DEV_ID,
744 					    fh->fat_entry.start_address,
745 					    newbuf, fh->fat_entry.data_size);
746 			if (res != TEE_SUCCESS)
747 				goto out;
748 		}
749 
750 		memcpy(newbuf + fh->pos, buf, size);
751 
752 		newaddr = tee_mm_get_smem(mm);
753 		res = tee_rpmb_write(CFG_RPMB_FS_DEV_ID, newaddr, newbuf,
754 				     newsize);
755 		if (res != TEE_SUCCESS)
756 			goto out;
757 
758 		fh->fat_entry.data_size = newsize;
759 		fh->fat_entry.start_address = newaddr;
760 		res = write_fat_entry(fh, true);
761 		if (res != TEE_SUCCESS)
762 			goto out;
763 	}
764 
765 	fh->pos += size;
766 out:
767 	if (pool_result)
768 		tee_mm_final(&p);
769 	if (newbuf)
770 		free(newbuf);
771 
772 	if (res == TEE_SUCCESS)
773 		return size;
774 
775 	return -1;
776 }
777 
778 tee_fs_off_t tee_rpmb_fs_lseek(int fd, tee_fs_off_t offset, int whence)
779 {
780 	struct rpmb_file_handle *fh;
781 	TEE_Result res;
782 	tee_fs_off_t ret = -1;
783 	tee_fs_off_t new_pos;
784 
785 	fh = handle_lookup(&fs_handle_db, fd);
786 	if (!fh)
787 		return TEE_ERROR_BAD_PARAMETERS;
788 
789 	res = read_fat(fh, NULL);
790 	if (res != TEE_SUCCESS)
791 		return -1;
792 
793 	switch (whence) {
794 	case TEE_FS_SEEK_SET:
795 		new_pos = offset;
796 		break;
797 
798 	case TEE_FS_SEEK_CUR:
799 		new_pos = fh->pos + offset;
800 		break;
801 
802 	case TEE_FS_SEEK_END:
803 		new_pos = fh->fat_entry.data_size + offset;
804 		break;
805 
806 	default:
807 		goto exit;
808 	}
809 
810 	if (new_pos < 0)
811 		new_pos = 0;
812 
813 	if (new_pos > TEE_DATA_MAX_POSITION) {
814 		EMSG("Position is beyond TEE_DATA_MAX_POSITION");
815 		goto exit;
816 	}
817 
818 	ret = fh->pos = new_pos;
819 exit:
820 	return ret;
821 }
822 
823 TEE_Result tee_rpmb_fs_rm(const char *filename)
824 {
825 	TEE_Result res = TEE_ERROR_GENERIC;
826 	struct rpmb_file_handle *fh = NULL;
827 
828 	if (!filename || strlen(filename) >= TEE_RPMB_FS_FILENAME_LENGTH - 1) {
829 		res = TEE_ERROR_BAD_PARAMETERS;
830 		goto out;
831 	}
832 
833 	fh = alloc_file_handle(filename);
834 	if (!fh) {
835 		res = TEE_ERROR_OUT_OF_MEMORY;
836 		goto out;
837 	}
838 
839 	res = read_fat(fh, NULL);
840 	if (res != TEE_SUCCESS)
841 		goto out;
842 
843 	/* Clear this file entry. */
844 	memset(&fh->fat_entry, 0, sizeof(struct rpmb_fat_entry));
845 	res = write_fat_entry(fh, false);
846 
847 out:
848 	free(fh);
849 	IMSG("Deleting file %s returned 0x%x\n", filename, res);
850 	return res;
851 }
852 
853 TEE_Result tee_rpmb_fs_rename(const char *old_name, const char *new_name)
854 {
855 	TEE_Result res = TEE_ERROR_GENERIC;
856 	struct rpmb_file_handle *fh_old = NULL;
857 	struct rpmb_file_handle *fh_new = NULL;
858 	uint32_t old_len;
859 	uint32_t new_len;
860 
861 	if (!old_name || !new_name) {
862 		res = TEE_ERROR_BAD_PARAMETERS;
863 		goto out;
864 	}
865 
866 	old_len = strlen(old_name);
867 	new_len = strlen(new_name);
868 
869 	if ((old_len >= TEE_RPMB_FS_FILENAME_LENGTH - 1) ||
870 	    (new_len >= TEE_RPMB_FS_FILENAME_LENGTH - 1) || (new_len == 0)) {
871 
872 		res = TEE_ERROR_BAD_PARAMETERS;
873 		goto out;
874 	}
875 
876 	fh_old = alloc_file_handle(old_name);
877 	if (!fh_old) {
878 		res = TEE_ERROR_OUT_OF_MEMORY;
879 		goto out;
880 	}
881 
882 	fh_new = alloc_file_handle(new_name);
883 	if (!fh_new) {
884 		res = TEE_ERROR_OUT_OF_MEMORY;
885 		goto out;
886 	}
887 
888 	res = read_fat(fh_old, NULL);
889 	if (res != TEE_SUCCESS)
890 		goto out;
891 
892 	res = read_fat(fh_new, NULL);
893 	if (res == TEE_SUCCESS) {
894 		res = TEE_ERROR_BAD_PARAMETERS;
895 		goto out;
896 	}
897 
898 	memset(fh_old->fat_entry.filename, 0, TEE_RPMB_FS_FILENAME_LENGTH);
899 	memcpy(fh_old->fat_entry.filename, new_name, new_len);
900 
901 	res = write_fat_entry(fh_old, false);
902 
903 out:
904 	free(fh_old);
905 	free(fh_new);
906 
907 	return res;
908 }
909 
910 int tee_rpmb_fs_mkdir(const char *path __unused, tee_fs_mode_t mode __unused)
911 {
912 	/*
913 	 * FIXME: mkdir() should really create some entry in the FAT so that
914 	 * access() would return success when the directory exists but is
915 	 * empty. This does not matter for the current use cases.
916 	 */
917 	return 0;
918 }
919 
920 int tee_rpmb_fs_ftruncate(int fd, tee_fs_off_t length)
921 {
922 	struct rpmb_file_handle *fh;
923 	tee_mm_pool_t p;
924 	bool pool_result = false;
925 	tee_mm_entry_t *mm;
926 	uint32_t newsize;
927 	uint8_t *newbuf = NULL;
928 	uintptr_t newaddr;
929 	TEE_Result res = TEE_ERROR_GENERIC;
930 
931 	if (length < 0 || length > INT32_MAX) {
932 		res = TEE_ERROR_BAD_PARAMETERS;
933 		goto out;
934 	}
935 	newsize = length;
936 
937 	fh = handle_lookup(&fs_handle_db, fd);
938 	if (!fh) {
939 		res = TEE_ERROR_BAD_PARAMETERS;
940 		goto out;
941 	}
942 
943 	res = read_fat(fh, NULL);
944 	if (res != TEE_SUCCESS)
945 		goto out;
946 
947 	if (newsize > fh->fat_entry.data_size) {
948 		/* Extend file */
949 
950 		pool_result = tee_mm_init(&p,
951 					  RPMB_STORAGE_START_ADDRESS,
952 					  fs_par->max_rpmb_address,
953 					  RPMB_BLOCK_SIZE_SHIFT,
954 					  TEE_MM_POOL_HI_ALLOC);
955 		if (!pool_result) {
956 			res = TEE_ERROR_OUT_OF_MEMORY;
957 			goto out;
958 		}
959 		res = read_fat(fh, &p);
960 		if (res != TEE_SUCCESS)
961 			goto out;
962 
963 		mm = tee_mm_alloc(&p, newsize);
964 		newbuf = calloc(newsize, 1);
965 		if (!mm || !newbuf) {
966 			res = TEE_ERROR_OUT_OF_MEMORY;
967 			goto out;
968 		}
969 
970 		if (fh->fat_entry.data_size) {
971 			res = tee_rpmb_read(CFG_RPMB_FS_DEV_ID,
972 					    fh->fat_entry.start_address,
973 					    newbuf, fh->fat_entry.data_size);
974 			if (res != TEE_SUCCESS)
975 				goto out;
976 		}
977 
978 		newaddr = tee_mm_get_smem(mm);
979 		res = tee_rpmb_write(CFG_RPMB_FS_DEV_ID, newaddr, newbuf,
980 				     newsize);
981 		if (res != TEE_SUCCESS)
982 			goto out;
983 
984 	} else {
985 		/* Don't change file location */
986 		newaddr = fh->fat_entry.start_address;
987 	}
988 
989 	/* fh->pos is unchanged */
990 	fh->fat_entry.data_size = newsize;
991 	fh->fat_entry.start_address = newaddr;
992 	res = write_fat_entry(fh, true);
993 
994 out:
995 	if (pool_result)
996 		tee_mm_final(&p);
997 	if (newbuf)
998 		free(newbuf);
999 
1000 	if (res == TEE_SUCCESS)
1001 		return 0;
1002 
1003 	return -1;
1004 }
1005 
1006 static void tee_rpmb_fs_dir_free(tee_fs_dir *dir)
1007 {
1008 	struct tee_rpmb_fs_dirent *e;
1009 
1010 	if (!dir)
1011 		return;
1012 
1013 	free(dir->current);
1014 
1015 	while ((e = SIMPLEQ_FIRST(&dir->next))) {
1016 		SIMPLEQ_REMOVE_HEAD(&dir->next, link);
1017 		free(e);
1018 	}
1019 }
1020 
1021 static TEE_Result tee_rpmb_fs_dir_populate(const char *path, tee_fs_dir *dir)
1022 {
1023 	struct tee_rpmb_fs_dirent *current = NULL;
1024 	struct rpmb_fat_entry *fat_entries = NULL;
1025 	uint32_t fat_address;
1026 	uint32_t filelen;
1027 	char *filename;
1028 	int i;
1029 	bool last_entry_found = false;
1030 	bool matched;
1031 	struct tee_rpmb_fs_dirent *next = NULL;
1032 	uint32_t pathlen;
1033 	TEE_Result res = TEE_ERROR_GENERIC;
1034 	uint32_t size;
1035 	char temp;
1036 
1037 	res = rpmb_fs_setup();
1038 	if (res != TEE_SUCCESS)
1039 		goto out;
1040 
1041 	res = get_fat_start_address(&fat_address);
1042 	if (res != TEE_SUCCESS)
1043 		goto out;
1044 
1045 	size = N_ENTRIES * sizeof(struct rpmb_fat_entry);
1046 	fat_entries = malloc(size);
1047 	if (!fat_entries) {
1048 		res = TEE_ERROR_OUT_OF_MEMORY;
1049 		goto out;
1050 	}
1051 
1052 	pathlen = strlen(path);
1053 	while (!last_entry_found) {
1054 		res = tee_rpmb_read(CFG_RPMB_FS_DEV_ID, fat_address,
1055 				    (uint8_t *)fat_entries, size);
1056 		if (res != TEE_SUCCESS)
1057 			goto out;
1058 
1059 		for (i = 0; i < N_ENTRIES; i++) {
1060 			filename = fat_entries[i].filename;
1061 			if (fat_entries[i].flags & FILE_IS_ACTIVE) {
1062 				matched = false;
1063 				filelen = strlen(filename);
1064 				if (filelen > pathlen) {
1065 					temp = filename[pathlen];
1066 					filename[pathlen] = '\0';
1067 					if (strcmp(filename, path) == 0)
1068 						matched = true;
1069 
1070 					filename[pathlen] = temp;
1071 				}
1072 
1073 				if (matched) {
1074 					next = malloc(sizeof(*next));
1075 					if (!next) {
1076 						res = TEE_ERROR_OUT_OF_MEMORY;
1077 						goto out;
1078 					}
1079 
1080 					memset(next, 0, sizeof(*next));
1081 					next->entry.d_name = next->name;
1082 					memcpy(next->name,
1083 						&filename[pathlen],
1084 						filelen - pathlen);
1085 
1086 					SIMPLEQ_INSERT_TAIL(&dir->next, next,
1087 							    link);
1088 					current = next;
1089 				}
1090 			}
1091 
1092 			if (fat_entries[i].flags & FILE_IS_LAST_ENTRY) {
1093 				last_entry_found = true;
1094 				break;
1095 			}
1096 
1097 			/* Move to next fat_entry. */
1098 			fat_address += sizeof(struct rpmb_fat_entry);
1099 		}
1100 	}
1101 
1102 	/* No directories were found. */
1103 	if (!current) {
1104 		res = TEE_ERROR_NO_DATA;
1105 		goto out;
1106 	}
1107 
1108 	res = TEE_SUCCESS;
1109 
1110 out:
1111 	if (res != TEE_SUCCESS)
1112 		tee_rpmb_fs_dir_free(dir);
1113 	if (fat_entries)
1114 		free(fat_entries);
1115 
1116 	return res;
1117 }
1118 
1119 static TEE_Result tee_rpmb_fs_opendir_internal(const char *path,
1120 						tee_fs_dir **dir)
1121 {
1122 	uint32_t len;
1123 	uint32_t max_size;
1124 	char path_local[TEE_RPMB_FS_FILENAME_LENGTH];
1125 	TEE_Result res = TEE_ERROR_GENERIC;
1126 	tee_fs_dir *rpmb_dir = NULL;
1127 
1128 	if (!path || !dir) {
1129 		res = TEE_ERROR_BAD_PARAMETERS;
1130 		goto out;
1131 	}
1132 
1133 	/*
1134 	 * There must be room for at least the NULL char and a char for the
1135 	 * filename after the path.
1136 	 */
1137 	max_size = TEE_RPMB_FS_FILENAME_LENGTH - 2;
1138 	len = strlen(path);
1139 	if (len > max_size || len == 0) {
1140 		res = TEE_ERROR_BAD_PARAMETERS;
1141 		goto out;
1142 	}
1143 
1144 	memset(path_local, 0, sizeof(path_local));
1145 	memcpy(path_local, path, len);
1146 
1147 	/* Add a slash to correctly match the full directory name. */
1148 	if (path_local[len - 1] != '/')
1149 		path_local[len] = '/';
1150 
1151 	rpmb_dir = calloc(1, sizeof(tee_fs_dir));
1152 	if (!rpmb_dir) {
1153 		res = TEE_ERROR_OUT_OF_MEMORY;
1154 		goto out;
1155 	}
1156 	SIMPLEQ_INIT(&rpmb_dir->next);
1157 
1158 	res = tee_rpmb_fs_dir_populate(path_local, rpmb_dir);
1159 	if (res != TEE_SUCCESS) {
1160 		free(rpmb_dir);
1161 		rpmb_dir = NULL;
1162 		goto out;
1163 	}
1164 
1165 	*dir = rpmb_dir;
1166 
1167 out:
1168 	return res;
1169 }
1170 
1171 tee_fs_dir *tee_rpmb_fs_opendir(const char *path)
1172 {
1173 	tee_fs_dir *dir = NULL;
1174 	TEE_Result res = TEE_ERROR_GENERIC;
1175 
1176 	res = tee_rpmb_fs_opendir_internal(path, &dir);
1177 	if (res != TEE_SUCCESS)
1178 		dir = NULL;
1179 
1180 	return dir;
1181 }
1182 
1183 
1184 struct tee_fs_dirent *tee_rpmb_fs_readdir(tee_fs_dir *dir)
1185 {
1186 	if (!dir)
1187 		return NULL;
1188 
1189 	free(dir->current);
1190 
1191 	dir->current = SIMPLEQ_FIRST(&dir->next);
1192 	if (!dir->current)
1193 		return NULL;
1194 
1195 	SIMPLEQ_REMOVE_HEAD(&dir->next, link);
1196 
1197 	return &dir->current->entry;
1198 }
1199 
1200 int tee_rpmb_fs_closedir(tee_fs_dir *dir)
1201 {
1202 	TEE_Result res = TEE_ERROR_GENERIC;
1203 
1204 	if (!dir) {
1205 		res = TEE_SUCCESS;
1206 		goto out;
1207 	}
1208 
1209 	tee_rpmb_fs_dir_free(dir);
1210 	free(dir);
1211 	res = TEE_SUCCESS;
1212 out:
1213 	if (res == TEE_SUCCESS)
1214 		return 0;
1215 
1216 	return -1;
1217 }
1218 
1219 int tee_rpmb_fs_rmdir(const char *path)
1220 {
1221 	tee_fs_dir *dir = NULL;
1222 	TEE_Result res = TEE_ERROR_GENERIC;
1223 	int ret = -1;
1224 
1225 	/* Open the directory anyting other than NO_DATA is a failure */
1226 	res = tee_rpmb_fs_opendir_internal(path, &dir);
1227 	if (res == TEE_SUCCESS) {
1228 		tee_rpmb_fs_closedir(dir);
1229 		ret = -1;
1230 
1231 	} else if (res == TEE_ERROR_NO_DATA) {
1232 		ret = 0;
1233 
1234 	} else {
1235 		/* The case any other failure is returned */
1236 		ret = -1;
1237 	}
1238 
1239 
1240 	return ret;
1241 }
1242 
1243 TEE_Result tee_rpmb_fs_stat(const char *filename,
1244 			    struct tee_rpmb_fs_stat *stat)
1245 {
1246 	TEE_Result res = TEE_ERROR_GENERIC;
1247 	struct rpmb_file_handle *fh = NULL;
1248 
1249 	if (!stat || !filename) {
1250 		res = TEE_ERROR_BAD_PARAMETERS;
1251 		goto out;
1252 	}
1253 
1254 	fh = alloc_file_handle(filename);
1255 	if (!fh) {
1256 		res = TEE_ERROR_OUT_OF_MEMORY;
1257 		goto out;
1258 	}
1259 
1260 	res = read_fat(fh, NULL);
1261 	if (res != TEE_SUCCESS)
1262 		goto out;
1263 
1264 	stat->size = (size_t)fh->fat_entry.data_size;
1265 	stat->reserved = 0;
1266 
1267 out:
1268 	free(fh);
1269 	return res;
1270 }
1271 
1272 int tee_rpmb_fs_access(const char *filename, int mode)
1273 {
1274 	struct tee_rpmb_fs_stat stat;
1275 	TEE_Result res;
1276 
1277 	/* Mode is currently ignored, this only checks for existence */
1278 	(void)mode;
1279 
1280 	res = tee_rpmb_fs_stat(filename, &stat);
1281 
1282 	if (res == TEE_SUCCESS)
1283 		return 0;
1284 
1285 	return -1;
1286 }
1287 
1288