1################################################################
2Memory Access Check of Trusted Firmware-M in Multi-Core Topology
3################################################################
4
5:Author: David Hu
6:Organization: Arm Limited
7:Contact: david.hu@arm.com
8
9************
10Introduction
11************
12
13On Armv8-M platforms with TrustZone, the platform's TF-M isolation HAL implementation usually relies
14on the `Armv8-M Security Extension`_ (CMSE) intrinsic ``cmse_check_address_range()`` to check memory
15access permissions. However, on multi-core platforms, the secure core may be an Armv6-M or Armv7-M
16core that does not implement CMSE. Even if CMSE is implemented on a multi-core platform, additional
17checks on system-level security and memory access management units may be required since CMSE
18intrinsics and TT instructions are only aware of MPU/SAU/IDAU inside the secure core.
19
20As a result, TF-M provides a common platform memory access check API and an implementation that
21works without CMSE support. Multi-core topology platforms may use the memory check API
22``tfm_has_access_to_region()``, which checks whether an access has proper permission to read or
23write the target memory region, as a substitute for ``cmse_check_address_range()`` when implementing
24the TF-M isolation HAL.
25
26The memory check API is defined in ``platform/ext/common/mem_check_v6m_v7m.h`` and the common
27implementation is provided in ``platform/ext/common/mem_check_v6m_v7m.c``. The HAL defined in
28``platform/ext/common/mem_check_v6m_v7m_hal.h`` must be implemented by each platform that uses the
29common implementation. This document discusses the design of the memory access check API and
30implementation.
31
32.. _Armv8-M Security Extension: https://developer.arm.com/documentation/100720/0100/Secure-Software-Guidelines/ARMv8-M-Security-Extension
33
34**************
35Overall Design
36**************
37
38Memory Access Check Policy
39==========================
40
41The policies vary in diverse Isolation Levels.
42
43When TF-M works in Isolation Level 1, the access check in multi-core topology
44checks
45
46- Memory region is valid according to system settings
47- Non-secure client call request should not access secure memory.
48- Secure services should not directly access non-secure memory. According to PSA
49  Firmware Framework, Secure services should call Secure Partition APIs to ask
50  TF-M SPM to fetch non-secure input/output buffer for them.
51- Whether read/write attribute match between access and memory region
52
53When TF-M works in Isolation Level 2, the access check in multi-core topology
54checks:
55
56- Memory region is valid according to system settings
57- Non-secure client call request should not access secure memory.
58- Secure services should not directly access non-secure memory. According to PSA
59  Firmware Framework, Secure services should call Secure Partition APIs to ask
60  TF-M SPM to fetch non-secure input/outputs buffer for them.
61- Whether read/write attribute match between access and memory region
62- Unprivileged secure access should not access privileged secure memory region
63
64The check policy in Isolation Level 3 will be defined according to TF-M future
65implementation.
66
67The above policies will be adjusted according to TF-M implementation and PSA
68specs.
69
70General Check Process in TF-M Core
71==================================
72
73The TF-M SPM calls the ``tfm_hal_memory_check()`` HAL API in both TrustZone-based and multi-core
74topology platforms to keep a uniform interface between SPM and platform.
75
76Multi-core platform specific ``tfm_hal_memory_check()`` implementations can invoke
77``tfm_has_access_to_region()`` to implement the entire memory access check routine.
78
79During the check process, ``tfm_has_access_to_region()`` compares the access permission with memory
80region attributes and determines whether the access is allowed to access the region according to
81policy described in `Memory Access Check Policy`_ above.
82
83``tfm_has_access_to_region()`` invokes 3 HAL APIs to retrieve attributes of target memory region.
84
85- ``tfm_hal_get_mem_security_attr()`` retrieves the security attributes of the target memory region.
86- ``tfm_hal_get_secure_access_attr()`` retrieves secure access attributes of the target memory
87  region.
88- ``tfm_hal_get_ns_access_attr()`` retrieves non-secure access attributes of the target memory
89  region.
90
91All three functions are implemented by multi-core platform support. The definitions are specified in
92the section `HAL APIs`_ below.
93
94The pseudo code of ``tfm_has_access_to_region()`` is shown below.
95
96.. code-block:: c
97    :linenos:
98    :emphasize-lines: 19,36,46
99
100    int32_t tfm_has_access_to_region(const void *p, size_t s, uint8_t flags)
101    {
102        struct security_attr_info_t security_attr;
103        struct mem_attr_info_t mem_attr;
104
105        /* Validate input parameters */
106        if (Validation failed) {
107            return error;
108        }
109
110        /* The memory access check should be executed inside TF-M PSA RoT */
111        if (Not in privileged level) {
112            abort;
113        }
114
115        /* Set initial value */
116        security_attr_init(&security_attr);
117
118        /* Retrieve security attributes of memory region */
119        tfm_hal_get_mem_security_attr(p, s, &security_attr);
120
121        /* Compare according to current Isolation Level */
122        if (Input flags mismatch security attributes) {
123            return error;
124        }
125
126        /* Set initial value */
127        mem_attr_init(&mem_attr);
128
129        if (The target memory region is in secure memory space) {
130            /* Retrieve access attributes of secure memory region */
131            tfm_hal_get_secure_access_attr(p, s, &mem_attr);
132
133            if (Not in Isolation Level 1) {
134                /* Secure memory protection unit(s) must be enabled in Isolation Level 2 and 3 */
135                if (Protection unit not enabled) {
136                    abort;
137                }
138            }
139        } else {
140            /* Retrieve access attributes of non-secure memory region. */
141            tfm_hal_get_ns_access_attr(p, s, &mem_attr);
142        }
143
144        /* Compare according to current Isolation Level and non-secure/secure access. */
145        if (Input flags match memory attributes) {
146            return success;
147        }
148
149        return error;
150    }
151
152.. note::
153   It cannot be guaranteed that TF-M provides a comprehensive memory access
154   check on non-secure memory for NSPE client call. If non-secure memory
155   protection or isolation is required in a multi-core system, NSPE software
156   should implement and execute the check functionalities in NSPE, rather than
157   relying on TF-M access check.
158
159   For example, all the access from NSPE client calls to non-secure memory are
160   classified as unprivileged in current TF-M implementation. Multi-core access
161   check may skip the privileged/unprivileged permission check for non-secure
162   access.
163
164   If a multi-core system enforces the privileged/unprivileged isolation and
165   protection of non-secure area, NSPE software should execute the corresponding
166   check functionalities before submitting the NSPE client call request to SPE.
167
168*******************
169Data Types and APIs
170*******************
171
172Data Types
173==========
174
175Access Permission Flags
176-----------------------
177
178The following flags are defined to indicate the access permission attributes.
179Each flag is mapped to the corresponding CMSE macro. Please refer to
180`ARMv8-M Security Extensions: Requirements on Development Tools
181<http://infocenter.arm.com/help/topic/com.arm.doc.ecm0359818/ECM0359818_armv8m_security_extensions_reqs_on_dev_tools_1_0.pdf>`_
182for details of each CMSE macro.
183
184``MEM_CHECK_MPU_READWRITE``
185^^^^^^^^^^^^^^^^^^^^^^^^^^^
186
187Mapped to CMSE macro ``CMSE_MPU_READWRITE`` to indicate that the access requires
188both read and write permission to the target memory region.
189
190.. code-block:: c
191
192    #define MEM_CHECK_MPU_READWRITE   (1 << 0x0)
193
194
195``MEM_CHECK_MPU_UNPRIV``
196^^^^^^^^^^^^^^^^^^^^^^^^
197
198Mapped to CMSE macro ``CMSE_MPU_UNPRIV`` to indicate that it is an unprivileged
199access.
200
201.. code-block:: c
202
203    #define MEM_CHECK_MPU_UNPRIV      (1 << 0x2)
204
205
206``MEM_CHECK_MPU_READ``
207^^^^^^^^^^^^^^^^^^^^^^
208
209Mapped to CMSE macro ``CMSE_MPU_READ``. It indicates that it is a read-only
210access to target memory region.
211
212.. code-block:: c
213
214    #define MEM_CHECK_MPU_READ        (1 << 0x3)
215
216
217``MEM_CHECK_NONSECURE``
218^^^^^^^^^^^^^^^^^^^^^^^
219
220Mapped to CSME macro ``CMSE_NONSECURE`` to indicate that it is a access from
221non-secure client call request.
222If this flag is unset, it indicates the access is required from SPE.
223
224.. code-block:: c
225
226    #define MEM_CHECK_AU_NONSECURE    (1 << 0x1)
227    #define MEM_CHECK_MPU_NONSECURE   (1 << 0x4)
228    #define MEM_CHECK_NONSECURE       (MEM_CHECK_AU_NONSECURE | \
229                                       MEM_CHECK_MPU_NONSECURE)
230
231Security Attributes Information
232-------------------------------
233
234The structure ``security_attr_info_t`` contains the security attributes
235information of the target memory region.
236``tfm_hal_get_mem_security_attr()`` implementation should fill the structure
237fields according to the platform specific secure isolation setting.
238
239.. code-block:: c
240
241    struct security_attr_info_t {
242        bool is_valid;
243        bool is_secure;
244    };
245
246| ``is_valid`` indicates whether the target memory region is valid according to
247  platform resource assignment and security isolation configurations.
248| ``is_secure`` indicates the target memory region is secure or non-secure. The
249  value is only valid when ``is_valid`` is ``true``.
250
251Memory Attributes Information
252-----------------------------
253
254The structure ``mem_attr_info_t`` contains the memory access attributes
255information of the target memory region.
256``tfm_hal_get_secure_access_attr()`` and ``tfm_hal_get_ns_access_attr()`` implementations should
257fill the structure fields according to the memory protection settings.
258
259.. code-block:: c
260
261    struct mem_attr_info_t {
262        bool is_mpu_enabled;
263        bool is_valid;
264        bool is_xn;
265        bool is_priv_rd_allow;
266        bool is_priv_wr_allow;
267        bool is_unpriv_rd_allow;
268        bool is_unpriv_wr_allow;
269    };
270
271| ``is_mpu_enabled`` indicates whether the MPU and other management unit are
272  enabled and work normally.
273| ``is_valid`` indicates whether the target memory region is valid according to
274  platform resource assignment and memory protection configurations.
275| ``is_xn`` indicates whether the target memory region is Execute Never. This
276  field is only valid when ``is_valid`` is ``true``.
277| ``is_priv_rd_allow`` and ``is_priv_wr_allow`` indicates whether the target
278  memory region allows privileged read/write. Both the fields are valid only
279  when  ``is_valid`` is ``true``.
280| ``is_unpriv_rd_allow`` and ``is_unpriv_wr_allow`` indicates whether the target
281  memory region allows unprivileged read/write. Both the fields are valid only
282  when  ``is_valid`` is ``true``.
283
284HAL APIs
285========
286
287``tfm_hal_get_mem_security_attr()``
288-----------------------------------
289
290``tfm_hal_get_mem_security_attr()`` retrieves the current active security configuration information
291and fills the ``security_attr_info_t``.
292
293.. code-block:: c
294
295    void tfm_hal_get_mem_security_attr(const void *p, size_t s,
296                                       struct security_attr_info_t *p_attr);
297
298+--------------------------------------------------------------------+
299| **Parameters**                                                     |
300+-------------+------------------------------------------------------+
301| ``p``       | Base address of the target memory region             |
302+-------------+------------------------------------------------------+
303| ``s``       | Size of the target memory region                     |
304+-------------+------------------------------------------------------+
305| ``p_attr``  | Pointer to the ``security_attr_info_t`` to be filled |
306+-------------+------------------------------------------------------+
307| **Return**                                                         |
308+-------------+------------------------------------------------------+
309| ``void``    | None                                                 |
310+-------------+------------------------------------------------------+
311
312The implementation should be decoupled from TF-M current isolation level or
313access check policy.
314
315All the fields in ``security_attr_info_t`` shall be explicitly set in
316``tfm_hal_get_mem_security_attr()``.
317
318If the target memory region crosses boundaries of different security regions or levels in security
319isolation configuration, ``tfm_hal_get_mem_security_attr()`` should determine whether the memory
320region violates current security isolation.
321It is recommended to mark the target memory region as invalid in such case, even if the adjoining
322regions or levels have the same security configuration.
323
324If the target memory region is not explicitly specified in memory security configuration,
325``tfm_hal_get_mem_security_attr()`` can return the following values according to actual use case:
326
327- Either set ``is_valid = false``
328- Or set ``is_valid = true`` and set ``is_secure`` according to platform specific policy.
329
330``tfm_hal_get_secure_access_attr()``
331----------------------------------------
332
333``tfm_hal_get_secure_access_attr()`` retrieves the secure memory protection configuration
334information and fills the ``mem_attr_info_t``.
335
336.. code-block:: c
337
338    void tfm_hal_get_secure_access_attr(const void *p, size_t s,
339                                        struct mem_attr_info_t *p_attr);
340
341+--------------------------------------------------------------+
342| **Parameters**                                               |
343+------------+-------------------------------------------------+
344| ``p``      | Base address of the target memory region        |
345+------------+-------------------------------------------------+
346| ``s``      | Size of the target memory region                |
347+------------+-------------------------------------------------+
348| ``p_attr`` | Pointer to the ``mem_attr_info_t`` to be filled |
349+------------+-------------------------------------------------+
350| **Return**                                                   |
351+------------+-------------------------------------------------+
352| ``void``   | None                                            |
353+------------+-------------------------------------------------+
354
355The implementation should be decoupled from TF-M current isolation level or
356access check policy.
357
358All the fields in ``mem_attr_info_t`` shall be explicitly set in
359``tfm_hal_get_secure_access_attr()``, according to current active memory protection configuration.
360It is recommended to retrieve the attributes from secure MPU and other hardware memory protection
361unit(s). The implementation can also be simplified by checking static system-level memory layout.
362
363If the target memory region is not specified in current active secure memory protection
364configuration, ``tfm_hal_get_secure_access_attr()`` can select the following values according to
365actual use case.
366
367- Either directly set ``is_valid`` to ``false``
368- Or set ``is_valid`` to ``true`` and set other fields according to other memory assignment
369  information, such as static system-level memory layout.
370
371If secure memory protection unit(s) is *disabled* and the target memory region is a valid area
372according to platform resource assignment, ``tfm_hal_get_secure_access_attr()`` must set
373``is_mpu_enabled`` to ``false`` and set other fields according to current system-level memory
374layout.
375
376``tfm_hal_get_ns_access_attr()``
377--------------------------------
378
379``tfm_hal_get_ns_access_attr()`` retrieves the non-secure memory protection configuration
380information and fills the ``mem_attr_info_t``.
381
382.. code-block:: c
383
384    void tfm_hal_get_ns_access_attr(const void *p, size_t s,
385                                    struct mem_attr_info_t *p_attr);
386
387+--------------------------------------------------------------+
388| **Parameters**                                               |
389+------------+-------------------------------------------------+
390| ``p``      | Base address of the target memory region        |
391+------------+-------------------------------------------------+
392| ``s``      | Size of the target memory region                |
393+------------+-------------------------------------------------+
394| ``p_attr`` | Pointer to the ``mem_attr_info_t`` to be filled |
395+------------+-------------------------------------------------+
396| **Return**                                                   |
397+------------+-------------------------------------------------+
398| ``void``   | None                                            |
399+------------+-------------------------------------------------+
400
401The implementation should be decoupled from TF-M current isolation level or
402access check policy.
403
404Since non-secure core runs asynchronously, the non-secure MPU setting may be modified by NSPE OS and
405therefore the attributes of the target memory region can be unavailable during
406``tfm_hal_get_ns_access_attr()`` execution in TF-M.
407When the target memory region is not specified in non-secure MPU, ``tfm_hal_get_ns_access_attr()``
408can set the fields according to other memory setting information, such as static system-level memory
409layout.
410
411If non-secure memory protection unit(s) is *disabled* and the target memory region is a valid area
412according to platform resource assignment, ``tfm_hal_get_ns_access_attr()`` can set the following
413fields in ``mem_attr_info_t`` to default values:
414
415- ``is_mpu_enabled = false``
416- ``is_valid = true``
417- ``is_xn = true``
418- ``is_priv_rd_allow = true``
419- ``is_unpriv_rd_allow = true``
420
421``is_priv_wr_allow`` and ``is_unpriv_wr_allow`` can be set according to current system-level memory
422layout, such as whether it is in code section or data section.
423
424General retrieval functions
425===========================
426
427TF-M implements 3 general retrieval functions to retrieve memory region security attributes or
428memory protection configurations, based on static system-level memory layout. Platform specific HAL
429functions can invoke those 3 general functions to simplify implementations.
430
431- ``tfm_get_mem_region_security_attr()`` retrieves general security attributes from static
432  system-level memory layout.
433- ``tfm_get_secure_mem_region_attr()`` retrieves general secure memory protection configurations
434  from static system-level memory layout.
435- ``tfm_get_ns_mem_region_attr()`` retrieves general non-secure memory protection configurations
436  from static system-level memory layout.
437
438If a multi-core platform's memory layout may vary in runtime, it shall not rely on these 3 functions
439to retrieve static configurations.
440These 3 functions run through memory layout table to check against each memory section one by one,
441with pure software implementation. It might cost more time compared to hardware-based memory access
442check.
443
444``tfm_get_mem_region_security_attr()``
445--------------------------------------
446
447``tfm_get_mem_region_security_attr()`` retrieves security attributes of target memory region
448according to the static system-level memory layout and fills the ``security_attr_info_t``.
449
450.. code-block:: c
451
452    void tfm_get_mem_region_security_attr(const void *p, size_t s,
453                                          struct security_attr_info_t *p_attr);
454
455+--------------------------------------------------------------------+
456| **Parameters**                                                     |
457+-------------+------------------------------------------------------+
458| ``p``       | Base address of the target memory region             |
459+-------------+------------------------------------------------------+
460| ``s``       | Size of the target memory region                     |
461+-------------+------------------------------------------------------+
462| ``p_attr``  | Pointer to the ``security_attr_info_t`` to be filled |
463+-------------+------------------------------------------------------+
464| **Return**                                                         |
465+-------------+------------------------------------------------------+
466| ``void``    | None                                                 |
467+-------------+------------------------------------------------------+
468
469``tfm_get_secure_mem_region_attr()``
470------------------------------------
471
472``tfm_get_secure_mem_region_attr()`` retrieves general secure memory protection configuration
473information of the target memory region according to the static system-level memory layout and fills
474the ``mem_attr_info_t``.
475
476.. code-block:: c
477
478    void tfm_get_secure_mem_region_attr(const void *p, size_t s,
479                                        struct mem_attr_info_t *p_attr);
480
481+--------------------------------------------------------------+
482| **Parameters**                                               |
483+------------+-------------------------------------------------+
484| ``p``      | Base address of the target memory region        |
485+------------+-------------------------------------------------+
486| ``s``      | Size of the target memory region                |
487+------------+-------------------------------------------------+
488| ``p_attr`` | Pointer to the ``mem_attr_info_t`` to be filled |
489+------------+-------------------------------------------------+
490| **Return**                                                   |
491+------------+-------------------------------------------------+
492| ``void``   | None                                            |
493+------------+-------------------------------------------------+
494
495``tfm_get_ns_mem_region_attr()``
496--------------------------------
497
498``tfm_get_ns_mem_region_attr()`` retrieves general non-secure memory protection configuration
499information of the target memory region according to the static system-level memory layout and fills
500the ``mem_attr_info_t``.
501
502.. code-block:: c
503
504    void tfm_get_ns_mem_region_attr(const void *p, size_t s,
505                                    struct mem_attr_info_t *p_attr);
506
507+--------------------------------------------------------------+
508| **Parameters**                                               |
509+------------+-------------------------------------------------+
510| ``p``      | Base address of the target memory region        |
511+------------+-------------------------------------------------+
512| ``s``      | Size of the target memory region                |
513+------------+-------------------------------------------------+
514| ``p_attr`` | Pointer to the ``mem_attr_info_t`` to be filled |
515+------------+-------------------------------------------------+
516| **Return**                                                   |
517+------------+-------------------------------------------------+
518| ``void``   | None                                            |
519+------------+-------------------------------------------------+
520
521--------------
522
523*Copyright (c) 2019-2024, Arm Limited. All rights reserved.*
524