summaryrefslogtreecommitdiff
path: root/drivers/tee/qcomtee/primordial_obj.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/tee/qcomtee/primordial_obj.c')
-rw-r--r--drivers/tee/qcomtee/primordial_obj.c113
1 files changed, 113 insertions, 0 deletions
diff --git a/drivers/tee/qcomtee/primordial_obj.c b/drivers/tee/qcomtee/primordial_obj.c
new file mode 100644
index 000000000000..b6f811e83b11
--- /dev/null
+++ b/drivers/tee/qcomtee/primordial_obj.c
@@ -0,0 +1,113 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+#include <linux/delay.h>
+#include "qcomtee.h"
+
+/**
+ * DOC: Primordial Object
+ *
+ * After boot, the kernel provides a static object of type
+ * %QCOMTEE_OBJECT_TYPE_CB called the primordial object. This object is used
+ * for native kernel services or privileged operations.
+ *
+ * We support:
+ * - %QCOMTEE_OBJECT_OP_MAP_REGION to map a memory object and return mapping
+ * object and mapping information (see qcomtee_mem_object_map()).
+ * - %QCOMTEE_OBJECT_OP_YIELD to yield by the thread running in QTEE.
+ * - %QCOMTEE_OBJECT_OP_SLEEP to wait for a period of time.
+ */
+
+#define QCOMTEE_OBJECT_OP_MAP_REGION 0
+#define QCOMTEE_OBJECT_OP_YIELD 1
+#define QCOMTEE_OBJECT_OP_SLEEP 2
+
+/* Mapping information format as expected by QTEE. */
+struct qcomtee_mapping_info {
+ u64 paddr;
+ u64 len;
+ u32 perms;
+} __packed;
+
+static int
+qcomtee_primordial_obj_dispatch(struct qcomtee_object_invoke_ctx *oic,
+ struct qcomtee_object *primordial_object_unused,
+ u32 op, struct qcomtee_arg *args)
+{
+ struct qcomtee_mapping_info *map_info;
+ struct qcomtee_object *mem_object;
+ struct qcomtee_object *map_object;
+ int err = 0;
+
+ switch (op) {
+ case QCOMTEE_OBJECT_OP_YIELD:
+ cond_resched();
+ /* No output object. */
+ oic->data = NULL;
+
+ break;
+ case QCOMTEE_OBJECT_OP_SLEEP:
+ /* Check message format matched QCOMTEE_OBJECT_OP_SLEEP op. */
+ if (qcomtee_args_len(args) != 1 ||
+ args[0].type != QCOMTEE_ARG_TYPE_IB ||
+ args[0].b.size < sizeof(u32))
+ return -EINVAL;
+
+ msleep(*(u32 *)(args[0].b.addr));
+ /* No output object. */
+ oic->data = NULL;
+
+ break;
+ case QCOMTEE_OBJECT_OP_MAP_REGION:
+ if (qcomtee_args_len(args) != 3 ||
+ args[0].type != QCOMTEE_ARG_TYPE_OB ||
+ args[1].type != QCOMTEE_ARG_TYPE_IO ||
+ args[2].type != QCOMTEE_ARG_TYPE_OO ||
+ args[0].b.size < sizeof(struct qcomtee_mapping_info))
+ return -EINVAL;
+
+ map_info = args[0].b.addr;
+ mem_object = args[1].o;
+
+ qcomtee_mem_object_map(mem_object, &map_object,
+ &map_info->paddr, &map_info->len,
+ &map_info->perms);
+
+ args[2].o = map_object;
+ /* One output object; pass it for cleanup to notify. */
+ oic->data = map_object;
+
+ qcomtee_object_put(mem_object);
+
+ break;
+ default:
+ err = -EINVAL;
+ }
+
+ return err;
+}
+
+/* Called after submitting the callback response. */
+static void qcomtee_primordial_obj_notify(struct qcomtee_object_invoke_ctx *oic,
+ struct qcomtee_object *unused,
+ int err)
+{
+ struct qcomtee_object *object = oic->data;
+
+ /* If err, QTEE did not obtain mapping object. Drop it. */
+ if (object && err)
+ qcomtee_object_put(object);
+}
+
+static struct qcomtee_object_operations qcomtee_primordial_obj_ops = {
+ .dispatch = qcomtee_primordial_obj_dispatch,
+ .notify = qcomtee_primordial_obj_notify,
+};
+
+struct qcomtee_object qcomtee_primordial_object = {
+ .name = "primordial",
+ .object_type = QCOMTEE_OBJECT_TYPE_CB,
+ .ops = &qcomtee_primordial_obj_ops
+};