1 /* 2 * Copyright (c) 2019-2023, Arm Limited. All rights reserved. 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 * 6 */ 7 8 #ifndef __PSA_API_H__ 9 #define __PSA_API_H__ 10 11 #include <stdint.h> 12 #include <stdbool.h> 13 #include "config_spm.h" 14 #ifdef TFM_PARTITION_NS_AGENT_MAILBOX 15 #include "ffm/agent_api.h" 16 #endif 17 #include "psa/client.h" 18 #include "psa/service.h" 19 20 #if PSA_FRAMEWORK_HAS_MM_IOVEC 21 22 /* 23 * The MM-IOVEC status 24 * The max total number of invec and outvec is 8. 25 * Each invec/outvec takes 4 bit, 32 bits in total. 26 * 27 * The encoding format of the MM-IOVEC status: 28 *-------------------------------------------------------------- 29 *| Bit | 31 - 28 | 27 - 24 | ... | 7 - 4 | 3 - 0 | 30 *-------------------------------------------------------------- 31 *| Vector | outvec[3] | outvec[2] | ... | invec[1] | invec[0] | 32 *-------------------------------------------------------------- 33 * 34 * Take invec[0] as an example: 35 * 36 * bit 0: whether invec[0] has been mapped. 37 * bit 1: whether invec[0] has been unmapped. 38 * bit 2: whether invec[0] has been accessed using psa_read(), psa_skip() or 39 * psa_write(). 40 * bit 3: reserved for invec[0]. 41 */ 42 43 #define IOVEC_STATUS_BITS 4 /* Each vector occupies 4 bits. */ 44 #define OUTVEC_IDX_BASE 4 /* 45 * Base index of outvec. 46 * There are four invecs in front of 47 * outvec. 48 */ 49 #define INVEC_IDX_BASE 0 /* Base index of invec. */ 50 51 #define IOVEC_MAPPED_BIT (1UL << 0) 52 #define IOVEC_UNMAPPED_BIT (1UL << 1) 53 #define IOVEC_ACCESSED_BIT (1UL << 2) 54 55 #define IOVEC_IS_MAPPED(handle, iovec_idx) \ 56 ((((handle)->iovec_status) >> ((iovec_idx) * IOVEC_STATUS_BITS)) & \ 57 IOVEC_MAPPED_BIT) 58 #define IOVEC_IS_UNMAPPED(handle, iovec_idx) \ 59 ((((handle)->iovec_status) >> ((iovec_idx) * IOVEC_STATUS_BITS)) & \ 60 IOVEC_UNMAPPED_BIT) 61 #define IOVEC_IS_ACCESSED(handle, iovec_idx) \ 62 ((((handle)->iovec_status) >> ((iovec_idx) * IOVEC_STATUS_BITS)) & \ 63 IOVEC_ACCESSED_BIT) 64 #define SET_IOVEC_MAPPED(handle, iovec_idx) \ 65 (((handle)->iovec_status) |= (IOVEC_MAPPED_BIT << \ 66 ((iovec_idx) * IOVEC_STATUS_BITS))) 67 #define SET_IOVEC_UNMAPPED(handle, iovec_idx) \ 68 (((handle)->iovec_status) |= (IOVEC_UNMAPPED_BIT << \ 69 ((iovec_idx) * IOVEC_STATUS_BITS))) 70 #define SET_IOVEC_ACCESSED(handle, iovec_idx) \ 71 (((handle)->iovec_status) |= (IOVEC_ACCESSED_BIT << \ 72 ((iovec_idx) * IOVEC_STATUS_BITS))) 73 74 #endif /* PSA_FRAMEWORK_HAS_MM_IOVEC */ 75 76 #ifdef TFM_PARTITION_NS_AGENT_MAILBOX 77 /** 78 * \brief handler for \ref agent_psa_call. 79 * 80 * \param[in] handle Handle to the service being accessed. 81 * \param[in] control A composited uint32_t value for controlling purpose, 82 * containing call types, numbers of in/out vectors and 83 * attributes of vectors. 84 * \param[in] params Combines the psa_invec and psa_outvec params 85 * for the psa_call() to be made, as well as 86 * NS agent's client identifier, which is ignored 87 * for connection-based services. 88 * \param[in] client_data_stateless Client data, treated as opaque by SPM. 89 * 90 * \retval PSA_SUCCESS Success. 91 * \retval "Does not return" The call is invalid, one or more of the 92 * following are true: 93 * \arg An invalid handle was passed. 94 * \arg The connection is already handling a request. 95 * \arg An invalid memory reference was provided. 96 * \arg in_num + out_num > PSA_MAX_IOVEC. 97 * \arg The message is unrecognized by the RoT 98 * Service or incorrectly formatted. 99 */ 100 psa_status_t tfm_spm_agent_psa_call(psa_handle_t handle, 101 uint32_t control, 102 const struct client_params_t *params, 103 const void *client_data_stateless); 104 105 #if CONFIG_TFM_CONNECTION_BASED_SERVICE_API == 1 106 107 /** 108 * \brief handler for \ref agent_psa_connect. 109 * 110 * \param[in] sid RoT Service identity. 111 * \param[in] version The version of the RoT Service. 112 * \param[in] ns_client_id NS agent's client identifier. 113 * \param[in] client_data Client data, treated as opaque by SPM. 114 * 115 * \retval PSA_SUCCESS Success. 116 * \retval PSA_ERROR_CONNECTION_REFUSED The SPM or RoT Service has refused the 117 * connection. 118 * \retval PSA_ERROR_CONNECTION_BUSY The SPM or RoT Service cannot make the 119 * connection at the moment. 120 * \retval "Does not return" The RoT Service ID and version are not 121 * supported, or the caller is not permitted to 122 * access the service. 123 */ 124 psa_handle_t tfm_spm_agent_psa_connect(uint32_t sid, uint32_t version, 125 int32_t ns_client_id, 126 const void *client_data); 127 #else /* CONFIG_TFM_CONNECTION_BASED_SERVICE_API == 1 */ 128 #define tfm_spm_agent_psa_connect NULL 129 #endif /* CONFIG_TFM_CONNECTION_BASED_SERVICE_API == 1 */ 130 #else /* TFM_PARTITION_NS_AGENT_MAILBOX */ 131 #define tfm_spm_agent_psa_connect NULL 132 #define tfm_spm_agent_psa_call NULL 133 #endif /* TFM_PARTITION_NS_AGENT_MAILBOX */ 134 135 /** 136 * \brief This function handles the specific programmer error cases. 137 * 138 * \param[in] status Standard error codes for the SPM. 139 * 140 * \retval void Status will not cause SPM panic 141 * \retval "SPM panic" Following programmer errors are triggered by SP: 142 * \arg PSA_ERROR_PROGRAMMER_ERROR 143 * \arg PSA_ERROR_CONNECTION_REFUSED 144 * \arg PSA_ERROR_CONNECTION_BUSY 145 */ 146 void spm_handle_programmer_errors(psa_status_t status); 147 148 /** 149 * \brief This function get the current PSA RoT lifecycle state. 150 * 151 * \return state The current security lifecycle state of the PSA 152 * RoT. The PSA state and implementation state are 153 * encoded as follows: 154 * \arg state[15:8] – PSA lifecycle state 155 * \arg state[7:0] – IMPLEMENTATION DEFINED state 156 */ 157 uint32_t tfm_spm_get_lifecycle_state(void); 158 159 /* PSA Client API function body, for privileged use only. */ 160 161 /** 162 * \brief handler for \ref psa_framework_version. 163 * 164 * \return version The version of the PSA Framework implementation 165 * that is providing the runtime services. 166 */ 167 uint32_t tfm_spm_client_psa_framework_version(void); 168 169 /** 170 * \brief handler for \ref psa_version. 171 * 172 * \param[in] sid RoT Service identity. 173 * 174 * \retval PSA_VERSION_NONE The RoT Service is not implemented, or the 175 * caller is not permitted to access the service. 176 * \retval > 0 The version of the implemented RoT Service. 177 */ 178 uint32_t tfm_spm_client_psa_version(uint32_t sid); 179 180 /** 181 * \brief handler for \ref psa_call. 182 * 183 * \param[in] handle Service handle to the established connection, 184 * \ref psa_handle_t 185 * \param[in] ctrl_param Parameters combined in uint32_t, 186 * includes request type, in_num and out_num. 187 * \param[in] inptr Array of input psa_invec structures. 188 * \ref psa_invec 189 * \param[in] outptr Array of output psa_outvec structures. 190 * \ref psa_outvec 191 * 192 * \retval PSA_SUCCESS Success. 193 * \retval "Does not return" The call is invalid, one or more of the 194 * following are true: 195 * \arg An invalid handle was passed. 196 * \arg The connection is already handling a request. 197 * \arg An invalid memory reference was provided. 198 * \arg in_num + out_num > PSA_MAX_IOVEC. 199 * \arg The message is unrecognized by the RoT 200 * Service or incorrectly formatted. 201 */ 202 psa_status_t tfm_spm_client_psa_call(psa_handle_t handle, 203 uint32_t ctrl_param, 204 const psa_invec *inptr, 205 psa_outvec *outptr); 206 207 /* Following PSA APIs are only needed by connection-based services */ 208 #if CONFIG_TFM_CONNECTION_BASED_SERVICE_API == 1 209 210 /** 211 * \brief handler for \ref psa_connect. 212 * 213 * \param[in] sid RoT Service identity. 214 * \param[in] version The version of the RoT Service. 215 * 216 * \retval PSA_SUCCESS Success. 217 * \retval PSA_ERROR_CONNECTION_REFUSED The SPM or RoT Service has refused the 218 * connection. 219 * \retval PSA_ERROR_CONNECTION_BUSY The SPM or RoT Service cannot make the 220 * connection at the moment. 221 * \retval "Does not return" The RoT Service ID and version are not 222 * supported, or the caller is not permitted to 223 * access the service. 224 */ 225 psa_status_t tfm_spm_client_psa_connect(uint32_t sid, uint32_t version); 226 227 /** 228 * \brief handler for \ref psa_close. 229 * 230 * \param[in] handle Service handle to the connection to be closed, 231 * \ref psa_handle_t 232 * 233 * \retval PSA_SUCCESS Success. 234 * \retval PSA_ERROR_PROGRAMMER_ERROR The call is invalid, one or more of the 235 * following are true: 236 * \arg Called with a stateless handle. 237 * \arg An invalid handle was provided that is not 238 * the null handle. 239 * \arg The connection is handling a request. 240 */ 241 psa_status_t tfm_spm_client_psa_close(psa_handle_t handle); 242 #else 243 #define tfm_spm_client_psa_connect NULL 244 #define tfm_spm_client_psa_close NULL 245 #endif /* CONFIG_TFM_CONNECTION_BASED_SERVICE_API */ 246 247 /* PSA Partition API function body, for privileged use only. */ 248 249 #if CONFIG_TFM_SPM_BACKEND_IPC == 1 \ 250 || CONFIG_TFM_FLIH_API == 1 || CONFIG_TFM_SLIH_API == 1 251 /** 252 * \brief Function body of \ref psa_wait. 253 * 254 * \param[in] signal_mask A set of signals to query. Signals that are not 255 * in this set will be ignored. 256 * \param[in] timeout Specify either blocking \ref PSA_BLOCK or 257 * polling \ref PSA_POLL operation. 258 * 259 * \retval >0 At least one signal is asserted. 260 * \retval 0 No signals are asserted. This is only seen when 261 * a polling timeout is used. 262 */ 263 psa_signal_t tfm_spm_partition_psa_wait(psa_signal_t signal_mask, 264 uint32_t timeout); 265 #endif 266 267 /* This API is only used in IPC backend. */ 268 #if CONFIG_TFM_SPM_BACKEND_IPC == 1 269 /** 270 * \brief Function body of \ref psa_get. 271 * 272 * \param[in] signal The signal value for an asserted RoT Service. 273 * \param[out] msg Pointer to \ref psa_msg_t object for receiving 274 * the message. 275 * 276 * \retval PSA_SUCCESS Success, *msg will contain the delivered 277 * message. 278 * \retval PSA_ERROR_DOES_NOT_EXIST Message could not be delivered. 279 * \retval "PROGRAMMER ERROR" The call is invalid because one or more of the 280 * following are true: 281 * \arg signal has more than a single bit set. 282 * \arg signal does not correspond to an RoT Service. 283 * \arg The RoT Service signal is not currently 284 * asserted. 285 * \arg The msg pointer provided is not a valid memory 286 * reference. 287 */ 288 psa_status_t tfm_spm_partition_psa_get(psa_signal_t signal, psa_msg_t *msg); 289 #endif /* CONFIG_TFM_SPM_BACKEND_IPC == 1 */ 290 291 /** 292 * \brief Function body of \ref psa_read. 293 * 294 * \param[in] msg_handle Handle for the client's message. 295 * \param[in] invec_idx Index of the input vector to read from. Must be 296 * less than \ref PSA_MAX_IOVEC. 297 * \param[out] buffer Buffer in the Secure Partition to copy the 298 * requested data to. 299 * \param[in] num_bytes Maximum number of bytes to be read from the 300 * client input vector. 301 * 302 * \retval >0 Number of bytes copied. 303 * \retval 0 There was no remaining data in this input 304 * vector. 305 * \retval "PROGRAMMER ERROR" The call is invalid, one or more of the 306 * following are true: 307 * \arg msg_handle is invalid. 308 * \arg msg_handle does not refer to a 309 * \ref PSA_IPC_CALL message. 310 * \arg invec_idx is equal to or greater than 311 * \ref PSA_MAX_IOVEC. 312 * \arg the memory reference for buffer is invalid or 313 * not writable. 314 */ 315 size_t tfm_spm_partition_psa_read(psa_handle_t msg_handle, uint32_t invec_idx, 316 void *buffer, size_t num_bytes); 317 318 /** 319 * \brief Function body of psa_skip. 320 * 321 * \param[in] msg_handle Handle for the client's message. 322 * \param[in] invec_idx Index of input vector to skip from. Must be 323 * less than \ref PSA_MAX_IOVEC. 324 * \param[in] num_bytes Maximum number of bytes to skip in the client 325 * input vector. 326 * 327 * \retval >0 Number of bytes skipped. 328 * \retval 0 There was no remaining data in this input 329 * vector. 330 * \retval "PROGRAMMER ERROR" The call is invalid, one or more of the 331 * following are true: 332 * \arg msg_handle is invalid. 333 * \arg msg_handle does not refer to a request 334 * message. 335 * \arg invec_idx is equal to or greater than 336 * \ref PSA_MAX_IOVEC. 337 */ 338 size_t tfm_spm_partition_psa_skip(psa_handle_t msg_handle, uint32_t invec_idx, 339 size_t num_bytes); 340 341 /** 342 * \brief Function body of \ref psa_write. 343 * 344 * \param[in] msg_handle Handle for the client's message. 345 * \param[out] outvec_idx Index of output vector in message to write to. 346 * Must be less than \ref PSA_MAX_IOVEC. 347 * \param[in] buffer Buffer with the data to write. 348 * \param[in] num_bytes Number of bytes to write to the client output 349 * vector. 350 * 351 * \retval PSA_SUCCESS Success. 352 * \retval "PROGRAMMER ERROR" The call is invalid, one or more of the 353 * following are true: 354 * \arg msg_handle is invalid. 355 * \arg msg_handle does not refer to a request 356 * message. 357 * \arg outvec_idx is equal to or greater than 358 * \ref PSA_MAX_IOVEC. 359 * \arg The memory reference for buffer is invalid. 360 * \arg The call attempts to write data past the end 361 * of the client output vector. 362 */ 363 psa_status_t tfm_spm_partition_psa_write(psa_handle_t msg_handle, uint32_t outvec_idx, 364 const void *buffer, size_t num_bytes); 365 366 /** 367 * \brief Function body of \ref psa_reply. 368 * 369 * \param[in] msg_handle Handle for the client's message. 370 * \param[in] status Message result value to be reported to the 371 * client. 372 * 373 * \retval Positive integer Success, the connection handle. 374 * \retval PSA_SUCCESS Success 375 * \retval "PROGRAMMER ERROR" The call is invalid, one or more of the 376 * following are true: 377 * \arg msg_handle is invalid. 378 * \arg An invalid status code is specified for the 379 * type of message. 380 */ 381 int32_t tfm_spm_partition_psa_reply(psa_handle_t msg_handle, 382 psa_status_t status); 383 384 #if CONFIG_TFM_DOORBELL_API == 1 385 /** 386 * \brief Function body of \ref psa_norify. 387 * 388 * \param[in] partition_id Secure Partition ID of the target partition. 389 * 390 * \retval PSA_SUCCESS Success. 391 * \retval PSA_NEED_SCHEDULE Require schedule thread. 392 * \retval "PROGRAMMER ERROR" partition_id does not correspond to a Secure 393 * Partition. 394 */ 395 psa_status_t tfm_spm_partition_psa_notify(int32_t partition_id); 396 397 /** 398 * \brief Function body of \ref psa_clear. 399 * 400 * \retval PSA_SUCCESS Success. 401 * \retval "PROGRAMMER ERROR" The Secure Partition's doorbell signal is not 402 * currently asserted. 403 */ 404 psa_status_t tfm_spm_partition_psa_clear(void); 405 #else 406 #define tfm_spm_partition_psa_notify NULL 407 #define tfm_spm_partition_psa_clear NULL 408 #endif /* CONFIG_TFM_DOORBELL_API == 1 */ 409 410 /** 411 * \brief Function body of \ref psa_panic. 412 * 413 * \retval "Should not return" 414 */ 415 psa_status_t tfm_spm_partition_psa_panic(void); 416 417 /* psa_set_rhandle is only needed by connection-based services */ 418 #if CONFIG_TFM_CONNECTION_BASED_SERVICE_API == 1 419 420 /** 421 * \brief Function body of \ref psa_set_rhandle. 422 * 423 * \param[in] msg_handle Handle for the client's message. 424 * \param[in] rhandle Reverse handle allocated by the RoT Service. 425 * 426 * \retval PSA_SUCCESS Success, rhandle will be provided with all 427 * subsequent messages delivered on this 428 * connection. 429 * \retval "PROGRAMMER ERROR" msg_handle is invalid. 430 */ 431 psa_status_t tfm_spm_partition_psa_set_rhandle(psa_handle_t msg_handle, void *rhandle); 432 #else 433 #define tfm_spm_partition_psa_set_rhandle NULL 434 #endif /* CONFIG_TFM_CONNECTION_BASED_SERVICE_API */ 435 436 #if CONFIG_TFM_FLIH_API == 1 || CONFIG_TFM_SLIH_API == 1 437 /** 438 * \brief Function body of \ref psa_irq_enable. 439 * 440 * \param[in] irq_signal The signal for the interrupt to be enabled. 441 * This must have a single bit set, which must be the 442 * signal value for an interrupt in the calling Secure 443 * Partition. 444 * 445 * \retval PSA_SUCCESS Success. 446 * \retval "PROGRAMMER ERROR" If one or more of the following are true: 447 * \arg \a irq_signal is not an interrupt signal. 448 * \arg \a irq_signal indicates more than one signal. 449 */ 450 psa_status_t tfm_spm_partition_psa_irq_enable(psa_signal_t irq_signal); 451 452 /** 453 * \brief Function body of psa_irq_disable. 454 * 455 * \param[in] irq_signal The signal for the interrupt to be disabled. 456 * This must have a single bit set, which must be the 457 * signal value for an interrupt in the calling Secure 458 * Partition. 459 * 460 * \retval 0 The interrupt was disabled prior to this call. 461 * 1 The interrupt was enabled prior to this call. 462 * \retval "PROGRAMMER ERROR" If one or more of the following are true: 463 * \arg \a irq_signal is not an interrupt signal. 464 * \arg \a irq_signal indicates more than one signal. 465 * 466 * \note The current implementation always return 1. Do not use the return. 467 */ 468 psa_irq_status_t tfm_spm_partition_psa_irq_disable(psa_signal_t irq_signal); 469 #else /* CONFIG_TFM_FLIH_API == 1 || CONFIG_TFM_SLIH_API == 1 */ 470 #define tfm_spm_partition_psa_irq_enable NULL 471 #define tfm_spm_partition_psa_irq_disable NULL 472 #endif /* CONFIG_TFM_FLIH_API == 1 || CONFIG_TFM_SLIH_API == 1 */ 473 474 /* This API is only used for FLIH. */ 475 #if CONFIG_TFM_FLIH_API == 1 476 /** 477 * \brief Function body of \ref psa_reset_signal. 478 * 479 * \param[in] irq_signal The interrupt signal to be reset. 480 * This must have a single bit set, corresponding to a 481 * currently asserted signal for an interrupt that is 482 * defined to use FLIH handling. 483 * 484 * \retval PSA_SUCCESS Success. 485 * \retval "Programmer Error" if one or more of the following are true: 486 * \arg \a irq_signal is not a signal for an interrupt 487 * that is specified with FLIH handling in the Secure 488 * Partition manifest. 489 * \arg \a irq_signal indicates more than one signal. 490 * \arg \a irq_signal is not currently asserted. 491 */ 492 psa_status_t tfm_spm_partition_psa_reset_signal(psa_signal_t irq_signal); 493 #else /* CONFIG_TFM_FLIH_API == 1 */ 494 #define tfm_spm_partition_psa_reset_signal NULL 495 #endif /* CONFIG_TFM_FLIH_API == 1 */ 496 497 /* This API is only used for SLIH. */ 498 #if CONFIG_TFM_SLIH_API == 1 499 /** 500 * \brief Function body of \ref psa_eoi. 501 * 502 * \param[in] irq_signal The interrupt signal that has been processed. 503 * 504 * \retval PSA_SUCCESS Success. 505 * \retval "PROGRAMMER ERROR" The call is invalid, one or more of the 506 * following are true: 507 * \arg irq_signal is not an interrupt signal. 508 * \arg irq_signal indicates more than one signal. 509 * \arg irq_signal is not currently asserted. 510 * \arg The interrupt is not using SLIH. 511 */ 512 psa_status_t tfm_spm_partition_psa_eoi(psa_signal_t irq_signal); 513 #else /* CONFIG_TFM_SLIH_API == 1 */ 514 #define tfm_spm_partition_psa_eoi NULL 515 #endif /* CONFIG_TFM_SLIH_API == 1 */ 516 517 #if PSA_FRAMEWORK_HAS_MM_IOVEC 518 519 /** 520 * \brief Function body of psa_map_invec. 521 */ 522 const void *tfm_spm_partition_psa_map_invec(psa_handle_t msg_handle, 523 uint32_t invec_idx); 524 525 /** 526 * \brief Function body of psa_unmap_invec. 527 */ 528 void tfm_spm_partition_psa_unmap_invec(psa_handle_t msg_handle, 529 uint32_t invec_idx); 530 531 /** 532 * \brief Function body of psa_map_outvet. 533 */ 534 void *tfm_spm_partition_psa_map_outvec(psa_handle_t msg_handle, 535 uint32_t outvec_idx); 536 537 /** 538 * \brief Function body of psa_unmap_outvec. 539 */ 540 void tfm_spm_partition_psa_unmap_outvec(psa_handle_t msg_handle, 541 uint32_t outvec_idx, size_t len); 542 543 #endif /* PSA_FRAMEWORK_HAS_MM_IOVEC */ 544 545 #endif /* __PSA_API_H__ */ 546