1 /* 2 * Copyright (c) 2020-2022, Arm Limited. All rights reserved. 3 * Copyright (c) 2021-2022 Cypress Semiconductor Corporation (an Infineon 4 * company) or an affiliate of Cypress Semiconductor Corporation. All rights 5 * reserved. 6 * 7 * SPDX-License-Identifier: BSD-3-Clause 8 * 9 */ 10 11 #ifndef __SPM_IPC_H__ 12 #define __SPM_IPC_H__ 13 14 #include <stdint.h> 15 #include "config_impl.h" 16 #include "config_spm.h" 17 #include "current.h" 18 #include "tfm_arch.h" 19 #include "lists.h" 20 #include "thread.h" 21 #include "psa/service.h" 22 #include "load/partition_defs.h" 23 #include "load/interrupt_defs.h" 24 25 #define TFM_HANDLE_STATUS_IDLE 0 /* Handle created */ 26 #define TFM_HANDLE_STATUS_ACTIVE 1 /* Handle in use */ 27 #define TFM_HANDLE_STATUS_TO_FREE 2 /* Free the handle */ 28 29 /* Privileged definitions for partition thread mode */ 30 #define TFM_PARTITION_UNPRIVILEGED_MODE (0U) 31 #define TFM_PARTITION_PRIVILEGED_MODE (1U) 32 33 #if TFM_LVL == 1 34 #define GET_PARTITION_PRIVILEGED_MODE(p_ldinf) TFM_PARTITION_PRIVILEGED_MODE 35 #else 36 #define GET_PARTITION_PRIVILEGED_MODE(p_ldinf) \ 37 (IS_PARTITION_PSA_ROT(p_ldinf) ? TFM_PARTITION_PRIVILEGED_MODE : \ 38 TFM_PARTITION_UNPRIVILEGED_MODE) 39 #endif 40 41 /* 42 * Set a number limit for stateless handle. 43 * Valid handle must be positive, set client handle minimum value to 1. 44 */ 45 #define STATIC_HANDLE_NUM_LIMIT 32 46 #define CLIENT_HANDLE_VALUE_MIN 1 47 48 #define STATIC_HANDLE_IDX_BIT_WIDTH 8 49 #define STATIC_HANDLE_IDX_MASK \ 50 (uint32_t)((1UL << STATIC_HANDLE_IDX_BIT_WIDTH) - 1) 51 #define GET_INDEX_FROM_STATIC_HANDLE(handle) \ 52 (uint32_t)((handle) & STATIC_HANDLE_IDX_MASK) 53 54 #define STATIC_HANDLE_VER_BIT_WIDTH 8 55 #define STATIC_HANDLE_VER_OFFSET 8 56 #define STATIC_HANDLE_VER_MASK \ 57 (uint32_t)((1UL << STATIC_HANDLE_VER_BIT_WIDTH) - 1) 58 #define GET_VERSION_FROM_STATIC_HANDLE(handle) \ 59 (uint32_t)(((handle) >> STATIC_HANDLE_VER_OFFSET) & STATIC_HANDLE_VER_MASK) 60 61 /* Validate the static handle indicator bit */ 62 #define STATIC_HANDLE_INDICATOR_OFFSET 30 63 #define IS_STATIC_HANDLE(handle) \ 64 ((handle) & (1UL << STATIC_HANDLE_INDICATOR_OFFSET)) 65 66 /* Valid index should be [0, STATIC_HANDLE_NUM_LIMIT-1] */ 67 #define IS_VALID_STATIC_HANDLE_IDX(index) \ 68 ((uint32_t)(index) < STATIC_HANDLE_NUM_LIMIT) 69 70 #define SPM_INVALID_PARTITION_IDX (~0U) 71 72 #define TFM_MSG_MAGIC_SFN 0x21216565 73 74 /* Get partition by thread or context data */ 75 #define GET_THRD_OWNER(x) TO_CONTAINER(x, struct partition_t, thrd) 76 #define GET_CTX_OWNER(x) TO_CONTAINER(x, struct partition_t, ctx_ctrl) 77 78 /* RoT connection handle list */ 79 struct conn_handle_t { 80 void *rhandle; /* Reverse handle value */ 81 uint32_t status; /* 82 * Status of handle, three valid 83 * options: 84 * TFM_HANDLE_STATUS_ACTIVE, 85 * TFM_HANDLE_STATUS_IDLE and 86 * TFM_HANDLE_STATUS_TO_FREE 87 */ 88 struct partition_t *p_client; /* Caller partition */ 89 struct service_t *service; /* RoT service pointer */ 90 union { 91 struct sync_obj_t ack_evnt; /* IPC - Ack response event */ 92 uint32_t sfn_magic; /* SFN - Indicate a SFN message */ 93 }; 94 psa_msg_t msg; /* PSA message body */ 95 psa_invec invec[PSA_MAX_IOVEC]; /* Put in/out vectors in msg body */ 96 psa_outvec outvec[PSA_MAX_IOVEC]; 97 psa_outvec *caller_outvec; /* 98 * Save caller outvec pointer for 99 * write length update 100 */ 101 #ifdef TFM_PARTITION_NS_AGENT_MAILBOX 102 const void *caller_data; /* 103 * Pointer to the private data of the 104 * caller. It identifies the NSPE PSA 105 * client calls in multi-core topology 106 */ 107 #endif 108 #if PSA_FRAMEWORK_HAS_MM_IOVEC 109 uint32_t iovec_status; /* MM-IOVEC status */ 110 #endif 111 struct conn_handle_t *p_handles; /* Handle(s) link */ 112 }; 113 114 /* Partition runtime type */ 115 struct partition_t { 116 const struct partition_load_info_t *p_ldinf; 117 void *p_interrupts; 118 void *p_metadata; 119 uintptr_t boundary; 120 uint32_t signals_allowed; 121 uint32_t signals_waiting; 122 volatile uint32_t signals_asserted; 123 #if CONFIG_TFM_SPM_BACKEND_IPC == 1 124 struct context_ctrl_t ctx_ctrl; 125 struct sync_obj_t waitobj; 126 struct thread_t thrd; /* IPC model */ 127 #else 128 uint32_t state; /* SFN model */ 129 #endif 130 struct conn_handle_t *p_handles; 131 struct partition_t *next; 132 }; 133 134 /* RoT Service data */ 135 struct service_t { 136 const struct service_load_info_t *p_ldinf; /* Service load info */ 137 struct partition_t *partition; /* Owner of the service */ 138 struct service_t *next; /* For list operation */ 139 }; 140 141 /** 142 * \brief Get the running partition ID. 143 * 144 * \return Returns the partition ID 145 */ 146 int32_t tfm_spm_partition_get_running_partition_id(void); 147 148 /******************** Service handle management functions ********************/ 149 150 /** 151 * \brief Create connection handle for client connect 152 * 153 * \retval NULL Create failed 154 * \retval "Not NULL" Service handle created 155 */ 156 struct conn_handle_t *tfm_spm_create_conn_handle(void); 157 158 /** 159 * \brief Validate connection handle for client connect 160 * 161 * \param[in] conn_handle Handle to be validated 162 * 163 * \retval PSA_SUCCESS Success 164 * \retval SPM_ERROR_GENERIC Invalid handle 165 */ 166 psa_status_t tfm_spm_validate_conn_handle(const struct conn_handle_t *conn_handle); 167 168 /** 169 * \brief Free connection handle which not used anymore. 170 * 171 * \param[in] conn_handle Connection handle created by 172 * tfm_spm_create_conn_handle() 173 * 174 * \retval "Does not return" Panic for not find service by handle 175 */ 176 void tfm_spm_free_conn_handle(struct conn_handle_t *conn_handle); 177 178 /******************** Partition management functions *************************/ 179 180 #if CONFIG_TFM_SPM_BACKEND_IPC == 1 181 /* 182 * Lookup and grab the last spotted handles containing the message 183 * by the given signal. Only ONE signal bit can be accepted in 'signal', 184 * multiple bits lead to 'no matched handles found to that signal'. 185 * 186 * Returns NULL if no handles matched with the given signal. 187 * Returns an internal handle instance if spotted, the instance 188 * is moved out of partition handles. Partition available signals 189 * also get updated based on the count of handles with given signal 190 * still in the partition handles. 191 */ 192 struct conn_handle_t *spm_get_handle_by_signal(struct partition_t *p_ptn, 193 psa_signal_t signal); 194 #endif /* CONFIG_TFM_SPM_BACKEND_IPC */ 195 196 #if CONFIG_TFM_DOORBELL_API == 1 197 /** 198 * \brief Get partition by Partition ID. 199 * 200 * \param[in] partition_id The Partition ID of the partition to get 201 * 202 * \retval NULL Failed 203 * \retval "Not NULL" Return the parttion context pointer 204 * \ref partition_t structures 205 */ 206 struct partition_t *tfm_spm_get_partition_by_id(int32_t partition_id); 207 #endif /* CONFIG_TFM_DOORBELL_API == 1 */ 208 209 /** 210 * \brief Get the service context by service ID. 211 * 212 * \param[in] sid RoT Service identity 213 * 214 * \retval NULL Failed 215 * \retval "Not NULL" Target service context pointer, 216 * \ref service_t structures 217 */ 218 struct service_t *tfm_spm_get_service_by_sid(uint32_t sid); 219 220 /************************ Message functions **********************************/ 221 222 #if CONFIG_TFM_CONNECTION_BASED_SERVICE_API == 1 223 /** 224 * \brief Convert the given client handle to SPM recognised 225 * handle and verify it. 226 * 227 * \param[in] handle A handle to an established connection that is 228 * returned by a prior psa_connect call. 229 * 230 * \return A SPM recognised handle or NULL. It is NULL when 231 * verification of the converted SPM handle fails. 232 * \ref conn_handle_t structures 233 */ 234 struct conn_handle_t *spm_get_handle_by_client_handle(psa_handle_t handle, 235 int32_t client_id); 236 #endif 237 238 /** 239 * \brief Convert the given message handle to SPM recognised 240 * handle and verify it. 241 * 242 * \param[in] msg_handle Message handle which is a reference generated 243 * by the SPM to a specific message. 244 * 245 * \return A SPM recognised handle or NULL. It is NULL when 246 * verification of the converted SPM handle fails. 247 * \ref conn_handle_t structures 248 */ 249 struct conn_handle_t *spm_get_handle_by_msg_handle(psa_handle_t msg_handle); 250 251 /** 252 * \brief Fill the user message in handle. 253 * 254 * \param[in] conn_handle The 'conn_handle' contains the user message. 255 * \param[in] service Target service context pointer, which can be 256 * obtained by partition management functions 257 * \prarm[in] handle Connect handle return by psa_connect(). 258 * \param[in] type Message type, PSA_IPC_CONNECT, PSA_IPC_CALL or 259 * PSA_IPC_DISCONNECT 260 * \param[in] client_id Partition ID of the sender of the message 261 * \param[in] invec Array of input \ref psa_invec structures 262 * \param[in] in_len Number of input \ref psa_invec structures 263 * \param[in] outvec Array of output \ref psa_outvec structures 264 * \param[in] out_len Number of output \ref psa_outvec structures 265 * \param[in] caller_outvec Array of caller output \ref psa_outvec structures 266 */ 267 void spm_fill_message(struct conn_handle_t *conn_handle, 268 struct service_t *service, 269 psa_handle_t handle, 270 int32_t type, int32_t client_id, 271 psa_invec *invec, size_t in_len, 272 psa_outvec *outvec, size_t out_len, 273 psa_outvec *caller_outvec); 274 275 /** 276 * \brief Check the client version according to 277 * version policy 278 * 279 * \param[in] service Target service context pointer, which can be get 280 * by partition management functions 281 * \param[in] version Client support version 282 * 283 * \retval PSA_SUCCESS Success 284 * \retval SPM_ERROR_BAD_PARAMETERS Bad parameters input 285 * \retval SPM_ERROR_VERSION Check failed 286 */ 287 int32_t tfm_spm_check_client_version(struct service_t *service, 288 uint32_t version); 289 290 /** 291 * \brief Check the client access authorization 292 * 293 * \param[in] sid Target RoT Service identity 294 * \param[in] service Target service context pointer, which can be get 295 * by partition management functions 296 * \param[in] ns_caller Whether from NS caller 297 * 298 * \retval PSA_SUCCESS Success 299 * \retval SPM_ERROR_GENERIC Authorization check failed 300 */ 301 int32_t tfm_spm_check_authorization(uint32_t sid, 302 struct service_t *service, 303 bool ns_caller); 304 305 /** 306 * \brief Get the ns_caller info from runtime context. 307 * 308 * \retval - true: the PSA API caller is from non-secure 309 * - false: the PSA API caller is from secure 310 */ 311 bool tfm_spm_is_ns_caller(void); 312 313 /** 314 * \brief Get ID of current RoT Service client. 315 * This API ensures the caller gets a valid ID. 316 * 317 * \param[in] ns_caller If the client is Non-Secure or not. 318 * 319 * \retval The client ID 320 */ 321 int32_t tfm_spm_get_client_id(bool ns_caller); 322 323 /* 324 * PendSV specified function. 325 * 326 * Parameters : 327 * p_actx - Architecture context storage pointer 328 * 329 * Return: 330 * Pointers to context control (sp, splimit, dummy, lr) of the current and 331 * the next thread. 332 * Each takes 32 bits. The context control is used by PendSV_Handler to do 333 * context switch. 334 */ 335 uint64_t ipc_schedule(void); 336 337 /** 338 * \brief SPM initialization implementation 339 * 340 * \details This function must be called under handler mode. 341 * \retval This function returns an EXC_RETURN value. Other 342 * faults would panic the execution and never 343 * returned. 344 */ 345 uint32_t tfm_spm_init(void); 346 347 /** 348 * \brief Converts a handle instance into a corresponded user handle. 349 */ 350 psa_handle_t tfm_spm_to_user_handle(struct conn_handle_t *handle_instance); 351 352 /** 353 * \brief Converts a user handle into a corresponded handle instance. 354 */ 355 struct conn_handle_t *tfm_spm_to_handle_instance(psa_handle_t user_handle); 356 357 /** 358 * \brief Move to handler mode by a SVC for specific purpose 359 */ 360 void tfm_core_handler_mode(void); 361 362 void update_caller_outvec_len(struct conn_handle_t *handle); 363 364 /* 365 * Set partition signal. 366 * 367 * Assert a signal to given partition. 368 */ 369 void spm_assert_signal(void *p_pt, psa_signal_t signal); 370 371 #if CONFIG_TFM_PSA_API_CROSS_CALL == 1 372 373 /* 374 * SPM dispatcher to handle the API call under non-privileged model. 375 * This API runs under callers stack, and switch to SPM stack when 376 * calling 'p_fn', then switch back to caller stack before returning 377 * to the caller. 378 * 379 * fn_addr - the target function to be called. 380 * frame_addr - Address of the customized ABI frame. The frame must be 381 * stored in the caller's stack (which means the frame variable 382 * must be a local variable). 383 */ 384 void spm_interface_cross_dispatcher(uintptr_t fn_addr, uintptr_t frame_addr); 385 386 /* Execute a customized ABI function in C */ 387 psa_status_t cross_call_entering_c(uintptr_t fn_addr, uintptr_t frame_addr); 388 389 /* Execute a customized ABI function in C */ 390 void cross_call_exiting_c(psa_status_t status, uintptr_t frame_addr); 391 392 #endif 393 394 #endif /* __SPM_IPC_H__ */ 395