Skip to content

Commit e4a125b

Browse files
carlocaionecarlescufi
authored andcommitted
dt: Make zephyr,memory-attr a capabilities bitmask
This is the final step in making the `zephyr,memory-attr` property actually useful. The problem with the current implementation is that `zephyr,memory-attr` is an enum type, this is making very difficult to use that to actually describe the memory capabilities. The solution proposed in this PR is to use the `zephyr,memory-attr` property as an OR-ed bitmask of memory attributes. With the change proposed in this PR it is possible in the DeviceTree to mark the memory regions with a bitmask of 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 or the usual DT helpers. The set of general attributes that can be specified in the property are defined and explained in `include/zephyr/dt-bindings/memory-attr/memory-attr.h` (the list can be extended when needed). For example, to mark a memory region in the DeviceTree as volatile, non-cacheable, out-of-order: mem: memory@10000000 { compatible = "mmio-sram"; reg = <0x10000000 0x1000>; zephyr,memory-attr = <( DT_MEM_VOLATILE | DT_MEM_NON_CACHEABLE | DT_MEM_OOO )>; }; The `zephyr,memory-attr` property can also be used to set architecture-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 on ARM, for example: mem: memory@10000000 { compatible = "mmio-sram"; reg = <0x10000000 0x1000>; zephyr,memory-region = "NOCACHE_REGION"; zephyr,memory-attr = <( DT_ARM_MPU(ATTR_MPU_RAM_NOCACHE) )>; }; See `include/zephyr/dt-bindings/memory-attr/memory-attr-mpu.h` to see how an architecture can define its own special memory attributes (in this case ARM MPU). The property can also be used to set custom software-specific attributes. For example we can think of marking a memory region as available to be used for memory allocation (not yet implemented): mem: memory@10000000 { compatible = "mmio-sram"; reg = <0x10000000 0x1000>; zephyr,memory-attr = <( DT_MEM_NON_CACHEABLE | DT_MEM_SW_ALLOCATABLE )>; }; Or maybe we can leverage the property to specify some alignment requirements for the region: mem: memory@10000000 { compatible = "mmio-sram"; reg = <0x10000000 0x1000>; zephyr,memory-attr = <( DT_MEM_CACHEABLE | DT_MEM_SW_ALIGN(32) )>; }; 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 `CONFIG_MEM_ATTR` (or by using the usual DT helpers). 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 `include/zephyr/mem_mgmt/mem_attr.h` Note that 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. Signed-off-by: Carlo Caione <[email protected]>
1 parent 7f04c35 commit e4a125b

File tree

72 files changed

+934
-515
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

72 files changed

+934
-515
lines changed

arch/arm/core/mpu/arm_mpu.c

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
#include "arm_core_mpu_dev.h"
1212
#include <zephyr/linker/linker-defs.h>
1313
#include <kernel_arch_data.h>
14+
#include <zephyr/mem_mgmt/mem_attr.h>
15+
#include <zephyr/dt-bindings/memory-attr/memory-attr-arm.h>
1416

1517
#define LOG_LEVEL CONFIG_MPU_LOG_LEVEL
1618
#include <zephyr/logging/log.h>
@@ -32,6 +34,13 @@ LOG_MODULE_DECLARE(mpu);
3234
#define NUM_MPU_REGIONS DT_PROP(MPU_NODEID, arm_num_mpu_regions)
3335
#endif
3436

37+
#define NODE_HAS_PROP_AND_OR(node_id, prop) \
38+
DT_NODE_HAS_PROP(node_id, prop) ||
39+
40+
BUILD_ASSERT((DT_FOREACH_STATUS_OKAY_NODE_VARGS(
41+
NODE_HAS_PROP_AND_OR, zephyr_memory_region_mpu) false) == false,
42+
"`zephyr,memory-region-mpu` was deprecated in favor of `zephyr,memory-attr`");
43+
3544
/*
3645
* Global status variable holding the number of HW MPU region indices, which
3746
* have been reserved by the MPU driver to program the static (fixed) memory
@@ -74,6 +83,79 @@ static int region_allocate_and_init(const uint8_t index,
7483
return index;
7584
}
7685

86+
#define _BUILD_REGION_CONF(reg, _ATTR) \
87+
(struct arm_mpu_region) ARM_MPU_REGION_INIT((reg).dt_name, \
88+
(reg).dt_addr, \
89+
(reg).dt_size, \
90+
_ATTR)
91+
92+
/* This internal function programs the MPU regions defined in the DT when using
93+
* the `zephyr,memory-attr = <( DT_MEM_ARM(...) )>` property.
94+
*/
95+
static int mpu_configure_regions_from_dt(uint8_t *reg_index)
96+
{
97+
const struct mem_attr_region_t *region;
98+
size_t num_regions;
99+
100+
num_regions = mem_attr_get_regions(&region);
101+
102+
for (size_t idx = 0; idx < num_regions; idx++) {
103+
struct arm_mpu_region region_conf;
104+
105+
switch (DT_MEM_ARM_MASK(region[idx].dt_attr)) {
106+
case DT_MEM_ARM_MPU_RAM:
107+
region_conf = _BUILD_REGION_CONF(region[idx], REGION_RAM_ATTR);
108+
break;
109+
#ifdef REGION_RAM_NOCACHE_ATTR
110+
case DT_MEM_ARM_MPU_RAM_NOCACHE:
111+
region_conf = _BUILD_REGION_CONF(region[idx], REGION_RAM_NOCACHE_ATTR);
112+
__ASSERT(!(region[idx].dt_attr & DT_MEM_CACHEABLE),
113+
"RAM_NOCACHE with DT_MEM_CACHEABLE attribute\n");
114+
break;
115+
#endif
116+
#ifdef REGION_FLASH_ATTR
117+
case DT_MEM_ARM_MPU_FLASH:
118+
region_conf = _BUILD_REGION_CONF(region[idx], REGION_FLASH_ATTR);
119+
break;
120+
#endif
121+
#ifdef REGION_PPB_ATTR
122+
case DT_MEM_ARM_MPU_PPB:
123+
region_conf = _BUILD_REGION_CONF(region[idx], REGION_PPB_ATTR);
124+
break;
125+
#endif
126+
#ifdef REGION_IO_ATTR
127+
case DT_MEM_ARM_MPU_IO:
128+
region_conf = _BUILD_REGION_CONF(region[idx], REGION_IO_ATTR);
129+
break;
130+
#endif
131+
#ifdef REGION_EXTMEM_ATTR
132+
case DT_MEM_ARM_MPU_EXTMEM:
133+
region_conf = _BUILD_REGION_CONF(region[idx], REGION_EXTMEM_ATTR);
134+
break;
135+
#endif
136+
default:
137+
/* Either the specified `ATTR_MPU_*` attribute does not
138+
* exists or the `REGION_*_ATTR` macro is not defined
139+
* for that attribute.
140+
*/
141+
LOG_ERR("Invalid attribute for the region\n");
142+
return -EINVAL;
143+
}
144+
#if defined(CONFIG_ARMV7_R)
145+
region_conf.size = size_to_mpu_rasr_size(region[idx].dt_size);
146+
#endif
147+
148+
if (region_allocate_and_init((*reg_index),
149+
(const struct arm_mpu_region *) &region_conf) < 0) {
150+
return -EINVAL;
151+
}
152+
153+
(*reg_index)++;
154+
}
155+
156+
return 0;
157+
}
158+
77159
/* This internal function programs an MPU region
78160
* of a given configuration at a given MPU index.
79161
*/
@@ -375,6 +457,11 @@ int z_arm_mpu_init(void)
375457
/* Update the number of programmed MPU regions. */
376458
static_regions_num = mpu_config.num_regions;
377459

460+
/* DT-defined MPU regions. */
461+
if (mpu_configure_regions_from_dt(&static_regions_num) == -EINVAL) {
462+
__ASSERT(0, "Failed to allocate MPU regions from DT\n");
463+
return -EINVAL;
464+
}
378465

379466
arm_core_mpu_enable();
380467

arch/arm/core/mpu/nxp_mpu.c

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,20 @@
1313
#include <zephyr/sys/math_extras.h>
1414
#include <zephyr/sys/barrier.h>
1515
#include <zephyr/linker/linker-defs.h>
16+
#include <zephyr/mem_mgmt/mem_attr.h>
17+
#include <zephyr/dt-bindings/memory-attr/memory-attr-arm.h>
1618

1719
#define LOG_LEVEL CONFIG_MPU_LOG_LEVEL
1820
#include <zephyr/logging/log.h>
1921
LOG_MODULE_DECLARE(mpu);
2022

23+
#define NODE_HAS_PROP_AND_OR(node_id, prop) \
24+
DT_NODE_HAS_PROP(node_id, prop) ||
25+
26+
BUILD_ASSERT((DT_FOREACH_STATUS_OKAY_NODE_VARGS(
27+
NODE_HAS_PROP_AND_OR, zephyr_memory_region_mpu) false) == false,
28+
"`zephyr,memory-region-mpu` was deprecated in favor of `zephyr,memory-attr`");
29+
2130
/*
2231
* Global status variable holding the number of HW MPU region indices, which
2332
* have been reserved by the MPU driver to program the static (fixed) memory
@@ -134,6 +143,60 @@ static int region_allocate_and_init(const uint8_t index,
134143
return index;
135144
}
136145

146+
#define _BUILD_REGION_CONF(reg, _ATTR) \
147+
(struct nxp_mpu_region) { .name = (reg).dt_name, \
148+
.base = (reg).dt_addr, \
149+
.end = (reg).dt_addr + (reg).dt_size, \
150+
.attr = _ATTR, \
151+
}
152+
153+
/* This internal function programs the MPU regions defined in the DT when using
154+
* the `zephyr,memory-attr = <( DT_MEM_ARM(...) )>` property.
155+
*/
156+
static int mpu_configure_regions_from_dt(uint8_t *reg_index)
157+
{
158+
const struct mem_attr_region_t *region;
159+
size_t num_regions;
160+
161+
num_regions = mem_attr_get_regions(&region);
162+
163+
for (size_t idx = 0; idx < num_regions; idx++) {
164+
struct nxp_mpu_region region_conf;
165+
166+
switch (DT_MEM_ARM_MASK(region[idx].dt_attr)) {
167+
case DT_MEM_ARM_MPU_RAM:
168+
region_conf = _BUILD_REGION_CONF(region[idx], REGION_RAM_ATTR);
169+
break;
170+
#ifdef REGION_FLASH_ATTR
171+
case DT_MEM_ARM_MPU_FLASH:
172+
region_conf = _BUILD_REGION_CONF(region[idx], REGION_FLASH_ATTR);
173+
break;
174+
#endif
175+
#ifdef REGION_IO_ATTR
176+
case DT_MEM_ARM_MPU_IO:
177+
region_conf = _BUILD_REGION_CONF(region[idx], REGION_IO_ATTR);
178+
break;
179+
#endif
180+
default:
181+
/* Either the specified `ATTR_MPU_*` attribute does not
182+
* exists or the `REGION_*_ATTR` macro is not defined
183+
* for that attribute.
184+
*/
185+
LOG_ERR("Invalid attribute for the region\n");
186+
return -EINVAL;
187+
}
188+
189+
if (region_allocate_and_init((*reg_index),
190+
(const struct nxp_mpu_region *) &region_conf) < 0) {
191+
return -EINVAL;
192+
}
193+
194+
(*reg_index)++;
195+
}
196+
197+
return 0;
198+
}
199+
137200
/**
138201
* This internal function is utilized by the MPU driver to combine a given
139202
* region attribute configuration and size and fill-in a driver-specific
@@ -636,6 +699,11 @@ int z_arm_mpu_init(void)
636699
/* Update the number of programmed MPU regions. */
637700
static_regions_num = mpu_config.num_regions;
638701

702+
/* DT-defined MPU regions. */
703+
if (mpu_configure_regions_from_dt(&static_regions_num) == -EINVAL) {
704+
__ASSERT(0, "Failed to allocate MPU regions from DT\n");
705+
return -EINVAL;
706+
}
639707

640708
arm_core_mpu_enable();
641709

arch/arm64/core/cortex_r/arm_mpu.c

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,18 @@
1515
#include <zephyr/sys/check.h>
1616
#include <zephyr/sys/barrier.h>
1717
#include <zephyr/cache.h>
18+
#include <zephyr/mem_mgmt/mem_attr.h>
19+
#include <zephyr/dt-bindings/memory-attr/memory-attr-arm.h>
1820

1921
LOG_MODULE_REGISTER(mpu, CONFIG_MPU_LOG_LEVEL);
2022

23+
#define NODE_HAS_PROP_AND_OR(node_id, prop) \
24+
DT_NODE_HAS_PROP(node_id, prop) ||
25+
26+
BUILD_ASSERT((DT_FOREACH_STATUS_OKAY_NODE_VARGS(
27+
NODE_HAS_PROP_AND_OR, zephyr_memory_region_mpu) false) == false,
28+
"`zephyr,memory-region-mpu` was deprecated in favor of `zephyr,memory-attr`");
29+
2130
#define MPU_DYNAMIC_REGION_AREAS_NUM 1
2231

2332
#ifdef CONFIG_USERSPACE
@@ -167,6 +176,64 @@ static ALWAYS_INLINE void region_init(const uint32_t index,
167176
mpu_set_region(index, rbar, rlar);
168177
}
169178

179+
#define _BUILD_REGION_CONF(reg, _ATTR) \
180+
(struct arm_mpu_region) { .name = (reg).dt_name, \
181+
.base = (reg).dt_addr, \
182+
.limit = (reg).dt_addr + (reg).dt_size, \
183+
.attr = _ATTR, \
184+
}
185+
186+
/* This internal function programs the MPU regions defined in the DT when using
187+
* the `zephyr,memory-attr = <( DT_MEM_ARM(...) )>` property.
188+
*/
189+
static int mpu_configure_regions_from_dt(uint8_t *reg_index)
190+
{
191+
const struct mem_attr_region_t *region;
192+
size_t num_regions;
193+
194+
num_regions = mem_attr_get_regions(&region);
195+
196+
for (size_t idx = 0; idx < num_regions; idx++) {
197+
struct arm_mpu_region region_conf;
198+
199+
switch (DT_MEM_ARM_MASK(region[idx].dt_attr)) {
200+
case DT_MEM_ARM_MPU_RAM:
201+
region_conf = _BUILD_REGION_CONF(region[idx], REGION_RAM_ATTR);
202+
break;
203+
#ifdef REGION_RAM_NOCACHE_ATTR
204+
case DT_MEM_ARM_MPU_RAM_NOCACHE:
205+
region_conf = _BUILD_REGION_CONF(region[idx], REGION_RAM_NOCACHE_ATTR);
206+
__ASSERT(!(region[idx].dt_attr & DT_MEM_CACHEABLE),
207+
"RAM_NOCACHE with DT_MEM_CACHEABLE attribute\n");
208+
break;
209+
#endif
210+
#ifdef REGION_FLASH_ATTR
211+
case DT_MEM_ARM_MPU_FLASH:
212+
region_conf = _BUILD_REGION_CONF(region[idx], REGION_FLASH_ATTR);
213+
break;
214+
#endif
215+
#ifdef REGION_IO_ATTR
216+
case DT_MEM_ARM_MPU_IO:
217+
region_conf = _BUILD_REGION_CONF(region[idx], REGION_IO_ATTR);
218+
break;
219+
#endif
220+
default:
221+
/* Either the specified `ATTR_MPU_*` attribute does not
222+
* exists or the `REGION_*_ATTR` macro is not defined
223+
* for that attribute.
224+
*/
225+
LOG_ERR("Invalid attribute for the region\n");
226+
return -EINVAL;
227+
}
228+
229+
region_init((*reg_index), (const struct arm_mpu_region *) &region_conf);
230+
231+
(*reg_index)++;
232+
}
233+
234+
return 0;
235+
}
236+
170237
/*
171238
* @brief MPU default configuration
172239
*
@@ -222,6 +289,12 @@ FUNC_NO_STACK_PROTECTOR void z_arm64_mm_init(bool is_primary_core)
222289
/* Update the number of programmed MPU regions. */
223290
static_regions_num = mpu_config.num_regions;
224291

292+
/* DT-defined MPU regions. */
293+
if (mpu_configure_regions_from_dt(&static_regions_num) == -EINVAL) {
294+
__ASSERT(0, "Failed to allocate MPU regions from DT\n");
295+
return;
296+
}
297+
225298
arm_core_mpu_enable();
226299

227300
if (!is_primary_core) {

boards/arm/arduino_giga_r1/arduino_giga_r1_m7.dts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
/dts-v1/;
88
#include <st/h7/stm32h747Xi_m7.dtsi>
99
#include <st/h7/stm32h747xihx-pinctrl.dtsi>
10+
#include <zephyr/dt-bindings/memory-attr/memory-attr-arm.h>
1011
#include "arduino_giga_r1.dtsi"
1112

1213
/ {
@@ -29,7 +30,7 @@
2930
device_type = "memory";
3031
reg = <0xc0000000 DT_SIZE_M(8)>;
3132
zephyr,memory-region = "SDRAM1";
32-
zephyr,memory-attr = "RAM";
33+
zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_RAM) )>;
3334
};
3435

3536
aliases {

boards/arm/stm32f746g_disco/stm32f746g_disco.dts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
#include <st/f7/stm32f746nghx-pinctrl.dtsi>
1010
#include "arduino_r3_connector.dtsi"
1111
#include <zephyr/dt-bindings/input/input-event-codes.h>
12+
#include <zephyr/dt-bindings/memory-attr/memory-attr.h>
13+
#include <zephyr/dt-bindings/memory-attr/memory-attr-arm.h>
1214

1315
/ {
1416
model = "STMicroelectronics STM32F746G DISCOVERY board";
@@ -51,7 +53,7 @@
5153
device_type = "memory";
5254
reg = <0xc0000000 DT_SIZE_M(16)>;
5355
zephyr,memory-region = "SDRAM1";
54-
zephyr,memory-attr = "RAM";
56+
zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_RAM) )>;
5557
};
5658

5759
aliases {

boards/arm/stm32f7508_dk/stm32f7508_dk.dts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
/dts-v1/;
99
#include <st/f7/stm32f750X8.dtsi>
1010
#include <st/f7/stm32f750n8hx-pinctrl.dtsi>
11+
#include <zephyr/dt-bindings/memory-attr/memory-attr-arm.h>
1112
#include "arduino_r3_connector.dtsi"
1213
#include <zephyr/dt-bindings/input/input-event-codes.h>
1314

@@ -52,7 +53,7 @@
5253
device_type = "memory";
5354
reg = <0xc0000000 DT_SIZE_M(16)>;
5455
zephyr,memory-region = "SDRAM1";
55-
zephyr,memory-attr = "RAM";
56+
zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_RAM) )>;
5657
};
5758

5859
aliases {

boards/arm/stm32f769i_disco/stm32f769i_disco.dts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
/dts-v1/;
88
#include <st/f7/stm32f769Xi.dtsi>
99
#include <st/f7/stm32f769nihx-pinctrl.dtsi>
10+
#include <zephyr/dt-bindings/memory-attr/memory-attr-arm.h>
1011
#include "arduino_r3_connector.dtsi"
1112
#include <zephyr/dt-bindings/input/input-event-codes.h>
1213

@@ -28,7 +29,7 @@
2829
device_type = "memory";
2930
reg = <0xc0000000 DT_SIZE_M(16)>;
3031
zephyr,memory-region = "SDRAM1";
31-
zephyr,memory-attr = "RAM";
32+
zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_RAM) )>;
3233
};
3334

3435
leds {

boards/arm/stm32h747i_disco/stm32h747i_disco_m7.dts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
/dts-v1/;
88
#include <st/h7/stm32h747Xi_m7.dtsi>
99
#include <st/h7/stm32h747xihx-pinctrl.dtsi>
10+
#include <zephyr/dt-bindings/memory-attr/memory-attr-arm.h>
1011
#include "stm32h747i_disco.dtsi"
1112

1213
/ {
@@ -27,7 +28,7 @@
2728
device_type = "memory";
2829
reg = <0xd0000000 DT_SIZE_M(32)>;
2930
zephyr,memory-region = "SDRAM2";
30-
zephyr,memory-attr = "RAM";
31+
zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_RAM) )>;
3132
};
3233

3334
leds {

0 commit comments

Comments
 (0)