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