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