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