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 <ccaione@baylibre.com>
This commit is contained in:
Carlo Caione 2023-08-16 12:48:26 +02:00 committed by Carles Cufí
parent 7f04c352c1
commit e4a125b6a4
72 changed files with 933 additions and 514 deletions

View File

@ -11,6 +11,8 @@
#include "arm_core_mpu_dev.h"
#include <zephyr/linker/linker-defs.h>
#include <kernel_arch_data.h>
#include <zephyr/mem_mgmt/mem_attr.h>
#include <zephyr/dt-bindings/memory-attr/memory-attr-arm.h>
#define LOG_LEVEL CONFIG_MPU_LOG_LEVEL
#include <zephyr/logging/log.h>
@ -32,6 +34,13 @@ LOG_MODULE_DECLARE(mpu);
#define NUM_MPU_REGIONS DT_PROP(MPU_NODEID, arm_num_mpu_regions)
#endif
#define NODE_HAS_PROP_AND_OR(node_id, prop) \
DT_NODE_HAS_PROP(node_id, prop) ||
BUILD_ASSERT((DT_FOREACH_STATUS_OKAY_NODE_VARGS(
NODE_HAS_PROP_AND_OR, zephyr_memory_region_mpu) false) == false,
"`zephyr,memory-region-mpu` was deprecated in favor of `zephyr,memory-attr`");
/*
* Global status variable holding the number of HW MPU region indices, which
* 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,
return index;
}
#define _BUILD_REGION_CONF(reg, _ATTR) \
(struct arm_mpu_region) ARM_MPU_REGION_INIT((reg).dt_name, \
(reg).dt_addr, \
(reg).dt_size, \
_ATTR)
/* This internal function programs the MPU regions defined in the DT when using
* the `zephyr,memory-attr = <( DT_MEM_ARM(...) )>` property.
*/
static int mpu_configure_regions_from_dt(uint8_t *reg_index)
{
const struct mem_attr_region_t *region;
size_t num_regions;
num_regions = mem_attr_get_regions(&region);
for (size_t idx = 0; idx < num_regions; idx++) {
struct arm_mpu_region region_conf;
switch (DT_MEM_ARM_MASK(region[idx].dt_attr)) {
case DT_MEM_ARM_MPU_RAM:
region_conf = _BUILD_REGION_CONF(region[idx], REGION_RAM_ATTR);
break;
#ifdef REGION_RAM_NOCACHE_ATTR
case DT_MEM_ARM_MPU_RAM_NOCACHE:
region_conf = _BUILD_REGION_CONF(region[idx], REGION_RAM_NOCACHE_ATTR);
__ASSERT(!(region[idx].dt_attr & DT_MEM_CACHEABLE),
"RAM_NOCACHE with DT_MEM_CACHEABLE attribute\n");
break;
#endif
#ifdef REGION_FLASH_ATTR
case DT_MEM_ARM_MPU_FLASH:
region_conf = _BUILD_REGION_CONF(region[idx], REGION_FLASH_ATTR);
break;
#endif
#ifdef REGION_PPB_ATTR
case DT_MEM_ARM_MPU_PPB:
region_conf = _BUILD_REGION_CONF(region[idx], REGION_PPB_ATTR);
break;
#endif
#ifdef REGION_IO_ATTR
case DT_MEM_ARM_MPU_IO:
region_conf = _BUILD_REGION_CONF(region[idx], REGION_IO_ATTR);
break;
#endif
#ifdef REGION_EXTMEM_ATTR
case DT_MEM_ARM_MPU_EXTMEM:
region_conf = _BUILD_REGION_CONF(region[idx], REGION_EXTMEM_ATTR);
break;
#endif
default:
/* Either the specified `ATTR_MPU_*` attribute does not
* exists or the `REGION_*_ATTR` macro is not defined
* for that attribute.
*/
LOG_ERR("Invalid attribute for the region\n");
return -EINVAL;
}
#if defined(CONFIG_ARMV7_R)
region_conf.size = size_to_mpu_rasr_size(region[idx].dt_size);
#endif
if (region_allocate_and_init((*reg_index),
(const struct arm_mpu_region *) &region_conf) < 0) {
return -EINVAL;
}
(*reg_index)++;
}
return 0;
}
/* This internal function programs an MPU region
* of a given configuration at a given MPU index.
*/
@ -375,6 +457,11 @@ int z_arm_mpu_init(void)
/* Update the number of programmed MPU regions. */
static_regions_num = mpu_config.num_regions;
/* DT-defined MPU regions. */
if (mpu_configure_regions_from_dt(&static_regions_num) == -EINVAL) {
__ASSERT(0, "Failed to allocate MPU regions from DT\n");
return -EINVAL;
}
arm_core_mpu_enable();

View File

@ -13,11 +13,20 @@
#include <zephyr/sys/math_extras.h>
#include <zephyr/sys/barrier.h>
#include <zephyr/linker/linker-defs.h>
#include <zephyr/mem_mgmt/mem_attr.h>
#include <zephyr/dt-bindings/memory-attr/memory-attr-arm.h>
#define LOG_LEVEL CONFIG_MPU_LOG_LEVEL
#include <zephyr/logging/log.h>
LOG_MODULE_DECLARE(mpu);
#define NODE_HAS_PROP_AND_OR(node_id, prop) \
DT_NODE_HAS_PROP(node_id, prop) ||
BUILD_ASSERT((DT_FOREACH_STATUS_OKAY_NODE_VARGS(
NODE_HAS_PROP_AND_OR, zephyr_memory_region_mpu) false) == false,
"`zephyr,memory-region-mpu` was deprecated in favor of `zephyr,memory-attr`");
/*
* Global status variable holding the number of HW MPU region indices, which
* 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,
return index;
}
#define _BUILD_REGION_CONF(reg, _ATTR) \
(struct nxp_mpu_region) { .name = (reg).dt_name, \
.base = (reg).dt_addr, \
.end = (reg).dt_addr + (reg).dt_size, \
.attr = _ATTR, \
}
/* This internal function programs the MPU regions defined in the DT when using
* the `zephyr,memory-attr = <( DT_MEM_ARM(...) )>` property.
*/
static int mpu_configure_regions_from_dt(uint8_t *reg_index)
{
const struct mem_attr_region_t *region;
size_t num_regions;
num_regions = mem_attr_get_regions(&region);
for (size_t idx = 0; idx < num_regions; idx++) {
struct nxp_mpu_region region_conf;
switch (DT_MEM_ARM_MASK(region[idx].dt_attr)) {
case DT_MEM_ARM_MPU_RAM:
region_conf = _BUILD_REGION_CONF(region[idx], REGION_RAM_ATTR);
break;
#ifdef REGION_FLASH_ATTR
case DT_MEM_ARM_MPU_FLASH:
region_conf = _BUILD_REGION_CONF(region[idx], REGION_FLASH_ATTR);
break;
#endif
#ifdef REGION_IO_ATTR
case DT_MEM_ARM_MPU_IO:
region_conf = _BUILD_REGION_CONF(region[idx], REGION_IO_ATTR);
break;
#endif
default:
/* Either the specified `ATTR_MPU_*` attribute does not
* exists or the `REGION_*_ATTR` macro is not defined
* for that attribute.
*/
LOG_ERR("Invalid attribute for the region\n");
return -EINVAL;
}
if (region_allocate_and_init((*reg_index),
(const struct nxp_mpu_region *) &region_conf) < 0) {
return -EINVAL;
}
(*reg_index)++;
}
return 0;
}
/**
* This internal function is utilized by the MPU driver to combine a given
* region attribute configuration and size and fill-in a driver-specific
@ -636,6 +699,11 @@ int z_arm_mpu_init(void)
/* Update the number of programmed MPU regions. */
static_regions_num = mpu_config.num_regions;
/* DT-defined MPU regions. */
if (mpu_configure_regions_from_dt(&static_regions_num) == -EINVAL) {
__ASSERT(0, "Failed to allocate MPU regions from DT\n");
return -EINVAL;
}
arm_core_mpu_enable();

View File

@ -15,9 +15,18 @@
#include <zephyr/sys/check.h>
#include <zephyr/sys/barrier.h>
#include <zephyr/cache.h>
#include <zephyr/mem_mgmt/mem_attr.h>
#include <zephyr/dt-bindings/memory-attr/memory-attr-arm.h>
LOG_MODULE_REGISTER(mpu, CONFIG_MPU_LOG_LEVEL);
#define NODE_HAS_PROP_AND_OR(node_id, prop) \
DT_NODE_HAS_PROP(node_id, prop) ||
BUILD_ASSERT((DT_FOREACH_STATUS_OKAY_NODE_VARGS(
NODE_HAS_PROP_AND_OR, zephyr_memory_region_mpu) false) == false,
"`zephyr,memory-region-mpu` was deprecated in favor of `zephyr,memory-attr`");
#define MPU_DYNAMIC_REGION_AREAS_NUM 1
#ifdef CONFIG_USERSPACE
@ -167,6 +176,64 @@ static ALWAYS_INLINE void region_init(const uint32_t index,
mpu_set_region(index, rbar, rlar);
}
#define _BUILD_REGION_CONF(reg, _ATTR) \
(struct arm_mpu_region) { .name = (reg).dt_name, \
.base = (reg).dt_addr, \
.limit = (reg).dt_addr + (reg).dt_size, \
.attr = _ATTR, \
}
/* This internal function programs the MPU regions defined in the DT when using
* the `zephyr,memory-attr = <( DT_MEM_ARM(...) )>` property.
*/
static int mpu_configure_regions_from_dt(uint8_t *reg_index)
{
const struct mem_attr_region_t *region;
size_t num_regions;
num_regions = mem_attr_get_regions(&region);
for (size_t idx = 0; idx < num_regions; idx++) {
struct arm_mpu_region region_conf;
switch (DT_MEM_ARM_MASK(region[idx].dt_attr)) {
case DT_MEM_ARM_MPU_RAM:
region_conf = _BUILD_REGION_CONF(region[idx], REGION_RAM_ATTR);
break;
#ifdef REGION_RAM_NOCACHE_ATTR
case DT_MEM_ARM_MPU_RAM_NOCACHE:
region_conf = _BUILD_REGION_CONF(region[idx], REGION_RAM_NOCACHE_ATTR);
__ASSERT(!(region[idx].dt_attr & DT_MEM_CACHEABLE),
"RAM_NOCACHE with DT_MEM_CACHEABLE attribute\n");
break;
#endif
#ifdef REGION_FLASH_ATTR
case DT_MEM_ARM_MPU_FLASH:
region_conf = _BUILD_REGION_CONF(region[idx], REGION_FLASH_ATTR);
break;
#endif
#ifdef REGION_IO_ATTR
case DT_MEM_ARM_MPU_IO:
region_conf = _BUILD_REGION_CONF(region[idx], REGION_IO_ATTR);
break;
#endif
default:
/* Either the specified `ATTR_MPU_*` attribute does not
* exists or the `REGION_*_ATTR` macro is not defined
* for that attribute.
*/
LOG_ERR("Invalid attribute for the region\n");
return -EINVAL;
}
region_init((*reg_index), (const struct arm_mpu_region *) &region_conf);
(*reg_index)++;
}
return 0;
}
/*
* @brief MPU default configuration
*
@ -222,6 +289,12 @@ FUNC_NO_STACK_PROTECTOR void z_arm64_mm_init(bool is_primary_core)
/* Update the number of programmed MPU regions. */
static_regions_num = mpu_config.num_regions;
/* DT-defined MPU regions. */
if (mpu_configure_regions_from_dt(&static_regions_num) == -EINVAL) {
__ASSERT(0, "Failed to allocate MPU regions from DT\n");
return;
}
arm_core_mpu_enable();
if (!is_primary_core) {

View File

@ -7,6 +7,7 @@
/dts-v1/;
#include <st/h7/stm32h747Xi_m7.dtsi>
#include <st/h7/stm32h747xihx-pinctrl.dtsi>
#include <zephyr/dt-bindings/memory-attr/memory-attr-arm.h>
#include "arduino_giga_r1.dtsi"
/ {
@ -29,7 +30,7 @@
device_type = "memory";
reg = <0xc0000000 DT_SIZE_M(8)>;
zephyr,memory-region = "SDRAM1";
zephyr,memory-attr = "RAM";
zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_RAM) )>;
};
aliases {

View File

@ -9,6 +9,8 @@
#include <st/f7/stm32f746nghx-pinctrl.dtsi>
#include "arduino_r3_connector.dtsi"
#include <zephyr/dt-bindings/input/input-event-codes.h>
#include <zephyr/dt-bindings/memory-attr/memory-attr.h>
#include <zephyr/dt-bindings/memory-attr/memory-attr-arm.h>
/ {
model = "STMicroelectronics STM32F746G DISCOVERY board";
@ -51,7 +53,7 @@
device_type = "memory";
reg = <0xc0000000 DT_SIZE_M(16)>;
zephyr,memory-region = "SDRAM1";
zephyr,memory-attr = "RAM";
zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_RAM) )>;
};
aliases {

View File

@ -8,6 +8,7 @@
/dts-v1/;
#include <st/f7/stm32f750X8.dtsi>
#include <st/f7/stm32f750n8hx-pinctrl.dtsi>
#include <zephyr/dt-bindings/memory-attr/memory-attr-arm.h>
#include "arduino_r3_connector.dtsi"
#include <zephyr/dt-bindings/input/input-event-codes.h>
@ -52,7 +53,7 @@
device_type = "memory";
reg = <0xc0000000 DT_SIZE_M(16)>;
zephyr,memory-region = "SDRAM1";
zephyr,memory-attr = "RAM";
zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_RAM) )>;
};
aliases {

View File

@ -7,6 +7,7 @@
/dts-v1/;
#include <st/f7/stm32f769Xi.dtsi>
#include <st/f7/stm32f769nihx-pinctrl.dtsi>
#include <zephyr/dt-bindings/memory-attr/memory-attr-arm.h>
#include "arduino_r3_connector.dtsi"
#include <zephyr/dt-bindings/input/input-event-codes.h>
@ -28,7 +29,7 @@
device_type = "memory";
reg = <0xc0000000 DT_SIZE_M(16)>;
zephyr,memory-region = "SDRAM1";
zephyr,memory-attr = "RAM";
zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_RAM) )>;
};
leds {

View File

@ -7,6 +7,7 @@
/dts-v1/;
#include <st/h7/stm32h747Xi_m7.dtsi>
#include <st/h7/stm32h747xihx-pinctrl.dtsi>
#include <zephyr/dt-bindings/memory-attr/memory-attr-arm.h>
#include "stm32h747i_disco.dtsi"
/ {
@ -27,7 +28,7 @@
device_type = "memory";
reg = <0xd0000000 DT_SIZE_M(32)>;
zephyr,memory-region = "SDRAM2";
zephyr,memory-attr = "RAM";
zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_RAM) )>;
};
leds {

View File

@ -7,6 +7,7 @@
/dts-v1/;
#include <st/h7/stm32h7b3Xi.dtsi>
#include <st/h7/stm32h7b3lihxq-pinctrl.dtsi>
#include <zephyr/dt-bindings/memory-attr/memory-attr-arm.h>
#include "arduino_r3_connector.dtsi"
#include <zephyr/dt-bindings/input/input-event-codes.h>
@ -54,7 +55,7 @@
device_type = "memory";
reg = <0xd0000000 DT_SIZE_M(16)>;
zephyr,memory-region = "SDRAM2";
zephyr,memory-attr = "RAM";
zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_RAM) )>;
};
transceiver0: can-phy0 {

View File

@ -6,6 +6,7 @@
/dts-v1/;
#include <arm64/fvp/fvp-aemv8r.dtsi>
#include <zephyr/dt-bindings/memory-attr/memory-attr-arm.h>
/ {
model = "FVP BaseR AEMv8R";
@ -41,7 +42,7 @@
compatible = "zephyr,memory-region", "mmio-dram";
reg = <0x9a000000 0x66000000>;
zephyr,memory-region = "DEVICE_REGION";
zephyr,memory-attr = "IO";
zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_IO) )>;
};
};
};

View File

@ -294,15 +294,6 @@ and properties related to them.
.. doxygengroup:: devicetree-mbox
.. _devicetree-memory-attr-api:
Memory attributes
=================
These conveniences may be used for nodes with a memory attribute property.
.. doxygengroup:: devicetree-memory-attr
.. _devicetree-pinctrl-api:
Pinctrl (pin control)

View File

@ -457,10 +457,6 @@ region will be allocated and programmed during system boot. When used with the
:dtcompatible:`zephyr,memory-region` devicetree compatible, it will result in a
linker section being generated associated to that MPU region.
The property ``zephyr,memory-attr`` is a string carrying the attributes
for the MPU region. It is converted to a C token for use defining the attributes
of the MPU region.
For example, to define a new non-cacheable memory region in devicetree:
.. code-block:: devicetree
@ -469,13 +465,11 @@ For example, to define a new non-cacheable memory region in devicetree:
compatible = "zephyr,memory-region", "mmio-sram";
reg = <0x20300000 0x100000>;
zephyr,memory-region = "SRAM_NO_CACHE";
zephyr,memory-attr = "RAM_NOCACHE";
zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_RAM_NOCACHE) )>;
};
This will automatically create a new MPU entry in
:zephyr_file:`soc/arm/common/cortex_m/arm_mpu_regions.c` with the correct name, base,
size and attributes gathered directly from the devicetree. See
:zephyr_file:`include/zephyr/linker/devicetree_regions.h` for more details.
This will automatically create a new MPU entry in with the correct name, base,
size and attributes gathered directly from the devicetree.
Static MPU regions
------------------

View File

@ -34,6 +34,19 @@ Required changes
SMP version 2 error code defines for in-tree modules have been updated to
replace the ``*_RET_RC_*`` parts with ``*_ERR_*``.
* ``zephyr,memory-region-mpu`` was renamed ``zephyr,memory-attr`` and its type
moved from 'enum' to 'int'. To have a seamless conversion this is the
required change in the DT:
.. code-block:: none
- "RAM" -> <( DT_MEM_ARM(ATTR_MPU_RAM) )>
- "RAM_NOCACHE" -> <( DT_MEM_ARM(ATTR_MPU_RAM_NOCACHE) )>
- "FLASH" -> <( DT_MEM_ARM(ATTR_MPU_FLASH) )>
- "PPB" -> <( DT_MEM_ARM(ATTR_MPU_PPB) )>
- "IO" -> <( DT_MEM_ARM(ATTR_MPU_IO) )>
- "EXTMEM" -> <( DT_MEM_ARM(ATTR_MPU_EXTMEM) )>
Recommended Changes
*******************

View File

@ -284,16 +284,6 @@ USB
Devicetree
**********
* ``zephyr,memory-region-mpu`` was renamed ``zephyr,memory-attr``
* The following macros were added:
:c:macro:`DT_FOREACH_NODE_VARGS`,
:c:macro:`DT_FOREACH_STATUS_OKAY_NODE_VARGS`
:c:macro:`DT_MEMORY_ATTR_FOREACH_NODE`
:c:macro:`DT_MEMORY_ATTR_APPLY`
:c:macro:`DT_MEM_FROM_FIXED_PARTITION`
:c:macro:`DT_FIXED_PARTITION_ADDR`
Libraries / Subsystems
**********************

View File

@ -18,6 +18,7 @@ OS Services
logging/index.rst
tracing/index.rst
resource_management/index.rst
mem_mgmt/index.rst
modbus/index.rst
notify.rst
pm/index.rst

View File

@ -0,0 +1,90 @@
.. _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) )>
API Reference
*************
.. doxygengroup:: memory_attr_interface

View File

@ -42,6 +42,8 @@ LOG_MODULE_REGISTER(adc_stm32);
#include <zephyr/drivers/clock_control/stm32_clock_control.h>
#include <zephyr/dt-bindings/adc/stm32_adc.h>
#include <zephyr/irq.h>
#include <zephyr/mem_mgmt/mem_attr.h>
#include <zephyr/dt-bindings/memory-attr/memory-attr-arm.h>
#if defined(CONFIG_SOC_SERIES_STM32F3X)
#if defined(ADC1_V2_5)
@ -253,27 +255,16 @@ static int adc_stm32_dma_start(const struct device *dev,
* The entire buffer must be in a single region.
* An example of how the SRAM region can be defined in the DTS:
* &sram4 {
* zephyr,memory-attr = "RAM_NOCACHE";
* zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_RAM_NOCACHE) | ... )>;
* };
*/
static bool address_in_non_cacheable_sram(const uint16_t *buffer, const uint16_t size)
{
/* Default if no valid SRAM region found or buffer+size not located in a single region */
bool cachable = false;
#define IS_NON_CACHEABLE_REGION_FN(node_id) \
COND_CODE_1(DT_NODE_HAS_PROP(node_id, zephyr_memory_attr), ({ \
const uint32_t region_start = DT_REG_ADDR(node_id); \
const uint32_t region_end = region_start + DT_REG_SIZE(node_id); \
if (((uint32_t)buffer >= region_start) && \
(((uint32_t)buffer + size) < region_end)) { \
cachable = strcmp(DT_PROP(node_id, zephyr_memory_attr), \
"RAM_NOCACHE") == 0; \
} \
}), \
(EMPTY))
DT_FOREACH_STATUS_OKAY(mmio_sram, IS_NON_CACHEABLE_REGION_FN);
if (mem_attr_check_buf((void *) buffer, (size_t) size, DT_MEM_ARM_MPU_RAM_NOCACHE) == 0) {
return true;
}
return cachable;
return false;
}
#endif /* defined(CONFIG_ADC_STM32_DMA) && defined(CONFIG_SOC_SERIES_STM32H7X) */

View File

@ -13,6 +13,7 @@
#include <zephyr/init.h>
#include <zephyr/drivers/clock_control.h>
#include <zephyr/drivers/dma/dma_stm32.h>
#include <zephyr/dt-bindings/memory-attr/memory-attr-arm.h>
#include <zephyr/logging/log.h>
#include <zephyr/irq.h>
@ -813,7 +814,7 @@ static int bdma_stm32_init(const struct device *dev)
* };
*/
#if DT_NODE_HAS_PROP(DT_NODELABEL(sram4), zephyr_memory_attr)
if (strcmp(DT_PROP(DT_NODELABEL(sram4), zephyr_memory_attr), "RAM_NOCACHE") != 0) {
if ((DT_PROP(DT_NODELABEL(sram4), zephyr_memory_attr) & DT_MEM_ARM_MPU_RAM_NOCACHE) == 0) {
LOG_ERR("SRAM4 is not set as non-cachable.");
return -EIO;
}

View File

@ -25,6 +25,7 @@ LOG_MODULE_REGISTER(spi_ll_stm32);
#include <zephyr/drivers/clock_control/stm32_clock_control.h>
#include <zephyr/drivers/clock_control.h>
#include <zephyr/irq.h>
#include <zephyr/mem_mgmt/mem_attr.h>
#ifdef CONFIG_NOCACHE_MEMORY
#include <zephyr/linker/linker-defs.h>
@ -81,7 +82,7 @@ struct mem_region {
};
static const struct mem_region nocache_mem_regions[] = {
DT_MEMORY_ATTR_FOREACH_NODE(GET_MEM_REGION_IF_NOCACHE)
DT_MEMORY_ATTR_FOREACH_STATUS_OKAY_NODE(GET_MEM_REGION_IF_NOCACHE)
};
#endif /* CONFIG_SOC_SERIES_STM32H7X */

View File

@ -8,6 +8,7 @@
#include <zephyr/dt-bindings/clock/mcux_lpc_syscon_clock.h>
#include <zephyr/dt-bindings/gpio/gpio.h>
#include <zephyr/dt-bindings/i2c/i2c.h>
#include <zephyr/dt-bindings/memory-attr/memory-attr-arm.h>
#include <mem.h>
/ {
@ -61,7 +62,7 @@
compatible = "zephyr,memory-region", "mmio-sram";
reg = <0x20010000 DT_SIZE_K(16)>;
zephyr,memory-region = "USB_SRAM";
zephyr,memory-attr = "RAM";
zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_RAM) )>;
};
};

View File

@ -9,6 +9,7 @@
#include <zephyr/dt-bindings/clock/mcux_lpc_syscon_clock.h>
#include <zephyr/dt-bindings/gpio/gpio.h>
#include <zephyr/dt-bindings/i2c/i2c.h>
#include <zephyr/dt-bindings/memory-attr/memory-attr-arm.h>
#include <mem.h>
/ {
@ -75,7 +76,7 @@
compatible = "zephyr,memory-region", "mmio-sram";
reg = <0x40100000 DT_SIZE_K(16)>;
zephyr,memory-region = "USB_SRAM";
zephyr,memory-attr = "RAM";
zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_RAM) )>;
};
};

View File

@ -10,6 +10,7 @@
#include <zephyr/dt-bindings/gpio/gpio.h>
#include <zephyr/dt-bindings/i2c/i2c.h>
#include <zephyr/dt-bindings/inputmux/inputmux_trigger_ports.h>
#include <zephyr/dt-bindings/memory-attr/memory-attr-arm.h>
#include <arm/armv8-m.dtsi>
/ {
@ -95,7 +96,7 @@
compatible = "zephyr,memory-region", "mmio-sram";
reg = <0x100000 DT_SIZE_K(16)>;
zephyr,memory-region = "USB_SRAM";
zephyr,memory-attr = "RAM";
zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_RAM) )>;
};
syscon: syscon@0 {

View File

@ -12,6 +12,7 @@
#include <zephyr/dt-bindings/i2c/i2c.h>
#include <zephyr/dt-bindings/mipi_dsi/mipi_dsi.h>
#include <zephyr/dt-bindings/inputmux/inputmux_trigger_ports.h>
#include <zephyr/dt-bindings/memory-attr/memory-attr-arm.h>
/ {
chosen {
@ -78,7 +79,7 @@
compatible = "zephyr,memory-region", "mmio-sram";
reg = <0x40140000 DT_SIZE_K(16)>;
zephyr,memory-region = "SRAM1";
zephyr,memory-attr = "RAM";
zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_RAM) )>;
};
};

View File

@ -10,6 +10,7 @@
#include <zephyr/dt-bindings/clock/mcux_lpc_syscon_clock.h>
#include <zephyr/dt-bindings/gpio/gpio.h>
#include <zephyr/dt-bindings/i2c/i2c.h>
#include <zephyr/dt-bindings/memory-attr/memory-attr-arm.h>
/ {
chosen {
@ -62,7 +63,7 @@
compatible = "zephyr,memory-region", "mmio-sram";
reg = <0x40140000 DT_SIZE_K(16)>;
zephyr,memory-region = "SRAM1";
zephyr,memory-attr = "RAM";
zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_RAM) )>;
};
};

View File

@ -16,6 +16,8 @@
#include <zephyr/dt-bindings/reset/stm32f2_4_7_reset.h>
#include <zephyr/dt-bindings/adc/adc.h>
#include <zephyr/dt-bindings/memory-controller/stm32-fmc-sdram.h>
#include <zephyr/dt-bindings/memory-attr/memory-attr.h>
#include <zephyr/dt-bindings/memory-attr/memory-attr-arm.h>
#include <freq.h>
/ {
@ -47,7 +49,7 @@
compatible = "zephyr,memory-region", "mmio-sram";
reg = <0x90000000 DT_SIZE_M(256)>;
zephyr,memory-region = "QSPI";
zephyr,memory-attr = "EXTMEM";
zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_EXTMEM) )>;
};
clocks {

View File

@ -17,6 +17,8 @@
#include <zephyr/dt-bindings/reset/stm32h7_reset.h>
#include <zephyr/dt-bindings/adc/adc.h>
#include <zephyr/dt-bindings/memory-controller/stm32-fmc-sdram.h>
#include <zephyr/dt-bindings/memory-attr/memory-attr.h>
#include <zephyr/dt-bindings/memory-attr/memory-attr-arm.h>
#include <freq.h>
/ {
@ -48,7 +50,7 @@
compatible = "zephyr,memory-region", "mmio-sram";
reg = <0x90000000 DT_SIZE_M(256)>;
zephyr,memory-region = "QSPI";
zephyr,memory-attr = "EXTMEM";
zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_EXTMEM) )>;
};
clocks {

View File

@ -4,17 +4,19 @@
include: [base.yaml]
properties:
zephyr,memory-attr:
zephyr,memory-region-mpu:
type: string
enum:
- "RAM"
- "RAM_NOCACHE"
- "FLASH"
- "PPB"
- "IO"
- "EXTMEM"
deprecated: true
description: |
Attribute for the memory region.
Signify that this node should result in a dedicated MPU region.
Deprecated in favor of 'zephyr,memory-attr'.
zephyr,memory-attr:
type: int
description: |
Attribute or set of attributes (bitmask) for the memory region. See
'include/zephyr/dt-bindings/memory-attr/memory-attr.h' for a
comprehensive list with description of possible values.
reg:
required: true

View File

@ -72,48 +72,6 @@
#error "Unsupported sram size configuration"
#endif
#define MPU_REGION_SIZE_32 REGION_32B
#define MPU_REGION_SIZE_64 REGION_64B
#define MPU_REGION_SIZE_128 REGION_128B
#define MPU_REGION_SIZE_256 REGION_256B
#define MPU_REGION_SIZE_512 REGION_512B
#define MPU_REGION_SIZE_1024 REGION_1K
#define MPU_REGION_SIZE_2048 REGION_2K
#define MPU_REGION_SIZE_4096 REGION_4K
#define MPU_REGION_SIZE_8192 REGION_8K
#define MPU_REGION_SIZE_16384 REGION_16K
#define MPU_REGION_SIZE_32768 REGION_32K
#define MPU_REGION_SIZE_65536 REGION_64K
#define MPU_REGION_SIZE_131072 REGION_128K
#define MPU_REGION_SIZE_262144 REGION_256K
#define MPU_REGION_SIZE_524288 REGION_512K
#define MPU_REGION_SIZE_1048576 REGION_1M
#define MPU_REGION_SIZE_2097152 REGION_2M
#define MPU_REGION_SIZE_4194304 REGION_4M
#define MPU_REGION_SIZE_8388608 REGION_8M
#define MPU_REGION_SIZE_16777216 REGION_16M
#define MPU_REGION_SIZE_33554432 REGION_32M
#define MPU_REGION_SIZE_67108864 REGION_64M
#define MPU_REGION_SIZE_134217728 REGION_128M
#define MPU_REGION_SIZE_268435456 REGION_256M
#define MPU_REGION_SIZE_536870912 REGION_512M
#define MPU_REGION_SIZE(x) MPU_REGION_SIZE_ ## x
#define ARM_MPU_REGION_INIT(p_name, p_base, p_size, p_attr) \
{ .name = p_name, \
.base = p_base, \
.attr = p_attr(MPU_REGION_SIZE(p_size)), \
}
#else
#define ARM_MPU_REGION_INIT(p_name, p_base, p_size, p_attr) \
{ .name = p_name, \
.base = p_base, \
.attr = p_attr(p_base, p_size), \
}
#endif /* !ARMV8_M_BASELINE && !ARMV8_M_MAINLINE */
#endif /* _ARM_CORTEX_M_MPU_MEM_CFG_H_ */

View File

@ -109,6 +109,12 @@
#define REGION_2G REGION_SIZE(2GB)
#define REGION_4G REGION_SIZE(4GB)
#define ARM_MPU_REGION_INIT(p_name, p_base, p_size, p_attr) \
{ .name = p_name, \
.base = p_base, \
.attr = p_attr(size_to_mpu_rasr_size(p_size)), \
}
/* Some helper defines for common regions */
/* On Cortex-M, we can only set the XN bit when CONFIG_XIP=y. When

View File

@ -188,6 +188,13 @@
* that they do not overlap with other MPU regions).
*/
#if defined(CONFIG_AARCH32_ARMV8_R)
#define ARM_MPU_REGION_INIT(p_name, p_base, p_size, p_attr) \
{ .name = p_name, \
.base = p_base, \
.attr = p_attr(p_base + p_size), \
}
#define REGION_RAM_ATTR(limit) \
{ \
.rbar = NOT_EXEC | \
@ -246,6 +253,12 @@
}
#else
#define ARM_MPU_REGION_INIT(p_name, p_base, p_size, p_attr) \
{ .name = p_name, \
.base = p_base, \
.attr = p_attr(p_base, p_size), \
}
/* On Cortex-M, we can only set the XN bit when CONFIG_XIP=y. When
* CONFIG_XIP=n, the entire image will be linked to SRAM, so we need to keep
* the SRAM region XN bit clear or the application code will not be executable.

View File

@ -227,14 +227,6 @@ struct arm_mpu_config {
.attr = _attr, \
}
#define MPU_REGION_ENTRY_FROM_DTS(_name, _base, _size, _attr) \
{ \
.name = _name, \
.base = _base, \
.limit = _base + _size, \
.attr = _attr, \
}
#define K_MEM_PARTITION_P_RW_U_RW ((k_mem_partition_attr_t) \
{(P_RW_U_RW_Msk), MPU_MAIR_INDEX_SRAM})
#define K_MEM_PARTITION_P_RW_U_NA ((k_mem_partition_attr_t) \

View File

@ -4315,6 +4315,5 @@
#include <zephyr/devicetree/can.h>
#include <zephyr/devicetree/reset.h>
#include <zephyr/devicetree/mbox.h>
#include <zephyr/devicetree/memory-attr.h>
#endif /* DEVICETREE_H */

View File

@ -1,163 +0,0 @@
/*
* Copyright (c) 2023 Carlo Caione <ccaione@baylibre.com>
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef ZEPHYR_INCLUDE_MEMORY_ATTR_H_
#define ZEPHYR_INCLUDE_MEMORY_ATTR_H_
#include <zephyr/devicetree.h>
#include <zephyr/linker/devicetree_regions.h>
#include <zephyr/sys/util.h>
/**
* @file
* @brief Memory-attr helpers
*/
/**
* @defgroup devicetree-memory-attr Memory attributes
* @ingroup devicetree
* @{
*/
/** @cond INTERNAL_HIDDEN */
#define _DT_MEM_ATTR zephyr_memory_attr
#define _DT_ATTR(token) UTIL_CAT(UTIL_CAT(REGION_, token), _ATTR)
#define _UNPACK(node_id, fn) \
fn(COND_CODE_1(DT_NODE_HAS_PROP(node_id, zephyr_memory_region), \
(LINKER_DT_NODE_REGION_NAME(node_id)), \
(DT_NODE_FULL_NAME(node_id))), \
DT_REG_ADDR(node_id), \
DT_REG_SIZE(node_id), \
_DT_ATTR(DT_STRING_TOKEN(node_id, _DT_MEM_ATTR))),
#define _APPLY(node_id, fn) \
COND_CODE_1(DT_NODE_HAS_PROP(node_id, _DT_MEM_ATTR), \
(_UNPACK(node_id, fn)), \
())
#define _FILTER(node_id, fn) \
COND_CODE_1(DT_NODE_HAS_PROP(node_id, _DT_MEM_ATTR), \
(fn(node_id)), \
())
/** @endcond */
/**
* @brief Invokes @p fn for every node in the tree with property
* `zephyr,memory-attr`
*
* The macro @p fn must take one parameter, which will be a node identifier
* with the `zephyr,memory-attr` property. The macro is expanded once for each
* node in the tree. The order that nodes are visited in is not specified.
*
* @param fn macro to invoke
*/
#define DT_MEMORY_ATTR_FOREACH_NODE(fn) \
DT_FOREACH_STATUS_OKAY_NODE_VARGS(_FILTER, fn)
/**
* @brief Invokes @p fn for MPU/MMU regions generation from the device tree
* nodes with `zephyr,memory-attr` property.
*
* Helper macro to invoke a @p fn macro on all the memory regions declared
* using the `zephyr,memory-attr` property
*
* The macro @p fn must take the form:
*
* @code{.c}
* #define MPU_FN(name, base, size, attr) ...
* @endcode
*
* The @p name, @p base and @p size parameters are retrieved from the DT node.
* When the `zephyr,memory-region` property is present in the node, the @p name
* parameter is retrived from there, otherwise the full node name is used.
*
* The `zephyr,memory-attr` enum property is passed as an extended token
* to the @p fn macro using the @p attr parameter in the form of a macro
* REGION_{attr}_ATTR.
*
* The following enums are supported for the `zephyr,memory-attr` property (see
* `zephyr,memory-attr.yaml` for a complete list):
*
* - RAM
* - RAM_NOCACHE
* - FLASH
* - PPB
* - IO
* - EXTMEM
*
* This means that usually the user code would provide some macros or defines
* with the same name of the extended property, that is:
*
* - REGION_RAM_ATTR
* - REGION_RAM_NOCACHE_ATTR
* - REGION_FLASH_ATTR
* - REGION_PPB_ATTR
* - REGION_IO_ATTR
* - REGION_EXTMEM_ATTR
*
* Example devicetree fragment:
*
* @code{.dts}
* / {
* soc {
* res0: memory@20000000 {
* reg = <0x20000000 0x4000>;
* zephyr,memory-region = "MY_NAME";
* zephyr,memory-attr = "RAM_NOCACHE";
* };
*
* res1: memory@30000000 {
* reg = <0x30000000 0x2000>;
* zephyr,memory-attr = "RAM";
* };
* };
* };
* @endcode
*
* Example usage:
*
* @code{.c}
* #define REGION_RAM_NOCACHE_ATTR 0xAAAA
* #define REGION_RAM_ATTR 0xBBBB
* #define REGION_FLASH_ATTR 0xCCCC
*
* #define MPU_FN(p_name, p_base, p_size, p_attr) \
* { \
* .name = p_name, \
* .base = p_base, \
* .size = p_size, \
* .attr = p_attr, \
* }
*
* static const struct arm_mpu_region mpu_regions[] = {
* DT_MEMORY_ATTR_APPLY(MPU_FN)
* };
* @endcode
*
* This expands to:
*
* @code{.c}
* static const struct arm_mpu_region mpu_regions[] = {
* { "MY_NAME", 0x20000000, 0x4000, 0xAAAA },
* { "memory@30000000", 0x30000000, 0x2000, 0xBBBB },
* };
* @endcode
*
* @param fn macro to invoke
*/
#define DT_MEMORY_ATTR_APPLY(fn) \
DT_FOREACH_STATUS_OKAY_NODE_VARGS(_APPLY, fn)
/**
* @}
*/
#endif /* ZEPHYR_INCLUDE_MEMORY_ATTR_H_ */

View File

@ -0,0 +1,39 @@
/*
* Copyright (c) 2023 Carlo Caione <ccaione@baylibre.com>
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_MEM_ATTR_ARM_H_
#define ZEPHYR_INCLUDE_DT_BINDINGS_MEM_ATTR_ARM_H_
#include <zephyr/sys/util_macro.h>
#include <zephyr/dt-bindings/memory-attr/memory-attr.h>
/*
* Architecture specific ARM MPU related attributes.
*
* This list is to seamlessy support the MPU regions configuration using DT and
* the `zephyr,memory-attr` property.
*
* This is legacy and it should NOT be extended further. If new MPU region
* types must be added, these must rely on the generic memory attributes.
*/
#define DT_MEM_ARM_MASK(x) ((x) & DT_MEM_ARCH_ATTR_MASK)
#define DT_MEM_ARM(x) ((x) << DT_MEM_ARCH_ATTR_SHIFT)
#define ATTR_MPU_RAM BIT(0)
#define ATTR_MPU_RAM_NOCACHE BIT(1)
#define ATTR_MPU_FLASH BIT(2)
#define ATTR_MPU_PPB BIT(3)
#define ATTR_MPU_IO BIT(4)
#define ATTR_MPU_EXTMEM BIT(5)
#define DT_MEM_ARM_MPU_RAM DT_MEM_ARM(ATTR_MPU_RAM)
#define DT_MEM_ARM_MPU_RAM_NOCACHE DT_MEM_ARM(ATTR_MPU_RAM_NOCACHE)
#define DT_MEM_ARM_MPU_FLASH DT_MEM_ARM(ATTR_MPU_FLASH)
#define DT_MEM_ARM_MPU_PPB DT_MEM_ARM(ATTR_MPU_PPB)
#define DT_MEM_ARM_MPU_IO DT_MEM_ARM(ATTR_MPU_IO)
#define DT_MEM_ARM_MPU_EXTMEM DT_MEM_ARM(ATTR_MPU_EXTMEM)
#define DT_MEM_ARM_MPU_UNKNOWN DT_MEM_ARCH_ATTR_UNKNOWN
#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_MEM_ATTR_ARM_H_ */

View File

@ -0,0 +1,37 @@
/*
* Copyright (c) 2023 Carlo Caione <ccaione@baylibre.com>
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_MEM_ATTR_RISCV_H_
#define ZEPHYR_INCLUDE_DT_BINDINGS_MEM_ATTR_RISCV_H_
#include <zephyr/sys/util_macro.h>
#include <zephyr/dt-bindings/memory-attr/memory-attr.h>
/*
* Architecture specific RISCV related attributes.
*/
#define DT_MEM_RISCV_MASK(x) ((x) & DT_MEM_ARCH_ATTR_MASK)
#define DT_MEM_RISCV(x) ((x) << DT_MEM_ARCH_ATTR_SHIFT)
#define ATTR_RISCV_TYPE_MAIN BIT(0)
#define ATTR_RISCV_TYPE_IO BIT(1)
#define ATTR_RISCV_TYPE_EMPTY BIT(2)
#define ATTR_RISCV_AMO_SWAP BIT(3)
#define ATTR_RISCV_AMO_LOGICAL BIT(4)
#define ATTR_RISCV_AMO_ARITHMETIC BIT(5)
#define ATTR_RISCV_IO_IDEMPOTENT_READ BIT(6)
#define ATTR_RISCV_IO_IDEMPOTENT_WRITE BIT(7)
#define DT_MEM_RISCV_TYPE_MAIN DT_MEM_RISCV(ATTR_RISCV_TYPE_MAIN)
#define DT_MEM_RISCV_TYPE_IO DT_MEM_RISCV(ATTR_RISCV_TYPE_IO)
#define DT_MEM_RISCV_TYPE_EMPTY DT_MEM_RISCV(ATTR_RISCV_TYPE_EMPTY)
#define DT_MEM_RISCV_AMO_SWAP DT_MEM_RISCV(ATTR_RISCV_AMO_SWAP)
#define DT_MEM_RISCV_AMO_LOGICAL DT_MEM_RISCV(ATTR_RISCV_AMO_LOGICAL)
#define DT_MEM_RISCV_AMO_ARITHMETIC DT_MEM_RISCV(ATTR_RISCV_AMO_ARITHMETIC)
#define DT_MEM_RISCV_IO_IDEMPOTENT_READ DT_MEM_RISCV(ATTR_RISCV_IO_IDEMPOTENT_READ)
#define DT_MEM_RISCV_IO_IDEMPOTENT_WRITE DT_MEM_RISCV(ATTR_RISCV_IO_IDEMPOTENT_WRITE)
#define DT_MEM_RISCV_UNKNOWN DT_MEM_ARCH_ATTR_UNKNOWN
#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_MEM_ATTR_RISCV_H_ */

View File

@ -0,0 +1,31 @@
/*
* Copyright (c) 2023 Carlo Caione <ccaione@baylibre.com>
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_MEM_ATTR_XTENSA_H_
#define ZEPHYR_INCLUDE_DT_BINDINGS_MEM_ATTR_XTENSA_H_
#include <zephyr/sys/util_macro.h>
#include <zephyr/dt-bindings/memory-attr/memory-attr.h>
/*
* Architecture specific Xtensa related attributes.
*/
#define DT_MEM_XTENSA_MASK(x) ((x) & DT_MEM_ARCH_ATTR_MASK)
#define DT_MEM_XTENSA(x) ((x) << DT_MEM_ARCH_ATTR_SHIFT)
#define ATTR_XTENSA_INSTR_ROM BIT(0)
#define ATTR_XTENSA_INSTR_RAM BIT(1)
#define ATTR_XTENSA_DATA_ROM BIT(2)
#define ATTR_XTENSA_DATA_RAM BIT(3)
#define ATTR_XTENSA_XLMI BIT(4)
#define DT_MEM_XTENSA_INSTR_ROM DT_MEM_XTENSA(ATTR_XTENSA_INSTR_ROM)
#define DT_MEM_XTENSA_INSTR_RAM DT_MEM_XTENSA(ATTR_XTENSA_INSTR_RAM)
#define DT_MEM_XTENSA_DATA_ROM DT_MEM_XTENSA(ATTR_XTENSA_DATA_ROM)
#define DT_MEM_XTENSA_DATA_RAM DT_MEM_XTENSA(ATTR_XTENSA_DATA_RAM)
#define DT_MEM_XTENSA_XLMI DT_MEM_XTENSA(ATTR_XTENSA_XLMI)
#define DT_MEM_XTENSA_UNKNOWN DT_MEM_ARCH_ATTR_UNKNOWN
#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_MEM_ATTR_XTENSA_H_ */

View File

@ -0,0 +1,48 @@
/*
* Copyright (c) 2023 Carlo Caione <ccaione@baylibre.com>
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_MEM_ATTR_H_
#define ZEPHYR_INCLUDE_DT_BINDINGS_MEM_ATTR_H_
#include <zephyr/sys/util_macro.h>
/*
* Generic memory attributes.
*
* Generic memory attributes that should be common to all architectures.
*/
#define DT_MEM_ATTR_MASK GENMASK(15, 0)
#define DT_MEM_ATTR_SHIFT (0)
#define DT_MEM_CACHEABLE BIT(0) /* cacheable */
#define DT_MEM_NON_VOLATILE BIT(1) /* non-volatile */
#define DT_MEM_OOO BIT(2) /* out-of-order */
#define DT_MEM_DMA BIT(3) /* DMA-able */
#define DT_MEM_UNKNOWN BIT(15) /* must be last */
/* to be continued */
/*
* Software specific memory attributes.
*
* Software can define their own memory attributes if needed using the
* provided mask.
*/
#define DT_MEM_SW_ATTR_MASK GENMASK(19, 16)
#define DT_MEM_SW_ATTR_SHIFT (16)
#define DT_MEM_SW_ATTR_UNKNOWN BIT(19)
/*
* Architecture specific memory attributes.
*
* Architectures can define their own memory attributes if needed using the
* provided mask.
*
* See for example `include/zephyr/dt-bindings/memory-attr/memory-attr-arm.h`
*/
#define DT_MEM_ARCH_ATTR_MASK GENMASK(31, 20)
#define DT_MEM_ARCH_ATTR_SHIFT (20)
#define DT_MEM_ARCH_ATTR_UNKNOWN BIT(31)
#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_MEM_ATTR_H_ */

View File

@ -0,0 +1,114 @@
/*
* Copyright (c) 2023 Carlo Caione <ccaione@baylibre.com>
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef ZEPHYR_INCLUDE_MEM_ATTR_H_
#define ZEPHYR_INCLUDE_MEM_ATTR_H_
/**
* @brief Memory-Attr Interface
* @defgroup memory_attr_interface Memory-Attr Interface
* @ingroup mem_mgmt
* @{
*/
#include <stddef.h>
#include <zephyr/types.h>
#include <zephyr/dt-bindings/memory-attr/memory-attr.h>
#ifdef __cplusplus
extern "C" {
#endif
/** @cond INTERNAL_HIDDEN */
#define __MEM_ATTR zephyr_memory_attr
#define _FILTER(node_id, fn) \
COND_CODE_1(DT_NODE_HAS_PROP(node_id, __MEM_ATTR), \
(fn(node_id)), \
())
/** @endcond */
/**
* @brief Invokes @p fn for every status `okay` node in the tree with property
* `zephyr,memory-attr`
*
* The macro @p fn must take one parameter, which will be a node identifier
* with the `zephyr,memory-attr` property. The macro is expanded once for each
* node in the tree with status `okay`. The order that nodes are visited in is
* not specified.
*
* @param fn macro to invoke
*/
#define DT_MEMORY_ATTR_FOREACH_STATUS_OKAY_NODE(fn) \
DT_FOREACH_STATUS_OKAY_NODE_VARGS(_FILTER, fn)
/**
* @brief memory-attr region structure.
*
* This structure represents the data gathered from DT about a memory-region
* marked with memory attributes.
*/
struct mem_attr_region_t {
/** Memory node full name */
const char *dt_name;
/** Memory region physical address */
uintptr_t dt_addr;
/** Memory region size */
size_t dt_size;
/** Memory region attributes */
uint32_t dt_attr;
};
/**
* @brief Get the list of memory regions.
*
* Get the list of enabled memory regions with their memory-attribute as
* gathered by DT.
*
* @param region Pointer to pointer to the list of memory regions.
*
* @retval Number of memory regions returned in the parameter.
*/
size_t mem_attr_get_regions(const struct mem_attr_region_t **region);
/**
* @brief Check if a buffer has correct size and attributes.
*
* This function is used to check if a given buffer with a given set of
* attributes fully match a memory region in terms of size and attributes.
*
* This is usually used to verify that a buffer has the expected attributes
* (for example the buffer is cacheable / non-cacheable or belongs to RAM /
* FLASH, etc...) and it has been correctly allocated.
*
* The expected set of attributes for the buffer is and-matched against the
* full set of attributes for the memory region it belongs to (bitmask). So the
* buffer is considered matching when at least that set of attributes are valid
* for the memory region (but the region can be marked also with other
* attributes besides the one passed as parameter).
*
* @param addr Virtual address of the user buffer.
* @param size Size of the user buffer.
* @param attr Expected / desired attribute for the buffer.
*
* @retval 0 if the buffer has the correct size and attribute.
* @retval -ENOSYS if the operation is not supported (for example if the MMU is enabled).
* @retval -ENOTSUP if the wrong parameters were passed.
* @retval -EINVAL if the buffer has the wrong set of attributes.
* @retval -ENOSPC if the buffer is too big for the region it belongs to.
* @retval -ENOBUFS if the buffer is entirely allocated outside a memory region.
*/
int mem_attr_check_buf(void *addr, size_t size, uint32_t attr);
#ifdef __cplusplus
}
#endif
/** @} */
#endif /* ZEPHYR_INCLUDE_MEM_ATTR_H_ */

View File

@ -88,7 +88,7 @@ enum shared_multi_heap_attr {
*/
struct shared_multi_heap_region {
/** Memory heap attribute */
unsigned int attr;
uint32_t attr;
/** Memory heap starting virtual address */
uintptr_t addr;

View File

@ -4,6 +4,8 @@
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/dt-bindings/memory-attr/memory-attr-arm.h>
/ {
chosen {
zephyr,ipc_shm = &ocram2_overlay;
@ -17,6 +19,6 @@
compatible = "zephyr,memory-region", "mmio-sram";
reg = <0x202c0000 DT_SIZE_K(16)>;
zephyr,memory-region="OCRAM2_OVERLAY";
zephyr,memory-attr = "IO";
zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_IO) )>;
};
};

View File

@ -4,6 +4,8 @@
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/dt-bindings/memory-attr/memory-attr-arm.h>
/ {
chosen {
zephyr,ipc_shm = &ocram2_overlay;
@ -17,6 +19,6 @@
compatible = "zephyr,memory-region", "mmio-sram";
reg = <0x202c0000 DT_SIZE_K(16)>;
zephyr,memory-region="OCRAM2_OVERLAY";
zephyr,memory-attr = "IO";
zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_IO) )>;
};
};

View File

@ -4,6 +4,8 @@
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/dt-bindings/memory-attr/memory-attr-arm.h>
/ {
chosen {
zephyr,ipc_shm = &ocram2_overlay;
@ -17,6 +19,6 @@
compatible = "zephyr,memory-region", "mmio-sram";
reg = <0x202c0000 DT_SIZE_K(16)>;
zephyr,memory-region="OCRAM2_OVERLAY";
zephyr,memory-attr = "IO";
zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_IO) )>;
};
};

View File

@ -33,7 +33,7 @@
compatible = "zephyr,memory-region", "mmio-sram";
reg = <0x202c0000 DT_SIZE_K(16)>;
zephyr,memory-region="OCRAM2_OVERLAY";
zephyr,memory-attr = "IO";
zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_IO) )>;
};
};

View File

@ -33,7 +33,7 @@
compatible = "zephyr,memory-region", "mmio-sram";
reg = <0x202c0000 DT_SIZE_K(16)>;
zephyr,memory-region="OCRAM2_OVERLAY";
zephyr,memory-attr = "IO";
zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_IO) )>;
};
};

View File

@ -33,7 +33,7 @@
compatible = "zephyr,memory-region", "mmio-sram";
reg = <0x202c0000 DT_SIZE_K(16)>;
zephyr,memory-region="OCRAM2_OVERLAY";
zephyr,memory-attr = "IO";
zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_IO) )>;
};
};

View File

@ -6,7 +6,6 @@
#include <zephyr/sys/slist.h>
#include <zephyr/arch/arm/mpu/arm_mpu.h>
#include <zephyr/devicetree/memory-attr.h>
#include <zephyr/arch/arm/cortex_m/arm_mpu_mem_cfg.h>
@ -29,9 +28,6 @@ static const struct arm_mpu_region mpu_regions[] = {
#else
REGION_RAM_ATTR(REGION_SRAM_SIZE)),
#endif
/* DT-defined regions */
DT_MEMORY_ATTR_APPLY(ARM_MPU_REGION_INIT)
};
const struct arm_mpu_config mpu_config = {

View File

@ -7,7 +7,6 @@
#define SDRAM_BASE_ADDR 0x80000000
#include <zephyr/devicetree.h>
#include <zephyr/devicetree/memory-attr.h>
#include <zephyr/arch/arm/cortex_m/arm_mpu_mem_cfg.h>
static const struct arm_mpu_region mpu_regions[] = {
@ -28,9 +27,6 @@ static const struct arm_mpu_region mpu_regions[] = {
*/
MPU_REGION_ENTRY("SDRAM0", SDRAM_BASE_ADDR, REGION_IO_ATTR(REGION_512M)),
#endif
/* DT-defined regions */
DT_MEMORY_ATTR_APPLY(ARM_MPU_REGION_INIT)
};
const struct arm_mpu_config mpu_config = {

View File

@ -35,9 +35,6 @@ static struct arm_mpu_region mpu_regions[] = {
.attr = {(uint32_t)_rom_attr},
},
#endif
/* DT-defined regions */
DT_MEMORY_ATTR_APPLY(ARM_MPU_REGION_INIT)
};
const struct arm_mpu_config mpu_config = {

View File

@ -38,9 +38,6 @@ static const struct arm_mpu_region mpu_regions[] = {
REGION_PPB_ATTR(REGION_256B)),
#endif
#endif
/* DT-defined regions */
DT_MEMORY_ATTR_APPLY(ARM_MPU_REGION_INIT)
};
const struct arm_mpu_config mpu_config = {

View File

@ -7,7 +7,6 @@
#include <zephyr/arch/arm64/cortex_r/arm_mpu.h>
#include <zephyr/linker/linker-defs.h>
#include <zephyr/devicetree/memory-attr.h>
#include <zephyr/sys/util.h>
static const struct arm_mpu_region mpu_regions[] = {
@ -39,9 +38,6 @@ static const struct arm_mpu_region mpu_regions[] = {
#endif
(uintptr_t)__kernel_ram_end,
REGION_RAM_ATTR),
/* Extra regions defined in device tree */
DT_MEMORY_ATTR_APPLY(MPU_REGION_ENTRY_FROM_DTS)
};
const struct arm_mpu_config mpu_config = {

View File

@ -17,6 +17,7 @@ add_subdirectory(fb)
add_subdirectory(fs)
add_subdirectory(ipc)
add_subdirectory(logging)
add_subdirectory(mem_mgmt)
add_subdirectory(mgmt)
add_subdirectory(modbus)
add_subdirectory(pm)

View File

@ -22,6 +22,7 @@ source "subsys/ipc/Kconfig"
source "subsys/jwt/Kconfig"
source "subsys/logging/Kconfig"
source "subsys/lorawan/Kconfig"
source "subsys/mem_mgmt/Kconfig"
source "subsys/mgmt/Kconfig"
source "subsys/modbus/Kconfig"
source "subsys/modem/Kconfig"

View File

@ -0,0 +1,3 @@
# SPDX-License-Identifier: Apache-2.0
zephyr_sources_ifdef(CONFIG_MEM_ATTR mem_attr.c)

12
subsys/mem_mgmt/Kconfig Normal file
View File

@ -0,0 +1,12 @@
# Copyright (c) 2023 Carlo Caione <ccaione@baylibre.com>
# SPDX-License-Identifier: Apache-2.0
config MEM_ATTR
bool "Memory Attributes management library"
default y if ARM_MPU
help
Enable a small library to manage the memory regions defined in the DT
with a `zephyr,memory-attr` property. This library builds at build
time an array of the memory regions defined in the DT that can be
probed at run-time using several helper functions. Set to `N` if
unsure to save RODATA space.

View File

@ -0,0 +1,61 @@
/*
* Copyright (c) 2023 Carlo Caione, <ccaione@baylibre.com>
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/kernel.h>
#include <zephyr/mem_mgmt/mem_attr.h>
#define _BUILD_MEM_ATTR_REGION(node_id) \
{ \
.dt_name = DT_NODE_FULL_NAME(node_id), \
.dt_addr = DT_REG_ADDR(node_id), \
.dt_size = DT_REG_SIZE(node_id), \
.dt_attr = DT_PROP(node_id, zephyr_memory_attr), \
},
static const struct mem_attr_region_t mem_attr_region[] = {
DT_MEMORY_ATTR_FOREACH_STATUS_OKAY_NODE(_BUILD_MEM_ATTR_REGION)
};
size_t mem_attr_get_regions(const struct mem_attr_region_t **region)
{
*region = mem_attr_region;
return ARRAY_SIZE(mem_attr_region);
}
int mem_attr_check_buf(void *v_addr, size_t size, uint32_t attr)
{
uintptr_t addr = (uintptr_t) v_addr;
/*
* If MMU is enabled the address of the buffer is a virtual address
* while the addresses in the DT are physical addresses. Given that we
* have no way of knowing whether a mapping exists, we simply bail out.
*/
if (IS_ENABLED(CONFIG_MMU)) {
return -ENOSYS;
}
if (size == 0) {
return -ENOTSUP;
}
for (size_t idx = 0; idx < ARRAY_SIZE(mem_attr_region); idx++) {
const struct mem_attr_region_t *region = &mem_attr_region[idx];
size_t region_end = region->dt_addr + region->dt_size;
/* Check if the buffer is in the region */
if ((addr >= region->dt_addr) && (addr < region_end)) {
/* Check if the buffer is entirely contained in the region */
if ((addr + size) <= region_end) {
/* check if the attribute is correct */
return (region->dt_attr & attr) == attr ? 0 : -EINVAL;
}
return -ENOSPC;
}
}
return -ENOBUFS;
}

View File

@ -1,8 +0,0 @@
# SPDX-License-Identifier: Apache-2.0
cmake_minimum_required(VERSION 3.20.0)
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
project(arm_mpu_regions)
target_sources(app PRIVATE src/main.c)

View File

@ -1,41 +0,0 @@
/*
* Copyright (c) 2021 Carlo Caione <ccaione@baylibre.com>
*
* SPDX-License-Identifier: Apache-2.0
*/
/ {
/delete-node/ memory@20000000;
sram0: memory@20000000 {
compatible = "mmio-sram";
reg = <0x20000000 0x200000>;
};
sram_cache: memory@20200000 {
compatible = "zephyr,memory-region", "mmio-sram";
reg = <0x20200000 0x100000>;
zephyr,memory-region = "SRAM_CACHE";
zephyr,memory-attr = "RAM";
};
sram_no_cache: memory@20300000 {
compatible = "zephyr,memory-region", "mmio-sram";
reg = <0x20300000 0x100000>;
zephyr,memory-region = "SRAM_NO_CACHE";
zephyr,memory-attr = "RAM_NOCACHE";
};
sram_dtcm_fake: memory@abcdabcd {
compatible = "zephyr,memory-region", "arm,dtcm";
reg = <0xabcdabcd 0x100000>;
zephyr,memory-region = "SRAM_DTCM_FAKE";
zephyr,memory-attr = "RAM";
};
sram_no_mpu: memory@deaddead {
compatible = "zephyr,memory-region", "mmio-sram";
reg = <0xdeaddead 0x100000>;
zephyr,memory-region = "SRAM_NO_MPU";
};
};

View File

@ -1,53 +0,0 @@
/*
* Copyright (c) 2021 Carlo Caione <ccaione@baylibre.com>
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/kernel.h>
#include <zephyr/linker/linker-defs.h>
#include <zephyr/sys/slist.h>
#include <zephyr/arch/arm/mpu/arm_mpu.h>
#include <zephyr/ztest.h>
#include <string.h>
extern const struct arm_mpu_config mpu_config;
static arm_mpu_region_attr_t cacheable = REGION_RAM_ATTR(REGION_1M);
static arm_mpu_region_attr_t noncacheable = REGION_RAM_NOCACHE_ATTR(REGION_1M);
ZTEST(test_c_arm_mpu_regions, test_regions)
{
int cnt = 0;
for (size_t i = 0; i < mpu_config.num_regions; i++) {
const struct arm_mpu_region *r = &mpu_config.mpu_regions[i];
if (!strcmp(r->name, "SRAM_CACHE")) {
zassert_equal(r->base, 0x20200000, "Wrong base");
zassert_equal(r->attr.rasr, cacheable.rasr,
"Wrong attr for SRAM_CACHE");
cnt++;
} else if (!strcmp(r->name, "SRAM_NO_CACHE")) {
zassert_equal(r->base, 0x20300000, "Wrong base");
zassert_equal(r->attr.rasr, noncacheable.rasr,
"Wrong attr for SRAM_NO_CACHE");
cnt++;
} else if (!strcmp(r->name, "SRAM_DTCM_FAKE")) {
zassert_equal(r->base, 0xabcdabcd, "Wrong base");
zassert_equal(r->attr.rasr, cacheable.rasr,
"Wrong attr for SRAM_DTCM_FAKE");
cnt++;
}
}
if (cnt != 3) {
/*
* SRAM0 and SRAM_NO_MPU should not create any MPU region.
* Check that.
*/
ztest_test_fail();
}
}
ZTEST_SUITE(test_c_arm_mpu_regions, NULL, NULL, NULL, NULL, NULL);

View File

@ -1,6 +0,0 @@
tests:
arch.mpu_regions.arm:
platform_allow: mps2_an385
tags:
- sram
- mpu

View File

@ -3,6 +3,9 @@
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/dt-bindings/memory-attr/memory-attr-arm.h>
&adc1 {
dmas = < &dmamux1 0 9 (STM32_DMA_PERIPH_TO_MEMORY |
STM32_DMA_MEM_INC | STM32_DMA_MEM_16BITS | STM32_DMA_PERIPH_16BITS) >;
@ -22,7 +25,7 @@
/* ADC driver expects a buffer in a non-cachable memory region */
&sram4 {
zephyr,memory-attr = "RAM_NOCACHE";
zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_RAM_NOCACHE) )>;
};
&dma1 {

View File

@ -2,6 +2,8 @@
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/dt-bindings/memory-attr/memory-attr-arm.h>
&dma1 {
status = "okay";
};
@ -18,7 +20,7 @@ test_dma0: &dmamux1 {
* to be non-cachable.
*/
&sram4 {
zephyr,memory-attr = "RAM_NOCACHE";
zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_RAM_NOCACHE) )>;
};
&bdma1 {

View File

@ -18,7 +18,7 @@ test_dma0: &dmamux1 {
* to be non-cachable.
*/
&sram4 {
zephyr,memory-attr = "RAM_NOCACHE";
zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_RAM_NOCACHE) )>;
};
&bdma1 {

View File

@ -4,6 +4,9 @@
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/dt-bindings/memory-attr/memory-attr.h>
#include <zephyr/dt-bindings/memory-attr/memory-attr-arm.h>
/ {
/delete-node/ memory@38000000;
@ -17,20 +20,20 @@
compatible = "zephyr,memory-region", "mmio-sram";
reg = <0x38100000 0x1000>;
zephyr,memory-region = "RES0";
zephyr,memory-attr = "RAM";
zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_RAM) )>;
};
res1: memory@38200000 {
compatible = "zephyr,memory-region", "mmio-sram";
reg = <0x38200000 0x2000>;
zephyr,memory-region = "RES1";
zephyr,memory-attr = "RAM_NOCACHE";
zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_RAM_NOCACHE) )>;
};
res2: memory@38300000 {
compatible = "zephyr,memory-region", "mmio-sram";
reg = <0x38300000 0x3000>;
zephyr,memory-region = "RES2";
zephyr,memory-attr = "RAM";
zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_RAM) )>;
};
};

View File

@ -4,20 +4,23 @@
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/dt-bindings/memory-attr/memory-attr.h>
#include <zephyr/dt-bindings/memory-attr/memory-attr-arm.h>
/ {
soc {
res0: memory@42000000 {
compatible = "zephyr,memory-region", "mmio-sram";
reg = <0x0 0x42000000 0x0 0x1000>;
zephyr,memory-region = "RES0";
zephyr,memory-attr = "RAM";
zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_RAM) )>;
};
res1: memory@43000000 {
compatible = "zephyr,memory-region", "mmio-sram";
reg = <0x0 0x43000000 0x0 0x2000>;
zephyr,memory-region = "RES1";
zephyr,memory-attr = "RAM_NOCACHE";
zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_RAM_NOCACHE) )>;
};
res_no_mpu: memory@45000000 {
@ -30,7 +33,7 @@
compatible = "zephyr,memory-region", "mmio-sram";
reg = <0x0 0x44000000 0x0 0x3000>;
zephyr,memory-region = "RES2";
zephyr,memory-attr = "RAM";
zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_RAM) )>;
};
};
};

View File

@ -8,6 +8,7 @@
#include <zephyr/ztest.h>
#include <zephyr/linker/linker-defs.h>
#include <zephyr/sys/mem_manage.h>
#include <zephyr/dt-bindings/memory-attr/memory-attr-arm.h>
#include <zephyr/multi_heap/shared_multi_heap.h>
@ -22,14 +23,14 @@ struct region_map {
uintptr_t p_addr;
};
#define FOREACH_REG(n) \
{ \
.region = { \
.addr = (uintptr_t) DT_INST_REG_ADDR(n), \
.size = DT_INST_REG_SIZE(n), \
.attr = DT_INST_ENUM_IDX_OR(n, zephyr_memory_attr, \
SMH_REG_ATTR_NUM), \
}, \
#define FOREACH_REG(n) \
{ \
.region = { \
.addr = (uintptr_t) DT_INST_REG_ADDR(n), \
.size = DT_INST_REG_SIZE(n), \
.attr = DT_INST_PROP_OR(n, zephyr_memory_attr, \
DT_MEM_ARM_MPU_UNKNOWN), \
}, \
},
struct region_map map[] = {
@ -66,7 +67,7 @@ static struct region_map *get_region_map(void *v_addr)
return NULL;
}
static inline enum shared_multi_heap_attr mpu_to_reg_attr(int mpu_attr)
static inline enum shared_multi_heap_attr mpu_to_reg_attr(uint32_t dt_attr)
{
/*
* All the memory regions defined in the DT with the MPU property `RAM`
@ -82,10 +83,10 @@ static inline enum shared_multi_heap_attr mpu_to_reg_attr(int mpu_attr)
* RAM -> SMH_REG_ATTR_CACHEABLE
* RAM_NOCACHE -> SMH_REG_ATTR_NON_CACHEABLE
*/
switch (mpu_attr) {
case 0: /* RAM */
switch (DT_MEM_ARM_MASK(dt_attr)) {
case DT_MEM_ARM_MPU_RAM:
return SMH_REG_ATTR_CACHEABLE;
case 1: /* RAM_NOCACHE */
case DT_MEM_ARM_MPU_RAM_NOCACHE:
return SMH_REG_ATTR_NON_CACHEABLE;
default:
/* How ? */
@ -104,7 +105,7 @@ static void fill_multi_heap(void)
reg_map = &map[idx];
/* zephyr,memory-attr property not found. Skip it. */
if (reg_map->region.attr == SMH_REG_ATTR_NUM) {
if (reg_map->region.attr == DT_MEM_ARM_MPU_UNKNOWN) {
continue;
}

View File

@ -645,18 +645,6 @@
val = "XA XPLUS XB", "XC XPLUS XD", "XA XMINUS XB", "XC XMINUS XD";
};
test_mem_ram: memory@aabbccdd {
compatible = "vnd,memory-attr";
reg = < 0xaabbccdd 0x4000 >;
zephyr,memory-attr = "RAM";
};
test_mem_ram_nocache: memory@44332211 {
compatible = "vnd,memory-attr";
reg = < 0x44332211 0x2000 >;
zephyr,memory-attr = "RAM_NOCACHE";
};
test-mtd@ffeeddcc {
reg = < 0x0 0x1000 >;
#address-cells = < 1 >;

View File

@ -2717,70 +2717,6 @@ ZTEST(devicetree_api, test_mbox)
DT_NODELABEL(test_mbox_zero_cell)), "");
}
ZTEST(devicetree_api, test_memory_attr)
{
#define REGION_RAM_ATTR (0xDEDE)
#define REGION_RAM_NOCACHE_ATTR (0xCACA)
#define TEST_FUNC(p_name, p_base, p_size, p_attr) \
{ .name = (p_name), \
.base = (p_base), \
.size = (p_size), \
.attr = (p_attr), \
}
struct vnd_memory_binding {
char *name;
uintptr_t base;
size_t size;
unsigned int attr;
};
struct vnd_memory_binding val_apply[] = {
DT_MEMORY_ATTR_APPLY(TEST_FUNC)
};
zassert_true(!strcmp(val_apply[0].name, "memory@aabbccdd"), "");
zassert_equal(val_apply[0].base, 0xaabbccdd, "");
zassert_equal(val_apply[0].size, 0x4000, "");
zassert_equal(val_apply[0].attr, 0xDEDE, "");
zassert_true(!strcmp(val_apply[1].name, "memory@44332211"), "");
zassert_equal(val_apply[1].base, 0x44332211, "");
zassert_equal(val_apply[1].size, 0x2000, "");
zassert_equal(val_apply[1].attr, 0xCACA, "");
#undef TEST_FUNC
#undef REGION_RAM_ATTR
#undef REGION_RAM_NOCACHE_ATTR
#define TEST_FUNC(node_id) DT_NODE_FULL_NAME(node_id),
static const char * const val_func[] = {
DT_MEMORY_ATTR_FOREACH_NODE(TEST_FUNC)
};
zassert_true(!strcmp(val_func[0], "memory@aabbccdd"), "");
zassert_true(!strcmp(val_func[1], "memory@44332211"), "");
#undef TEST_FUNC
#define TEST_FUNC(node_id) \
COND_CODE_1(DT_ENUM_HAS_VALUE(node_id, \
zephyr_memory_attr, \
RAM_NOCACHE), \
(DT_REG_ADDR(node_id)), \
())
uintptr_t val_filt[] = {
DT_MEMORY_ATTR_FOREACH_NODE(TEST_FUNC)
};
zassert_equal(val_filt[0], 0x44332211, "");
#undef TEST_FUNC
}
ZTEST(devicetree_api, test_fixed_partitions)
{
/* Test finding fixed partitions by the 'label' property. */

View File

@ -0,0 +1,8 @@
#SPDX-License-Identifier: Apache-2.0
cmake_minimum_required(VERSION 3.20.0)
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
project(test_mem_attr)
FILE(GLOB app_sources src/*.c)
target_sources(app PRIVATE ${app_sources})

View File

@ -0,0 +1,28 @@
/*
* Copyright (c) 2023 Carlo Caione <ccaione@baylibre.com>
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/dt-bindings/memory-attr/memory-attr.h>
#include <zephyr/dt-bindings/memory-attr/memory-attr-arm.h>
/ {
mem_ram: memory@10000000 {
compatible = "vnd,memory-attr";
reg = <0x10000000 0x1000>;
zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_FLASH) | DT_MEM_NON_VOLATILE )>;
};
mem_ram_nocache: memory@20000000 {
compatible = "vnd,memory-attr";
reg = <0x20000000 0x2000>;
zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_RAM_NOCACHE) )>;
};
mem_ram_disabled: memory@30000000 {
compatible = "vnd,memory-attr";
reg = <0x30000000 0x3000>;
zephyr,memory-attr = <( DT_MEM_CACHEABLE | DT_MEM_OOO )>;
status = "disabled";
};
};

View File

@ -1,2 +1,3 @@
CONFIG_ZTEST=y
CONFIG_ZTEST_NEW_API=y
CONFIG_MEM_ATTR=y

View File

@ -0,0 +1,87 @@
/*
* Copyright (c) 2023 Carlo Caione <ccaione@baylibre.com>
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/ztest.h>
#include <zephyr/mem_mgmt/mem_attr.h>
#include <zephyr/dt-bindings/memory-attr/memory-attr-arm.h>
ZTEST(mem_attr, test_mem_attr)
{
const struct mem_attr_region_t *region;
size_t num_regions;
num_regions = mem_attr_get_regions(&region);
zassert_equal(num_regions, 2, "No regions returned");
/*
* Check the data in the regions
*/
for (size_t idx = 0; idx < num_regions; idx++) {
if (region[idx].dt_size == 0x1000) {
zassert_equal(region[idx].dt_addr, 0x10000000, "Wrong region address");
zassert_equal(region[idx].dt_size, 0x1000, "Wrong region size");
zassert_equal(region[idx].dt_attr, DT_MEM_ARM_MPU_FLASH |
DT_MEM_NON_VOLATILE,
"Wrong region address");
zassert_true((strcmp(region[idx].dt_name, "memory@10000000") == 0),
"Wrong name");
} else {
zassert_equal(region[idx].dt_addr, 0x20000000, "Wrong region address");
zassert_equal(region[idx].dt_size, 0x2000, "Wrong region size");
zassert_equal(region[idx].dt_attr, DT_MEM_ARM_MPU_RAM_NOCACHE,
"Wrong region address");
zassert_true((strcmp(region[idx].dt_name, "memory@20000000") == 0),
"Wrong name");
}
}
/*
* Check the input sanitization
*/
zassert_equal(mem_attr_check_buf((void *) 0x10000000, 0x0, DT_MEM_NON_VOLATILE),
-ENOTSUP, "Unexpected return value");
/*
* Check a buffer with the correct properties
*/
zassert_equal(mem_attr_check_buf((void *) 0x10000100, 0x100,
DT_MEM_ARM_MPU_FLASH | DT_MEM_NON_VOLATILE),
0, "Unexpected return value");
zassert_equal(mem_attr_check_buf((void *) 0x20000000, 0x2000, DT_MEM_ARM_MPU_RAM_NOCACHE),
0, "Unexpected return value");
/*
* Check partial attributes
*/
zassert_equal(mem_attr_check_buf((void *) 0x10000100, 0x100, DT_MEM_NON_VOLATILE),
0, "Unexpected return value");
/*
* Check a buffer with the wrong attribute
*/
zassert_equal(mem_attr_check_buf((void *) 0x20000000, 0x2000, DT_MEM_OOO),
-EINVAL, "Unexpected return value");
/*
* Check a buffer outsize the regions
*/
zassert_equal(mem_attr_check_buf((void *) 0x40000000, 0x1000, DT_MEM_NON_VOLATILE),
-ENOBUFS, "Unexpected return value");
/*
* Check a buffer too big for the region
*/
zassert_equal(mem_attr_check_buf((void *) 0x10000000, 0x2000, DT_MEM_NON_VOLATILE),
-ENOSPC, "Unexpected return value");
/*
* Check a buffer in a disabled region
*/
zassert_equal(mem_attr_check_buf((void *) 0x30000000, 0x1000, DT_MEM_OOO),
-ENOBUFS, "Unexpected return value");
}
ZTEST_SUITE(mem_attr, NULL, NULL, NULL, NULL, NULL);

View File

@ -0,0 +1,8 @@
common:
platform_allow:
- native_posix
- native_posix_64
integration_platforms:
- native_posix
tests:
mem_mgmt.mem_attr.default: {}