Skip to content

Commit ae57e9c

Browse files
committed
dt/mpu: Generate MPU regions from SRAM 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 new "mpu-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 = "mpu-region", "mmio-sram"; reg = <0x20200000 0x100000>; zephyr,memory-region = "SRAM_CACHE"; zephyr,memory-region-mpu = "REGION_RAM_ATTR"; }; 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". This patch is also introducing a trivial test. Signed-off-by: Carlo Caione <ccaione@baylibre.com>
1 parent 3457ebc commit ae57e9c

File tree

10 files changed

+265
-0
lines changed

10 files changed

+265
-0
lines changed

dts/bindings/base/mpu-region.yaml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# Copyright (c) 2021, Carlo Caione <ccaione@baylibre.com>
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
description: MPU region
5+
6+
compatible: "mpu-region"
7+
8+
include: [base.yaml, mem-region.yaml]
9+
10+
properties:
11+
zephyr,memory-region:
12+
required: true
13+
14+
zephyr,memory-region-mpu:
15+
type: string
16+
required: true
17+
description: |
18+
Signify that this node should result in a dedicated MPU region. The
19+
region address and size are taken from the <reg> property, while the MPU
20+
attribute is the value of this property.
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
/*
2+
* Copyright (c) 2021, Carlo Caione <ccaione@baylibre.com>
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#include <devicetree.h>
8+
#include <linker/devicetree_regions.h>
9+
#include <sys/util_macro.h>
10+
11+
/**
12+
* @cond INTERNAL_HIDDEN
13+
*/
14+
15+
#define _DT_COMPATIBLE mpu_region
16+
17+
/**
18+
* Check that the node_id has both properties:
19+
* - zephyr,memory-region-mpu
20+
* - zephyr,memory-region
21+
*
22+
* and call the EXPAND_MPU_FN() macro
23+
*/
24+
#define _CHECK_ATTR_FN(node_id, EXPAND_MPU_FN, ...) \
25+
COND_CODE_1(UTIL_AND(DT_NODE_HAS_PROP(node_id, zephyr_memory_region_mpu), \
26+
DT_NODE_HAS_PROP(node_id, zephyr_memory_region)), \
27+
(EXPAND_MPU_FN(node_id, __VA_ARGS__)), \
28+
())
29+
30+
/**
31+
* Call the user-provided MPU_FN() macro passing the expected arguments
32+
*/
33+
#define _EXPAND_MPU_FN(node_id, MPU_FN, ...) \
34+
MPU_FN(LINKER_DT_NODE_REGION_NAME(node_id), \
35+
DT_REG_ADDR(node_id), \
36+
DT_REG_SIZE(node_id), \
37+
DT_STRING_TOKEN(node_id, zephyr_memory_region_mpu)),
38+
39+
/**
40+
* Call _CHECK_ATTR_FN() for each enabled node passing EXPAND_MPU_FN() as
41+
* explicit argument and the user-provided MPU_FN() macro in __VA_ARGS__
42+
*/
43+
#define _CHECK_APPLY_FN(compat, EXPAND_MPU_FN, ...) \
44+
DT_FOREACH_STATUS_OKAY_VARGS(compat, _CHECK_ATTR_FN, EXPAND_MPU_FN, __VA_ARGS__)
45+
46+
/**
47+
* @endcond
48+
*/
49+
50+
/**
51+
* Helper macro to apply an MPU_FN macro to all the memory regions declared
52+
* using the 'zephyr,memory-region-mpu' property and the 'mpu-region'
53+
* compatible.
54+
*
55+
* @p mpu_fn must take the form:
56+
*
57+
* @code{.c}
58+
* #define MPU_FN(name, base, size, attr) ...
59+
* @endcode
60+
*
61+
* Example:
62+
*
63+
* @code{.c}
64+
* static const struct arm_mpu_region mpu_regions[] = {
65+
* ...
66+
* DT_REGION_MPU(MPU_FN)
67+
* ...
68+
* };
69+
* @endcode
70+
*/
71+
#define 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
@@ -62,6 +62,48 @@
6262
#error "Unsupported sram size configuration"
6363
#endif
6464

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

67109
#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_mpu.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+
DT_REGION_MPU(ARM_MPU_REGION_INIT)
3135
};
3236

3337
const struct arm_mpu_config mpu_config = {
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# SPDX-License-Identifier: Apache-2.0
2+
3+
cmake_minimum_required(VERSION 3.20.0)
4+
5+
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
6+
project(arm_mpu_regions)
7+
8+
target_sources(app PRIVATE src/main.c)
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/*
2+
* Copyright (c) 2021 Carlo Caione <ccaione@baylibre.com>
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
/ {
8+
/delete-node/ memory@20000000;
9+
10+
sram0: memory@20000000 {
11+
compatible = "mmio-sram";
12+
reg = <0x20000000 0x200000>;
13+
};
14+
15+
sram_cache: memory@20200000 {
16+
compatible = "mpu-region", "mmio-sram";
17+
reg = <0x20200000 0x100000>;
18+
zephyr,memory-region = "SRAM_CACHE";
19+
zephyr,memory-region-mpu = "REGION_RAM_ATTR";
20+
};
21+
22+
sram_no_cache: memory@20300000 {
23+
compatible = "mpu-region", "mmio-sram";
24+
reg = <0x20300000 0x100000>;
25+
zephyr,memory-region = "SRAM_NO_CACHE";
26+
zephyr,memory-region-mpu = "REGION_RAM_NOCACHE_ATTR";
27+
};
28+
29+
sram_dtcm_fake: memory@abcdabcd {
30+
compatible = "mpu-region", "arm,dtcm";
31+
reg = <0xabcdabcd 0x100000>;
32+
zephyr,memory-region = "SRAM_DTCM_FAKE";
33+
zephyr,memory-region-mpu = "REGION_RAM_ATTR";
34+
};
35+
};
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/*
2+
* Copyright (c) Carlo Caione <ccaione@baylibre.com>
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#include <autoconf.h>
8+
#include <linker/sections.h>
9+
#include <devicetree.h>
10+
11+
#include <linker/linker-defs.h>
12+
#include <linker/linker-tool.h>
13+
#include <linker/devicetree_regions.h>
14+
15+
MEMORY
16+
{
17+
LINKER_DT_REGION_FROM_NODE(DT_NODELABEL(sram_cache), rw)
18+
LINKER_DT_REGION_FROM_NODE(DT_NODELABEL(sram_no_cache), rw)
19+
LINKER_DT_REGION_FROM_NODE(DT_NODELABEL(sram_dtcm_fake), rw)
20+
}
21+
22+
#include <arch/arm/aarch32/cortex_m/scripts/linker.ld>
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
CONFIG_ZTEST=y
2+
CONFIG_HAVE_CUSTOM_LINKER_SCRIPT=y
3+
CONFIG_CUSTOM_LINKER_SCRIPT="linker_sram_regions.ld"
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/*
2+
* Copyright (c) 2021 Carlo Caione <ccaione@baylibre.com>
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#include <zephyr.h>
8+
#include <linker/linker-defs.h>
9+
#include <sys/slist.h>
10+
#include <arch/arm/aarch32/mpu/arm_mpu.h>
11+
#include <ztest.h>
12+
#include <string.h>
13+
14+
extern const struct arm_mpu_config mpu_config;
15+
16+
static arm_mpu_region_attr_t cacheable = REGION_RAM_ATTR(REGION_1M);
17+
static arm_mpu_region_attr_t noncacheable = REGION_RAM_NOCACHE_ATTR(REGION_1M);
18+
19+
static void test_regions(void)
20+
{
21+
int cnt = 0;
22+
23+
for (size_t i = 0; i < mpu_config.num_regions; i++) {
24+
const struct arm_mpu_region *r = &mpu_config.mpu_regions[i];
25+
26+
if (!strcmp(r->name, "SRAM_CACHE")) {
27+
zassert_equal(r->base, 0x20200000, "Wrong base");
28+
zassert_equal(r->attr.rasr, cacheable.rasr,
29+
"Wrong attr for SRAM_CACHE");
30+
cnt++;
31+
} else if (!strcmp(r->name, "SRAM_NO_CACHE")) {
32+
zassert_equal(r->base, 0x20300000, "Wrong base");
33+
zassert_equal(r->attr.rasr, noncacheable.rasr,
34+
"Wrong attr for SRAM_NO_CACHE");
35+
cnt++;
36+
} else if (!strcmp(r->name, "SRAM_DTCM_FAKE")) {
37+
zassert_equal(r->base, 0xabcdabcd, "Wrong base");
38+
zassert_equal(r->attr.rasr, cacheable.rasr,
39+
"Wrong attr for SRAM_DTCM_FAKE");
40+
cnt++;
41+
}
42+
}
43+
44+
if (cnt != 3) {
45+
ztest_test_fail();
46+
}
47+
}
48+
49+
void test_main(void)
50+
{
51+
ztest_test_suite(test_c_arm_mpu_regions,
52+
ztest_unit_test(test_regions)
53+
);
54+
55+
ztest_run_test_suite(test_c_arm_mpu_regions);
56+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
tests:
2+
misc.arm_mpu_regions:
3+
platform_allow: mps2_an385
4+
tags: sample board sram mpu

0 commit comments

Comments
 (0)