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 158 return res; 159 } 160 161 return TEE_ERROR_NOT_SUPPORTED; 162 } 163 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 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 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