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