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