1############################## 2Mailbox NS Agent Design Update 3############################## 4 5:Organization: Arm Limited 6:Contact: tf-m@lists.trustedfirmware.org 7 8********** 9Background 10********** 11The SPE component that maintains the non-secure clients' request is called 12'NS Agent' in TF-M. Besides the Trustzone-based isolation mechanism, there is 13one other isolation mechanism that implements individual PEs in physically 14isolated cores respectively. NSPE and SPE transfer non-secure client requests 15via inter-processor communication based on mailboxes. The component that 16handles inter-processor communication messages is called ``Mailbox NS Agent``. 17 18.. note:: 19 There may be hardware components and software solutions containing 'mailbox' 20 in their names. The concept ``mailbox`` in this document represent the 21 mechanism described above, which is not referring to the external concepts. 22 23When the first version ``Mailbox NS Agent`` was introduced, the generic FF-M 24interrupt handling was not ready. Hence a customized solution 25``Multiple Core`` is implemented. This customized implementation: 26 27- Perform customized operations on SPM internal data in a deferred interrupt 28 handler. 29- Process mailbox operations as special cases in SPM common logic. 30 31These behaviours couple SPM tightly with mailbox logic, which bring issues for 32maintenance. To address the issue, an updated design shall: 33 34- Make SPM manage other components in a unified way (For example, it is 35 simpler for SPM if all non-SPM components under the IPC model act as 36 ``processes``). 37- Can use FF-M compliant interrupt mechanism and APIs. 38 39Following the above guidelines makes the ``Mailbox NS Agent`` work like a 40``partition``. The agent has an endless loop and waits for signals, calls FF-M 41API based on the parsing result on the communication messages. But there are 42still issues after looking closer to the requirements of the agent: 43 44- SPM treats FF-M Client API caller's ID as the client ID. While the mailbox NS 45 agent may represent multiple non-secure clients. Hence it needs to tell 46 SPM which non-secure client it is representing, and the default FF-M Client 47 API does not have such capability. 48- FF-M Client API blocks caller before the call is replied; while the 49 mailbox NS Agent needs to respond to the non-secure interrupts in time. 50 Blocking while waiting for a reply may cause the non-secure communication 51 message not to be handled in time. 52 53Extra design items need to be added to address the issues. 54 55************* 56Design Update 57************* 58The below figure shows the overall design to cover various component types. 59NS Agents are the implementation-defined components that provide FF-M compliant 60Client API to the non-secure clients. Hence from the view of the non-secure 61clients, the FF-M client API behaviour follows the FF-M definition. And NS 62Agent needs customization in SPM since it has extra requirements compared to 63a generic secure partition. 64 65.. figure:: /design_docs/media/mailbox_ns_agent1.* 66 :align: center 67 :name: fig-mailbox1 68 :width: 70% 69 70 Component types and the callable API set 71 72.. note:: 73 3 non-SPM component types here: FF-M-compliant Secure Partition 74 (aka ``partition``), Trustzone-based NS Agent (aka ``Trustzone NS Agent``) 75 and mailbox-based NS Agent (aka ``Mailbox NS Agent``). 76 ``Trustzone NS Agent`` is mentioned here for the comparison purpose. The 77 implementation details for this NS agent type is not introduced here. 78 79To make the programming model close to the FF-M compliance, the 80``Mailbox NS Agent`` is designed as: 81 82- Working like a standard Secure Partition under the IPC model, has one 83 single thread, can call FF-M standard API. 84- Having a manifest file to describe the attributes and resources and a 85 positive value ``Partition ID`` in the manifest. 86 87Services rely on the ``client_id`` to apply policy-checking, hence SPM 88needs to know which ``client_id`` the mailbox NS Agent is representing when 89mailbox API is calling Client API. The standard API treats the caller as the 90client of the service, which means that a specific API is required to 91support identifying the represented non-secure client. SPM sets the non-secure 92``client_id`` into the message right at the moment the message is 93going to be sent. Before this point, SPM performs the call based on the 94agent's ID. 95 96This specifc ``Agent API`` is non-blocking, unlike the standard FF-M Client 97APIs. This can improve the communication efficiency between NS clients and 98mailbox NS agents. With this mechanism, extra signals and APIs for message 99acknowledges are also required. 100 101.. note:: 102 A standard Secure Partition gets errors when calling the ``Agent API``. 103 104Updated programming interfaces 105============================== 106These Client APIs are expanded from the standard Client APIs: 107 108- ``agent_psa_connect()`` is extended from ``psa_connect()``. 109- ``agent_psa_close()`` is extended from ``psa_close()``. 110- ``agent_psa_call()`` is extended from ``psa_call()``. 111 112And to cooperate with the changed behaviour of these APIs, extra defined 113signals and types are also involved. 114 115.. note:: 116 Namespace ``agent`` is involved for NS Agent callable API; namespace ``tfm`` 117 is involved for TF-M specific concepts. Even though ``agent`` is TF-M 118 specific at the current stage, it is proposed to be a common concept for 119 general FF-M compliant implementations, hence assigning ``agent`` for 120 proposed API and data structures. 121 122Input and output vectors 123======================== 124When non-secure clients call ``psa_call()``, a mailbox message containing 125``psa_call()`` parameters is delivered into ``Mailbox NS Agent`` and the agent 126needs to extract parameters from the message and then call ``agent_psa_call()``. 127Revisit the ``psa_call()`` prototype to see the parameters: 128 129.. code-block:: c 130 131 psa_status_t psa_call(psa_handle_t handle, 132 int32_t type, 133 const psa_invec *in_vec, 134 size_t in_len, 135 psa_outvec *out_vec, 136 size_t out_len); 137 138Interface ``agent_psa_call()`` has 4 arguments only, to avoid ABI complexity 139when more than 4 arguments get involved. Then input and output vectors must 140be squashed into a new type to achieve this squashing. There are several 141scenarios to be considered: 142 143- In the shared-memory-based mailbox scheme, the non-secure interface layer 144 puts ``psa_invec`` and ``psa_outvec`` instances and their members in the 145 shared memory. The pointers of these items are delivered to 146 ``Mailbox NS Agent`` for the agent's referencing. All vectors are 147 non-secure in this case. 148- Still, in the shared-memory-based mailbox scheme, but this time not all 149 parameters are prepared by non-secure clients. Some of the items are 150 allocated by the agent. Secure and non-secure vectors get mixed in this case. 151- In the scheme that a memory address can not be delivered (A serial 152 interface e.g.), ``Mailbox NS Agent`` allocates ``psa_invec`` and 153 ``psa_outvec`` in local memory to collect pointers and sizes of received 154 buffers. All the vectors are secure in this case. 155 156Based on these scenarios, and the case that an agent might access depending 157services with the agent itself's identifier and secure vectors, a straight 158conclusion is that the memory source information - secure or non-secure - for 159input and output vectors and their pointing memories need to be indicated by 160the agent so that SPM can perform a memory check towards given vectors. 161 162Most of the SPE platforms have the capability to identify if a given memory 163pointer is secure or not, which makes this indication look duplicated. But the 164indication is necessary for these scenarios: 165 166- The SPE platform identifies the memory source by the address mapped into 167 SPE's address space, but this mapping happens inside the agent instead of 168 SPM. It is the agent who receives the mailbox data and maps it, so it knows 169 which addresses need mapping and the others do not. 170- The SPE platform just does not have such capability. The addresses from the 171 mailbox can be treated as non-secure always but there are cases that the 172 agent itself needs to access services with its own memory instead of 173 representing the non-secure clients. 174 175To cover the above mentioned scenarios, guidelines are listed for input and 176output vector processing: 177 178- The agent needs to tell SPM where vectors and descriptors come from, to 179 assist SPM performs a proper memory checking. The source information is 180 encoded in the parameter ``control``. 181- When SPE platforms have the capability to identify the memory sources, 182 platforms can decide whether to skip the indication or not, in the HAL. 183 184A composition type is created for packing the vectors: 185 186.. code-block:: c 187 188 struct client_params_t { 189 int32_t ns_client_id_stateless; 190 const psa_invec *p_invecs; 191 psa_outvec *p_outvecs; 192 }; 193 194``ns_client_id_stateless`` indicates the non-secure client id when the client 195is accessing a stateless service. This member is ignored if the target service 196is a connection-based one. 197 198.. note:: 199 The vectors and non-secure client ID are recorded in the internal handle. 200 Hence it is safe to claim ``client_params_t`` instance as local variable. 201 202Agent-specific Client API 203========================= 204``agent_psa_connect()`` and ``agent_psa_close()`` are the APIs added to support 205agent forwarding NS requests. 206 207.. code-block:: c 208 209 psa_handle_t agent_psa_connect(uint32_t sid, uint32_t version, 210 int32_t ns_client_id, const void *client_data); 211 psa_status_t agent_psa_close(psa_handle_t handle, int32_t ns_client_id); 212 213One extra parameter ``ns_client_id`` added to tell SPM which NS client the 214agent is representing when API gets called. It is recorded in the handle 215association data in SPM and requires to be a negative value; ZERO or positive 216values are invalid non-secure client IDs, SPM does not use these invalid IDs 217in the message. Instead, it puts the agent's ID into the messaging in this 218case. This mechanism can provide chances for the agents calling APIs for their 219own service accessing and API works asynchronously. 220 221As mentioned, the standard FF-M Client service accessing API are blocked until 222the IPC message gets replied to. While this API returns immediately without 223waiting for acknowledgement. Unless an error occurred, these agent-specific 224API returns PSA_SUCCESS always. The replies for these access requests are 225always fetched initiative by the agent with a ``psa_get()``. 226 227.. code-block:: c 228 229 psa_status_t agent_psa_call(psa_handle_t handle, uint32_t control, 230 const struct client_param_t *params, 231 const void *client_data_stateless); 232 233Compared to the standard ``psa_call()``, this API: 234 235- Squashes the ``psa_invec``, ``psa_outvec``, and ``ns_client_id_stateless`` 236 into parameter ``params``. 237- One extra parameter ``client_data_stateless`` for ``agent_psa_call()`` stands 238 for the auxiliary data added. This member is ignored for connection-based 239 services because ``agent_psa_connect()`` already assigned one in the 240 connected handle. 241- Has a composite argument ``control``. 242 243The encoding scheme for ``control``: 244 245====== ====== ================================================================ 246Bit(s) Name Description 247====== ====== ================================================================ 24827 NSIV `1`: Input vectors in non-secure memory. `0`: Secure memory. 24924-26 IVNUM Number of input vectors. 25019 NSOV `1`: Output vectors in non-secure memory. `0`: Secure memory. 25116-18 OVNUM Number of output vectors. 2520-15 type signed 16-bit service `type`. 253====== ====== ================================================================ 254 255.. note:: 256 ``control`` is a 32-bit unsigned integer and bits not mentioned in the 257 table are reserved for future usage. 258 259Agent-specific signal 260===================== 261To cooperate with the agent-specific API, one extra acknowledgement signal is 262defined: 263 264.. code-block:: c 265 266 #define ASYNC_MSG_REPLY (0x00000004u) 267 268This signal can be sent to agent type component only. An agent can call 269``psa_get()`` with this signal to get one acknowledged message. This signal is 270cleared when all queued messages for the agent have been retrieved using 271``psa_get()``. SPM assembles the information into agent provided message object. 272For the stateless handle, the internal handle object is freed after this 273``psa_get()`` call. The agent can know what kind of message is acknowledged by 274the ``type`` member in the ``psa_msg_t``, and the ``client_data`` passed in is 275put in member ``rhandle``. If no 'ASYNC_MSG_REPLY' signals pending, calling 276``psa_get()`` gets ``panic``. 277 278Code Example 279============ 280 281.. code-block:: c 282 283 /* 284 * The actual implementation can change this __customized_t freely, or 285 * discard this type and apply some in-house mechanism - the example 286 * here is to introduce how an agent works only. 287 */ 288 struct __customized_t { 289 int32_t type; 290 int32_t client_id; 291 psa_handle_t handle; 292 psa_handle_t status; 293 }; 294 295 void mailbox_main(void) 296 { 297 psa_signal_t signals; 298 psa_status_t status; 299 psa_msg_t msg; 300 struct client_param_t client_param; 301 struct __customized_t ns_msg; 302 303 while (1) { 304 signals = psa_wait(ALL, BLOCK); 305 306 if (signals & MAILBOX_INTERRUPT_SIGNAL) { 307 /* NS memory check needs to be performed. */ 308 __customized_platform_get_mail(&ns_msg); 309 310 /* 311 * MACRO 'SID', 'VER', 'NSID', 'INVEC_LEN', 'OUTVEC_LEN', and 312 * 'VECTORS' represent necessary information extraction from 313 * 'ns_msg', put MACRO names here and leave the details to the 314 * implementation. 315 */ 316 if (ns_msg.type == PSA_IPC_CONNECT) { 317 status = agent_psa_connect(SID(ns_msg), VER(ns_msg), 318 NSID(ns_msg), &ns_msg); 319 } else if (ns_msg.type == PSA_IPC_CLOSE) { 320 status = agent_psa_close(ns_msg.handle, NSID(ns_msg)); 321 } else { 322 /* Other types as call type and let API check errors. */ 323 client_param.ns_client_id_stateless = NSID(ns_msg); 324 325 /* 326 * Use MACRO to demonstrate two cases: local vector 327 * descriptor and direct descriptor forwarding. 328 */ 329 330 /* Point to vector pointers in ns_msg. */ 331 PACK_VECTOR_POINTERS(client_param, ns_msg); 332 status = agent_psa_call(ns_msg.handle, 333 PARAM_PACK(ns_msg.type, 334 INVEC_LEN(ns_msg), 335 OUTVEC_LEN(ns_msg))| 336 NSIV | NSOV, 337 &client_param, 338 &ns_msg); 339 } 340 /* 341 * The service access reply is always fetched by a later 342 * `psa_get` hence here only errors need to be dispatched. 343 */ 344 error_dispatch(status); 345 346 } else if (signals & ASYNC_MSG_REPLY) { 347 /* The handle is freed for stateless service after 'psa_get'. */ 348 status = psa_get(ASYNC_MSG_REPLY, &msg); 349 ms_msg = msg.rhandle; 350 ns_msg.status = status; 351 __customized_platform__send_mail(&ns_msg); 352 } 353 } 354 } 355 356.. note:: 357 ``__customized*`` API are implementation-specific APIs to be implemented by 358 the mailbox Agent developer. 359 360Customized manifest attribute 361============================= 362Three extra customized manifest attributes are added: 363 364=============== ==================================================== 365Name Description 366=============== ==================================================== 367ns_agent Indicate if manifest owner is an Agent. 368--------------- ---------------------------------------------------- 369client_id_base The minimum client ID value (<0) 370--------------- ---------------------------------------------------- 371client_id_limit The maximum client ID value (<0) 372=============== ==================================================== 373 374``client_id_base`` and ``client_id_limit`` are negative numbers. This means that 375``client_id_base <= client_id_limit``, but 376``abs(client_id_base) >= abs(client_id_limit)``. SPM can detect ID overlap when 377initialising secure partitions 378 379The Non-secure callers are expected to provide a negative (<0) client ID when 380calling PSA API. A uniform mapping is implemented across all the NS agents, 381where the mapping is defined as the following: 382 383+---------------------------------------------+---------------------+ 384|NS client ID |Transformed client ID| 385+=============================================+=====================+ 386| -1 | client_id_limit | 387+---------------------------------------------+---------------------+ 388| -2 | client_id_limit - 1 | 389+---------------------------------------------+---------------------+ 390| ... | 391+---------------------------------------------+---------------------+ 392|-(abs(client_id_limit)-abs(client_id_base)+1)| client_id_base | 393+---------------------------------------------+---------------------+ 394 395Any other IDs provided by the NSPE will result in PSA_ERROR_INVALID_ARGUMENT. 396 397*********************** 398Manifest tooling update 399*********************** 400The manifest for agents involves specific keys ('ns_agent' e.g.), these keys 401give hints about how to achieve out-of-FF-M partitions which might be abused 402easily by developers, for example, claim partitions as agents. Some 403restrictions need to be applied in the manifest tool to limit the general 404secure service development referencing these keys. 405 406.. note:: 407 The limitations can mitigate the abuse but can't prevent it, as developers 408 own all the source code they are working with. 409 410One mechanism: adding a confirmation in the partition list file. 411 412.. parsed-literal:: 413 414 "description": "Non-Secure Mailbox Agent", 415 "manifest": "${CMAKE_SOURCE_DIR}/secure_fw/partitions/ns_agent_mailbox/ns_agent_mailbox.yaml", 416 "non_ffm_attributes": "ns_agent", "other_option", 417 418``non_ffm_attributes`` tells the manifest tool that ``ns_agent`` is valid 419in ns_agent_mailbox.yaml. Otherwise, the manifest tool reports an error when a 420non-agent service abuses ns_agent in its manifest. 421 422*********************************** 423Runtime programming characteristics 424*********************************** 425 426Mailbox agent shall not be blocked by Agent-specific APIs. It can be blocked when: 427 428- It is calling standard PSA Client APIs. 429- It is calling ``psa_wait()``. 430 431IDLE processing 432=============== 433Only ONE place is recommended to enter IDLE. The place is decided based on the 434system topologies: 435 436- If there is one Trustzone-based NSPE, this NSPE is the recommended place no 437 matter how many mailbox agents there are in the system. 438- If there are only mailbox-based NSPEs, entering IDLE can happen in 439 one of the mailbox agents. 440 441The solution is: 442 443- An IDLE entering API is provided in SPRTL. 444- A partition without specific flag can't call this API. 445- The manifest tooling counts the partitions with this specific flag, and 446 assert errors when multiple instances are found. 447 448-------------- 449 450*Copyright (c) 2022-2024, Arm Limited. All rights reserved.* 451*Copyright (c) 2023 Cypress Semiconductor Corporation (an Infineon company) 452or an affiliate of Cypress Semiconductor Corporation. All rights reserved.* 453