xref: /optee_os/core/mm/file.c (revision 9f31ef5ae72a9cd592957fefde290cbc2f8891dd)
1*9f31ef5aSJens Wiklander // SPDX-License-Identifier: BSD-2-Clause
2*9f31ef5aSJens Wiklander /*
3*9f31ef5aSJens Wiklander  * Copyright (c) 2019, Linaro Limited
4*9f31ef5aSJens Wiklander  */
5*9f31ef5aSJens Wiklander 
6*9f31ef5aSJens Wiklander #include <kernel/panic.h>
7*9f31ef5aSJens Wiklander #include <kernel/refcount.h>
8*9f31ef5aSJens Wiklander #include <mm/file.h>
9*9f31ef5aSJens Wiklander #include <mm/fobj.h>
10*9f31ef5aSJens Wiklander #include <stdlib.h>
11*9f31ef5aSJens Wiklander #include <string.h>
12*9f31ef5aSJens Wiklander #include <sys/queue.h>
13*9f31ef5aSJens Wiklander #include <types_ext.h>
14*9f31ef5aSJens Wiklander #include <util.h>
15*9f31ef5aSJens Wiklander 
16*9f31ef5aSJens Wiklander /*
17*9f31ef5aSJens Wiklander  * struct file - file resources
18*9f31ef5aSJens Wiklander  * @tag:	Tag or hash uniquely identifying a file
19*9f31ef5aSJens Wiklander  * @taglen:	Byte length of @tag
20*9f31ef5aSJens Wiklander  * @refc:	Reference counter
21*9f31ef5aSJens Wiklander  * @link:	Linked list element
22*9f31ef5aSJens Wiklander  * @num_slices:	Number of elements in the @slices array below
23*9f31ef5aSJens Wiklander  * @slices:	Array of file slices holding the fobjs of this file
24*9f31ef5aSJens Wiklander  *
25*9f31ef5aSJens Wiklander  * A file is constructed of slices which may be shared in different
26*9f31ef5aSJens Wiklander  * mappings/contexts. There may be holes in the file for ranges of the file
27*9f31ef5aSJens Wiklander  * that can't be shared.
28*9f31ef5aSJens Wiklander  */
29*9f31ef5aSJens Wiklander struct file {
30*9f31ef5aSJens Wiklander 	uint8_t tag[FILE_TAG_SIZE];
31*9f31ef5aSJens Wiklander 	unsigned int taglen;
32*9f31ef5aSJens Wiklander 	struct refcount refc;
33*9f31ef5aSJens Wiklander 	TAILQ_ENTRY(file) link;
34*9f31ef5aSJens Wiklander 	unsigned int num_slices;
35*9f31ef5aSJens Wiklander 	struct file_slice slices[];
36*9f31ef5aSJens Wiklander };
37*9f31ef5aSJens Wiklander 
38*9f31ef5aSJens Wiklander static struct mutex file_mu = MUTEX_INITIALIZER;
39*9f31ef5aSJens Wiklander static TAILQ_HEAD(, file) file_head = TAILQ_HEAD_INITIALIZER(file_head);
40*9f31ef5aSJens Wiklander 
41*9f31ef5aSJens Wiklander static int file_tag_cmp(const struct file *f, const uint8_t *tag,
42*9f31ef5aSJens Wiklander 			unsigned int taglen)
43*9f31ef5aSJens Wiklander {
44*9f31ef5aSJens Wiklander 	if (f->taglen != taglen)
45*9f31ef5aSJens Wiklander 		return -1;
46*9f31ef5aSJens Wiklander 	return memcmp(tag, f->tag, taglen);
47*9f31ef5aSJens Wiklander }
48*9f31ef5aSJens Wiklander 
49*9f31ef5aSJens Wiklander static struct file *file_find_tag_unlocked(const uint8_t *tag,
50*9f31ef5aSJens Wiklander 					   unsigned int taglen)
51*9f31ef5aSJens Wiklander {
52*9f31ef5aSJens Wiklander 	struct file *f = NULL;
53*9f31ef5aSJens Wiklander 
54*9f31ef5aSJens Wiklander 	TAILQ_FOREACH(f, &file_head, link)
55*9f31ef5aSJens Wiklander 		if (!file_tag_cmp(f, tag, taglen))
56*9f31ef5aSJens Wiklander 			return f;
57*9f31ef5aSJens Wiklander 
58*9f31ef5aSJens Wiklander 	return NULL;
59*9f31ef5aSJens Wiklander }
60*9f31ef5aSJens Wiklander 
61*9f31ef5aSJens Wiklander static void file_free(struct file *f)
62*9f31ef5aSJens Wiklander {
63*9f31ef5aSJens Wiklander 	size_t n = 0;
64*9f31ef5aSJens Wiklander 
65*9f31ef5aSJens Wiklander 	for (n = 0; n < f->num_slices; n++)
66*9f31ef5aSJens Wiklander 		fobj_put(f->slices[n].fobj);
67*9f31ef5aSJens Wiklander 
68*9f31ef5aSJens Wiklander 	free(f);
69*9f31ef5aSJens Wiklander }
70*9f31ef5aSJens Wiklander 
71*9f31ef5aSJens Wiklander struct file *file_new(uint8_t *tag, unsigned int taglen,
72*9f31ef5aSJens Wiklander 		      struct file_slice *slices, unsigned int num_slices)
73*9f31ef5aSJens Wiklander {
74*9f31ef5aSJens Wiklander 	unsigned int s = 0;
75*9f31ef5aSJens Wiklander 	unsigned int n = 0;
76*9f31ef5aSJens Wiklander 	struct file *f = NULL;
77*9f31ef5aSJens Wiklander 	bool did_insert = false;
78*9f31ef5aSJens Wiklander 
79*9f31ef5aSJens Wiklander 	if (taglen > sizeof(f->tag))
80*9f31ef5aSJens Wiklander 		return NULL;
81*9f31ef5aSJens Wiklander 	if (MUL_OVERFLOW(num_slices, sizeof(*slices), &s))
82*9f31ef5aSJens Wiklander 		return NULL;
83*9f31ef5aSJens Wiklander 	if (ADD_OVERFLOW(s, sizeof(*f), &s))
84*9f31ef5aSJens Wiklander 		return NULL;
85*9f31ef5aSJens Wiklander 	f = calloc(1, s);
86*9f31ef5aSJens Wiklander 	if (!f)
87*9f31ef5aSJens Wiklander 		return NULL;
88*9f31ef5aSJens Wiklander 
89*9f31ef5aSJens Wiklander 	memcpy(f->tag, tag, taglen);
90*9f31ef5aSJens Wiklander 	f->taglen = taglen;
91*9f31ef5aSJens Wiklander 	refcount_set(&f->refc, 1);
92*9f31ef5aSJens Wiklander 	for (n = 0; n < num_slices; n++) {
93*9f31ef5aSJens Wiklander 		if (file_find_slice(f, slices[n].page_offset))
94*9f31ef5aSJens Wiklander 			goto err;
95*9f31ef5aSJens Wiklander 
96*9f31ef5aSJens Wiklander 		f->slices[n].fobj = fobj_get(slices[n].fobj);
97*9f31ef5aSJens Wiklander 		f->num_slices = n + 1;
98*9f31ef5aSJens Wiklander 		if (!f->slices[n].fobj ||
99*9f31ef5aSJens Wiklander 		    ADD_OVERFLOW(slices[n].page_offset,
100*9f31ef5aSJens Wiklander 				 slices[n].fobj->num_pages, &s))
101*9f31ef5aSJens Wiklander 			goto err;
102*9f31ef5aSJens Wiklander 		f->slices[n].page_offset = slices[n].page_offset;
103*9f31ef5aSJens Wiklander 	}
104*9f31ef5aSJens Wiklander 
105*9f31ef5aSJens Wiklander 	mutex_lock(&file_mu);
106*9f31ef5aSJens Wiklander 	if (!file_find_tag_unlocked(tag, taglen)) {
107*9f31ef5aSJens Wiklander 		TAILQ_INSERT_TAIL(&file_head, f, link);
108*9f31ef5aSJens Wiklander 		did_insert = true;
109*9f31ef5aSJens Wiklander 	}
110*9f31ef5aSJens Wiklander 	mutex_unlock(&file_mu);
111*9f31ef5aSJens Wiklander 
112*9f31ef5aSJens Wiklander 	if (did_insert)
113*9f31ef5aSJens Wiklander 		return f;
114*9f31ef5aSJens Wiklander err:
115*9f31ef5aSJens Wiklander 	file_free(f);
116*9f31ef5aSJens Wiklander 
117*9f31ef5aSJens Wiklander 	return NULL;
118*9f31ef5aSJens Wiklander }
119*9f31ef5aSJens Wiklander 
120*9f31ef5aSJens Wiklander struct file *file_get(struct file *f)
121*9f31ef5aSJens Wiklander {
122*9f31ef5aSJens Wiklander 	if (f && !refcount_inc(&f->refc))
123*9f31ef5aSJens Wiklander 		panic();
124*9f31ef5aSJens Wiklander 
125*9f31ef5aSJens Wiklander 	return f;
126*9f31ef5aSJens Wiklander }
127*9f31ef5aSJens Wiklander 
128*9f31ef5aSJens Wiklander struct file *file_get_by_tag(uint8_t *tag, unsigned int taglen)
129*9f31ef5aSJens Wiklander {
130*9f31ef5aSJens Wiklander 	struct file *f = NULL;
131*9f31ef5aSJens Wiklander 
132*9f31ef5aSJens Wiklander 	mutex_lock(&file_mu);
133*9f31ef5aSJens Wiklander 	f = file_get(file_find_tag_unlocked(tag, taglen));
134*9f31ef5aSJens Wiklander 	mutex_unlock(&file_mu);
135*9f31ef5aSJens Wiklander 
136*9f31ef5aSJens Wiklander 	return f;
137*9f31ef5aSJens Wiklander }
138*9f31ef5aSJens Wiklander 
139*9f31ef5aSJens Wiklander void file_put(struct file *f)
140*9f31ef5aSJens Wiklander {
141*9f31ef5aSJens Wiklander 	bool did_remove = false;
142*9f31ef5aSJens Wiklander 
143*9f31ef5aSJens Wiklander 	if (!f)
144*9f31ef5aSJens Wiklander 		return;
145*9f31ef5aSJens Wiklander 
146*9f31ef5aSJens Wiklander 	mutex_lock(&file_mu);
147*9f31ef5aSJens Wiklander 	if (refcount_dec(&f->refc)) {
148*9f31ef5aSJens Wiklander 		TAILQ_REMOVE(&file_head, f, link);
149*9f31ef5aSJens Wiklander 		did_remove = true;
150*9f31ef5aSJens Wiklander 	}
151*9f31ef5aSJens Wiklander 	mutex_unlock(&file_mu);
152*9f31ef5aSJens Wiklander 
153*9f31ef5aSJens Wiklander 	if (did_remove)
154*9f31ef5aSJens Wiklander 		file_free(f);
155*9f31ef5aSJens Wiklander }
156*9f31ef5aSJens Wiklander 
157*9f31ef5aSJens Wiklander struct file_slice *file_find_slice(struct file *f, unsigned int page_offset)
158*9f31ef5aSJens Wiklander {
159*9f31ef5aSJens Wiklander 	size_t n = 0;
160*9f31ef5aSJens Wiklander 
161*9f31ef5aSJens Wiklander 	if (!f)
162*9f31ef5aSJens Wiklander 		return NULL;
163*9f31ef5aSJens Wiklander 
164*9f31ef5aSJens Wiklander 	for (n = 0; n < f->num_slices; n++) {
165*9f31ef5aSJens Wiklander 		struct file_slice *fs = f->slices + n;
166*9f31ef5aSJens Wiklander 
167*9f31ef5aSJens Wiklander 		if (page_offset >= fs->page_offset &&
168*9f31ef5aSJens Wiklander 		    page_offset < fs->page_offset + fs->fobj->num_pages)
169*9f31ef5aSJens Wiklander 			return fs;
170*9f31ef5aSJens Wiklander 	}
171*9f31ef5aSJens Wiklander 
172*9f31ef5aSJens Wiklander 	return NULL;
173*9f31ef5aSJens Wiklander }
174