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 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 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 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 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 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 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 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 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