1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (C) 2019 Linaro Ltd. 4 */ 5 6 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 7 8 #include <linux/kernel.h> 9 #include <linux/slab.h> 10 #include <linux/tee_drv.h> 11 #include <linux/uuid.h> 12 #include "optee_private.h" 13 14 /* 15 * Get device UUIDs 16 * 17 * [out] memref[0] Array of device UUIDs 18 * 19 * Return codes: 20 * TEE_SUCCESS - Invoke command success 21 * TEE_ERROR_BAD_PARAMETERS - Incorrect input param 22 * TEE_ERROR_SHORT_BUFFER - Output buffer size less than required 23 */ 24 #define PTA_CMD_GET_DEVICES 0x0 25 26 static int optee_ctx_match(struct tee_ioctl_version_data *ver, const void *data) 27 { 28 if (ver->impl_id == TEE_IMPL_ID_OPTEE) 29 return 1; 30 else 31 return 0; 32 } 33 34 static int get_devices(struct tee_context *ctx, u32 session, 35 struct tee_shm *device_shm, u32 *shm_size) 36 { 37 int ret = 0; 38 struct tee_ioctl_invoke_arg inv_arg; 39 struct tee_param param[4]; 40 41 memset(&inv_arg, 0, sizeof(inv_arg)); 42 memset(¶m, 0, sizeof(param)); 43 44 /* Invoke PTA_CMD_GET_DEVICES function */ 45 inv_arg.func = PTA_CMD_GET_DEVICES; 46 inv_arg.session = session; 47 inv_arg.num_params = 4; 48 49 /* Fill invoke cmd params */ 50 param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT; 51 param[0].u.memref.shm = device_shm; 52 param[0].u.memref.size = *shm_size; 53 param[0].u.memref.shm_offs = 0; 54 55 ret = tee_client_invoke_func(ctx, &inv_arg, param); 56 if ((ret < 0) || ((inv_arg.ret != TEEC_SUCCESS) && 57 (inv_arg.ret != TEEC_ERROR_SHORT_BUFFER))) { 58 pr_err("PTA_CMD_GET_DEVICES invoke function err: %x\n", 59 inv_arg.ret); 60 return -EINVAL; 61 } 62 63 *shm_size = param[0].u.memref.size; 64 65 return 0; 66 } 67 68 static int optee_register_device(const uuid_t *device_uuid, u32 device_id) 69 { 70 struct tee_client_device *optee_device = NULL; 71 int rc; 72 73 optee_device = kzalloc(sizeof(*optee_device), GFP_KERNEL); 74 if (!optee_device) 75 return -ENOMEM; 76 77 optee_device->dev.bus = &tee_bus_type; 78 dev_set_name(&optee_device->dev, "optee-clnt%u", device_id); 79 uuid_copy(&optee_device->id.uuid, device_uuid); 80 81 rc = device_register(&optee_device->dev); 82 if (rc) { 83 pr_err("device registration failed, err: %d\n", rc); 84 kfree(optee_device); 85 } 86 87 return rc; 88 } 89 90 int optee_enumerate_devices(void) 91 { 92 const uuid_t pta_uuid = 93 UUID_INIT(0x7011a688, 0xddde, 0x4053, 94 0xa5, 0xa9, 0x7b, 0x3c, 0x4d, 0xdf, 0x13, 0xb8); 95 struct tee_ioctl_open_session_arg sess_arg; 96 struct tee_shm *device_shm = NULL; 97 const uuid_t *device_uuid = NULL; 98 struct tee_context *ctx = NULL; 99 u32 shm_size = 0, idx, num_devices = 0; 100 int rc; 101 102 memset(&sess_arg, 0, sizeof(sess_arg)); 103 104 /* Open context with OP-TEE driver */ 105 ctx = tee_client_open_context(NULL, optee_ctx_match, NULL, NULL); 106 if (IS_ERR(ctx)) 107 return -ENODEV; 108 109 /* Open session with device enumeration pseudo TA */ 110 memcpy(sess_arg.uuid, pta_uuid.b, TEE_IOCTL_UUID_LEN); 111 sess_arg.clnt_login = TEE_IOCTL_LOGIN_PUBLIC; 112 sess_arg.num_params = 0; 113 114 rc = tee_client_open_session(ctx, &sess_arg, NULL); 115 if ((rc < 0) || (sess_arg.ret != TEEC_SUCCESS)) { 116 /* Device enumeration pseudo TA not found */ 117 rc = 0; 118 goto out_ctx; 119 } 120 121 rc = get_devices(ctx, sess_arg.session, NULL, &shm_size); 122 if (rc < 0 || !shm_size) 123 goto out_sess; 124 125 device_shm = tee_shm_alloc(ctx, shm_size, 126 TEE_SHM_MAPPED | TEE_SHM_DMA_BUF); 127 if (IS_ERR(device_shm)) { 128 pr_err("tee_shm_alloc failed\n"); 129 rc = PTR_ERR(device_shm); 130 goto out_sess; 131 } 132 133 rc = get_devices(ctx, sess_arg.session, device_shm, &shm_size); 134 if (rc < 0) 135 goto out_shm; 136 137 device_uuid = tee_shm_get_va(device_shm, 0); 138 if (IS_ERR(device_uuid)) { 139 pr_err("tee_shm_get_va failed\n"); 140 rc = PTR_ERR(device_uuid); 141 goto out_shm; 142 } 143 144 num_devices = shm_size / sizeof(uuid_t); 145 146 for (idx = 0; idx < num_devices; idx++) { 147 rc = optee_register_device(&device_uuid[idx], idx); 148 if (rc) 149 goto out_shm; 150 } 151 152 out_shm: 153 tee_shm_free(device_shm); 154 out_sess: 155 tee_client_close_session(ctx, sess_arg.session); 156 out_ctx: 157 tee_client_close_context(ctx); 158 159 return rc; 160 } 161