1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3 * Copyright (c) 2019-2021, Linaro Limited
4 * Copyright (c) 2019-2021, STMicroelectronics
5 */
6 #include <compiler.h>
7 #include <config.h>
8 #include <drivers/scmi-msg.h>
9 #include <scmi/scmi_server.h>
10 #include <kernel/pseudo_ta.h>
11 #include <pta_scmi_client.h>
12 #include <stdint.h>
13 #include <string.h>
14
supported_caps(void)15 static uint32_t supported_caps(void)
16 {
17 uint32_t caps = 0;
18
19 if (IS_ENABLED2(_CFG_SCMI_PTA_SMT_HEADER))
20 caps |= PTA_SCMI_CAPS_SMT_HEADER;
21
22 if (IS_ENABLED2(_CFG_SCMI_PTA_MSG_HEADER))
23 caps |= PTA_SCMI_CAPS_MSG_HEADER;
24
25 return caps;
26 }
27
cmd_capabilities(uint32_t ptypes,TEE_Param param[TEE_NUM_PARAMS])28 static TEE_Result cmd_capabilities(uint32_t ptypes,
29 TEE_Param param[TEE_NUM_PARAMS])
30 {
31 const uint32_t exp_ptypes = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_OUTPUT,
32 TEE_PARAM_TYPE_NONE,
33 TEE_PARAM_TYPE_NONE,
34 TEE_PARAM_TYPE_NONE);
35
36 if (ptypes != exp_ptypes)
37 return TEE_ERROR_BAD_PARAMETERS;
38
39 param[0].value.a = supported_caps();
40 param[0].value.b = 0;
41
42 return TEE_SUCCESS;
43 }
44
cmd_process_smt_channel(uint32_t ptypes,TEE_Param params[TEE_NUM_PARAMS])45 static TEE_Result cmd_process_smt_channel(uint32_t ptypes,
46 TEE_Param params[TEE_NUM_PARAMS])
47 {
48 const uint32_t exp_ptypes = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT,
49 TEE_PARAM_TYPE_NONE,
50 TEE_PARAM_TYPE_NONE,
51 TEE_PARAM_TYPE_NONE);
52 unsigned int channel_id = params[0].value.a;
53
54 if (ptypes != exp_ptypes)
55 return TEE_ERROR_BAD_PARAMETERS;
56
57 if (IS_ENABLED(CFG_SCMI_MSG_SMT)) {
58 struct scmi_msg_channel *channel = NULL;
59
60 channel = plat_scmi_get_channel(channel_id);
61 if (!channel)
62 return TEE_ERROR_BAD_PARAMETERS;
63
64 scmi_smt_threaded_entry(channel_id);
65
66 return TEE_SUCCESS;
67 }
68
69 if (IS_ENABLED(CFG_SCMI_SCPFW))
70 return scmi_server_smt_process_thread(channel_id);
71
72 return TEE_ERROR_NOT_SUPPORTED;
73 }
74
cmd_process_smt_message(uint32_t ptypes,TEE_Param params[TEE_NUM_PARAMS])75 static TEE_Result cmd_process_smt_message(uint32_t ptypes,
76 TEE_Param params[TEE_NUM_PARAMS])
77 {
78 const uint32_t exp_ptypes = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT,
79 TEE_PARAM_TYPE_MEMREF_INOUT,
80 TEE_PARAM_TYPE_NONE,
81 TEE_PARAM_TYPE_NONE);
82 unsigned int channel_id = params[0].value.a;
83 TEE_Param *param1 = params + 1;
84
85 if (ptypes != exp_ptypes)
86 return TEE_ERROR_BAD_PARAMETERS;
87
88 if (IS_ENABLED(CFG_SCMI_MSG_SMT)) {
89 struct scmi_msg_channel *channel = NULL;
90
91 if (param1->memref.size < SMT_BUF_SLOT_SIZE)
92 return TEE_ERROR_BAD_PARAMETERS;
93
94 channel = plat_scmi_get_channel(channel_id);
95 if (!channel)
96 return TEE_ERROR_BAD_PARAMETERS;
97
98 /*
99 * Caller provides the buffer, we bind channel to that buffer.
100 * Once message is processed, unbind the buffer since it is
101 * valid only for the current invocation.
102 */
103 scmi_smt_set_shared_buffer(channel, param1->memref.buffer);
104 scmi_smt_threaded_entry(channel_id);
105 scmi_smt_set_shared_buffer(channel, NULL);
106
107 return TEE_SUCCESS;
108 }
109
110 return TEE_ERROR_NOT_SUPPORTED;
111 }
112
cmd_process_msg_channel(uint32_t ptypes,TEE_Param params[TEE_NUM_PARAMS])113 static TEE_Result cmd_process_msg_channel(uint32_t ptypes,
114 TEE_Param params[TEE_NUM_PARAMS])
115 {
116 TEE_Result res = TEE_ERROR_GENERIC;
117 const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT,
118 TEE_PARAM_TYPE_MEMREF_INPUT,
119 TEE_PARAM_TYPE_MEMREF_OUTPUT,
120 TEE_PARAM_TYPE_NONE);
121 unsigned int channel_id = params[0].value.a;
122 void *in_buf = params[1].memref.buffer;
123 size_t in_size = params[1].memref.size;
124 void *out_buf = params[2].memref.buffer;
125 size_t out_size = params[2].memref.size;
126
127 if (ptypes != exp_pt || !in_buf || !out_buf)
128 return TEE_ERROR_BAD_PARAMETERS;
129
130 if (IS_ENABLED(CFG_SCMI_MSG_DRIVERS)) {
131 struct scmi_msg_channel *channel = NULL;
132
133 if (!IS_ENABLED(CFG_SCMI_MSG_SHM_MSG))
134 return TEE_ERROR_NOT_SUPPORTED;
135
136 channel = plat_scmi_get_channel(channel_id);
137 if (!channel)
138 return TEE_ERROR_BAD_PARAMETERS;
139
140 res = scmi_msg_threaded_entry(channel_id, in_buf, in_size,
141 out_buf, &out_size);
142 if (!res)
143 params[2].memref.size = out_size;
144
145 return res;
146 }
147
148 if (IS_ENABLED(CFG_SCMI_SCPFW)) {
149 if (!in_buf || !out_buf)
150 return TEE_ERROR_BAD_PARAMETERS;
151
152 res = scmi_server_msg_process_thread(channel_id, in_buf,
153 in_size, out_buf,
154 &out_size);
155 if (!res) {
156 params[2].memref.size = (uint32_t)out_size;
157 IMSG("scmi optee shm: out %zu", out_size);
158 }
159
160 return res;
161 }
162
163 return TEE_ERROR_NOT_SUPPORTED;
164 }
165
cmd_get_channel_handle(uint32_t ptypes,TEE_Param params[TEE_NUM_PARAMS])166 static TEE_Result cmd_get_channel_handle(uint32_t ptypes,
167 TEE_Param params[TEE_NUM_PARAMS])
168 {
169 const uint32_t exp_ptypes = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INOUT,
170 TEE_PARAM_TYPE_NONE,
171 TEE_PARAM_TYPE_NONE,
172 TEE_PARAM_TYPE_NONE);
173 unsigned int channel_id = params[0].value.a;
174 unsigned int caps = params[0].value.b;
175
176 if (ptypes != exp_ptypes || caps & ~PTA_SCMI_CAPS_MASK)
177 return TEE_ERROR_BAD_PARAMETERS;
178
179 if (!(caps & supported_caps()))
180 return TEE_ERROR_NOT_SUPPORTED;
181
182 if (IS_ENABLED(CFG_SCMI_MSG_DRIVERS)) {
183 struct scmi_msg_channel *channel = NULL;
184
185 channel = plat_scmi_get_channel(channel_id);
186 if (!channel)
187 return TEE_ERROR_BAD_PARAMETERS;
188
189 channel->threaded = true;
190 params[0].value.a = scmi_smt_channel_handle(channel_id);
191
192 return TEE_SUCCESS;
193 }
194
195 if (IS_ENABLED(CFG_SCMI_SCPFW)) {
196 /* Only check the channel ID is known from SCP-firwmare */
197 return scmi_server_get_channel(channel_id, NULL);
198 }
199
200 return TEE_ERROR_NOT_SUPPORTED;
201 }
202
pta_scmi_open_session(uint32_t ptypes __unused,TEE_Param par[TEE_NUM_PARAMS]__unused,void ** session __unused)203 static TEE_Result pta_scmi_open_session(uint32_t ptypes __unused,
204 TEE_Param par[TEE_NUM_PARAMS] __unused,
205 void **session __unused)
206 {
207 struct ts_session *ts = ts_get_current_session();
208 struct tee_ta_session *ta_session = to_ta_session(ts);
209
210 /* Only REE kernel is allowed to access SCMI resources */
211 if (ta_session->clnt_id.login != TEE_LOGIN_REE_KERNEL) {
212 DMSG("Expecting TEE_LOGIN_REE_KERNEL");
213 return TEE_ERROR_ACCESS_DENIED;
214 }
215
216 if (IS_ENABLED(CFG_SCMI_MSG_DRIVERS) || IS_ENABLED(CFG_SCMI_SCPFW))
217 return TEE_SUCCESS;
218
219 return TEE_ERROR_NOT_SUPPORTED;
220 }
221
pta_scmi_invoke_command(void * session __unused,uint32_t cmd,uint32_t ptypes,TEE_Param params[TEE_NUM_PARAMS])222 static TEE_Result pta_scmi_invoke_command(void *session __unused, uint32_t cmd,
223 uint32_t ptypes,
224 TEE_Param params[TEE_NUM_PARAMS])
225 {
226 FMSG("SCMI command %#"PRIx32" ptypes %#"PRIx32, cmd, ptypes);
227
228 switch (cmd) {
229 case PTA_SCMI_CMD_CAPABILITIES:
230 return cmd_capabilities(ptypes, params);
231 case PTA_SCMI_CMD_PROCESS_SMT_CHANNEL:
232 return cmd_process_smt_channel(ptypes, params);
233 case PTA_SCMI_CMD_PROCESS_SMT_CHANNEL_MESSAGE:
234 return cmd_process_smt_message(ptypes, params);
235 case PTA_SCMI_CMD_PROCESS_MSG_CHANNEL:
236 return cmd_process_msg_channel(ptypes, params);
237 case PTA_SCMI_CMD_GET_CHANNEL_HANDLE:
238 return cmd_get_channel_handle(ptypes, params);
239 default:
240 return TEE_ERROR_NOT_SUPPORTED;
241 }
242 }
243
244 pseudo_ta_register(.uuid = PTA_SCMI_UUID, .name = PTA_SCMI_NAME,
245 .flags = PTA_DEFAULT_FLAGS | TA_FLAG_CONCURRENT |
246 TA_FLAG_DEVICE_ENUM,
247 .open_session_entry_point = pta_scmi_open_session,
248 .invoke_command_entry_point = pta_scmi_invoke_command);
249