xref: /linux/drivers/tee/qcomtee/async.c (revision 38057e323657695ec8f814aff0cdd1c7e00d3e9b)
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