Docs: Implementation details for Mailbox Agent API
The purpose is to cover as much detail as could, and here are
the contained items:
- API implementation.
- Partition-level operations for agents.
- IDLE processing.
Signed-off-by: Ken Liu <Ken.Liu@arm.com>
Change-Id: Ifec409eb059d0a3928bb8ff1d20683f656ef2673
diff --git a/docs/design_docs/dual-cpu/mailbox_ns_agent_update.rst b/docs/design_docs/dual-cpu/mailbox_ns_agent_update.rst
index 40ee9d6..f6760d1 100644
--- a/docs/design_docs/dual-cpu/mailbox_ns_agent_update.rst
+++ b/docs/design_docs/dual-cpu/mailbox_ns_agent_update.rst
@@ -106,9 +106,9 @@
clients, it is the agent's duty to identify the non-secure clients it is
representing.
-Updated Programming Items
-=========================
-These Client APIs are the expansion based on the standard Client APIs:
+Updated programming interfaces
+==============================
+These Client APIs are expanded from the standard Client APIs:
- ``agent_psa_connect`` is extended from ``psa_connect``.
- ``agent_psa_call`` is extended from ``psa_call``.
@@ -272,6 +272,172 @@
``__customized*`` API are implementation-specific APIs to be implemented by
the mailbox Agent developer.
+****************************
+API implementation reference
+****************************
+Takes ``psa_call`` as the example here to showcase the difference between the
+interface and its calling implementation logic. The prototype of the
+implementation logic for ``psa_call`` in SPM is:
+
+.. code-block:: c
+
+ psa_status_t tfm_spm_client_psa_call(psa_handle_t handle,
+ uint32_t ctrl_param,
+ const psa_invec *inptr,
+ psa_outvec *outptr);
+
+And the prototype for agent-specific ``agent_psa_call``:
+
+.. code-block:: c
+
+ psa_status_t agent_psa_call(psa_handle_t handle, int32_t ctrl_param,
+ client_vectors_t *vecs, client_param_t *params);
+
+
+``agent_psa_call`` reuses the existing ``tfm_spm_client_psa_call`` as the
+internal implementation, the procedure after ``agent_psa_call`` gets called is
+slightly different compared to a classic ``psa_call`` procedure
+(Error handling is not described here as it works as usual):
+
+- Extract ``inptr`` and ``outptr`` from ``vecs`` before calling
+ ``tfm_spm_client_psa_call``.
+- After ``tfm_spm_client_psa_call`` created a ``psa_msg_t`` instance, the
+ member ``client_id`` in the instance needs to be updated to a value given by
+ ``ns_client_id`` of argument ``params`` to indicate the non-secure client
+ the mailbox agent is representing.
+- The member ``client_data`` in the argument ``params`` needs to be recorded
+ for a future reply usage.
+
+Here ``tfm_spm_client_psa_call`` needs more inputs to accomplish the required
+operations such as NS client ID updating and backup the ``client_data``. But
+it would be inefficient if these inputs were given by arguments, because the
+caller was not always an agent so in most of the cases these extra arguments
+were not used, but the classic ``psa_call`` procedure would be forced to fill
+them always before calling ``tfm_spm_client_psa_call``.
+
+A solution referencing the local storage scheme can save the cost spent on
+extra arguments passing, this solution:
+
+- Calls an agent-specific callback for the extra steps during
+ ``tfm_spm_client_psa_call`` when the caller is a mailbox agent.
+- Puts callback required inputs in the local storage.
+
+Here is the pseudo-code for this solution:
+
+.. code-block:: c
+
+ psa_status_t tfm_spm_client_psa_call(psa_handle_t handle,
+ uint32_t ctrl_param,
+ const psa_invec *inptr,
+ psa_outvec *outptr)
+ {
+ ...
+ if (CALLER()->flags & MAILBOX_AGENT) {
+ post_handling_mailbox(p_connection);
+ }
+ ...
+ }
+
+ void post_handling_mailbox(connection_t *p_conn)
+ {
+ p_conn->msg.client_id = LOCAL_STORAGE()->client_param.ns_client_id;
+ p_conn->msg.client_data = LOCAL_STORAGE()->client_param.client_data;
+ }
+
+The ``client_data`` saved in the connection instance will be returned to the
+caller when it calls ``psa_get`` to retrieve the reply.
+
+Local storage for SPM
+=====================
+The local storage mechanism can be similar to what :doc:`SPRTL </design_docs/services/secure_partition_runtime_library>`
+does. The stack top is still the ideal place for local storage indicator
+because SPM also has its dedicated stack. For Armv8m, shifting the xSPLIM to
+detect stack overflow is an advantage. For earlier architecture versions, a
+global variable saving the stack top is still applicable.
+
+.. important::
+ This mechanism may conflict with some private 'alloca' implementations,
+ remember the local storage must be put at the top of the stack,
+ and `alloca` working buffer is put after (usually higher addresses for the
+ descending stack case) the local storage data.
+
+Example:
+
+.. code-block:: c
+
+ void *claim_local_storage(uint32_t sz)
+ {
+ PSPLIM += sz;
+ return PSPLIM;
+ }
+
+Customized manifest attribute
+=============================
+Two extra customized manifest attributes are added:
+
+============= ====================================================
+Name Description
+============= ====================================================
+ns_agent Indicate if manifest owner is an Agent.
+------------- ----------------------------------------------------
+ns_client_ids Possible non-secure Client ID values (<0).
+============= ====================================================
+
+Attribute 'ns_client_ids' can be a set of numbers, or it can use a range
+expression such as [min, max]. The tooling can detect ID overlap between
+multiple non-secure agents.
+
+***********************
+Manifest tooling update
+***********************
+The manifest for agents involves specific keys ('ns_agent' e.g.), these keys
+give hints about how to achieve out-of-FFM partitions which might be abused
+easily by developers, for example, claim partitions as agents. Some
+restrictions need to be applied in the manifest tool to limit the general
+secure service development referencing these keys.
+
+.. note::
+ The limitations can mitigate the abuse but can't prevent it, as developers
+ own all the source code they are working with.
+
+One mechanism: adding a confirmation in the partition list file.
+
+.. parsed-literal::
+
+ "description": "Non-Secure Mailbox Agent",
+ "manifest": "${CMAKE_SOURCE_DIR}/secure_fw/partitions/ns_agent_mailbox/ns_agent_mailbox.yaml",
+ "non_ffm_attributes": "ns_agent", "other_option",
+
+``non_ffm_attributes`` tells the manifest tool that ``ns_agent`` is valid
+in ns_agent_mailbox.ymal. Otherwise, the manifest tool reports an error when a
+non-agent service abuses ns_agent in its manifest.
+
+***********************************
+Runtime programming characteristics
+***********************************
+
+Mailbox agent shall not be blocked by Agent-specific APIs. It can be blocked when:
+
+- It is calling standard PSA Client APIs.
+- It is calling ``psa_wait``.
+
+IDLE processing
+===============
+Only ONE place is recommended to enter IDLE. The place is decided based on the
+system topologies:
+
+- If there is one Trustzone-based NSPE, this NSPE is the recommended place no
+ matter how many mailbox agents are in the system.
+- If there are only mailbox-based NSPEs, entering IDLE can happen in
+ one of the mailbox agents.
+
+The solution is:
+
+- An IDLE entering API is provided in SPRTL.
+- A partition without specific flag can't call this API.
+- The manifest tooling counts the partitions with this specific flag, and
+ assert errors when multiple instances are found.
+
--------------
*Copyright (c) 2022, Arm Limited. All rights reserved.*