summaryrefslogtreecommitdiff
path: root/core/tee/tee_pobj.c
diff options
context:
space:
mode:
Diffstat (limited to 'core/tee/tee_pobj.c')
-rw-r--r--core/tee/tee_pobj.c190
1 files changed, 190 insertions, 0 deletions
diff --git a/core/tee/tee_pobj.c b/core/tee/tee_pobj.c
new file mode 100644
index 0000000..a7aee31
--- /dev/null
+++ b/core/tee/tee_pobj.c
@@ -0,0 +1,190 @@
+/*
+ * Copyright (c) 2014, STMicroelectronics International N.V.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <kernel/mutex.h>
+#include <stdlib.h>
+#include <string.h>
+#include <tee/tee_pobj.h>
+#include <trace.h>
+
+static TAILQ_HEAD(tee_pobjs, tee_pobj) tee_pobjs =
+ TAILQ_HEAD_INITIALIZER(tee_pobjs);
+static struct mutex pobjs_mutex = MUTEX_INITIALIZER;
+
+static TEE_Result tee_pobj_check_access(uint32_t oflags, uint32_t nflags)
+{
+ /* meta is exclusive */
+ if ((oflags & TEE_DATA_FLAG_ACCESS_WRITE_META) ||
+ (nflags & TEE_DATA_FLAG_ACCESS_WRITE_META))
+ return TEE_ERROR_ACCESS_CONFLICT;
+
+ /*
+ * Excerpt of TEE Internal Core API Specification v1.1:
+ * If more than one handle is opened on the same object, and if any
+ * of these object handles was opened with the flag
+ * TEE_DATA_FLAG_ACCESS_READ, then all the object handles MUST have been
+ * opened with the flag TEE_DATA_FLAG_SHARE_READ
+ */
+ if (((oflags & TEE_DATA_FLAG_ACCESS_READ) ||
+ (nflags & TEE_DATA_FLAG_ACCESS_READ)) &&
+ !((nflags & TEE_DATA_FLAG_SHARE_READ) &&
+ (oflags & TEE_DATA_FLAG_SHARE_READ)))
+ return TEE_ERROR_ACCESS_CONFLICT;
+
+ /*
+ * Excerpt of TEE Internal Core API Specification v1.1:
+ * An object can be opened with only share flags, which locks the access
+ * to an object against a given mode.
+ * An object can be opened with no flag set, which completely locks all
+ * subsequent attempts to access the object
+ */
+ if ((nflags & TEE_DATA_FLAG_SHARE_READ) !=
+ (oflags & TEE_DATA_FLAG_SHARE_READ))
+ return TEE_ERROR_ACCESS_CONFLICT;
+
+ /* Same on WRITE access */
+ if (((oflags & TEE_DATA_FLAG_ACCESS_WRITE) ||
+ (nflags & TEE_DATA_FLAG_ACCESS_WRITE)) &&
+ !((nflags & TEE_DATA_FLAG_SHARE_WRITE) &&
+ (oflags & TEE_DATA_FLAG_SHARE_WRITE)))
+ return TEE_ERROR_ACCESS_CONFLICT;
+ if ((nflags & TEE_DATA_FLAG_SHARE_WRITE) !=
+ (oflags & TEE_DATA_FLAG_SHARE_WRITE))
+ return TEE_ERROR_ACCESS_CONFLICT;
+
+ return TEE_SUCCESS;
+}
+
+TEE_Result tee_pobj_get(TEE_UUID *uuid, void *obj_id, uint32_t obj_id_len,
+ uint32_t flags, const struct tee_file_operations *fops,
+ struct tee_pobj **obj)
+{
+ struct tee_pobj *o;
+ TEE_Result res;
+
+ *obj = NULL;
+
+ mutex_lock(&pobjs_mutex);
+ /* Check if file is open */
+ TAILQ_FOREACH(o, &tee_pobjs, link) {
+ if ((obj_id_len == o->obj_id_len) &&
+ (memcmp(obj_id, o->obj_id, obj_id_len) == 0) &&
+ (memcmp(uuid, &o->uuid, sizeof(TEE_UUID)) == 0) &&
+ (fops == o->fops)) {
+ *obj = o;
+ }
+ }
+
+ if (*obj) {
+ res = tee_pobj_check_access((*obj)->flags, flags);
+ if (res != TEE_SUCCESS)
+ *obj = NULL;
+ else
+ (*obj)->refcnt++;
+ goto out;
+ }
+
+ /* new file */
+ o = calloc(sizeof(struct tee_pobj), 1);
+ if (!o) {
+ res = TEE_ERROR_OUT_OF_MEMORY;
+ goto out;
+ }
+
+ o->refcnt = 1;
+ memcpy(&o->uuid, uuid, sizeof(TEE_UUID));
+ o->flags = flags;
+ o->fops = fops;
+
+ o->obj_id = malloc(obj_id_len);
+ if (o->obj_id == NULL) {
+ free(o);
+ res = TEE_ERROR_OUT_OF_MEMORY;
+ goto out;
+ }
+ memcpy(o->obj_id, obj_id, obj_id_len);
+ o->obj_id_len = obj_id_len;
+
+ TAILQ_INSERT_TAIL(&tee_pobjs, o, link);
+ *obj = o;
+
+ res = TEE_SUCCESS;
+out:
+ mutex_unlock(&pobjs_mutex);
+ return res;
+}
+
+TEE_Result tee_pobj_release(struct tee_pobj *obj)
+{
+ if (obj == NULL)
+ return TEE_ERROR_BAD_PARAMETERS;
+
+ mutex_lock(&pobjs_mutex);
+ obj->refcnt--;
+ if (obj->refcnt == 0) {
+ TAILQ_REMOVE(&tee_pobjs, obj, link);
+ free(obj->obj_id);
+ free(obj);
+ }
+ mutex_unlock(&pobjs_mutex);
+
+ return TEE_SUCCESS;
+}
+
+TEE_Result tee_pobj_rename(struct tee_pobj *obj, void *obj_id,
+ uint32_t obj_id_len)
+{
+ TEE_Result res = TEE_SUCCESS;
+ void *new_obj_id = NULL;
+
+ if (obj == NULL || obj_id == NULL)
+ return TEE_ERROR_BAD_PARAMETERS;
+
+ mutex_lock(&pobjs_mutex);
+ if (obj->refcnt != 1) {
+ res = TEE_ERROR_BAD_STATE;
+ goto exit;
+ }
+
+ new_obj_id = malloc(obj_id_len);
+ if (new_obj_id == NULL) {
+ res = TEE_ERROR_OUT_OF_MEMORY;
+ goto exit;
+ }
+ memcpy(new_obj_id, obj_id, obj_id_len);
+
+ /* update internal data */
+ free(obj->obj_id);
+ obj->obj_id = new_obj_id;
+ obj->obj_id_len = obj_id_len;
+ new_obj_id = NULL;
+
+exit:
+ mutex_unlock(&pobjs_mutex);
+ free(new_obj_id);
+ return res;
+}