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 FFM
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 FFM
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 FFM 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 FFM Client
47  API does not have such capability.
48- FFM 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: FFM-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 FFM 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 FFM standard API.
84- Having a manifest file to describe the attributes and resources and a
85  positive valued ``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_call()`` is extended from ``psa_call()``.
110
111And to cooperate with the changed behaviour of these APIs, extra defined
112signals and types are also involved.
113
114.. note::
115  Namespace ``agent`` is involved for NS Agent callable API; namespace ``tfm``
116  is involved for TF-M specific concepts. Even though ``agent`` is TF-M
117  specific at the current stage, it is proposed to be a common concept for
118  general FF-M compliant implementations, hence assigning ``agent`` for
119  proposed API and data structures.
120
121Input and output vectors
122========================
123When non-secure clients call ``psa_call()``, a mailbox message containing
124``psa_call()`` parameters is delivered into ``Mailbox NS Agent`` and the agent
125needs to extract parameters from the message and then call ``agent_psa_call()``.
126Revisit the ``psa_call()`` prototype to see the parameters:
127
128.. code-block:: c
129
130  psa_status_t psa_call(psa_handle_t handle,
131                        int32_t type,
132                        const psa_invec *in_vec,
133                        size_t in_len,
134                        psa_outvec *out_vec,
135                        size_t out_len);
136
137Interface ``agent_psa_call()`` has 4 arguments only, to avoid ABI complexity
138when more than 4 arguments get involved. Then input and output vectors must
139be squashed into a new type to achieve this squashing. There are several
140scenarios to be considered:
141
142- In the shared-memory-based mailbox scheme, the non-secure interface layer
143  puts ``psa_invec`` and ``psa_outvec`` instances and their members in the
144  shared memory. The pointers of these items are delivered to
145  ``Mailbox NS Agent`` for the agent's referencing. All vectors are
146  non-secure in this case.
147- Still, in the shared-memory-based mailbox scheme, but this time not all
148  parameters are prepared by non-secure clients. Some of the items are
149  allocated by the agent. Secure and non-secure vectors get mixed in this case.
150- In the scheme that a memory address can not be delivered (A serial
151  interface e.g.), ``Mailbox NS Agent`` allocates ``psa_invec`` and
152  ``psa_outvec`` in local memory to collect pointers and sizes of received
153  buffers. All the vectors are secure in this case.
154
155Based on these scenarios, and the case that an agent might access depending
156services with the agent itself's identifier and secure vectors, a straight
157conclusion is that the memory source information - secure or non-secure - for
158input and output vectors and their pointing memories need to be indicated by
159the agent so that SPM can perform a memory check towards given vectors.
160
161Most of the SPE platforms have the capability to identify if a given memory
162pointer is secure or not, which makes this indication look duplicated. But the
163indication is necessary for these scenarios:
164
165- The SPE platform identifies the memory source by the address mapped into
166  SPE's address space, but this mapping happens inside the agent instead of
167  SPM. It is the agent who receives the mailbox data and maps it, so it knows
168  which addresses need mapping and the others do not.
169- The SPE platform just does not have such capability. The addresses from the
170  mailbox can be treated as non-secure always but there are cases that the
171  agent itself needs to access services with its own memory instead of
172  representing the non-secure clients.
173
174To cover the above mentioned scenarios, guidelines are listed for input and
175output vector processing:
176
177- The agent needs to tell SPM where vectors and descriptors come from, to
178  assist SPM performs a proper memory checking. The source information is
179  encoded in the parameter ``control``.
180- When SPE platforms have the capability to identify the memory sources,
181  platforms can decide whether to skip the indication or not, in the HAL.
182
183A composition type is created for packing the vectors:
184
185.. code-block:: c
186
187  struct client_param_t {
188    int32_t         ns_client_id_stateless;
189    const psa_invec *p_invecs;
190    psa_outvec      *p_outvecs;
191  };
192
193``ns_client_id_stateless`` indicates the non-secure client id when the client
194is accessing a stateless service. This member is ignored if the target service
195is a connection-based one.
196
197.. note::
198  The vectors and non-secure client ID are recorded in the internal handle.
199  Hence it is safe to claim ``client_param_t`` instance as local variable.
200
201Agent-specific Client API
202=========================
203``agent_psa_connect()`` is the API added to support agent forwarding NS
204requests.
205
206.. code-block:: c
207
208  psa_handle_t agent_psa_connect(uint32_t sid, uint32_t version,
209                                 int32_t ns_client_id, const void *client_data);
210
211One extra parameter ``ns_client_id`` added to tell SPM which NS client the
212agent is representing when API gets called. It is recorded in the handle
213association data in SPM and requires to be a negative value; ZERO or positive
214values are invalid non-secure client IDs, SPM does not use these invalid IDs
215in the message. Instead, it puts the agent's ID into the messaging in this
216case. This mechanism can provide chances for the agents calling APIs for their
217own service accessing and API works asynchronously.
218
219As mentioned, the standard FFM Client service accessing API are blocked until
220the IPC message gets replied to. While this API returns immediately without
221waiting for acknowledgement. Unless an error occurred, these agent-specific
222API returns PSA_SUCCESS always. The replies for these access requests are
223always fetched initiative by the agent with a ``psa_get()``.
224
225.. code-block:: c
226
227  psa_status_t agent_psa_call(psa_handle_t handle, uint32_t control,
228                              const struct client_param_t   *params,
229                              const void   *client_data_stateless);
230
231Compared to the standard ``psa_call()``, this API:
232
233- Squashes the ``psa_invec``, ``psa_outvec``, and ``ns_client_id_stateless``
234  into parameter ``params``.
235- One extra parameter ``client_data_stateless`` for ``agent_psa_call()`` stands
236  for the auxiliary data added. This member is ignored for connection-based
237  services because ``agent_psa_connect()`` already assigned one in the
238  connected handle.
239- Has a composited agrument ``control``.
240
241The encoding scheme for ``control``:
242
243====== ====== ================================================================
244Bit(s) Name   Description
245====== ====== ================================================================
24627     NSIV   `1`: Input vectors in non-secure memory. `0`: Secure memory.
24724-26  IVNUM  Number of input vectors.
24819     NSOV   `1`: Output vectors in non-secure memory. `0`: Secure memory.
24916-18  OVNUM  Number of output vectors.
2500-15   type   signed 16-bit service `type`.
251====== ====== ================================================================
252
253.. note::
254  ``control`` is a 32-bit unsigned integer and bits not mentioned in the
255  table are reserved for future usage.
256
257Agent-specific signal
258=====================
259To cooperate with the agent-specific API, one extra acknowledgement signal is
260defined:
261
262.. code-block:: c
263
264  #define ASYNC_MSG_REPLY            (0x00000004u)
265
266This signal can be sent to agent type component only. An agent can call
267``psa_get()`` with this signal to get one acknowledged message. This signal is
268cleared when all queued messages for the agent have been retrieved using
269``psa_get()``. SPM assembles the information into agent provided message object.
270For the stateless handle, the internal handle object is freed after this
271``psa_get()`` call. The agent can know what kind of message is acknowledged by
272the ``type`` member in the ``psa_msg_t``, and the ``client_data`` passed in is
273put in member ``rhandle``. If no 'ASYNC_MSG_REPLY' signals pending, calling
274``psa_get()`` gets ``panic``.
275
276Code Example
277============
278
279.. code-block:: c
280
281  /*
282   * The actual implementation can change this __customized_t freely, or
283   * discard this type and apply some in-house mechanism - the example
284   * here is to introduce how an agent works only.
285   */
286  struct __customized_t {
287      int32_t      type;
288      int32_t      client_id;
289      psa_handle_t handle;
290      psa_handle_t status;
291  };
292
293  void mailbox_main(void)
294  {
295      psa_signal_t   signals;
296      psa_status_t   status;
297      psa_msg_t      msg;
298      struct client_param_t client_param;
299      struct __customized_t ns_msg;
300
301      while (1) {
302          signals = psa_wait(ALL, BLOCK);
303
304          if (signals & MAILBOX_INTERRUPT_SIGNAL) {
305              /* NS memory check needs to be performed. */
306              __customized_platform_get_mail(&ns_msg);
307
308              /*
309               * MACRO 'SID', 'VER', 'NSID', 'INVEC_LEN', 'OUTVEC_LEN', and
310               * 'VECTORS' represent necessary information extraction from
311               * 'ns_msg', put MACRO names here and leave the details to the
312               * implementation.
313               */
314              if (ns_msg.type == PSA_IPC_CONNECT) {
315                  status = agent_psa_connect(SID(ns_msg), VER(ns_msg),
316                                             NSID(ns_msg), &ns_msg);
317              } else if (ns_msg.type == PSA_IPC_CLOSE) {
318                  psa_close(ns_msg.handle);
319              } else {
320                  /* Other types as call type and let API check errors. */
321                  client_param.ns_client_id_stateless = NSID(ns_msg);
322
323                  /*
324                   * Use MACRO to demonstrate two cases: local vector
325                   * descriptor and direct descriptor forwarding.
326                   */
327
328                  /* Point to vector pointers in ns_msg. */
329                  PACK_VECTOR_POINTERS(client_param, ns_msg);
330                  status = agent_psa_call(ns_msg.handle,
331                                          PARAM_PACK(ns_msg.type,
332                                                     INVEC_LEN(ns_msg),
333                                                     OUTVEC_LEN(ns_msg))|
334                                                     NSIV | NSOV,
335                                          &client_param,
336                                          &ns_msg);
337              }
338              /*
339               * The service access reply is always fetched by a later
340               * `psa_get` hence here only errors need to be dispatched.
341               */
342              error_dispatch(status);
343
344          } else if (signals & ASYNC_MSG_REPLY) {
345              /* The handle is freed for stateless service after 'psa_get'. */
346              status        = psa_get(ASYNC_MSG_REPLY, &msg);
347              ms_msg        = msg.rhandle;
348              ns_msg.status = status;
349              __customized_platform__send_mail(&ns_msg);
350          }
351      }
352  }
353
354.. note::
355  ``__customized*`` API are implementation-specific APIs to be implemented by
356  the mailbox Agent developer.
357
358Customized manifest attribute
359=============================
360Two extra customized manifest attributes are added:
361
362============= ====================================================
363Name          Description
364============= ====================================================
365ns_agent      Indicate if manifest owner is an Agent.
366------------- ----------------------------------------------------
367ns_client_ids Possible non-secure Client ID values (<0).
368============= ====================================================
369
370Attribute 'ns_client_ids' can be a set of numbers, or it can use a range
371expression such as [min, max]. The tooling can detect ID overlap between
372multiple non-secure agents.
373
374.. note::
375  Per-non-secure-client dependencies scheme is now assumed to be implemented
376  by agent customization. Feedback if there are requirements for a unified
377  scheme.
378
379***********************
380Manifest tooling update
381***********************
382The manifest for agents involves specific keys ('ns_agent' e.g.), these keys
383give hints about how to achieve out-of-FFM partitions which might be abused
384easily by developers, for example, claim partitions as agents. Some
385restrictions need to be applied in the manifest tool to limit the general
386secure service development referencing these keys.
387
388.. note::
389  The limitations can mitigate the abuse but can't prevent it, as developers
390  own all the source code they are working with.
391
392One mechanism: adding a confirmation in the partition list file.
393
394.. parsed-literal::
395
396  "description": "Non-Secure Mailbox Agent",
397  "manifest": "${CMAKE_SOURCE_DIR}/secure_fw/partitions/ns_agent_mailbox/ns_agent_mailbox.yaml",
398  "non_ffm_attributes": "ns_agent", "other_option",
399
400``non_ffm_attributes`` tells the manifest tool that ``ns_agent`` is valid
401in ns_agent_mailbox.ymal. Otherwise, the manifest tool reports an error when a
402non-agent service abuses ns_agent in its manifest.
403
404***********************************
405Runtime programming characteristics
406***********************************
407
408Mailbox agent shall not be blocked by Agent-specific APIs. It can be blocked when:
409
410- It is calling standard PSA Client APIs.
411- It is calling ``psa_wait()``.
412
413IDLE processing
414===============
415Only ONE place is recommended to enter IDLE. The place is decided based on the
416system topologies:
417
418- If there is one Trustzone-based NSPE, this NSPE is the recommended place no
419  matter how many mailbox agents are in the system.
420- If there are only mailbox-based NSPEs, entering IDLE can happen in
421  one of the mailbox agents.
422
423The solution is:
424
425- An IDLE entering API is provided in SPRTL.
426- A partition without specific flag can't call this API.
427- The manifest tooling counts the partitions with this specific flag, and
428  assert errors when multiple instances are found.
429
430--------------
431
432*Copyright (c) 2022-2023, Arm Limited. All rights reserved.*
433*Copyright (c) 2023 Cypress Semiconductor Corporation (an Infineon company)
434or an affiliate of Cypress Semiconductor Corporation. All rights reserved.*
435