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