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