2 * Copyright (c) 2015, Linaro Limited
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
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.
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.
29 #include <kernel/mutex.h>
30 #include <kernel/panic.h>
31 #include <kernel/thread.h>
32 #include <mm/core_memprot.h>
33 #include <optee_msg_supplicant.h>
36 #include <string_ext.h>
38 #include <sys/queue.h>
39 #include <tee/fs_htree.h>
40 #include <tee/tee_cryp_provider.h>
41 #include <tee/tee_fs.h>
42 #include <tee/tee_fs_rpc.h>
44 #include <utee_defines.h>
47 #define BLOCK_SHIFT 12
49 #define BLOCK_SIZE (1 << BLOCK_SHIFT)
52 struct tee_fs_htree *ht;
56 static int pos_to_block_num(int position)
58 return position >> BLOCK_SHIFT;
61 static struct mutex ree_fs_mutex = MUTEX_INITIALIZER;
63 static TEE_Result ree_fs_opendir_rpc(const TEE_UUID *uuid,
64 struct tee_fs_dir **d)
67 return tee_fs_rpc_opendir(OPTEE_MSG_RPC_CMD_FS, uuid, d);
70 static void ree_fs_closedir_rpc(struct tee_fs_dir *d)
73 tee_fs_rpc_closedir(OPTEE_MSG_RPC_CMD_FS, d);
76 static TEE_Result ree_fs_readdir_rpc(struct tee_fs_dir *d,
77 struct tee_fs_dirent **ent)
79 return tee_fs_rpc_readdir(OPTEE_MSG_RPC_CMD_FS, d, ent);
82 static TEE_Result out_of_place_write(struct tee_fs_fd *fdp, size_t pos,
83 const void *buf, size_t len)
86 size_t start_block_num = pos_to_block_num(pos);
87 size_t end_block_num = pos_to_block_num(pos + len - 1);
88 size_t remain_bytes = len;
89 uint8_t *data_ptr = (uint8_t *)buf;
91 struct tee_fs_htree_meta *meta = tee_fs_htree_get_meta(fdp->ht);
93 block = malloc(BLOCK_SIZE);
95 return TEE_ERROR_OUT_OF_MEMORY;
97 while (start_block_num <= end_block_num) {
98 size_t offset = pos % BLOCK_SIZE;
99 size_t size_to_write = MIN(remain_bytes, (size_t)BLOCK_SIZE);
101 if (size_to_write + offset > BLOCK_SIZE)
102 size_to_write = BLOCK_SIZE - offset;
104 if (start_block_num * BLOCK_SIZE <
105 ROUNDUP(meta->length, BLOCK_SIZE)) {
106 res = tee_fs_htree_read_block(&fdp->ht,
107 start_block_num, block);
108 if (res != TEE_SUCCESS)
111 memset(block, 0, BLOCK_SIZE);
115 memcpy(block + offset, data_ptr, size_to_write);
117 memset(block + offset, 0, size_to_write);
119 res = tee_fs_htree_write_block(&fdp->ht, start_block_num,
121 if (res != TEE_SUCCESS)
125 data_ptr += size_to_write;
126 remain_bytes -= size_to_write;
128 pos += size_to_write;
131 if (pos > meta->length)
139 static TEE_Result get_offs_size(enum tee_fs_htree_type type, size_t idx,
140 uint8_t vers, size_t *offs, size_t *size)
142 const size_t node_size = sizeof(struct tee_fs_htree_node_image);
143 const size_t block_nodes = BLOCK_SIZE / (node_size * 2);
147 assert(vers == 0 || vers == 1);
153 * tee_fs_htree_image vers 0 @ offs = 0
154 * tee_fs_htree_image vers 1 @ offs = sizeof(tee_fs_htree_image)
157 * tee_fs_htree_node_image 0 vers 0 @ offs = 0
158 * tee_fs_htree_node_image 0 vers 1 @ offs = node_size
159 * tee_fs_htree_node_image 1 vers 0 @ offs = node_size * 2
160 * tee_fs_htree_node_image 1 vers 1 @ offs = node_size * 3
162 * tee_fs_htree_node_image 61 vers 0 @ offs = node_size * 122
163 * tee_fs_htree_node_image 61 vers 1 @ offs = node_size * 123
166 * data block 0 vers 0
169 * data block 0 vers 1
173 * data block 61 vers 0
176 * data block 61 vers 1
179 * tee_fs_htree_node_image 62 vers 0 @ offs = 0
180 * tee_fs_htree_node_image 62 vers 1 @ offs = node_size
181 * tee_fs_htree_node_image 63 vers 0 @ offs = node_size * 2
182 * tee_fs_htree_node_image 63 vers 1 @ offs = node_size * 3
184 * tee_fs_htree_node_image 121 vers 0 @ offs = node_size * 122
185 * tee_fs_htree_node_image 121 vers 1 @ offs = node_size * 123
191 case TEE_FS_HTREE_TYPE_HEAD:
192 *offs = sizeof(struct tee_fs_htree_image) * vers;
193 *size = sizeof(struct tee_fs_htree_image);
195 case TEE_FS_HTREE_TYPE_NODE:
196 pbn = 1 + ((idx / block_nodes) * block_nodes * 2);
197 *offs = pbn * BLOCK_SIZE +
198 2 * node_size * (idx % block_nodes) +
202 case TEE_FS_HTREE_TYPE_BLOCK:
203 bidx = 2 * idx + vers;
204 pbn = 2 + bidx + bidx / (block_nodes * 2 - 1);
205 *offs = pbn * BLOCK_SIZE;
209 return TEE_ERROR_GENERIC;
213 static TEE_Result ree_fs_rpc_read_init(void *aux,
214 struct tee_fs_rpc_operation *op,
215 enum tee_fs_htree_type type, size_t idx,
216 uint8_t vers, void **data)
218 struct tee_fs_fd *fdp = aux;
223 res = get_offs_size(type, idx, vers, &offs, &size);
224 if (res != TEE_SUCCESS)
227 return tee_fs_rpc_read_init(op, OPTEE_MSG_RPC_CMD_FS, fdp->fd,
231 static TEE_Result ree_fs_rpc_write_init(void *aux,
232 struct tee_fs_rpc_operation *op,
233 enum tee_fs_htree_type type, size_t idx,
234 uint8_t vers, void **data)
236 struct tee_fs_fd *fdp = aux;
241 res = get_offs_size(type, idx, vers, &offs, &size);
242 if (res != TEE_SUCCESS)
245 return tee_fs_rpc_write_init(op, OPTEE_MSG_RPC_CMD_FS, fdp->fd,
249 static const struct tee_fs_htree_storage ree_fs_storage_ops = {
250 .block_size = BLOCK_SIZE,
251 .rpc_read_init = ree_fs_rpc_read_init,
252 .rpc_read_final = tee_fs_rpc_read_final,
253 .rpc_write_init = ree_fs_rpc_write_init,
254 .rpc_write_final = tee_fs_rpc_write_final,
257 static TEE_Result open_internal(struct tee_pobj *po, bool create,
258 struct tee_file_handle **fh)
261 struct tee_fs_fd *fdp = NULL;
263 fdp = calloc(1, sizeof(struct tee_fs_fd));
265 return TEE_ERROR_OUT_OF_MEMORY;
268 mutex_lock(&ree_fs_mutex);
271 res = tee_fs_rpc_create(OPTEE_MSG_RPC_CMD_FS, po, &fdp->fd);
273 res = tee_fs_rpc_open(OPTEE_MSG_RPC_CMD_FS, po, &fdp->fd);
275 if (res != TEE_SUCCESS)
278 res = tee_fs_htree_open(create, &ree_fs_storage_ops, fdp, &fdp->ht);
280 if (res == TEE_SUCCESS) {
281 *fh = (struct tee_file_handle *)fdp;
284 tee_fs_rpc_close(OPTEE_MSG_RPC_CMD_FS, fdp->fd);
286 tee_fs_rpc_remove(OPTEE_MSG_RPC_CMD_FS, po);
290 mutex_unlock(&ree_fs_mutex);
294 static TEE_Result ree_fs_open(struct tee_pobj *po, struct tee_file_handle **fh)
296 return open_internal(po, false, fh);
299 static TEE_Result ree_fs_create(struct tee_pobj *po,
300 struct tee_file_handle **fh)
302 return open_internal(po, true, fh);
305 static void ree_fs_close(struct tee_file_handle **fh)
307 struct tee_fs_fd *fdp = (struct tee_fs_fd *)*fh;
310 tee_fs_htree_close(&fdp->ht);
311 tee_fs_rpc_close(OPTEE_MSG_RPC_CMD_FS, fdp->fd);
317 static TEE_Result ree_fs_ftruncate_internal(struct tee_fs_fd *fdp,
318 tee_fs_off_t new_file_len)
321 struct tee_fs_htree_meta *meta = tee_fs_htree_get_meta(fdp->ht);
323 if ((size_t)new_file_len > meta->length) {
324 size_t ext_len = new_file_len - meta->length;
326 res = out_of_place_write(fdp, meta->length, NULL, ext_len);
327 if (res != TEE_SUCCESS)
333 res = get_offs_size(TEE_FS_HTREE_TYPE_BLOCK,
334 ROUNDUP(new_file_len, BLOCK_SIZE) /
335 BLOCK_SIZE, 1, &offs, &sz);
336 if (res != TEE_SUCCESS)
339 res = tee_fs_htree_truncate(&fdp->ht,
340 new_file_len / BLOCK_SIZE);
341 if (res != TEE_SUCCESS)
344 res = tee_fs_rpc_truncate(OPTEE_MSG_RPC_CMD_FS, fdp->fd,
346 if (res != TEE_SUCCESS)
349 meta->length = new_file_len;
352 return tee_fs_htree_sync_to_storage(&fdp->ht);
355 static TEE_Result ree_fs_read(struct tee_file_handle *fh, size_t pos,
356 void *buf, size_t *len)
362 uint8_t *data_ptr = buf;
363 uint8_t *block = NULL;
364 struct tee_fs_fd *fdp = (struct tee_fs_fd *)fh;
365 struct tee_fs_htree_meta *meta = tee_fs_htree_get_meta(fdp->ht);
367 mutex_lock(&ree_fs_mutex);
370 if ((pos + remain_bytes) < remain_bytes || pos > meta->length)
372 else if (pos + remain_bytes > meta->length)
373 remain_bytes = meta->length - pos;
382 start_block_num = pos_to_block_num(pos);
383 end_block_num = pos_to_block_num(pos + remain_bytes - 1);
385 block = malloc(BLOCK_SIZE);
387 res = TEE_ERROR_OUT_OF_MEMORY;
391 while (start_block_num <= end_block_num) {
392 size_t offset = pos % BLOCK_SIZE;
393 size_t size_to_read = MIN(remain_bytes, (size_t)BLOCK_SIZE);
395 if (size_to_read + offset > BLOCK_SIZE)
396 size_to_read = BLOCK_SIZE - offset;
398 res = tee_fs_htree_read_block(&fdp->ht, start_block_num, block);
399 if (res != TEE_SUCCESS)
402 memcpy(data_ptr, block + offset, size_to_read);
404 data_ptr += size_to_read;
405 remain_bytes -= size_to_read;
412 mutex_unlock(&ree_fs_mutex);
417 static TEE_Result ree_fs_write(struct tee_file_handle *fh, size_t pos,
418 const void *buf, size_t len)
421 struct tee_fs_fd *fdp = (struct tee_fs_fd *)fh;
427 mutex_lock(&ree_fs_mutex);
429 file_size = tee_fs_htree_get_meta(fdp->ht)->length;
431 if ((pos + len) < len) {
432 res = TEE_ERROR_BAD_PARAMETERS;
436 if (file_size < pos) {
437 res = ree_fs_ftruncate_internal(fdp, pos);
438 if (res != TEE_SUCCESS)
442 res = out_of_place_write(fdp, pos, buf, len);
443 if (res != TEE_SUCCESS)
447 if (res == TEE_SUCCESS)
448 res = tee_fs_htree_sync_to_storage(&fdp->ht);
449 mutex_unlock(&ree_fs_mutex);
453 static TEE_Result ree_fs_rename(struct tee_pobj *old, struct tee_pobj *new,
458 mutex_lock(&ree_fs_mutex);
459 res = tee_fs_rpc_rename(OPTEE_MSG_RPC_CMD_FS, old, new, overwrite);
460 mutex_unlock(&ree_fs_mutex);
465 static TEE_Result ree_fs_remove(struct tee_pobj *po)
469 mutex_lock(&ree_fs_mutex);
470 res = tee_fs_rpc_remove(OPTEE_MSG_RPC_CMD_FS, po);
471 mutex_unlock(&ree_fs_mutex);
476 static TEE_Result ree_fs_truncate(struct tee_file_handle *fh, size_t len)
479 struct tee_fs_fd *fdp = (struct tee_fs_fd *)fh;
481 mutex_lock(&ree_fs_mutex);
482 res = ree_fs_ftruncate_internal(fdp, len);
483 mutex_unlock(&ree_fs_mutex);
488 const struct tee_file_operations ree_fs_ops = {
490 .create = ree_fs_create,
491 .close = ree_fs_close,
493 .write = ree_fs_write,
494 .truncate = ree_fs_truncate,
495 .rename = ree_fs_rename,
496 .remove = ree_fs_remove,
497 .opendir = ree_fs_opendir_rpc,
498 .closedir = ree_fs_closedir_rpc,
499 .readdir = ree_fs_readdir_rpc,