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 "qcomtee.h" 9 10 #define QCOMTEE_ASYNC_VERSION_1_0 0x00010000U /* Maj: 0x0001, Min: 0x0000. */ 11 #define QCOMTEE_ASYNC_VERSION_1_1 0x00010001U /* Maj: 0x0001, Min: 0x0001. */ 12 #define QCOMTEE_ASYNC_VERSION_1_2 0x00010002U /* Maj: 0x0001, Min: 0x0002. */ 13 #define QCOMTEE_ASYNC_VERSION_CURRENT QCOMTEE_ASYNC_VERSION_1_2 14 15 #define QCOMTEE_ASYNC_VERSION_MAJOR(n) upper_16_bits(n) 16 #define QCOMTEE_ASYNC_VERSION_MINOR(n) lower_16_bits(n) 17 18 #define QCOMTEE_ASYNC_VERSION_CURRENT_MAJOR \ 19 QCOMTEE_ASYNC_VERSION_MAJOR(QCOMTEE_ASYNC_VERSION_CURRENT) 20 #define QCOMTEE_ASYNC_VERSION_CURRENT_MINOR \ 21 QCOMTEE_ASYNC_VERSION_MINOR(QCOMTEE_ASYNC_VERSION_CURRENT) 22 23 /** 24 * struct qcomtee_async_msg_hdr - Asynchronous message header format. 25 * @version: current async protocol version of the remote endpoint. 26 * @op: async operation. 27 * 28 * @version specifies the endpoint's (QTEE or driver) supported async protocol. 29 * For example, if QTEE sets @version to %QCOMTEE_ASYNC_VERSION_1_1, QTEE 30 * handles operations supported in %QCOMTEE_ASYNC_VERSION_1_1 or 31 * %QCOMTEE_ASYNC_VERSION_1_0. @op determines the message format. 32 */ 33 struct qcomtee_async_msg_hdr { 34 u32 version; 35 u32 op; 36 }; 37 38 /* Size of an empty async message. */ 39 #define QCOMTEE_ASYNC_MSG_ZERO sizeof(struct qcomtee_async_msg_hdr) 40 41 /** 42 * struct qcomtee_async_release_msg - Release asynchronous message. 43 * @hdr: message header as &struct qcomtee_async_msg_hdr. 44 * @counts: number of objects in @object_ids. 45 * @object_ids: array of object IDs that should be released. 46 * 47 * Available in Maj = 0x0001, Min >= 0x0000. 48 */ 49 struct qcomtee_async_release_msg { 50 struct qcomtee_async_msg_hdr hdr; 51 u32 counts; 52 u32 object_ids[] __counted_by(counts); 53 }; 54 55 /** 56 * qcomtee_get_async_buffer() - Get the start of the asynchronous message. 57 * @oic: context used for the current invocation. 58 * @async_buffer: return buffer to extract from or fill in async messages. 59 * 60 * If @oic is used for direct object invocation, the whole outbound buffer 61 * is available for the async message. If @oic is used for a callback request, 62 * the tail of the outbound buffer (after the callback request message) is 63 * available for the async message. 64 * 65 * The start of the async buffer is aligned, see qcomtee_msg_offset_align(). 66 */ 67 static void qcomtee_get_async_buffer(struct qcomtee_object_invoke_ctx *oic, 68 struct qcomtee_buffer *async_buffer) 69 { 70 struct qcomtee_msg_callback *msg; 71 unsigned int offset; 72 int i; 73 74 if (!(oic->flags & QCOMTEE_OIC_FLAG_BUSY)) { 75 /* The outbound buffer is empty. Using the whole buffer. */ 76 offset = 0; 77 } else { 78 msg = (struct qcomtee_msg_callback *)oic->out_msg.addr; 79 80 /* Start offset in a message for buffer arguments. */ 81 offset = qcomtee_msg_buffer_args(struct qcomtee_msg_callback, 82 qcomtee_msg_args(msg)); 83 84 /* Add size of IB arguments. */ 85 qcomtee_msg_for_each_input_buffer(i, msg) 86 offset += qcomtee_msg_offset_align(msg->args[i].b.size); 87 88 /* Add size of OB arguments. */ 89 qcomtee_msg_for_each_output_buffer(i, msg) 90 offset += qcomtee_msg_offset_align(msg->args[i].b.size); 91 } 92 93 async_buffer->addr = oic->out_msg.addr + offset; 94 async_buffer->size = oic->out_msg.size - offset; 95 } 96 97 /** 98 * async_release() - Process QTEE async release requests. 99 * @oic: context used for the current invocation. 100 * @msg: async message for object release. 101 * @size: size of the async buffer available. 102 * 103 * Return: Size of the outbound buffer used when processing @msg. 104 */ 105 static size_t async_release(struct qcomtee_object_invoke_ctx *oic, 106 struct qcomtee_async_msg_hdr *async_msg, 107 size_t size) 108 { 109 struct qcomtee_async_release_msg *msg; 110 struct qcomtee_object *object; 111 int i; 112 113 msg = (struct qcomtee_async_release_msg *)async_msg; 114 115 for (i = 0; i < msg->counts; i++) { 116 object = qcomtee_idx_erase(oic, msg->object_ids[i]); 117 qcomtee_object_put(object); 118 } 119 120 return struct_size(msg, object_ids, msg->counts); 121 } 122 123 /** 124 * qcomtee_fetch_async_reqs() - Fetch and process asynchronous messages. 125 * @oic: context used for the current invocation. 126 * 127 * Calls handlers to process the requested operations in the async message. 128 * Currently, only supports async release requests. 129 */ 130 void qcomtee_fetch_async_reqs(struct qcomtee_object_invoke_ctx *oic) 131 { 132 struct qcomtee_async_msg_hdr *async_msg; 133 struct qcomtee_buffer async_buffer; 134 size_t consumed, used = 0; 135 u16 major_ver; 136 137 qcomtee_get_async_buffer(oic, &async_buffer); 138 139 while (async_buffer.size - used > QCOMTEE_ASYNC_MSG_ZERO) { 140 async_msg = (struct qcomtee_async_msg_hdr *)(async_buffer.addr + 141 used); 142 /* 143 * QTEE assumes that the unused space of the async buffer is 144 * zeroed; so if version is zero, the buffer is unused. 145 */ 146 if (async_msg->version == 0) 147 goto out; 148 149 major_ver = QCOMTEE_ASYNC_VERSION_MAJOR(async_msg->version); 150 /* Major version mismatch is a compatibility break. */ 151 if (major_ver != QCOMTEE_ASYNC_VERSION_CURRENT_MAJOR) { 152 pr_err("Async message version mismatch (%u != %u)\n", 153 major_ver, QCOMTEE_ASYNC_VERSION_CURRENT_MAJOR); 154 155 goto out; 156 } 157 158 switch (async_msg->op) { 159 case QCOMTEE_MSG_OBJECT_OP_RELEASE: 160 consumed = async_release(oic, async_msg, 161 async_buffer.size - used); 162 break; 163 default: 164 pr_err("Unsupported async message %u\n", async_msg->op); 165 goto out; 166 } 167 168 /* Supported operation but unable to parse the message. */ 169 if (!consumed) { 170 pr_err("Unable to parse async message for op %u\n", 171 async_msg->op); 172 goto out; 173 } 174 175 /* Next async message. */ 176 used += qcomtee_msg_offset_align(consumed); 177 } 178 179 out: 180 /* Reset the async buffer so async requests do not loop to QTEE. */ 181 memzero_explicit(async_buffer.addr, async_buffer.size); 182 } 183