1.. _mem_mgmt_api:
2
3Memory Attributes
4#################
5
6It is possible in the devicetree to mark the memory regions with attributes by
7using the ``zephyr,memory-attr`` property. This property and the related memory
8region can then be retrieved at run-time by leveraging a provided helper
9library.
10
11The set of general attributes that can be specified in the property are defined
12and explained in :zephyr_file:`include/zephyr/dt-bindings/memory-attr/memory-attr.h`.
13
14For example, to mark a memory region in the devicetree as non-volatile, cacheable,
15out-of-order:
16
17.. code-block:: devicetree
18
19   mem: memory@10000000 {
20       compatible = "mmio-sram";
21       reg = <0x10000000 0x1000>;
22       zephyr,memory-attr = <( DT_MEM_NON_VOLATILE | DT_MEM_CACHEABLE | DT_MEM_OOO )>;
23   };
24
25.. note::
26
27   The ``zephyr,memory-attr`` usage does not result in any memory region
28   actually created. When it is needed to create an actual section out of the
29   devicetree defined memory region, it is possible to use the compatible
30   :dtcompatible:`zephyr,memory-region` that will result (only when supported
31   by the architecture) in a new linker section and region.
32
33The ``zephyr,memory-attr`` property can also be used to set
34architecture-specific and software-specific custom attributes that can be
35interpreted at run time. This is leveraged, among other things, to create MPU
36regions out of devicetree defined memory regions, for example:
37
38.. code-block:: devicetree
39
40   mem: memory@10000000 {
41       compatible = "mmio-sram";
42       reg = <0x10000000 0x1000>;
43       zephyr,memory-region = "NOCACHE_REGION";
44       zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_RAM_NOCACHE) )>;
45   };
46
47See :zephyr_file:`include/zephyr/dt-bindings/memory-attr/memory-attr-arm.h` and
48:ref:`arm_cortex_m_developer_guide` for more details about MPU usage.
49
50The conventional and recommended way to deal and manage with memory regions
51marked with attributes is by using the provided ``mem-attr`` helper library by
52enabling :kconfig:option:`CONFIG_MEM_ATTR`. When this option is enabled the
53list of memory regions and their attributes are compiled in a user-accessible
54array and a set of functions is made available that can be used to query, probe
55and act on regions and attributes (see next section for more details).
56
57.. note::
58
59   The ``zephyr,memory-attr`` property is only a descriptive property of the
60   capabilities of the associated memory region, but it does not result in any
61   actual setting for the memory to be set. The user, code or subsystem willing
62   to use this information to do some work (for example creating an MPU region
63   out of the property) must use either the provided ``mem-attr`` library or
64   the usual devicetree helpers to perform the required work / setting.
65
66A test for the ``mem-attr`` library and its usage is provided in
67``tests/subsys/mem_mgmt/mem_attr/``.
68
69Migration guide from `zephyr,memory-region-mpu`
70***********************************************
71
72When the ``zephyr,memory-attr`` property was introduced, the
73``zephyr,memory-region-mpu`` property was removed and deprecated.
74
75The developers that are still using the deprecated property can move to the new
76one by renaming the property and changing its value according to the following list:
77
78.. code-block:: none
79
80   "RAM"         -> <( DT_ARM_MPU(ATTR_MPU_RAM) )>
81   "RAM_NOCACHE" -> <( DT_ARM_MPU(ATTR_MPU_RAM_NOCACHE) )>
82   "FLASH"       -> <( DT_ARM_MPU(ATTR_MPU_FLASH) )>
83   "PPB"         -> <( DT_ARM_MPU(ATTR_MPU_PPB) )>
84   "IO"          -> <( DT_ARM_MPU(ATTR_MPU_IO) )>
85   "EXTMEM"      -> <( DT_ARM_MPU(ATTR_MPU_EXTMEM) )>
86
87Memory Attributes Heap Allocator
88********************************
89
90It is possible to leverage the memory attribute property ``zephyr,memory-attr``
91to define and create a set of memory heaps from which the user can allocate
92memory from with certain attributes / capabilities.
93
94When the :kconfig:option:`CONFIG_MEM_ATTR_HEAP` is set, every region marked
95with one of the memory attributes listed in in
96:zephyr_file:`include/zephyr/dt-bindings/memory-attr/memory-attr-sw.h` is added
97to a pool of memory heaps used for dynamic allocation of memory buffers with
98certain attributes.
99
100Here a non exhaustive list of possible attributes:
101
102.. code-block:: none
103
104   DT_MEM_SW_ALLOC_CACHE
105   DT_MEM_SW_ALLOC_NON_CACHE
106   DT_MEM_SW_ALLOC_DMA
107
108For example we can define several memory regions with different attributes and
109use the appropriate attribute to indicate that it is possible to dynamically
110allocate memory from those regions:
111
112.. code-block:: devicetree
113
114   mem_cacheable: memory@10000000 {
115       compatible = "mmio-sram";
116       reg = <0x10000000 0x1000>;
117       zephyr,memory-attr = <( DT_MEM_CACHEABLE | DT_MEM_SW_ALLOC_CACHE )>;
118   };
119
120   mem_non_cacheable: memory@20000000 {
121       compatible = "mmio-sram";
122       reg = <0x20000000 0x1000>;
123       zephyr,memory-attr = <( DT_MEM_NON_CACHEABLE | ATTR_SW_ALLOC_NON_CACHE )>;
124   };
125
126   mem_cacheable_big: memory@30000000 {
127       compatible = "mmio-sram";
128       reg = <0x30000000 0x10000>;
129       zephyr,memory-attr = <( DT_MEM_CACHEABLE | DT_MEM_OOO | DT_MEM_SW_ALLOC_CACHE )>;
130   };
131
132   mem_cacheable_dma: memory@40000000 {
133       compatible = "mmio-sram";
134       reg = <0x40000000 0x10000>;
135       zephyr,memory-attr = <( DT_MEM_CACHEABLE      | DT_MEM_DMA |
136                               DT_MEM_SW_ALLOC_CACHE | DT_MEM_SW_ALLOC_DMA )>;
137   };
138
139The user can then dynamically carve memory out of those regions using the
140provided functions, the library will take care of allocating memory from the
141correct heap depending on the provided attribute and size:
142
143.. code-block:: c
144
145   // Init the pool
146   mem_attr_heap_pool_init();
147
148   // Allocate 0x100 bytes of cacheable memory from `mem_cacheable`
149   block = mem_attr_heap_alloc(DT_MEM_SW_ALLOC_CACHE, 0x100);
150
151   // Allocate 0x200 bytes of non-cacheable memory aligned to 32 bytes
152   // from `mem_non_cacheable`
153   block = mem_attr_heap_aligned_alloc(ATTR_SW_ALLOC_NON_CACHE, 0x100, 32);
154
155   // Allocate 0x100 bytes of cacheable and dma-able memory from `mem_cacheable_dma`
156   block = mem_attr_heap_alloc(DT_MEM_SW_ALLOC_CACHE | DT_MEM_SW_ALLOC_DMA, 0x100);
157
158When several regions are marked with the same attributes, the memory is allocated:
159
1601. From the regions where the ``zephyr,memory-attr`` property has the requested
161   property (or properties).
162
1632. Among the regions as at point 1, from the smallest region if there is any
164   unallocated space left for the requested size
165
1663. If there is not enough space, from the next bigger region able to
167   accommodate the requested size
168
169The following example shows the point 3:
170
171.. code-block:: c
172
173   // This memory is allocated from `mem_non_cacheable`
174   block = mem_attr_heap_alloc(DT_MEM_SW_ALLOC_CACHE, 0x100);
175
176   // This memory is allocated from `mem_cacheable_big`
177   block = mem_attr_heap_alloc(DT_MEM_SW_ALLOC_CACHE, 0x5000);
178
179.. note::
180
181    The framework is assuming that the memory regions used to create the heaps
182    are usable by the code and available at init time. The user must take of
183    initializing and setting the memory area before calling
184    :c:func:`mem_attr_heap_pool_init`.
185
186    That means that the region must be correctly configured in terms of MPU /
187    MMU (if needed) and that an actual heap can be created out of it, for
188    example by leveraging the ``zephyr,memory-region`` property to create a
189    proper linker section to accommodate the heap.
190
191API Reference
192*************
193
194.. doxygengroup:: memory_attr_interface
195.. doxygengroup:: memory_attr_heap
196