Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

tee: qcom: enable TEE_IOC_SHM_ALLOC ioctl

Enable userspace to allocate shared memory with QTEE. Since
QTEE handles shared memory as object, a wrapper is implemented
to represent tee_shm as an object. The shared memory identifier,
obtained through TEE_IOC_SHM_ALLOC, is transferred to the driver using
TEE_IOCTL_PARAM_ATTR_TYPE_OBJREF_INPUT/OUTPUT.

Tested-by: Neil Armstrong <neil.armstrong@linaro.org>
Acked-by: Sumit Garg <sumit.garg@oss.qualcomm.com>
Tested-by: Harshal Dev <quic_hdev@quicinc.com>
Signed-off-by: Amirreza Zarrabi <amirreza.zarrabi@oss.qualcomm.com>
Signed-off-by: Jens Wiklander <jens.wiklander@linaro.org>

authored by

Amirreza Zarrabi and committed by
Jens Wiklander
87ab676d 0f7bfdcb

+267 -4
+1
drivers/tee/qcomtee/Makefile
··· 3 3 qcomtee-objs += async.o 4 4 qcomtee-objs += call.o 5 5 qcomtee-objs += core.o 6 + qcomtee-objs += mem_obj.o 6 7 qcomtee-objs += primordial_obj.o 7 8 qcomtee-objs += shm.o 8 9 qcomtee-objs += user_obj.o
+8 -1
drivers/tee/qcomtee/call.c
··· 122 122 err = qcomtee_user_param_to_object(&arg->o, param, ctx); 123 123 /* param is a QTEE object: */ 124 124 else if (param->u.objref.flags & QCOMTEE_OBJREF_FLAG_TEE) 125 - err = qcomtee_context_find_qtee_object(&arg->o, param, ctx); 125 + err = qcomtee_context_find_qtee_object(&arg->o, param, ctx); 126 + /* param is a memory object: */ 127 + else if (param->u.objref.flags & QCOMTEE_OBJREF_FLAG_MEM) 128 + err = qcomtee_memobj_param_to_object(&arg->o, param, ctx); 126 129 127 130 /* 128 131 * For callback objects, call qcomtee_object_get() to keep a temporary ··· 171 168 if (is_qcomtee_user_object(object)) 172 169 return qcomtee_user_param_from_object(param, object, 173 170 ctx); 171 + /* object is a memory object: */ 172 + else if (is_qcomtee_memobj_object(object)) 173 + return qcomtee_memobj_param_from_object(param, object, 174 + ctx); 174 175 175 176 break; 176 177 case QCOMTEE_OBJECT_TYPE_TEE:
+169
drivers/tee/qcomtee/mem_obj.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* 3 + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. 4 + */ 5 + 6 + #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 7 + 8 + #include <linux/firmware/qcom/qcom_scm.h> 9 + #include <linux/mm.h> 10 + 11 + #include "qcomtee.h" 12 + 13 + /** 14 + * DOC: Memory and Mapping Objects 15 + * 16 + * QTEE uses memory objects for memory sharing with Linux. 17 + * A memory object can be a standard dma_buf or a contiguous memory range, 18 + * e.g., tee_shm. A memory object should support one operation: map. When 19 + * invoked by QTEE, a mapping object is generated. A mapping object supports 20 + * one operation: unmap. 21 + * 22 + * (1) To map a memory object, QTEE invokes the primordial object with 23 + * %QCOMTEE_OBJECT_OP_MAP_REGION operation; see 24 + * qcomtee_primordial_obj_dispatch(). 25 + * (2) To unmap a memory object, QTEE releases the mapping object which 26 + * calls qcomtee_mem_object_release(). 27 + * 28 + * The map operation is implemented in the primordial object as a privileged 29 + * operation instead of qcomtee_mem_object_dispatch(). Otherwise, on 30 + * platforms without shm_bridge, a user can trick QTEE into writing to the 31 + * kernel memory by passing a user object as a memory object and returning a 32 + * random physical address as the result of the mapping request. 33 + */ 34 + 35 + struct qcomtee_mem_object { 36 + struct qcomtee_object object; 37 + struct tee_shm *shm; 38 + /* QTEE requires these felids to be page aligned. */ 39 + phys_addr_t paddr; /* Physical address of range. */ 40 + size_t size; /* Size of the range. */ 41 + }; 42 + 43 + #define to_qcomtee_mem_object(o) \ 44 + container_of((o), struct qcomtee_mem_object, object) 45 + 46 + static struct qcomtee_object_operations qcomtee_mem_object_ops; 47 + 48 + /* Is it a memory object using tee_shm? */ 49 + int is_qcomtee_memobj_object(struct qcomtee_object *object) 50 + { 51 + return object != NULL_QCOMTEE_OBJECT && 52 + typeof_qcomtee_object(object) == QCOMTEE_OBJECT_TYPE_CB && 53 + object->ops == &qcomtee_mem_object_ops; 54 + } 55 + 56 + static int qcomtee_mem_object_dispatch(struct qcomtee_object_invoke_ctx *oic, 57 + struct qcomtee_object *object, u32 op, 58 + struct qcomtee_arg *args) 59 + { 60 + return -EINVAL; 61 + } 62 + 63 + static void qcomtee_mem_object_release(struct qcomtee_object *object) 64 + { 65 + struct qcomtee_mem_object *mem_object = to_qcomtee_mem_object(object); 66 + 67 + /* Matching get is in qcomtee_memobj_param_to_object(). */ 68 + tee_shm_put(mem_object->shm); 69 + kfree(mem_object); 70 + } 71 + 72 + static struct qcomtee_object_operations qcomtee_mem_object_ops = { 73 + .release = qcomtee_mem_object_release, 74 + .dispatch = qcomtee_mem_object_dispatch, 75 + }; 76 + 77 + /** 78 + * qcomtee_memobj_param_to_object() - OBJREF parameter to &struct qcomtee_object. 79 + * @object: object returned. 80 + * @param: TEE parameter. 81 + * @ctx: context in which the conversion should happen. 82 + * 83 + * @param is an OBJREF with %QCOMTEE_OBJREF_FLAG_MEM flags. 84 + * 85 + * Return: On success return 0 or <0 on failure. 86 + */ 87 + int qcomtee_memobj_param_to_object(struct qcomtee_object **object, 88 + struct tee_param *param, 89 + struct tee_context *ctx) 90 + { 91 + struct qcomtee_mem_object *mem_object __free(kfree) = NULL; 92 + struct tee_shm *shm; 93 + int err; 94 + 95 + mem_object = kzalloc(sizeof(*mem_object), GFP_KERNEL); 96 + if (!mem_object) 97 + return -ENOMEM; 98 + 99 + shm = tee_shm_get_from_id(ctx, param->u.objref.id); 100 + if (IS_ERR(shm)) 101 + return PTR_ERR(shm); 102 + 103 + /* mem-object wrapping the memref. */ 104 + err = qcomtee_object_user_init(&mem_object->object, 105 + QCOMTEE_OBJECT_TYPE_CB, 106 + &qcomtee_mem_object_ops, "tee-shm-%d", 107 + shm->id); 108 + if (err) { 109 + tee_shm_put(shm); 110 + 111 + return err; 112 + } 113 + 114 + mem_object->paddr = shm->paddr; 115 + mem_object->size = shm->size; 116 + mem_object->shm = shm; 117 + 118 + *object = &no_free_ptr(mem_object)->object; 119 + 120 + return 0; 121 + } 122 + 123 + /* Reverse what qcomtee_memobj_param_to_object() does. */ 124 + int qcomtee_memobj_param_from_object(struct tee_param *param, 125 + struct qcomtee_object *object, 126 + struct tee_context *ctx) 127 + { 128 + struct qcomtee_mem_object *mem_object; 129 + 130 + mem_object = to_qcomtee_mem_object(object); 131 + /* Sure if the memobj is in a same context it is originated from. */ 132 + if (mem_object->shm->ctx != ctx) 133 + return -EINVAL; 134 + 135 + param->u.objref.id = mem_object->shm->id; 136 + param->u.objref.flags = QCOMTEE_OBJREF_FLAG_MEM; 137 + 138 + /* Passing shm->id to userspace; drop the reference. */ 139 + qcomtee_object_put(object); 140 + 141 + return 0; 142 + } 143 + 144 + /** 145 + * qcomtee_mem_object_map() - Map a memory object. 146 + * @object: memory object. 147 + * @map_object: created mapping object. 148 + * @mem_paddr: physical address of the memory. 149 + * @mem_size: size of the memory. 150 + * @perms: QTEE access permissions. 151 + * 152 + * Return: On success return 0 or <0 on failure. 153 + */ 154 + int qcomtee_mem_object_map(struct qcomtee_object *object, 155 + struct qcomtee_object **map_object, u64 *mem_paddr, 156 + u64 *mem_size, u32 *perms) 157 + { 158 + struct qcomtee_mem_object *mem_object = to_qcomtee_mem_object(object); 159 + 160 + /* Reuses the memory object as a mapping object by re-sharing it. */ 161 + qcomtee_object_get(&mem_object->object); 162 + 163 + *map_object = &mem_object->object; 164 + *mem_paddr = mem_object->paddr; 165 + *mem_size = mem_object->size; 166 + *perms = QCOM_SCM_PERM_RW; 167 + 168 + return 0; 169 + }
+50
drivers/tee/qcomtee/primordial_obj.c
··· 14 14 * for native kernel services or privileged operations. 15 15 * 16 16 * We support: 17 + * - %QCOMTEE_OBJECT_OP_MAP_REGION to map a memory object and return mapping 18 + * object and mapping information (see qcomtee_mem_object_map()). 17 19 * - %QCOMTEE_OBJECT_OP_YIELD to yield by the thread running in QTEE. 18 20 * - %QCOMTEE_OBJECT_OP_SLEEP to wait for a period of time. 19 21 */ 20 22 23 + #define QCOMTEE_OBJECT_OP_MAP_REGION 0 21 24 #define QCOMTEE_OBJECT_OP_YIELD 1 22 25 #define QCOMTEE_OBJECT_OP_SLEEP 2 26 + 27 + /* Mapping information format as expected by QTEE. */ 28 + struct qcomtee_mapping_info { 29 + u64 paddr; 30 + u64 len; 31 + u32 perms; 32 + } __packed; 23 33 24 34 static int 25 35 qcomtee_primordial_obj_dispatch(struct qcomtee_object_invoke_ctx *oic, 26 36 struct qcomtee_object *primordial_object_unused, 27 37 u32 op, struct qcomtee_arg *args) 28 38 { 39 + struct qcomtee_mapping_info *map_info; 40 + struct qcomtee_object *mem_object; 41 + struct qcomtee_object *map_object; 29 42 int err = 0; 30 43 31 44 switch (op) { ··· 46 33 cond_resched(); 47 34 /* No output object. */ 48 35 oic->data = NULL; 36 + 49 37 break; 50 38 case QCOMTEE_OBJECT_OP_SLEEP: 51 39 /* Check message format matched QCOMTEE_OBJECT_OP_SLEEP op. */ ··· 58 44 msleep(*(u32 *)(args[0].b.addr)); 59 45 /* No output object. */ 60 46 oic->data = NULL; 47 + 48 + break; 49 + case QCOMTEE_OBJECT_OP_MAP_REGION: 50 + if (qcomtee_args_len(args) != 3 || 51 + args[0].type != QCOMTEE_ARG_TYPE_OB || 52 + args[1].type != QCOMTEE_ARG_TYPE_IO || 53 + args[2].type != QCOMTEE_ARG_TYPE_OO || 54 + args[0].b.size < sizeof(struct qcomtee_mapping_info)) 55 + return -EINVAL; 56 + 57 + map_info = args[0].b.addr; 58 + mem_object = args[1].o; 59 + 60 + qcomtee_mem_object_map(mem_object, &map_object, 61 + &map_info->paddr, &map_info->len, 62 + &map_info->perms); 63 + 64 + args[2].o = map_object; 65 + /* One output object; pass it for cleanup to notify. */ 66 + oic->data = map_object; 67 + 68 + qcomtee_object_put(mem_object); 69 + 61 70 break; 62 71 default: 63 72 err = -EINVAL; ··· 89 52 return err; 90 53 } 91 54 55 + /* Called after submitting the callback response. */ 56 + static void qcomtee_primordial_obj_notify(struct qcomtee_object_invoke_ctx *oic, 57 + struct qcomtee_object *unused, 58 + int err) 59 + { 60 + struct qcomtee_object *object = oic->data; 61 + 62 + /* If err, QTEE did not obtain mapping object. Drop it. */ 63 + if (object && err) 64 + qcomtee_object_put(object); 65 + } 66 + 92 67 static struct qcomtee_object_operations qcomtee_primordial_obj_ops = { 93 68 .dispatch = qcomtee_primordial_obj_dispatch, 69 + .notify = qcomtee_primordial_obj_notify, 94 70 }; 95 71 96 72 struct qcomtee_object qcomtee_primordial_object = {
+39
drivers/tee/qcomtee/qcomtee.h
··· 15 15 /* Flags relating to object reference. */ 16 16 #define QCOMTEE_OBJREF_FLAG_TEE BIT(0) 17 17 #define QCOMTEE_OBJREF_FLAG_USER BIT(1) 18 + #define QCOMTEE_OBJREF_FLAG_MEM BIT(2) 18 19 19 20 /** 20 21 * struct qcomtee - Main service struct. ··· 143 142 144 143 /* (2) Primordial Object. */ 145 144 extern struct qcomtee_object qcomtee_primordial_object; 145 + 146 + /* (3) Memory Object API. */ 147 + 148 + /* Is it a memory object using tee_shm? */ 149 + int is_qcomtee_memobj_object(struct qcomtee_object *object); 150 + 151 + /** 152 + * qcomtee_memobj_param_to_object() - OBJREF parameter to &struct qcomtee_object. 153 + * @object: object returned. 154 + * @param: TEE parameter. 155 + * @ctx: context in which the conversion should happen. 156 + * 157 + * @param is an OBJREF with %QCOMTEE_OBJREF_FLAG_MEM flags. 158 + * 159 + * Return: On success return 0 or <0 on failure. 160 + */ 161 + int qcomtee_memobj_param_to_object(struct qcomtee_object **object, 162 + struct tee_param *param, 163 + struct tee_context *ctx); 164 + 165 + /* Reverse what qcomtee_memobj_param_to_object() does. */ 166 + int qcomtee_memobj_param_from_object(struct tee_param *param, 167 + struct qcomtee_object *object, 168 + struct tee_context *ctx); 169 + 170 + /** 171 + * qcomtee_mem_object_map() - Map a memory object. 172 + * @object: memory object. 173 + * @map_object: created mapping object. 174 + * @mem_paddr: physical address of the memory. 175 + * @mem_size: size of the memory. 176 + * @perms: QTEE access permissions. 177 + * 178 + * Return: On success return 0 or <0 on failure. 179 + */ 180 + int qcomtee_mem_object_map(struct qcomtee_object *object, 181 + struct qcomtee_object **map_object, u64 *mem_paddr, 182 + u64 *mem_size, u32 *perms); 146 183 147 184 #endif /* QCOMTEE_H */
-3
drivers/tee/qcomtee/shm.c
··· 117 117 static int pool_op_alloc(struct tee_shm_pool *pool, struct tee_shm *shm, 118 118 size_t size, size_t align) 119 119 { 120 - if (!(shm->flags & TEE_SHM_PRIV)) 121 - return -ENOMEM; 122 - 123 120 return tee_dyn_shm_alloc_helper(shm, size, align, qcomtee_shm_register); 124 121 } 125 122