xref: /optee_os/core/mm/file.c (revision bae0f170e3217a9322f4c36879a65bc12f50e96a)
19f31ef5aSJens Wiklander // SPDX-License-Identifier: BSD-2-Clause
29f31ef5aSJens Wiklander /*
39f31ef5aSJens Wiklander  * Copyright (c) 2019, Linaro Limited
49f31ef5aSJens Wiklander  */
59f31ef5aSJens Wiklander 
69f31ef5aSJens Wiklander #include <kernel/panic.h>
79f31ef5aSJens Wiklander #include <kernel/refcount.h>
89f31ef5aSJens Wiklander #include <mm/file.h>
99f31ef5aSJens Wiklander #include <mm/fobj.h>
109f31ef5aSJens Wiklander #include <stdlib.h>
119f31ef5aSJens Wiklander #include <string.h>
129f31ef5aSJens Wiklander #include <sys/queue.h>
139f31ef5aSJens Wiklander #include <types_ext.h>
149f31ef5aSJens Wiklander #include <util.h>
159f31ef5aSJens Wiklander 
16*bae0f170SJens Wiklander struct file_slice_elem {
17*bae0f170SJens Wiklander 	struct file_slice slice;
18*bae0f170SJens Wiklander 	SLIST_ENTRY(file_slice_elem) link;
19*bae0f170SJens Wiklander };
20*bae0f170SJens Wiklander 
219f31ef5aSJens Wiklander /*
229f31ef5aSJens Wiklander  * struct file - file resources
239f31ef5aSJens Wiklander  * @tag:	Tag or hash uniquely identifying a file
249f31ef5aSJens Wiklander  * @taglen:	Byte length of @tag
259f31ef5aSJens Wiklander  * @refc:	Reference counter
269f31ef5aSJens Wiklander  * @link:	Linked list element
279f31ef5aSJens Wiklander  * @num_slices:	Number of elements in the @slices array below
289f31ef5aSJens Wiklander  * @slices:	Array of file slices holding the fobjs of this file
299f31ef5aSJens Wiklander  *
309f31ef5aSJens Wiklander  * A file is constructed of slices which may be shared in different
319f31ef5aSJens Wiklander  * mappings/contexts. There may be holes in the file for ranges of the file
329f31ef5aSJens Wiklander  * that can't be shared.
339f31ef5aSJens Wiklander  */
349f31ef5aSJens Wiklander struct file {
359f31ef5aSJens Wiklander 	uint8_t tag[FILE_TAG_SIZE];
369f31ef5aSJens Wiklander 	unsigned int taglen;
379f31ef5aSJens Wiklander 	struct refcount refc;
389f31ef5aSJens Wiklander 	TAILQ_ENTRY(file) link;
39*bae0f170SJens Wiklander 	struct mutex mu;
40*bae0f170SJens Wiklander 	SLIST_HEAD(, file_slice_elem) slice_head;
419f31ef5aSJens Wiklander };
429f31ef5aSJens Wiklander 
439f31ef5aSJens Wiklander static struct mutex file_mu = MUTEX_INITIALIZER;
449f31ef5aSJens Wiklander static TAILQ_HEAD(, file) file_head = TAILQ_HEAD_INITIALIZER(file_head);
459f31ef5aSJens Wiklander 
469f31ef5aSJens Wiklander static int file_tag_cmp(const struct file *f, const uint8_t *tag,
479f31ef5aSJens Wiklander 			unsigned int taglen)
489f31ef5aSJens Wiklander {
499f31ef5aSJens Wiklander 	if (f->taglen != taglen)
509f31ef5aSJens Wiklander 		return -1;
519f31ef5aSJens Wiklander 	return memcmp(tag, f->tag, taglen);
529f31ef5aSJens Wiklander }
539f31ef5aSJens Wiklander 
549f31ef5aSJens Wiklander static struct file *file_find_tag_unlocked(const uint8_t *tag,
559f31ef5aSJens Wiklander 					   unsigned int taglen)
569f31ef5aSJens Wiklander {
579f31ef5aSJens Wiklander 	struct file *f = NULL;
589f31ef5aSJens Wiklander 
599f31ef5aSJens Wiklander 	TAILQ_FOREACH(f, &file_head, link)
609f31ef5aSJens Wiklander 		if (!file_tag_cmp(f, tag, taglen))
619f31ef5aSJens Wiklander 			return f;
629f31ef5aSJens Wiklander 
639f31ef5aSJens Wiklander 	return NULL;
649f31ef5aSJens Wiklander }
659f31ef5aSJens Wiklander 
669f31ef5aSJens Wiklander static void file_free(struct file *f)
679f31ef5aSJens Wiklander {
68*bae0f170SJens Wiklander 	mutex_destroy(&f->mu);
699f31ef5aSJens Wiklander 
70*bae0f170SJens Wiklander 	while (!SLIST_EMPTY(&f->slice_head)) {
71*bae0f170SJens Wiklander 		struct file_slice_elem *fse = SLIST_FIRST(&f->slice_head);
72*bae0f170SJens Wiklander 
73*bae0f170SJens Wiklander 		SLIST_REMOVE_HEAD(&f->slice_head, link);
74*bae0f170SJens Wiklander 		fobj_put(fse->slice.fobj);
75*bae0f170SJens Wiklander 		free(fse);
76*bae0f170SJens Wiklander 	}
779f31ef5aSJens Wiklander 
789f31ef5aSJens Wiklander 	free(f);
799f31ef5aSJens Wiklander }
809f31ef5aSJens Wiklander 
81*bae0f170SJens Wiklander TEE_Result file_add_slice(struct file *f, struct fobj *fobj,
82*bae0f170SJens Wiklander 			  unsigned int page_offset)
839f31ef5aSJens Wiklander {
84*bae0f170SJens Wiklander 	struct file_slice_elem *fse = NULL;
859f31ef5aSJens Wiklander 	unsigned int s = 0;
869f31ef5aSJens Wiklander 
87*bae0f170SJens Wiklander 	/* Check for conflicts */
88*bae0f170SJens Wiklander 	if (file_find_slice(f, page_offset))
89*bae0f170SJens Wiklander 		return TEE_ERROR_BAD_PARAMETERS;
909f31ef5aSJens Wiklander 
91*bae0f170SJens Wiklander 	fse = calloc(1, sizeof(*fse));
92*bae0f170SJens Wiklander 	if (!fse)
93*bae0f170SJens Wiklander 		return TEE_ERROR_OUT_OF_MEMORY;
949f31ef5aSJens Wiklander 
95*bae0f170SJens Wiklander 	fse->slice.fobj = fobj_get(fobj);
96*bae0f170SJens Wiklander 	if (!fse->slice.fobj ||
97*bae0f170SJens Wiklander 	    ADD_OVERFLOW(page_offset, fse->slice.fobj->num_pages, &s)) {
98*bae0f170SJens Wiklander 		fobj_put(fse->slice.fobj);
99*bae0f170SJens Wiklander 		free(fse);
100*bae0f170SJens Wiklander 		return TEE_ERROR_BAD_PARAMETERS;
1019f31ef5aSJens Wiklander 	}
1029f31ef5aSJens Wiklander 
103*bae0f170SJens Wiklander 	fse->slice.page_offset = page_offset;
104*bae0f170SJens Wiklander 	SLIST_INSERT_HEAD(&f->slice_head, fse, link);
1059f31ef5aSJens Wiklander 
106*bae0f170SJens Wiklander 	return TEE_SUCCESS;
1079f31ef5aSJens Wiklander }
1089f31ef5aSJens Wiklander 
1099f31ef5aSJens Wiklander struct file *file_get(struct file *f)
1109f31ef5aSJens Wiklander {
1119f31ef5aSJens Wiklander 	if (f && !refcount_inc(&f->refc))
1129f31ef5aSJens Wiklander 		panic();
1139f31ef5aSJens Wiklander 
1149f31ef5aSJens Wiklander 	return f;
1159f31ef5aSJens Wiklander }
1169f31ef5aSJens Wiklander 
117*bae0f170SJens Wiklander struct file *file_get_by_tag(const uint8_t *tag, unsigned int taglen)
1189f31ef5aSJens Wiklander {
1199f31ef5aSJens Wiklander 	struct file *f = NULL;
1209f31ef5aSJens Wiklander 
121*bae0f170SJens Wiklander 	if (taglen > sizeof(f->tag))
122*bae0f170SJens Wiklander 		return NULL;
123*bae0f170SJens Wiklander 
1249f31ef5aSJens Wiklander 	mutex_lock(&file_mu);
1259f31ef5aSJens Wiklander 	f = file_get(file_find_tag_unlocked(tag, taglen));
126*bae0f170SJens Wiklander 	if (f)
127*bae0f170SJens Wiklander 		goto out;
128*bae0f170SJens Wiklander 	f = calloc(1, sizeof(*f));
129*bae0f170SJens Wiklander 	if (!f)
130*bae0f170SJens Wiklander 		goto out;
131*bae0f170SJens Wiklander 	memcpy(f->tag, tag, taglen);
132*bae0f170SJens Wiklander 	f->taglen = taglen;
133*bae0f170SJens Wiklander 	refcount_set(&f->refc, 1);
134*bae0f170SJens Wiklander 	mutex_init(&f->mu);
135*bae0f170SJens Wiklander 	SLIST_INIT(&f->slice_head);
136*bae0f170SJens Wiklander 	TAILQ_INSERT_TAIL(&file_head, f, link);
137*bae0f170SJens Wiklander 
138*bae0f170SJens Wiklander out:
1399f31ef5aSJens Wiklander 	mutex_unlock(&file_mu);
1409f31ef5aSJens Wiklander 
1419f31ef5aSJens Wiklander 	return f;
1429f31ef5aSJens Wiklander }
1439f31ef5aSJens Wiklander 
1449f31ef5aSJens Wiklander void file_put(struct file *f)
1459f31ef5aSJens Wiklander {
146*bae0f170SJens Wiklander 	if (f && refcount_dec(&f->refc)) {
1479f31ef5aSJens Wiklander 		mutex_lock(&file_mu);
1489f31ef5aSJens Wiklander 		TAILQ_REMOVE(&file_head, f, link);
1499f31ef5aSJens Wiklander 		mutex_unlock(&file_mu);
1509f31ef5aSJens Wiklander 
1519f31ef5aSJens Wiklander 		file_free(f);
1529f31ef5aSJens Wiklander 	}
1539f31ef5aSJens Wiklander 
154*bae0f170SJens Wiklander }
155*bae0f170SJens Wiklander 
1569f31ef5aSJens Wiklander struct file_slice *file_find_slice(struct file *f, unsigned int page_offset)
1579f31ef5aSJens Wiklander {
158*bae0f170SJens Wiklander 	struct file_slice_elem *fse = NULL;
1599f31ef5aSJens Wiklander 
160*bae0f170SJens Wiklander 	assert(f->mu.state);
1619f31ef5aSJens Wiklander 
162*bae0f170SJens Wiklander 	SLIST_FOREACH(fse, &f->slice_head, link) {
163*bae0f170SJens Wiklander 		struct file_slice *fs = &fse->slice;
1649f31ef5aSJens Wiklander 
1659f31ef5aSJens Wiklander 		if (page_offset >= fs->page_offset &&
1669f31ef5aSJens Wiklander 		    page_offset < fs->page_offset + fs->fobj->num_pages)
1679f31ef5aSJens Wiklander 			return fs;
1689f31ef5aSJens Wiklander 	}
1699f31ef5aSJens Wiklander 
1709f31ef5aSJens Wiklander 	return NULL;
1719f31ef5aSJens Wiklander }
172*bae0f170SJens Wiklander 
173*bae0f170SJens Wiklander void file_lock(struct file *f)
174*bae0f170SJens Wiklander {
175*bae0f170SJens Wiklander 	mutex_lock(&f->mu);
176*bae0f170SJens Wiklander }
177*bae0f170SJens Wiklander 
178*bae0f170SJens Wiklander bool file_trylock(struct file *f)
179*bae0f170SJens Wiklander {
180*bae0f170SJens Wiklander 	return mutex_trylock(&f->mu);
181*bae0f170SJens Wiklander }
182*bae0f170SJens Wiklander 
183*bae0f170SJens Wiklander void file_unlock(struct file *f)
184*bae0f170SJens Wiklander {
185*bae0f170SJens Wiklander 	mutex_unlock(&f->mu);
186*bae0f170SJens Wiklander }
187