Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions doc/services/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
9 changes: 9 additions & 0 deletions doc/services/mem_mgmt/index.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
.. _mem_mgmt_api:

Memory Attributes management API
================================

API Reference
*************

.. doxygengroup:: memory_attr_interface
3 changes: 3 additions & 0 deletions dts/bindings/base/zephyr,memory-attr.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@

include: [base.yaml]

# XXX: This list MUST be kept in sync with
# include/zephyr/dt-bindings/memory-attr/memory-attr.h

properties:
zephyr,memory-attr:
type: string
Expand Down
20 changes: 18 additions & 2 deletions include/zephyr/devicetree/memory-attr.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,21 @@

/** @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 Invokes @p fn for every node in the tree with property
* `zephyr,memory-attr`
Expand All @@ -59,14 +74,15 @@
* @param fn macro to invoke
*/
#define DT_MEMORY_ATTR_FOREACH_NODE(fn) \
DT_FOREACH_STATUS_OKAY_NODE_VARGS(_FILTER, fn)
DT_FOREACH_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
* using the `zephyr,memory-attr` property. The macro is expanded once for each
* node in the tree with status `okay`.
*
* The macro @p fn must take the form:
*
Expand Down
25 changes: 25 additions & 0 deletions include/zephyr/dt-bindings/memory-attr/memory-attr.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
* Copyright (c) 2023 Carlo Caione <[email protected]>
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_MEM_ATTR_H_
#define ZEPHYR_INCLUDE_DT_BINDINGS_MEM_ATTR_H_

/* Ideally we'd generate this enum to match what's coming out of the YAML,
* however, we dont have a good way to know how to name such an enum from the
* generation point of view, so for now we just hand code the enum. This
* enum is expected to match the order in the yaml (dts/bindings/base/zephyr,memory-attr.yaml)
*/

enum dt_memory_attr {
DT_MEMORY_ATTR_RAM,
DT_MEMORY_ATTR_RAM_NOCACHE,
DT_MEMORY_ATTR_FLASH,
DT_MEMORY_ATTR_PPB,
DT_MEMORY_ATTR_IO,
DT_MEMORY_ATTR_EXTMEM,
DT_MEMORY_ATTR_UNKNOWN, /* must be last */
};

#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_MEM_ATTR_H_ */
79 changes: 79 additions & 0 deletions include/zephyr/mem_mgmt/mem_attr.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/*
* Copyright (c) 2023 Carlo Caione <[email protected]>
*
* 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

/**
* @brief memory-attr region structure.
*
* This structure represents the data gathered from DT about a memory-region
* marked with memory attribute.
*/
struct mem_attr_region_t {
/** Memory region physical address */
uintptr_t dt_addr;
/** Memory region size */
size_t dt_size;
/** Memory region attribute */
enum dt_memory_attr dt_attr;
};

/**
* @brief Get the list of memory regions.
*
* Get the list of enabled memory regions with their memory-attribute as
* gathered by DT.
*
* @retval a const struct pointer to the memory regions array.
* @retval NULL if there are no regions.
*/
const struct mem_attr_region_t *mem_attr_get_regions(void);

/**
* @brief Check if a buffer has correct size and attributes.
*
* This function is used to check if a given buffer with a given attribute
* fully match a memory regions 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...).
*
* @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 attribute.
* @retval -ENOSPC if the buffer is too big for the region it belongs to.
* @retval -ENOBUFS if the buffer is allocated outside a memory region.
*/
int mem_attr_check_buf(void *addr, size_t size, enum dt_memory_attr attr);

#ifdef __cplusplus
}
#endif

/** @} */

#endif /* ZEPHYR_INCLUDE_MEM_ATTR_H_ */
1 change: 1 addition & 0 deletions subsys/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,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)
Expand Down
1 change: 1 addition & 0 deletions subsys/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -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/net/Kconfig"
Expand Down
3 changes: 3 additions & 0 deletions subsys/mem_mgmt/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# SPDX-License-Identifier: Apache-2.0

zephyr_sources_ifdef(CONFIG_MEM_ATTR mem_attr.c)
11 changes: 11 additions & 0 deletions subsys/mem_mgmt/Kconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Copyright (c) 2023 Carlo Caione <[email protected]>
# SPDX-License-Identifier: Apache-2.0

config MEM_ATTR
bool "Memory Attributes management library"
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.
62 changes: 62 additions & 0 deletions subsys/mem_mgmt/mem_attr.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/*
* Copyright (c) 2023 Carlo Caione, <[email protected]>
*
* 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_addr = DT_REG_ADDR(node_id), \
.dt_size = DT_REG_SIZE(node_id), \
.dt_attr = DT_ENUM_IDX(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)
};

const struct mem_attr_region_t *mem_attr_get_regions(void)
{
if (ARRAY_SIZE(mem_attr_region) == 0) {
return NULL;
}

return mem_attr_region;
}

int mem_attr_check_buf(void *v_addr, size_t size, enum dt_memory_attr 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 (v_addr == NULL || size == 0 || attr >= DT_MEMORY_ATTR_UNKNOWN) {
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) ? 0 : -EINVAL;
}
return -ENOSPC;
}
}
return -ENOBUFS;
}
13 changes: 7 additions & 6 deletions tests/kernel/mem_heap/shared_multi_heap/src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -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.h>

#include <zephyr/multi_heap/shared_multi_heap.h>

Expand All @@ -28,7 +29,7 @@ struct region_map {
.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), \
DT_MEMORY_ATTR_UNKNOWN), \
}, \
},

Expand Down Expand Up @@ -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(enum dt_memory_attr dt_attr)
{
/*
* All the memory regions defined in the DT with the MPU property `RAM`
Expand All @@ -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_attr) {
case DT_MEMORY_ATTR_RAM:
return SMH_REG_ATTR_CACHEABLE;
case 1: /* RAM_NOCACHE */
case DT_MEMORY_ATTR_RAM_NOCACHE:
return SMH_REG_ATTR_NON_CACHEABLE;
default:
/* How ? */
Expand All @@ -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_MEMORY_ATTR_UNKNOWN) {
continue;
}

Expand Down
7 changes: 7 additions & 0 deletions tests/lib/devicetree/api/app.overlay
Original file line number Diff line number Diff line change
Expand Up @@ -649,6 +649,13 @@
zephyr,memory-attr = "RAM_NOCACHE";
};

test_mem_disabled: memory@11223344 {
compatible = "vnd,memory-attr";
reg = < 0x11223344 0x1000 >;
zephyr,memory-attr = "FLASH";
status = "disabled";
};

};

test_64 {
Expand Down
10 changes: 10 additions & 0 deletions tests/lib/devicetree/api/src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -2753,6 +2753,16 @@ ZTEST(devicetree_api, test_memory_attr)
zassert_equal(val_filt[0], 0x44332211, "");

#undef TEST_FUNC

#define TEST_FUNC(node_id) DT_REG_SIZE(node_id),

size_t val_status_ok[] = {
DT_MEMORY_ATTR_FOREACH_STATUS_OKAY_NODE(TEST_FUNC)
};

zassert_equal(ARRAY_SIZE(val_status_ok), 2, "");

#undef TEST_FUNC
}

ZTEST(devicetree_api, test_string_token)
Expand Down
8 changes: 8 additions & 0 deletions tests/subsys/mem_mgmt/mem_attr/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -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})
26 changes: 26 additions & 0 deletions tests/subsys/mem_mgmt/mem_attr/app.overlay
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*
* Copyright (c) 2023 Carlo Caione <[email protected]>
* SPDX-License-Identifier: Apache-2.0
*/

/ {
mem_ram: memory@10000000 {
compatible = "vnd,memory-attr";
reg = <0x10000000 0x1000>;
zephyr,memory-attr = "RAM";
};

mem_ram_nocache: memory@20000000 {
compatible = "vnd,memory-attr";
reg = <0x20000000 0x2000>;
zephyr,memory-attr = "RAM_NOCACHE";
};

mem_ram_disabled: memory@30000000 {
compatible = "vnd,memory-attr";
reg = <0x30000000 0x3000>;
zephyr,memory-attr = "FLASH";
status = "disabled";
};

};
3 changes: 3 additions & 0 deletions tests/subsys/mem_mgmt/mem_attr/prj.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
CONFIG_ZTEST=y
CONFIG_ZTEST_NEW_API=y
CONFIG_MEM_ATTR=y
Loading