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