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 u32 ret = 0; 38 struct tee_ioctl_invoke_arg inv_arg = {0}; 39 struct tee_param param[4] = {0}; 40 41 /* Invoke PTA_CMD_GET_DEVICES function */ 42 inv_arg.func = PTA_CMD_GET_DEVICES; 43 inv_arg.session = session; 44 inv_arg.num_params = 4; 45 46 /* Fill invoke cmd params */ 47 param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT; 48 param[0].u.memref.shm = device_shm; 49 param[0].u.memref.size = *shm_size; 50 param[0].u.memref.shm_offs = 0; 51 52 ret = tee_client_invoke_func(ctx, &inv_arg, param); 53 if ((ret < 0) || ((inv_arg.ret != TEEC_SUCCESS) && 54 (inv_arg.ret != TEEC_ERROR_SHORT_BUFFER))) { 55 pr_err("PTA_CMD_GET_DEVICES invoke function err: %x\n", 56 inv_arg.ret); 57 return -EINVAL; 58 } 59 60 *shm_size = param[0].u.memref.size; 61 62 return 0; 63 } 64 65 static int optee_register_device(const uuid_t *device_uuid, u32 device_id) 66 { 67 struct tee_client_device *optee_device = NULL; 68 int rc; 69 70 optee_device = kzalloc(sizeof(*optee_device), GFP_KERNEL); 71 if (!optee_device) 72 return -ENOMEM; 73 74 optee_device->dev.bus = &tee_bus_type; 75 dev_set_name(&optee_device->dev, "optee-clnt%u", device_id); 76 uuid_copy(&optee_device->id.uuid, device_uuid); 77 78 rc = device_register(&optee_device->dev); 79 if (rc) { 80 pr_err("device registration failed, err: %d\n", rc); 81 kfree(optee_device); 82 } 83 84 return rc; 85 } 86 87 int optee_enumerate_devices(void) 88 { 89 const uuid_t pta_uuid = 90 UUID_INIT(0x7011a688, 0xddde, 0x4053, 91 0xa5, 0xa9, 0x7b, 0x3c, 0x4d, 0xdf, 0x13, 0xb8); 92 struct tee_ioctl_open_session_arg sess_arg = {0}; 93 struct tee_shm *device_shm = NULL; 94 const uuid_t *device_uuid = NULL; 95 struct tee_context *ctx = NULL; 96 u32 shm_size = 0, idx, num_devices = 0; 97 int rc; 98 99 /* Open context with OP-TEE driver */ 100 ctx = tee_client_open_context(NULL, optee_ctx_match, NULL, NULL); 101 if (IS_ERR(ctx)) 102 return -ENODEV; 103 104 /* Open session with device enumeration pseudo TA */ 105 memcpy(sess_arg.uuid, pta_uuid.b, TEE_IOCTL_UUID_LEN); 106 sess_arg.clnt_login = TEE_IOCTL_LOGIN_PUBLIC; 107 sess_arg.num_params = 0; 108 109 rc = tee_client_open_session(ctx, &sess_arg, NULL); 110 if ((rc < 0) || (sess_arg.ret != TEEC_SUCCESS)) { 111 /* Device enumeration pseudo TA not found */ 112 rc = 0; 113 goto out_ctx; 114 } 115 116 rc = get_devices(ctx, sess_arg.session, NULL, &shm_size); 117 if (rc < 0 || !shm_size) 118 goto out_sess; 119 120 device_shm = tee_shm_alloc(ctx, shm_size, 121 TEE_SHM_MAPPED | TEE_SHM_DMA_BUF); 122 if (IS_ERR(device_shm)) { 123 pr_err("tee_shm_alloc failed\n"); 124 rc = PTR_ERR(device_shm); 125 goto out_sess; 126 } 127 128 rc = get_devices(ctx, sess_arg.session, device_shm, &shm_size); 129 if (rc < 0) 130 goto out_shm; 131 132 device_uuid = tee_shm_get_va(device_shm, 0); 133 if (IS_ERR(device_uuid)) { 134 pr_err("tee_shm_get_va failed\n"); 135 rc = PTR_ERR(device_uuid); 136 goto out_shm; 137 } 138 139 num_devices = shm_size / sizeof(uuid_t); 140 141 for (idx = 0; idx < num_devices; idx++) { 142 rc = optee_register_device(&device_uuid[idx], idx); 143 if (rc) 144 goto out_shm; 145 } 146 147 out_shm: 148 tee_shm_free(device_shm); 149 out_sess: 150 tee_client_close_session(ctx, sess_arg.session); 151 out_ctx: 152 tee_client_close_context(ctx); 153 154 return rc; 155 } 156