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/mailbox_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 128 /** 129 * \brief handler for \ref agent_psa_close. 130 * 131 * \param[in] handle Service handle to the connection to be closed, 132 * \param[in] ns_client_id NS agent's client identifier. 133 * 134 * \retval PSA_SUCCESS Success. 135 * \retval PSA_ERROR_PROGRAMMER_ERROR The call is invalid, one or more of the 136 * following are true: 137 * \arg Called with a stateless handle. 138 * \arg An invalid handle was provided that is not 139 * the null handle. 140 * \arg The connection is handling a request. 141 */ 142 psa_status_t tfm_spm_agent_psa_close(psa_handle_t handle, int32_t ns_client_id); 143 144 #else /* CONFIG_TFM_CONNECTION_BASED_SERVICE_API == 1 */ 145 #define tfm_spm_agent_psa_connect NULL 146 #define tfm_spm_agent_psa_close NULL 147 #endif /* CONFIG_TFM_CONNECTION_BASED_SERVICE_API == 1 */ 148 #else /* TFM_PARTITION_NS_AGENT_MAILBOX */ 149 #define tfm_spm_agent_psa_connect NULL 150 #define tfm_spm_agent_psa_close NULL 151 #define tfm_spm_agent_psa_call NULL 152 #endif /* TFM_PARTITION_NS_AGENT_MAILBOX */ 153 154 /** 155 * \brief This function handles the specific programmer error cases. 156 * 157 * \param[in] status Standard error codes for the SPM. 158 * 159 * \retval void Status will not cause SPM panic 160 * \retval "SPM panic" Following programmer errors are triggered by SP: 161 * \arg PSA_ERROR_PROGRAMMER_ERROR 162 * \arg PSA_ERROR_CONNECTION_REFUSED 163 * \arg PSA_ERROR_CONNECTION_BUSY 164 */ 165 void spm_handle_programmer_errors(psa_status_t status); 166 167 /** 168 * \brief This function get the current PSA RoT lifecycle state. 169 * 170 * \return state The current security lifecycle state of the PSA 171 * RoT. The PSA state and implementation state are 172 * encoded as follows: 173 * \arg state[15:8] – PSA lifecycle state 174 * \arg state[7:0] – IMPLEMENTATION DEFINED state 175 */ 176 uint32_t tfm_spm_get_lifecycle_state(void); 177 178 /* PSA Client API function body, for privileged use only. */ 179 180 /** 181 * \brief handler for \ref psa_framework_version. 182 * 183 * \return version The version of the PSA Framework implementation 184 * that is providing the runtime services. 185 */ 186 uint32_t tfm_spm_client_psa_framework_version(void); 187 188 /** 189 * \brief handler for \ref psa_version. 190 * 191 * \param[in] sid RoT Service identity. 192 * 193 * \retval PSA_VERSION_NONE The RoT Service is not implemented, or the 194 * caller is not permitted to access the service. 195 * \retval > 0 The version of the implemented RoT Service. 196 */ 197 uint32_t tfm_spm_client_psa_version(uint32_t sid); 198 199 /** 200 * \brief handler for \ref psa_call. 201 * 202 * \param[in] handle Service handle to the established connection, 203 * \ref psa_handle_t 204 * \param[in] ctrl_param Parameters combined in uint32_t, 205 * includes request type, in_num and out_num. 206 * \param[in] inptr Array of input psa_invec structures. 207 * \ref psa_invec 208 * \param[in] outptr Array of output psa_outvec structures. 209 * \ref psa_outvec 210 * 211 * \retval PSA_SUCCESS Success. 212 * \retval "Does not return" The call is invalid, one or more of the 213 * following are true: 214 * \arg An invalid handle was passed. 215 * \arg The connection is already handling a request. 216 * \arg An invalid memory reference was provided. 217 * \arg in_num + out_num > PSA_MAX_IOVEC. 218 * \arg The message is unrecognized by the RoT 219 * Service or incorrectly formatted. 220 */ 221 psa_status_t tfm_spm_client_psa_call(psa_handle_t handle, 222 uint32_t ctrl_param, 223 const psa_invec *inptr, 224 psa_outvec *outptr); 225 226 /* Following PSA APIs are only needed by connection-based services */ 227 #if CONFIG_TFM_CONNECTION_BASED_SERVICE_API == 1 228 229 /** 230 * \brief handler for \ref psa_connect. 231 * 232 * \param[in] sid RoT Service identity. 233 * \param[in] version The version of the RoT Service. 234 * 235 * \retval PSA_SUCCESS Success. 236 * \retval PSA_ERROR_CONNECTION_REFUSED The SPM or RoT Service has refused the 237 * connection. 238 * \retval PSA_ERROR_CONNECTION_BUSY The SPM or RoT Service cannot make the 239 * connection at the moment. 240 * \retval "Does not return" The RoT Service ID and version are not 241 * supported, or the caller is not permitted to 242 * access the service. 243 */ 244 psa_status_t tfm_spm_client_psa_connect(uint32_t sid, uint32_t version); 245 246 /** 247 * \brief handler for \ref psa_close. 248 * 249 * \param[in] handle Service handle to the connection to be closed, 250 * \ref psa_handle_t 251 * 252 * \retval PSA_SUCCESS Success. 253 * \retval PSA_ERROR_PROGRAMMER_ERROR The call is invalid, one or more of the 254 * following are true: 255 * \arg Called with a stateless handle. 256 * \arg An invalid handle was provided that is not 257 * the null handle. 258 * \arg The connection is handling a request. 259 */ 260 psa_status_t tfm_spm_client_psa_close(psa_handle_t handle); 261 #else 262 #define tfm_spm_client_psa_connect NULL 263 #define tfm_spm_client_psa_close NULL 264 #endif /* CONFIG_TFM_CONNECTION_BASED_SERVICE_API */ 265 266 /* PSA Partition API function body, for privileged use only. */ 267 268 #if CONFIG_TFM_SPM_BACKEND_IPC == 1 \ 269 || CONFIG_TFM_FLIH_API == 1 || CONFIG_TFM_SLIH_API == 1 270 /** 271 * \brief Function body of \ref psa_wait. 272 * 273 * \param[in] signal_mask A set of signals to query. Signals that are not 274 * in this set will be ignored. 275 * \param[in] timeout Specify either blocking \ref PSA_BLOCK or 276 * polling \ref PSA_POLL operation. 277 * 278 * \retval >0 At least one signal is asserted. 279 * \retval 0 No signals are asserted. This is only seen when 280 * a polling timeout is used. 281 */ 282 psa_signal_t tfm_spm_partition_psa_wait(psa_signal_t signal_mask, 283 uint32_t timeout); 284 #endif 285 286 /* This API is only used in IPC backend. */ 287 #if CONFIG_TFM_SPM_BACKEND_IPC == 1 288 /** 289 * \brief Function body of \ref psa_get. 290 * 291 * \param[in] signal The signal value for an asserted RoT Service. 292 * \param[out] msg Pointer to \ref psa_msg_t object for receiving 293 * the message. 294 * 295 * \retval PSA_SUCCESS Success, *msg will contain the delivered 296 * message. 297 * \retval PSA_ERROR_DOES_NOT_EXIST Message could not be delivered. 298 * \retval "PROGRAMMER ERROR" The call is invalid because one or more of the 299 * following are true: 300 * \arg signal has more than a single bit set. 301 * \arg signal does not correspond to an RoT Service. 302 * \arg The RoT Service signal is not currently 303 * asserted. 304 * \arg The msg pointer provided is not a valid memory 305 * reference. 306 */ 307 psa_status_t tfm_spm_partition_psa_get(psa_signal_t signal, psa_msg_t *msg); 308 #endif /* CONFIG_TFM_SPM_BACKEND_IPC == 1 */ 309 310 /** 311 * \brief Function body of \ref psa_read. 312 * 313 * \param[in] msg_handle Handle for the client's message. 314 * \param[in] invec_idx Index of the input vector to read from. Must be 315 * less than \ref PSA_MAX_IOVEC. 316 * \param[out] buffer Buffer in the Secure Partition to copy the 317 * requested data to. 318 * \param[in] num_bytes Maximum number of bytes to be read from the 319 * client input vector. 320 * 321 * \retval >0 Number of bytes copied. 322 * \retval 0 There was no remaining data in this input 323 * vector. 324 * \retval "PROGRAMMER ERROR" The call is invalid, one or more of the 325 * following are true: 326 * \arg msg_handle is invalid. 327 * \arg msg_handle does not refer to a 328 * \ref PSA_IPC_CALL message. 329 * \arg invec_idx is equal to or greater than 330 * \ref PSA_MAX_IOVEC. 331 * \arg the memory reference for buffer is invalid or 332 * not writable. 333 */ 334 size_t tfm_spm_partition_psa_read(psa_handle_t msg_handle, uint32_t invec_idx, 335 void *buffer, size_t num_bytes); 336 337 /** 338 * \brief Function body of psa_skip. 339 * 340 * \param[in] msg_handle Handle for the client's message. 341 * \param[in] invec_idx Index of input vector to skip from. Must be 342 * less than \ref PSA_MAX_IOVEC. 343 * \param[in] num_bytes Maximum number of bytes to skip in the client 344 * input vector. 345 * 346 * \retval >0 Number of bytes skipped. 347 * \retval 0 There was no remaining data in this input 348 * vector. 349 * \retval "PROGRAMMER ERROR" The call is invalid, one or more of the 350 * following are true: 351 * \arg msg_handle is invalid. 352 * \arg msg_handle does not refer to a request 353 * message. 354 * \arg invec_idx is equal to or greater than 355 * \ref PSA_MAX_IOVEC. 356 */ 357 size_t tfm_spm_partition_psa_skip(psa_handle_t msg_handle, uint32_t invec_idx, 358 size_t num_bytes); 359 360 /** 361 * \brief Function body of \ref psa_write. 362 * 363 * \param[in] msg_handle Handle for the client's message. 364 * \param[out] outvec_idx Index of output vector in message to write to. 365 * Must be less than \ref PSA_MAX_IOVEC. 366 * \param[in] buffer Buffer with the data to write. 367 * \param[in] num_bytes Number of bytes to write to the client output 368 * vector. 369 * 370 * \retval PSA_SUCCESS Success. 371 * \retval "PROGRAMMER ERROR" The call is invalid, one or more of the 372 * following are true: 373 * \arg msg_handle is invalid. 374 * \arg msg_handle does not refer to a request 375 * message. 376 * \arg outvec_idx is equal to or greater than 377 * \ref PSA_MAX_IOVEC. 378 * \arg The memory reference for buffer is invalid. 379 * \arg The call attempts to write data past the end 380 * of the client output vector. 381 */ 382 psa_status_t tfm_spm_partition_psa_write(psa_handle_t msg_handle, uint32_t outvec_idx, 383 const void *buffer, size_t num_bytes); 384 385 /** 386 * \brief Function body of \ref psa_reply. 387 * 388 * \param[in] msg_handle Handle for the client's message. 389 * \param[in] status Message result value to be reported to the 390 * client. 391 * 392 * \retval Positive integer Success, the connection handle. 393 * \retval PSA_SUCCESS Success 394 * \retval "PROGRAMMER ERROR" The call is invalid, one or more of the 395 * following are true: 396 * \arg msg_handle is invalid. 397 * \arg An invalid status code is specified for the 398 * type of message. 399 */ 400 int32_t tfm_spm_partition_psa_reply(psa_handle_t msg_handle, 401 psa_status_t status); 402 403 #if CONFIG_TFM_DOORBELL_API == 1 404 /** 405 * \brief Function body of \ref psa_norify. 406 * 407 * \param[in] partition_id Secure Partition ID of the target partition. 408 * 409 * \retval PSA_SUCCESS Success. 410 * \retval PSA_NEED_SCHEDULE Require schedule thread. 411 * \retval "PROGRAMMER ERROR" partition_id does not correspond to a Secure 412 * Partition. 413 */ 414 psa_status_t tfm_spm_partition_psa_notify(int32_t partition_id); 415 416 /** 417 * \brief Function body of \ref psa_clear. 418 * 419 * \retval PSA_SUCCESS Success. 420 * \retval "PROGRAMMER ERROR" The Secure Partition's doorbell signal is not 421 * currently asserted. 422 */ 423 psa_status_t tfm_spm_partition_psa_clear(void); 424 #else 425 #define tfm_spm_partition_psa_notify NULL 426 #define tfm_spm_partition_psa_clear NULL 427 #endif /* CONFIG_TFM_DOORBELL_API == 1 */ 428 429 /** 430 * \brief Function body of \ref psa_panic. 431 * 432 * \retval "Should not return" 433 */ 434 psa_status_t tfm_spm_partition_psa_panic(void); 435 436 /* psa_set_rhandle is only needed by connection-based services */ 437 #if CONFIG_TFM_CONNECTION_BASED_SERVICE_API == 1 438 439 /** 440 * \brief Function body of \ref psa_set_rhandle. 441 * 442 * \param[in] msg_handle Handle for the client's message. 443 * \param[in] rhandle Reverse handle allocated by the RoT Service. 444 * 445 * \retval PSA_SUCCESS Success, rhandle will be provided with all 446 * subsequent messages delivered on this 447 * connection. 448 * \retval "PROGRAMMER ERROR" msg_handle is invalid. 449 */ 450 psa_status_t tfm_spm_partition_psa_set_rhandle(psa_handle_t msg_handle, void *rhandle); 451 #else 452 #define tfm_spm_partition_psa_set_rhandle NULL 453 #endif /* CONFIG_TFM_CONNECTION_BASED_SERVICE_API */ 454 455 #if CONFIG_TFM_FLIH_API == 1 || CONFIG_TFM_SLIH_API == 1 456 /** 457 * \brief Function body of \ref psa_irq_enable. 458 * 459 * \param[in] irq_signal The signal for the interrupt to be enabled. 460 * This must have a single bit set, which must be the 461 * signal value for an interrupt in the calling Secure 462 * Partition. 463 * 464 * \retval PSA_SUCCESS Success. 465 * \retval "PROGRAMMER ERROR" If one or more of the following are true: 466 * \arg \a irq_signal is not an interrupt signal. 467 * \arg \a irq_signal indicates more than one signal. 468 */ 469 psa_status_t tfm_spm_partition_psa_irq_enable(psa_signal_t irq_signal); 470 471 /** 472 * \brief Function body of psa_irq_disable. 473 * 474 * \param[in] irq_signal The signal for the interrupt to be disabled. 475 * This must have a single bit set, which must be the 476 * signal value for an interrupt in the calling Secure 477 * Partition. 478 * 479 * \retval 0 The interrupt was disabled prior to this call. 480 * 1 The interrupt was enabled prior to this call. 481 * \retval "PROGRAMMER ERROR" If one or more of the following are true: 482 * \arg \a irq_signal is not an interrupt signal. 483 * \arg \a irq_signal indicates more than one signal. 484 * 485 * \note The current implementation always return 1. Do not use the return. 486 */ 487 psa_irq_status_t tfm_spm_partition_psa_irq_disable(psa_signal_t irq_signal); 488 #else /* CONFIG_TFM_FLIH_API == 1 || CONFIG_TFM_SLIH_API == 1 */ 489 #define tfm_spm_partition_psa_irq_enable NULL 490 #define tfm_spm_partition_psa_irq_disable NULL 491 #endif /* CONFIG_TFM_FLIH_API == 1 || CONFIG_TFM_SLIH_API == 1 */ 492 493 /* This API is only used for FLIH. */ 494 #if CONFIG_TFM_FLIH_API == 1 495 /** 496 * \brief Function body of \ref psa_reset_signal. 497 * 498 * \param[in] irq_signal The interrupt signal to be reset. 499 * This must have a single bit set, corresponding to a 500 * currently asserted signal for an interrupt that is 501 * defined to use FLIH handling. 502 * 503 * \retval PSA_SUCCESS Success. 504 * \retval "Programmer Error" if one or more of the following are true: 505 * \arg \a irq_signal is not a signal for an interrupt 506 * that is specified with FLIH handling in the Secure 507 * Partition manifest. 508 * \arg \a irq_signal indicates more than one signal. 509 * \arg \a irq_signal is not currently asserted. 510 */ 511 psa_status_t tfm_spm_partition_psa_reset_signal(psa_signal_t irq_signal); 512 #else /* CONFIG_TFM_FLIH_API == 1 */ 513 #define tfm_spm_partition_psa_reset_signal NULL 514 #endif /* CONFIG_TFM_FLIH_API == 1 */ 515 516 /* This API is only used for SLIH. */ 517 #if CONFIG_TFM_SLIH_API == 1 518 /** 519 * \brief Function body of \ref psa_eoi. 520 * 521 * \param[in] irq_signal The interrupt signal that has been processed. 522 * 523 * \retval PSA_SUCCESS Success. 524 * \retval "PROGRAMMER ERROR" The call is invalid, one or more of the 525 * following are true: 526 * \arg irq_signal is not an interrupt signal. 527 * \arg irq_signal indicates more than one signal. 528 * \arg irq_signal is not currently asserted. 529 * \arg The interrupt is not using SLIH. 530 */ 531 psa_status_t tfm_spm_partition_psa_eoi(psa_signal_t irq_signal); 532 #else /* CONFIG_TFM_SLIH_API == 1 */ 533 #define tfm_spm_partition_psa_eoi NULL 534 #endif /* CONFIG_TFM_SLIH_API == 1 */ 535 536 #if PSA_FRAMEWORK_HAS_MM_IOVEC 537 538 /** 539 * \brief Function body of psa_map_invec. 540 */ 541 const void *tfm_spm_partition_psa_map_invec(psa_handle_t msg_handle, 542 uint32_t invec_idx); 543 544 /** 545 * \brief Function body of psa_unmap_invec. 546 */ 547 void tfm_spm_partition_psa_unmap_invec(psa_handle_t msg_handle, 548 uint32_t invec_idx); 549 550 /** 551 * \brief Function body of psa_map_outvet. 552 */ 553 void *tfm_spm_partition_psa_map_outvec(psa_handle_t msg_handle, 554 uint32_t outvec_idx); 555 556 /** 557 * \brief Function body of psa_unmap_outvec. 558 */ 559 void tfm_spm_partition_psa_unmap_outvec(psa_handle_t msg_handle, 560 uint32_t outvec_idx, size_t len); 561 562 #endif /* PSA_FRAMEWORK_HAS_MM_IOVEC */ 563 564 #endif /* __PSA_API_H__ */ 565