xref: /optee_os/core/tee/tee_rpmb_fs.c (revision 923c1f343db556196600a1788c437715083264f8)
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 DEV_ID                          0
47 #define RPMB_FS_MAGIC                   0x52504D42
48 #define FS_VERSION                      2
49 #define N_ENTRIES                       8
50 
51 #define FILE_IS_ACTIVE                  (1u << 0)
52 #define FILE_IS_LAST_ENTRY              (1u << 1)
53 
54 /**
55  * FS parameters: Information often used by internal functions.
56  * fat_start_address will be set by rpmb_fs_setup().
57  * rpmb_fs_parameters can be read by any other function.
58  */
59 struct rpmb_fs_parameters {
60 	uint32_t fat_start_address;
61 	uint32_t max_rpmb_address;
62 };
63 
64 /**
65  * File entry for a single file in a RPMB_FS partition.
66  */
67 struct rpmb_fat_entry {
68 	uint32_t start_address;
69 	uint32_t data_size;
70 	uint32_t flags;
71 	uint32_t write_counter;
72 	char filename[TEE_RPMB_FS_FILENAME_LENGTH];
73 };
74 
75 /**
76  * FAT entry context with reference to a FAT entry and its
77  * location in RPMB.
78  */
79 struct rpmb_file_handle {
80 	/* Pointer to a fat_entry */
81 	struct rpmb_fat_entry fat_entry;
82 	/* Pointer to a filename */
83 	char filename[TEE_RPMB_FS_FILENAME_LENGTH];
84 	/* Adress for current entry in RPMB */
85 	uint32_t rpmb_fat_address;
86 	/* Current position */
87 	uint32_t pos;
88 };
89 
90 /**
91  * RPMB_FS partition data
92  */
93 struct rpmb_fs_partition {
94 	uint32_t rpmb_fs_magic;
95 	uint32_t fs_version;
96 	uint32_t write_counter;
97 	uint32_t fat_start_address;
98 	/* Do not use reserved[] for other purpose than partition data. */
99 	uint8_t reserved[112];
100 };
101 
102 /**
103  * A node in a list of directory entries. entry->name is a
104  * pointer to name here.
105  */
106 struct tee_rpmb_fs_dirent {
107 	struct tee_fs_dirent entry;
108 	char name[TEE_RPMB_FS_FILENAME_LENGTH];
109 	SIMPLEQ_ENTRY(tee_rpmb_fs_dirent) link;
110 };
111 
112 /**
113  * The RPMB directory representation. It contains a queue of
114  * RPMB directory entries: 'next'.
115  * The current pointer points to the last directory entry
116  * returned by readdir().
117  */
118 struct tee_fs_dir {
119 	struct tee_rpmb_fs_dirent *current;
120 	SIMPLEQ_HEAD(next_head, tee_rpmb_fs_dirent) next;
121 };
122 
123 static TEE_Result get_fat_start_address(uint32_t *addr);
124 
125 static struct rpmb_fs_parameters *fs_par;
126 
127 static struct handle_db fs_handle_db = HANDLE_DB_INITIALIZER;
128 
129 static void dump_fat(void)
130 {
131 	TEE_Result res = TEE_ERROR_GENERIC;
132 	struct rpmb_fat_entry *fat_entries = NULL;
133 	uint32_t fat_address;
134 	size_t size;
135 	int i;
136 	bool last_entry_found = false;
137 
138 	res = get_fat_start_address(&fat_address);
139 	if (res != TEE_SUCCESS)
140 		goto out;
141 
142 	size = N_ENTRIES * sizeof(struct rpmb_fat_entry);
143 	fat_entries = malloc(size);
144 	if (!fat_entries) {
145 		res = TEE_ERROR_OUT_OF_MEMORY;
146 		goto out;
147 	}
148 
149 	while (!last_entry_found) {
150 		res = tee_rpmb_read(DEV_ID, fat_address,
151 				    (uint8_t *)fat_entries, size);
152 		if (res != TEE_SUCCESS)
153 			goto out;
154 
155 		for (i = 0; i < N_ENTRIES; i++) {
156 
157 			FMSG("flags 0x%x, size %d, address 0x%x, filename '%s'",
158 				fat_entries[i].flags,
159 				fat_entries[i].data_size,
160 				fat_entries[i].start_address,
161 				fat_entries[i].filename);
162 
163 			if ((fat_entries[i].flags & FILE_IS_LAST_ENTRY) != 0) {
164 				last_entry_found = true;
165 				break;
166 			}
167 
168 			/* Move to next fat_entry. */
169 			fat_address += sizeof(struct rpmb_fat_entry);
170 		}
171 	}
172 
173 out:
174 	free(fat_entries);
175 }
176 
177 #if (TRACE_LEVEL >= TRACE_DEBUG)
178 static void dump_fh(struct rpmb_file_handle *fh)
179 {
180 	DMSG("fh->filename=%s", fh->filename);
181 	DMSG("fh->pos=%u", fh->pos);
182 	DMSG("fh->rpmb_fat_address=%u", fh->rpmb_fat_address);
183 	DMSG("fh->fat_entry.start_address=%u", fh->fat_entry.start_address);
184 	DMSG("fh->fat_entry.data_size=%u", fh->fat_entry.data_size);
185 }
186 #else
187 static void dump_fh(struct rpmb_file_handle *fh __unused)
188 {
189 }
190 #endif
191 
192 static struct rpmb_file_handle *alloc_file_handle(const char *filename)
193 {
194 	struct rpmb_file_handle *fh = NULL;
195 
196 	fh = calloc(1, sizeof(struct rpmb_file_handle));
197 	if (!fh)
198 		return NULL;
199 
200 	if (filename)
201 		strlcpy(fh->filename, filename, sizeof(fh->filename));
202 
203 	return fh;
204 }
205 
206 /**
207  * write_fat_entry: Store info in a fat_entry to RPMB.
208  */
209 static TEE_Result write_fat_entry(struct rpmb_file_handle *fh,
210 				  bool update_write_counter)
211 {
212 	TEE_Result res = TEE_ERROR_GENERIC;
213 
214 	/* Protect partition data. */
215 	if (fh->rpmb_fat_address < sizeof(struct rpmb_fs_partition)) {
216 		res = TEE_ERROR_ACCESS_CONFLICT;
217 		goto out;
218 	}
219 
220 	if (fh->rpmb_fat_address % sizeof(struct rpmb_fat_entry) != 0) {
221 		res = TEE_ERROR_BAD_PARAMETERS;
222 		goto out;
223 	}
224 
225 	if (update_write_counter) {
226 		res = tee_rpmb_get_write_counter(DEV_ID,
227 						 &fh->fat_entry.write_counter);
228 		if (res != TEE_SUCCESS)
229 			goto out;
230 	}
231 
232 	res = tee_rpmb_write(DEV_ID, fh->rpmb_fat_address,
233 			     (uint8_t *)&fh->fat_entry,
234 			     sizeof(struct rpmb_fat_entry));
235 
236 	dump_fat();
237 
238 out:
239 	return res;
240 }
241 
242 /**
243  * rpmb_fs_setup: Setup rpmb fs.
244  * Set initial partition and FS values and write to RPMB.
245  * Store frequently used data in RAM.
246  */
247 static TEE_Result rpmb_fs_setup(void)
248 {
249 	TEE_Result res = TEE_ERROR_GENERIC;
250 	struct rpmb_fs_partition *partition_data = NULL;
251 	struct rpmb_file_handle *fh = NULL;
252 	uint32_t max_rpmb_block = 0;
253 
254 	if (fs_par) {
255 		res = TEE_SUCCESS;
256 		goto out;
257 	}
258 
259 	res = tee_rpmb_get_max_block(DEV_ID, &max_rpmb_block);
260 	if (res != TEE_SUCCESS)
261 		goto out;
262 
263 	partition_data = calloc(1, sizeof(struct rpmb_fs_partition));
264 	if (!partition_data) {
265 		res = TEE_ERROR_OUT_OF_MEMORY;
266 		goto out;
267 	}
268 
269 	res = tee_rpmb_read(DEV_ID, RPMB_STORAGE_START_ADDRESS,
270 			    (uint8_t *)partition_data,
271 			    sizeof(struct rpmb_fs_partition));
272 	if (res != TEE_SUCCESS)
273 		goto out;
274 
275 #ifndef CFG_RPMB_RESET_FAT
276 	if (partition_data->rpmb_fs_magic == RPMB_FS_MAGIC) {
277 		if (partition_data->fs_version == FS_VERSION) {
278 			res = TEE_SUCCESS;
279 			goto store_fs_par;
280 		} else {
281 			/* Wrong software is in use. */
282 			res = TEE_ERROR_ACCESS_DENIED;
283 			goto out;
284 		}
285 	}
286 #else
287 	EMSG("**** Clearing Storage ****");
288 #endif
289 
290 	/* Setup new partition data. */
291 	partition_data->rpmb_fs_magic = RPMB_FS_MAGIC;
292 	partition_data->fs_version = FS_VERSION;
293 	partition_data->fat_start_address = RPMB_FS_FAT_START_ADDRESS;
294 
295 	/* Initial FAT entry with FILE_IS_LAST_ENTRY flag set. */
296 	fh = alloc_file_handle(NULL);
297 	if (!fh) {
298 		res = TEE_ERROR_OUT_OF_MEMORY;
299 		goto out;
300 	}
301 	fh->fat_entry.flags = FILE_IS_LAST_ENTRY;
302 	fh->rpmb_fat_address = partition_data->fat_start_address;
303 
304 	/* Write init FAT entry and partition data to RPMB. */
305 	res = write_fat_entry(fh, true);
306 	if (res != TEE_SUCCESS)
307 		goto out;
308 
309 	res =
310 	    tee_rpmb_get_write_counter(DEV_ID, &partition_data->write_counter);
311 	if (res != TEE_SUCCESS)
312 		goto out;
313 	res = tee_rpmb_write(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(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(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(DEV_ID, start_addr, size)) {
721 
722 		DMSG("Updating data in-place");
723 		res = tee_rpmb_write(DEV_ID, start_addr, buf, size);
724 		if (res != TEE_SUCCESS)
725 			goto out;
726 	} else {
727 		/*
728 		 * File must be extended, or update cannot be atomic: allocate,
729 		 * read, update, write.
730 		 */
731 
732 		DMSG("Need to re-allocate");
733 		newsize = MAX(end, fh->fat_entry.data_size);
734 		mm = tee_mm_alloc(&p, newsize);
735 		newbuf = calloc(newsize, 1);
736 		if (!mm || !newbuf) {
737 			res = TEE_ERROR_OUT_OF_MEMORY;
738 			goto out;
739 		}
740 
741 		if (fh->fat_entry.data_size) {
742 			res = tee_rpmb_read(DEV_ID,
743 					    fh->fat_entry.start_address,
744 					    newbuf, fh->fat_entry.data_size);
745 			if (res != TEE_SUCCESS)
746 				goto out;
747 		}
748 
749 		memcpy(newbuf + fh->pos, buf, size);
750 
751 		newaddr = tee_mm_get_smem(mm);
752 		res = tee_rpmb_write(DEV_ID, newaddr, newbuf, newsize);
753 		if (res != TEE_SUCCESS)
754 			goto out;
755 
756 		fh->fat_entry.data_size = newsize;
757 		fh->fat_entry.start_address = newaddr;
758 		res = write_fat_entry(fh, true);
759 		if (res != TEE_SUCCESS)
760 			goto out;
761 	}
762 
763 	fh->pos += size;
764 out:
765 	if (pool_result)
766 		tee_mm_final(&p);
767 	if (newbuf)
768 		free(newbuf);
769 
770 	if (res == TEE_SUCCESS)
771 		return size;
772 
773 	return -1;
774 }
775 
776 tee_fs_off_t tee_rpmb_fs_lseek(int fd, tee_fs_off_t offset, int whence)
777 {
778 	struct rpmb_file_handle *fh;
779 	TEE_Result res;
780 	tee_fs_off_t ret = -1;
781 	tee_fs_off_t new_pos;
782 
783 	fh = handle_lookup(&fs_handle_db, fd);
784 	if (!fh)
785 		return TEE_ERROR_BAD_PARAMETERS;
786 
787 	res = read_fat(fh, NULL);
788 	if (res != TEE_SUCCESS)
789 		return -1;
790 
791 	switch (whence) {
792 	case TEE_FS_SEEK_SET:
793 		new_pos = offset;
794 		break;
795 
796 	case TEE_FS_SEEK_CUR:
797 		new_pos = fh->pos + offset;
798 		break;
799 
800 	case TEE_FS_SEEK_END:
801 		new_pos = fh->fat_entry.data_size + offset;
802 		break;
803 
804 	default:
805 		goto exit;
806 	}
807 
808 	if (new_pos < 0)
809 		new_pos = 0;
810 
811 	if (new_pos > TEE_DATA_MAX_POSITION) {
812 		EMSG("Position is beyond TEE_DATA_MAX_POSITION");
813 		goto exit;
814 	}
815 
816 	ret = fh->pos = new_pos;
817 exit:
818 	return ret;
819 }
820 
821 TEE_Result tee_rpmb_fs_rm(const char *filename)
822 {
823 	TEE_Result res = TEE_ERROR_GENERIC;
824 	struct rpmb_file_handle *fh = NULL;
825 
826 	if (!filename || strlen(filename) >= TEE_RPMB_FS_FILENAME_LENGTH - 1) {
827 		res = TEE_ERROR_BAD_PARAMETERS;
828 		goto out;
829 	}
830 
831 	fh = alloc_file_handle(filename);
832 	if (!fh) {
833 		res = TEE_ERROR_OUT_OF_MEMORY;
834 		goto out;
835 	}
836 
837 	res = read_fat(fh, NULL);
838 	if (res != TEE_SUCCESS)
839 		goto out;
840 
841 	/* Clear this file entry. */
842 	memset(&fh->fat_entry, 0, sizeof(struct rpmb_fat_entry));
843 	res = write_fat_entry(fh, false);
844 
845 out:
846 	free(fh);
847 	IMSG("Deleting file %s returned 0x%x\n", filename, res);
848 	return res;
849 }
850 
851 TEE_Result tee_rpmb_fs_rename(const char *old_name, const char *new_name)
852 {
853 	TEE_Result res = TEE_ERROR_GENERIC;
854 	struct rpmb_file_handle *fh_old = NULL;
855 	struct rpmb_file_handle *fh_new = NULL;
856 	uint32_t old_len;
857 	uint32_t new_len;
858 
859 	if (!old_name || !new_name) {
860 		res = TEE_ERROR_BAD_PARAMETERS;
861 		goto out;
862 	}
863 
864 	old_len = strlen(old_name);
865 	new_len = strlen(new_name);
866 
867 	if ((old_len >= TEE_RPMB_FS_FILENAME_LENGTH - 1) ||
868 	    (new_len >= TEE_RPMB_FS_FILENAME_LENGTH - 1) || (new_len == 0)) {
869 
870 		res = TEE_ERROR_BAD_PARAMETERS;
871 		goto out;
872 	}
873 
874 	fh_old = alloc_file_handle(old_name);
875 	if (!fh_old) {
876 		res = TEE_ERROR_OUT_OF_MEMORY;
877 		goto out;
878 	}
879 
880 	fh_new = alloc_file_handle(new_name);
881 	if (!fh_new) {
882 		res = TEE_ERROR_OUT_OF_MEMORY;
883 		goto out;
884 	}
885 
886 	res = read_fat(fh_old, NULL);
887 	if (res != TEE_SUCCESS)
888 		goto out;
889 
890 	res = read_fat(fh_new, NULL);
891 	if (res == TEE_SUCCESS) {
892 		res = TEE_ERROR_BAD_PARAMETERS;
893 		goto out;
894 	}
895 
896 	memset(fh_old->fat_entry.filename, 0, TEE_RPMB_FS_FILENAME_LENGTH);
897 	memcpy(fh_old->fat_entry.filename, new_name, new_len);
898 
899 	res = write_fat_entry(fh_old, false);
900 
901 out:
902 	free(fh_old);
903 	free(fh_new);
904 
905 	return res;
906 }
907 
908 int tee_rpmb_fs_mkdir(const char *path __unused, tee_fs_mode_t mode __unused)
909 {
910 	/*
911 	 * FIXME: mkdir() should really create some entry in the FAT so that
912 	 * access() would return success when the directory exists but is
913 	 * empty. This does not matter for the current use cases.
914 	 */
915 	return 0;
916 }
917 
918 int tee_rpmb_fs_ftruncate(int fd, tee_fs_off_t length)
919 {
920 	struct rpmb_file_handle *fh;
921 	tee_mm_pool_t p;
922 	bool pool_result = false;
923 	tee_mm_entry_t *mm;
924 	uint32_t newsize;
925 	uint8_t *newbuf = NULL;
926 	uintptr_t newaddr;
927 	TEE_Result res = TEE_ERROR_GENERIC;
928 
929 	if (length < 0 || length > INT32_MAX) {
930 		res = TEE_ERROR_BAD_PARAMETERS;
931 		goto out;
932 	}
933 	newsize = length;
934 
935 	fh = handle_lookup(&fs_handle_db, fd);
936 	if (!fh) {
937 		res = TEE_ERROR_BAD_PARAMETERS;
938 		goto out;
939 	}
940 
941 	res = read_fat(fh, NULL);
942 	if (res != TEE_SUCCESS)
943 		goto out;
944 
945 	if (newsize > fh->fat_entry.data_size) {
946 		/* Extend file */
947 
948 		pool_result = tee_mm_init(&p,
949 					  RPMB_STORAGE_START_ADDRESS,
950 					  fs_par->max_rpmb_address,
951 					  RPMB_BLOCK_SIZE_SHIFT,
952 					  TEE_MM_POOL_HI_ALLOC);
953 		if (!pool_result) {
954 			res = TEE_ERROR_OUT_OF_MEMORY;
955 			goto out;
956 		}
957 		res = read_fat(fh, &p);
958 		if (res != TEE_SUCCESS)
959 			goto out;
960 
961 		mm = tee_mm_alloc(&p, newsize);
962 		newbuf = calloc(newsize, 1);
963 		if (!mm || !newbuf) {
964 			res = TEE_ERROR_OUT_OF_MEMORY;
965 			goto out;
966 		}
967 
968 		if (fh->fat_entry.data_size) {
969 			res = tee_rpmb_read(DEV_ID,
970 					    fh->fat_entry.start_address,
971 					    newbuf, fh->fat_entry.data_size);
972 			if (res != TEE_SUCCESS)
973 				goto out;
974 		}
975 
976 		newaddr = tee_mm_get_smem(mm);
977 		res = tee_rpmb_write(DEV_ID, newaddr, newbuf, newsize);
978 		if (res != TEE_SUCCESS)
979 			goto out;
980 
981 	} else {
982 		/* Don't change file location */
983 		newaddr = fh->fat_entry.start_address;
984 	}
985 
986 	/* fh->pos is unchanged */
987 	fh->fat_entry.data_size = newsize;
988 	fh->fat_entry.start_address = newaddr;
989 	res = write_fat_entry(fh, true);
990 
991 out:
992 	if (pool_result)
993 		tee_mm_final(&p);
994 	if (newbuf)
995 		free(newbuf);
996 
997 	if (res == TEE_SUCCESS)
998 		return 0;
999 
1000 	return -1;
1001 }
1002 
1003 static void tee_rpmb_fs_dir_free(tee_fs_dir *dir)
1004 {
1005 	struct tee_rpmb_fs_dirent *e;
1006 
1007 	if (!dir)
1008 		return;
1009 
1010 	free(dir->current);
1011 
1012 	while ((e = SIMPLEQ_FIRST(&dir->next))) {
1013 		SIMPLEQ_REMOVE_HEAD(&dir->next, link);
1014 		free(e);
1015 	}
1016 }
1017 
1018 static TEE_Result tee_rpmb_fs_dir_populate(const char *path, tee_fs_dir *dir)
1019 {
1020 	struct tee_rpmb_fs_dirent *current = NULL;
1021 	struct rpmb_fat_entry *fat_entries = NULL;
1022 	uint32_t fat_address;
1023 	uint32_t filelen;
1024 	char *filename;
1025 	int i;
1026 	bool last_entry_found = false;
1027 	bool matched;
1028 	struct tee_rpmb_fs_dirent *next = NULL;
1029 	uint32_t pathlen;
1030 	TEE_Result res = TEE_ERROR_GENERIC;
1031 	uint32_t size;
1032 	char temp;
1033 
1034 	res = rpmb_fs_setup();
1035 	if (res != TEE_SUCCESS)
1036 		goto out;
1037 
1038 	res = get_fat_start_address(&fat_address);
1039 	if (res != TEE_SUCCESS)
1040 		goto out;
1041 
1042 	size = N_ENTRIES * sizeof(struct rpmb_fat_entry);
1043 	fat_entries = malloc(size);
1044 	if (!fat_entries) {
1045 		res = TEE_ERROR_OUT_OF_MEMORY;
1046 		goto out;
1047 	}
1048 
1049 	pathlen = strlen(path);
1050 	while (!last_entry_found) {
1051 		res = tee_rpmb_read(DEV_ID, fat_address,
1052 				    (uint8_t *)fat_entries, size);
1053 		if (res != TEE_SUCCESS)
1054 			goto out;
1055 
1056 		for (i = 0; i < N_ENTRIES; i++) {
1057 			filename = fat_entries[i].filename;
1058 			if (fat_entries[i].flags & FILE_IS_ACTIVE) {
1059 				matched = false;
1060 				filelen = strlen(filename);
1061 				if (filelen > pathlen) {
1062 					temp = filename[pathlen];
1063 					filename[pathlen] = '\0';
1064 					if (strcmp(filename, path) == 0)
1065 						matched = true;
1066 
1067 					filename[pathlen] = temp;
1068 				}
1069 
1070 				if (matched) {
1071 					next = malloc(sizeof(*next));
1072 					if (!next) {
1073 						res = TEE_ERROR_OUT_OF_MEMORY;
1074 						goto out;
1075 					}
1076 
1077 					memset(next, 0, sizeof(*next));
1078 					next->entry.d_name = next->name;
1079 					memcpy(next->name,
1080 						&filename[pathlen],
1081 						filelen - pathlen);
1082 
1083 					SIMPLEQ_INSERT_TAIL(&dir->next, next,
1084 							    link);
1085 					current = next;
1086 				}
1087 			}
1088 
1089 			if (fat_entries[i].flags & FILE_IS_LAST_ENTRY) {
1090 				last_entry_found = true;
1091 				break;
1092 			}
1093 
1094 			/* Move to next fat_entry. */
1095 			fat_address += sizeof(struct rpmb_fat_entry);
1096 		}
1097 	}
1098 
1099 	/* No directories were found. */
1100 	if (!current) {
1101 		res = TEE_ERROR_NO_DATA;
1102 		goto out;
1103 	}
1104 
1105 	res = TEE_SUCCESS;
1106 
1107 out:
1108 	if (res != TEE_SUCCESS)
1109 		tee_rpmb_fs_dir_free(dir);
1110 	if (fat_entries)
1111 		free(fat_entries);
1112 
1113 	return res;
1114 }
1115 
1116 static TEE_Result tee_rpmb_fs_opendir_internal(const char *path,
1117 						tee_fs_dir **dir)
1118 {
1119 	uint32_t len;
1120 	uint32_t max_size;
1121 	char path_local[TEE_RPMB_FS_FILENAME_LENGTH];
1122 	TEE_Result res = TEE_ERROR_GENERIC;
1123 	tee_fs_dir *rpmb_dir = NULL;
1124 
1125 	if (!path || !dir) {
1126 		res = TEE_ERROR_BAD_PARAMETERS;
1127 		goto out;
1128 	}
1129 
1130 	/*
1131 	 * There must be room for at least the NULL char and a char for the
1132 	 * filename after the path.
1133 	 */
1134 	max_size = TEE_RPMB_FS_FILENAME_LENGTH - 2;
1135 	len = strlen(path);
1136 	if (len > max_size || len == 0) {
1137 		res = TEE_ERROR_BAD_PARAMETERS;
1138 		goto out;
1139 	}
1140 
1141 	memset(path_local, 0, sizeof(path_local));
1142 	memcpy(path_local, path, len);
1143 
1144 	/* Add a slash to correctly match the full directory name. */
1145 	if (path_local[len - 1] != '/')
1146 		path_local[len] = '/';
1147 
1148 	rpmb_dir = calloc(1, sizeof(tee_fs_dir));
1149 	if (!rpmb_dir) {
1150 		res = TEE_ERROR_OUT_OF_MEMORY;
1151 		goto out;
1152 	}
1153 	SIMPLEQ_INIT(&rpmb_dir->next);
1154 
1155 	res = tee_rpmb_fs_dir_populate(path_local, rpmb_dir);
1156 	if (res != TEE_SUCCESS) {
1157 		free(rpmb_dir);
1158 		rpmb_dir = NULL;
1159 		goto out;
1160 	}
1161 
1162 	*dir = rpmb_dir;
1163 
1164 out:
1165 	return res;
1166 }
1167 
1168 tee_fs_dir *tee_rpmb_fs_opendir(const char *path)
1169 {
1170 	tee_fs_dir *dir = NULL;
1171 	TEE_Result res = TEE_ERROR_GENERIC;
1172 
1173 	res = tee_rpmb_fs_opendir_internal(path, &dir);
1174 	if (res != TEE_SUCCESS)
1175 		dir = NULL;
1176 
1177 	return dir;
1178 }
1179 
1180 
1181 struct tee_fs_dirent *tee_rpmb_fs_readdir(tee_fs_dir *dir)
1182 {
1183 	if (!dir)
1184 		return NULL;
1185 
1186 	free(dir->current);
1187 
1188 	dir->current = SIMPLEQ_FIRST(&dir->next);
1189 	if (!dir->current)
1190 		return NULL;
1191 
1192 	SIMPLEQ_REMOVE_HEAD(&dir->next, link);
1193 
1194 	return &dir->current->entry;
1195 }
1196 
1197 int tee_rpmb_fs_closedir(tee_fs_dir *dir)
1198 {
1199 	TEE_Result res = TEE_ERROR_GENERIC;
1200 
1201 	if (!dir) {
1202 		res = TEE_SUCCESS;
1203 		goto out;
1204 	}
1205 
1206 	tee_rpmb_fs_dir_free(dir);
1207 	free(dir);
1208 	res = TEE_SUCCESS;
1209 out:
1210 	if (res == TEE_SUCCESS)
1211 		return 0;
1212 
1213 	return -1;
1214 }
1215 
1216 int tee_rpmb_fs_rmdir(const char *path)
1217 {
1218 	tee_fs_dir *dir = NULL;
1219 	TEE_Result res = TEE_ERROR_GENERIC;
1220 	int ret = -1;
1221 
1222 	/* Open the directory anyting other than NO_DATA is a failure */
1223 	res = tee_rpmb_fs_opendir_internal(path, &dir);
1224 	if (res == TEE_SUCCESS) {
1225 		tee_rpmb_fs_closedir(dir);
1226 		ret = -1;
1227 
1228 	} else if (res == TEE_ERROR_NO_DATA) {
1229 		ret = 0;
1230 
1231 	} else {
1232 		/* The case any other failure is returned */
1233 		ret = -1;
1234 	}
1235 
1236 
1237 	return ret;
1238 }
1239 
1240 TEE_Result tee_rpmb_fs_stat(const char *filename,
1241 			    struct tee_rpmb_fs_stat *stat)
1242 {
1243 	TEE_Result res = TEE_ERROR_GENERIC;
1244 	struct rpmb_file_handle *fh = NULL;
1245 
1246 	if (!stat || !filename) {
1247 		res = TEE_ERROR_BAD_PARAMETERS;
1248 		goto out;
1249 	}
1250 
1251 	fh = alloc_file_handle(filename);
1252 	if (!fh) {
1253 		res = TEE_ERROR_OUT_OF_MEMORY;
1254 		goto out;
1255 	}
1256 
1257 	res = read_fat(fh, NULL);
1258 	if (res != TEE_SUCCESS)
1259 		goto out;
1260 
1261 	stat->size = (size_t)fh->fat_entry.data_size;
1262 	stat->reserved = 0;
1263 
1264 out:
1265 	free(fh);
1266 	return res;
1267 }
1268 
1269 int tee_rpmb_fs_access(const char *filename, int mode)
1270 {
1271 	struct tee_rpmb_fs_stat stat;
1272 	TEE_Result res;
1273 
1274 	/* Mode is currently ignored, this only checks for existence */
1275 	(void)mode;
1276 
1277 	res = tee_rpmb_fs_stat(filename, &stat);
1278 
1279 	if (res == TEE_SUCCESS)
1280 		return 0;
1281 
1282 	return -1;
1283 }
1284 
1285