| .. _mem_mgmt_api: |
| |
| Memory Attributes |
| ################# |
| |
| It is possible in the devicetree to mark the memory regions with attributes by |
| using the ``zephyr,memory-attr`` property. This property and the related memory |
| region can then be retrieved at run-time by leveraging a provided helper |
| library. |
| |
| The set of general attributes that can be specified in the property are defined |
| and explained in :zephyr_file:`include/zephyr/dt-bindings/memory-attr/memory-attr.h`. |
| |
| For example, to mark a memory region in the devicetree as non-volatile, cacheable, |
| out-of-order: |
| |
| .. code-block:: devicetree |
| |
| mem: memory@10000000 { |
| compatible = "mmio-sram"; |
| reg = <0x10000000 0x1000>; |
| zephyr,memory-attr = <( DT_MEM_NON_VOLATILE | DT_MEM_CACHEABLE | DT_MEM_OOO )>; |
| }; |
| |
| .. note:: |
| |
| The ``zephyr,memory-attr`` usage does not result in any memory region |
| actually created. When it is needed to create an actual section out of the |
| devicetree defined memory region, it is possible to use the compatible |
| :dtcompatible:`zephyr,memory-region` that will result (only when supported |
| by the architecture) in a new linker section and region. |
| |
| The ``zephyr,memory-attr`` property can also be used to set |
| architecture-specific and software-specific custom attributes that can be |
| interpreted at run time. This is leveraged, among other things, to create MPU |
| regions out of devicetree defined memory regions, for example: |
| |
| .. code-block:: devicetree |
| |
| mem: memory@10000000 { |
| compatible = "mmio-sram"; |
| reg = <0x10000000 0x1000>; |
| zephyr,memory-region = "NOCACHE_REGION"; |
| zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_RAM_NOCACHE) )>; |
| }; |
| |
| See :zephyr_file:`include/zephyr/dt-bindings/memory-attr/memory-attr-arm.h` and |
| :ref:`arm_cortex_m_developer_guide` for more details about MPU usage. |
| |
| The conventional and recommended way to deal and manage with memory regions |
| marked with attributes is by using the provided ``mem-attr`` helper library by |
| enabling :kconfig:option:`CONFIG_MEM_ATTR`. When this option is enabled the |
| list of memory regions and their attributes are compiled in a user-accessible |
| array and a set of functions is made available that can be used to query, probe |
| and act on regions and attributes (see next section for more details). |
| |
| .. note:: |
| |
| The ``zephyr,memory-attr`` property is only a descriptive property of the |
| capabilities of the associated memory region, but it does not result in any |
| actual setting for the memory to be set. The user, code or subsystem willing |
| to use this information to do some work (for example creating an MPU region |
| out of the property) must use either the provided ``mem-attr`` library or |
| the usual devicetree helpers to perform the required work / setting. |
| |
| A test for the ``mem-attr`` library and its usage is provided in |
| ``tests/subsys/mem_mgmt/mem_attr/``. |
| |
| Migration guide from `zephyr,memory-region-mpu` |
| *********************************************** |
| |
| When the ``zephyr,memory-attr`` property was introduced, the |
| ``zephyr,memory-region-mpu`` property was removed and deprecated. |
| |
| The developers that are still using the deprecated property can move to the new |
| one by renaming the property and changing its value according to the following list: |
| |
| .. code-block:: none |
| |
| "RAM" -> <( DT_ARM_MPU(ATTR_MPU_RAM) )> |
| "RAM_NOCACHE" -> <( DT_ARM_MPU(ATTR_MPU_RAM_NOCACHE) )> |
| "FLASH" -> <( DT_ARM_MPU(ATTR_MPU_FLASH) )> |
| "PPB" -> <( DT_ARM_MPU(ATTR_MPU_PPB) )> |
| "IO" -> <( DT_ARM_MPU(ATTR_MPU_IO) )> |
| "EXTMEM" -> <( DT_ARM_MPU(ATTR_MPU_EXTMEM) )> |
| |
| Memory Attributes Heap Allocator |
| ******************************** |
| |
| It is possible to leverage the memory attribute property ``zephyr,memory-attr`` |
| to define and create a set of memory heaps from which the user can allocate |
| memory from with certain attributes / capabilities. |
| |
| When the :kconfig:option:`CONFIG_MEM_ATTR_HEAP` is set, every region marked |
| with one of the memory attributes listed in in |
| :zephyr_file:`include/zephyr/dt-bindings/memory-attr/memory-attr-sw.h` is added |
| to a pool of memory heaps used for dynamic allocation of memory buffers with |
| certain attributes. |
| |
| Here a non exhaustive list of possible attributes: |
| |
| .. code-block:: none |
| |
| DT_MEM_SW_ALLOC_CACHE |
| DT_MEM_SW_ALLOC_NON_CACHE |
| DT_MEM_SW_ALLOC_DMA |
| |
| For example we can define several memory regions with different attributes and |
| use the appropriate attribute to indicate that it is possible to dynamically |
| allocate memory from those regions: |
| |
| .. code-block:: devicetree |
| |
| mem_cacheable: memory@10000000 { |
| compatible = "mmio-sram"; |
| reg = <0x10000000 0x1000>; |
| zephyr,memory-attr = <( DT_MEM_CACHEABLE | DT_MEM_SW_ALLOC_CACHE )>; |
| }; |
| |
| mem_non_cacheable: memory@20000000 { |
| compatible = "mmio-sram"; |
| reg = <0x20000000 0x1000>; |
| zephyr,memory-attr = <( DT_MEM_NON_CACHEABLE | ATTR_SW_ALLOC_NON_CACHE )>; |
| }; |
| |
| mem_cacheable_big: memory@30000000 { |
| compatible = "mmio-sram"; |
| reg = <0x30000000 0x10000>; |
| zephyr,memory-attr = <( DT_MEM_CACHEABLE | DT_MEM_OOO | DT_MEM_SW_ALLOC_CACHE )>; |
| }; |
| |
| mem_cacheable_dma: memory@40000000 { |
| compatible = "mmio-sram"; |
| reg = <0x40000000 0x10000>; |
| zephyr,memory-attr = <( DT_MEM_CACHEABLE | DT_MEM_DMA | |
| DT_MEM_SW_ALLOC_CACHE | DT_MEM_SW_ALLOC_DMA )>; |
| }; |
| |
| The user can then dynamically carve memory out of those regions using the |
| provided functions, the library will take care of allocating memory from the |
| correct heap depending on the provided attribute and size: |
| |
| .. code-block:: c |
| |
| // Init the pool |
| mem_attr_heap_pool_init(); |
| |
| // Allocate 0x100 bytes of cacheable memory from `mem_cacheable` |
| block = mem_attr_heap_alloc(DT_MEM_SW_ALLOC_CACHE, 0x100); |
| |
| // Allocate 0x200 bytes of non-cacheable memory aligned to 32 bytes |
| // from `mem_non_cacheable` |
| block = mem_attr_heap_aligned_alloc(ATTR_SW_ALLOC_NON_CACHE, 0x100, 32); |
| |
| // Allocate 0x100 bytes of cacheable and dma-able memory from `mem_cacheable_dma` |
| block = mem_attr_heap_alloc(DT_MEM_SW_ALLOC_CACHE | DT_MEM_SW_ALLOC_DMA, 0x100); |
| |
| When several regions are marked with the same attributes, the memory is allocated: |
| |
| 1. From the regions where the ``zephyr,memory-attr`` property has the requested |
| property (or properties). |
| |
| 2. Among the regions as at point 1, from the smallest region if there is any |
| unallocated space left for the requested size |
| |
| 3. If there is not enough space, from the next bigger region able to |
| accommodate the requested size |
| |
| The following example shows the point 3: |
| |
| .. code-block:: c |
| |
| // This memory is allocated from `mem_non_cacheable` |
| block = mem_attr_heap_alloc(DT_MEM_SW_ALLOC_CACHE, 0x100); |
| |
| // This memory is allocated from `mem_cacheable_big` |
| block = mem_attr_heap_alloc(DT_MEM_SW_ALLOC_CACHE, 0x5000); |
| |
| .. note:: |
| |
| The framework is assuming that the memory regions used to create the heaps |
| are usable by the code and available at init time. The user must take of |
| initializing and setting the memory area before calling |
| :c:func:`mem_attr_heap_pool_init`. |
| |
| That means that the region must be correctly configured in terms of MPU / |
| MMU (if needed) and that an actual heap can be created out of it, for |
| example by leveraging the ``zephyr,memory-region`` property to create a |
| proper linker section to accommodate the heap. |
| |
| API Reference |
| ************* |
| |
| .. doxygengroup:: memory_attr_interface |
| .. doxygengroup:: memory_attr_heap |