Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
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 */
33struct 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 */
49struct 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 */
67static 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 */
105static 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 */
130void 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
179out:
180 /* Reset the async buffer so async requests do not loop to QTEE. */
181 memzero_explicit(async_buffer.addr, async_buffer.size);
182}