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