xref: /optee_os/core/pta/scmi.c (revision 602ff4f69104a4e7ff9341cc6802cb121712ea2d)
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 
158 		return res;
159 	}
160 
161 	return TEE_ERROR_NOT_SUPPORTED;
162 }
163 
cmd_get_channel_handle(uint32_t ptypes,TEE_Param params[TEE_NUM_PARAMS])164 static TEE_Result cmd_get_channel_handle(uint32_t ptypes,
165 					 TEE_Param params[TEE_NUM_PARAMS])
166 {
167 	const uint32_t exp_ptypes = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INOUT,
168 						    TEE_PARAM_TYPE_NONE,
169 						    TEE_PARAM_TYPE_NONE,
170 						    TEE_PARAM_TYPE_NONE);
171 	unsigned int channel_id = params[0].value.a;
172 	unsigned int caps = params[0].value.b;
173 
174 	if (ptypes != exp_ptypes || caps & ~PTA_SCMI_CAPS_MASK)
175 		return TEE_ERROR_BAD_PARAMETERS;
176 
177 	if (!(caps & supported_caps()))
178 		return TEE_ERROR_NOT_SUPPORTED;
179 
180 	if (IS_ENABLED(CFG_SCMI_MSG_DRIVERS)) {
181 		struct scmi_msg_channel *channel = NULL;
182 
183 		channel = plat_scmi_get_channel(channel_id);
184 		if (!channel)
185 			return TEE_ERROR_BAD_PARAMETERS;
186 
187 		channel->threaded = true;
188 		params[0].value.a = scmi_smt_channel_handle(channel_id);
189 
190 		return TEE_SUCCESS;
191 	}
192 
193 	if (IS_ENABLED(CFG_SCMI_SCPFW)) {
194 		/* Only check the channel ID is known from SCP-firwmare */
195 		return scmi_server_get_channel(channel_id, NULL);
196 	}
197 
198 	return TEE_ERROR_NOT_SUPPORTED;
199 }
200 
pta_scmi_open_session(uint32_t ptypes __unused,TEE_Param par[TEE_NUM_PARAMS]__unused,void ** session __unused)201 static TEE_Result pta_scmi_open_session(uint32_t ptypes __unused,
202 					TEE_Param par[TEE_NUM_PARAMS] __unused,
203 					void **session __unused)
204 {
205 	struct ts_session *ts = ts_get_current_session();
206 	struct tee_ta_session *ta_session = to_ta_session(ts);
207 
208 	/* Only REE kernel is allowed to access SCMI resources */
209 	if (ta_session->clnt_id.login != TEE_LOGIN_REE_KERNEL) {
210 		DMSG("Expecting TEE_LOGIN_REE_KERNEL");
211 		return TEE_ERROR_ACCESS_DENIED;
212 	}
213 
214 	if (IS_ENABLED(CFG_SCMI_MSG_DRIVERS) || IS_ENABLED(CFG_SCMI_SCPFW))
215 		return TEE_SUCCESS;
216 
217 	return TEE_ERROR_NOT_SUPPORTED;
218 }
219 
pta_scmi_invoke_command(void * session __unused,uint32_t cmd,uint32_t ptypes,TEE_Param params[TEE_NUM_PARAMS])220 static TEE_Result pta_scmi_invoke_command(void *session __unused, uint32_t cmd,
221 					  uint32_t ptypes,
222 					  TEE_Param params[TEE_NUM_PARAMS])
223 {
224 	FMSG("SCMI command %#"PRIx32" ptypes %#"PRIx32, cmd, ptypes);
225 
226 	switch (cmd) {
227 	case PTA_SCMI_CMD_CAPABILITIES:
228 		return cmd_capabilities(ptypes, params);
229 	case PTA_SCMI_CMD_PROCESS_SMT_CHANNEL:
230 		return cmd_process_smt_channel(ptypes, params);
231 	case PTA_SCMI_CMD_PROCESS_SMT_CHANNEL_MESSAGE:
232 		return cmd_process_smt_message(ptypes, params);
233 	case PTA_SCMI_CMD_PROCESS_MSG_CHANNEL:
234 		return cmd_process_msg_channel(ptypes, params);
235 	case PTA_SCMI_CMD_GET_CHANNEL_HANDLE:
236 		return cmd_get_channel_handle(ptypes, params);
237 	default:
238 		return TEE_ERROR_NOT_SUPPORTED;
239 	}
240 }
241 
242 pseudo_ta_register(.uuid = PTA_SCMI_UUID, .name = PTA_SCMI_NAME,
243 		   .flags = PTA_DEFAULT_FLAGS | TA_FLAG_CONCURRENT |
244 			    TA_FLAG_DEVICE_ENUM,
245 		   .open_session_entry_point = pta_scmi_open_session,
246 		   .invoke_command_entry_point = pta_scmi_invoke_command);
247