Skip to content

Commit b91d21d

Browse files
carlocaionecarlescufi
authored andcommitted
dt: mpu: Generate MPU regions from DT nodes
Currently the only way for a BOARD/SOC to configure at compile time the MPU regions is to add, in a soc-specific file, the 'mpu_config' struct adding static entries for the new regions with the needed attributes (cacheable, non-cacheable, etc...). This exported struct is then read by the MPU driver at boot time and used to properly setup the MPU regions. At the same time it is now possible to introduce new memory regions in the DT using the newly introduced 'zephyr,memory-region' attribute. What is missing is the link between these two solutions: that is how to declare the memory regions in the DT and automatically configure these regions in the MPU with the correct attributes. This patch is trying to address exactly this problem. It is now possible to declare the memory regions in the DT and define the MPU attributes for the regions using the 'zephyr,memory-region-mpu' property. When this new property is present together with the 'zephyr,memory-region' property and a the 'zephyr,memory-region' compatible, the 'mpu_config' struct is automatically extended at compile-time to host the DT defined regions with the correct MPU attributes. So for example in the DT we can now have: sram_cache: memory@20200000 { compatible = "zephyr,memory-region", "mmio-sram"; reg = <0x20200000 0x100000>; zephyr,memory-region = "SRAM_CACHE"; zephyr,memory-region-mpu = "RAM"; }; and a new region will be created called "SRAM_CACHE" and a new MPU region will be configure at boot time with the attribute "REGION_RAM_ATTR". Signed-off-by: Carlo Caione <[email protected]>
1 parent e4aed1c commit b91d21d

File tree

5 files changed

+197
-0
lines changed

5 files changed

+197
-0
lines changed

doc/guides/arch/arm_cortex_m.rst

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -440,12 +440,45 @@ are programmed during system boot.
440440
SRAM. (An exception to this setting is when :kconfig:option:`CONFIG_MPU_GAP_FILLING` is disabled (Arm v8-M only);
441441
in that case no SRAM MPU programming is done so the access is determined by the default
442442
Arm memory map policies, allowing for privileged-only RWX permissions on SRAM).
443+
* All the memory regions defined in the devicetree with the compatible
444+
:dtcompatible:`zephyr,memory-region` and at least the property
445+
``zephyr,memory-region-mpu`` defining the MPU permissions for the memory region.
446+
See the next section for more details.
443447

444448
The above MPU regions are defined in :file:`soc/arm/common/arm_mpu_regions.c`.
445449
Alternative MPU configurations are allowed by enabling :kconfig:option:`CONFIG_CPU_HAS_CUSTOM_FIXED_SOC_MPU_REGIONS`.
446450
When enabled, this option signifies that the Cortex-M SoC will define and
447451
configure its own fixed MPU regions in the SoC definition.
448452

453+
Fixed MPU regions defined in devicetree
454+
---------------------------------------
455+
456+
The user can define memory regions to be allocated and created in the linker
457+
script using nodes with the :dtcompatible:`zephyr,memory-region` devicetree
458+
compatible. When the property ``zephyr,memory-region-mpu`` is present in such
459+
a node, a new MPU region will be allocated and programmed during system
460+
boot.
461+
462+
The property ``zephyr,memory-region-mpu`` is a string carrying the attributes
463+
for the MPU region. It is converted to a C token for use defining the attributes
464+
of the MPU region.
465+
466+
For example, to define a new non-cacheable memory region in devicetree:
467+
468+
.. code-block:: devicetree
469+
470+
sram_no_cache: memory@20300000 {
471+
compatible = "zephyr,memory-region", "mmio-sram";
472+
reg = <0x20300000 0x100000>;
473+
zephyr,memory-region = "SRAM_NO_CACHE";
474+
zephyr,memory-region-mpu = "RAM_NOCACHE";
475+
};
476+
477+
This will automatically create a new MPU entry in
478+
:zephyr_file:`soc/arm/common/arm_mpu_regions.c` with the correct name, base,
479+
size and attributes gathered directly from the devicetree. See
480+
:zephyr_file:`include/linker/devicetree_regions.h` for more details.
481+
449482
Static MPU regions
450483
------------------
451484

dts/bindings/base/zephyr,memory-region.yaml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,15 @@ properties:
1616
memory region in the final executable. The region address and size
1717
is taken from the <reg> property, while the name is the value of
1818
this property.
19+
20+
zephyr,memory-region-mpu:
21+
type: string
22+
required: false
23+
enum:
24+
- "RAM"
25+
- "RAM_NOCACHE"
26+
- "FLASH"
27+
description: |
28+
Signify that this node should result in a dedicated MPU region. The
29+
region address and size are taken from the <reg> property, while the MPU
30+
attribute is the value of this property.

include/linker/devicetree_regions.h

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,8 @@
8585
#define _DT_SECTION_SIZE(node_id) UTIL_CAT(_DT_SECTION_PREFIX(node_id), _size)
8686
#define _DT_SECTION_LOAD(node_id) UTIL_CAT(_DT_SECTION_PREFIX(node_id), _load_start)
8787

88+
#define _DT_ATTR(token) UTIL_CAT(UTIL_CAT(REGION_, token), _ATTR)
89+
8890
/**
8991
* @brief Declare a memory region
9092
*
@@ -153,6 +155,35 @@
153155
_DT_SECTION_SIZE(node_id) = _DT_SECTION_END(node_id) - _DT_SECTION_START(node_id); \
154156
_DT_SECTION_LOAD(node_id) = LOADADDR(LINKER_DT_NODE_REGION_NAME_TOKEN(node_id));
155157

158+
/**
159+
* Call the user-provided MPU_FN() macro passing the expected arguments
160+
*/
161+
#define _EXPAND_MPU_FN(node_id, MPU_FN, ...) \
162+
MPU_FN(LINKER_DT_NODE_REGION_NAME(node_id), \
163+
DT_REG_ADDR(node_id), \
164+
DT_REG_SIZE(node_id), \
165+
_DT_ATTR(DT_STRING_TOKEN(node_id, zephyr_memory_region_mpu))),
166+
167+
/**
168+
* Check that the node_id has both properties:
169+
* - zephyr,memory-region-mpu
170+
* - zephyr,memory-region
171+
*
172+
* and call the EXPAND_MPU_FN() macro
173+
*/
174+
#define _CHECK_ATTR_FN(node_id, EXPAND_MPU_FN, ...) \
175+
COND_CODE_1(UTIL_AND(DT_NODE_HAS_PROP(node_id, zephyr_memory_region_mpu), \
176+
DT_NODE_HAS_PROP(node_id, zephyr_memory_region)), \
177+
(EXPAND_MPU_FN(node_id, __VA_ARGS__)), \
178+
())
179+
180+
/**
181+
* Call _CHECK_ATTR_FN() for each enabled node passing EXPAND_MPU_FN() as
182+
* explicit argument and the user-provided MPU_FN() macro in __VA_ARGS__
183+
*/
184+
#define _CHECK_APPLY_FN(compat, EXPAND_MPU_FN, ...) \
185+
DT_FOREACH_STATUS_OKAY_VARGS(compat, _CHECK_ATTR_FN, EXPAND_MPU_FN, __VA_ARGS__)
186+
156187
/** @endcond */
157188

158189
/**
@@ -172,3 +203,78 @@
172203
*/
173204
#define LINKER_DT_SECTIONS() \
174205
DT_FOREACH_STATUS_OKAY(_DT_COMPATIBLE, _SECTION_DECLARE)
206+
207+
/**
208+
* @brief Generate MPU regions from the device tree nodes with compatible
209+
* 'zephyr,memory-region' and 'zephyr,memory-region-mpu' attribute.
210+
*
211+
* Helper macro to apply an MPU_FN macro to all the memory regions declared
212+
* using the 'zephyr,memory-region-mpu' property and the 'zephyr,memory-region'
213+
* compatible.
214+
*
215+
* @p MPU_FN must take the form:
216+
*
217+
* @code{.c}
218+
* #define MPU_FN(name, base, size, attr) ...
219+
* @endcode
220+
*
221+
* The 'name', 'base' and 'size' parameters are taken from the DT node.
222+
*
223+
* The 'zephyr,memory-region-mpu' enum property is passed as an extended token
224+
* to the MPU_FN macro using the 'attr' parameter, in the form
225+
* REGION_{attr}_ATTR.
226+
*
227+
* Currently only three enums are supported for the 'zephyr,memory-region-mpu'
228+
* property:
229+
*
230+
* - RAM
231+
* - RAM_NOCACHE
232+
* - FLASH
233+
*
234+
* This means that usually the arch code would provide some macros or defines
235+
* with the same name of the extended property, that is:
236+
*
237+
* - REGION_RAM_ATTR
238+
* - REGION_RAM_NOCACHE_ATTR
239+
* - REGION_FLASH_ATTR
240+
*
241+
* Example devicetree fragment:
242+
*
243+
* / {
244+
* soc {
245+
* sram1: memory@2000000 {
246+
* zephyr,memory-region = "MY_NAME";
247+
* zephyr,memory-region-mpu = "RAM_NOCACHE";
248+
* };
249+
* };
250+
* };
251+
*
252+
* The 'attr' parameter of the MPU_FN function will be the extended
253+
* 'REGION_RAM_NOCACHE_ATTR' token and the arch code will be usually
254+
* implementing a macro with the same name.
255+
*
256+
* Example:
257+
*
258+
* @code{.c}
259+
*
260+
* #define REGION_RAM_NOCACHE_ATTR 0xAAAA
261+
* #define REGION_RAM_ATTR 0xBBBB
262+
* #define REGION_FLASH_ATTR 0xCCCC
263+
*
264+
* #define MPU_FN(p_name, p_base, p_size, p_attr) \
265+
* { \
266+
* .name = p_name, \
267+
* .base = p_base, \
268+
* .size = p_size, \
269+
* .attr = p_attr, \
270+
* }
271+
*
272+
* static const struct arm_mpu_region mpu_regions[] = {
273+
* ...
274+
* LINKER_DT_REGION_MPU(MPU_FN)
275+
* ...
276+
* };
277+
* @endcode
278+
*
279+
*/
280+
#define LINKER_DT_REGION_MPU(mpu_fn) _CHECK_APPLY_FN(_DT_COMPATIBLE, _EXPAND_MPU_FN, mpu_fn)

soc/arm/common/cortex_m/arm_mpu_mem_cfg.h

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,48 @@
6666
#error "Unsupported sram size configuration"
6767
#endif
6868

69+
#define MPU_REGION_SIZE_32 REGION_32B
70+
#define MPU_REGION_SIZE_64 REGION_64B
71+
#define MPU_REGION_SIZE_128 REGION_128B
72+
#define MPU_REGION_SIZE_256 REGION_256B
73+
#define MPU_REGION_SIZE_512 REGION_512B
74+
#define MPU_REGION_SIZE_1024 REGION_1K
75+
#define MPU_REGION_SIZE_2048 REGION_2K
76+
#define MPU_REGION_SIZE_4096 REGION_4K
77+
#define MPU_REGION_SIZE_8192 REGION_8K
78+
#define MPU_REGION_SIZE_16384 REGION_16K
79+
#define MPU_REGION_SIZE_32768 REGION_32K
80+
#define MPU_REGION_SIZE_65536 REGION_64K
81+
#define MPU_REGION_SIZE_131072 REGION_128K
82+
#define MPU_REGION_SIZE_262144 REGION_256K
83+
#define MPU_REGION_SIZE_524288 REGION_512K
84+
#define MPU_REGION_SIZE_1048576 REGION_1M
85+
#define MPU_REGION_SIZE_2097152 REGION_2M
86+
#define MPU_REGION_SIZE_4194304 REGION_4M
87+
#define MPU_REGION_SIZE_8388608 REGION_8M
88+
#define MPU_REGION_SIZE_16777216 REGION_16M
89+
#define MPU_REGION_SIZE_33554432 REGION_32M
90+
#define MPU_REGION_SIZE_67108864 REGION_64M
91+
#define MPU_REGION_SIZE_134217728 REGION_128M
92+
#define MPU_REGION_SIZE_268435456 REGION_256M
93+
#define MPU_REGION_SIZE_536870912 REGION_512M
94+
95+
#define MPU_REGION_SIZE(x) MPU_REGION_SIZE_ ## x
96+
97+
#define ARM_MPU_REGION_INIT(p_name, p_base, p_size, p_attr) \
98+
{ .name = p_name, \
99+
.base = p_base, \
100+
.attr = p_attr(MPU_REGION_SIZE(p_size)), \
101+
}
102+
103+
#else
104+
105+
#define ARM_MPU_REGION_INIT(p_name, p_base, p_size, p_attr) \
106+
{ .name = p_name, \
107+
.base = p_base, \
108+
.attr = p_attr(p_base, p_size), \
109+
}
110+
69111
#endif /* !ARMV8_M_BASELINE && !ARMV8_M_MAINLINE */
70112

71113
#endif /* _ARM_CORTEX_M_MPU_MEM_CFG_H_ */

soc/arm/common/cortex_m/arm_mpu_regions.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
#include <sys/slist.h>
88
#include <arch/arm/aarch32/mpu/arm_mpu.h>
9+
#include <linker/devicetree_regions.h>
910

1011
#include "arm_mpu_mem_cfg.h"
1112

@@ -28,6 +29,9 @@ static const struct arm_mpu_region mpu_regions[] = {
2829
#else
2930
REGION_RAM_ATTR(REGION_SRAM_SIZE)),
3031
#endif
32+
33+
/* DT-defined regions */
34+
LINKER_DT_REGION_MPU(ARM_MPU_REGION_INIT)
3135
};
3236

3337
const struct arm_mpu_config mpu_config = {

0 commit comments

Comments
 (0)