Skip to content

Commit 09fd6b6

Browse files
carlocaionecarlescufi
authored andcommitted
mem_mgmt: Add a memory attributes memory allocator
Using this new library it is now possible to leverage the memory attribute property 'zephyr,memory-attr' to define and create a set of memory heaps from which the user can allocate memory from with certain attributes / capabilities. When the CONFIG_MEM_ATTR_HEAP option is set, every region marked with one of the memory attributes listed in include/zephyr/dt-bindings/memory-attr/memory-attr-sw.h is added to a pool of memory heaps used for dynamic allocation of memory buffers with certain attributes. Signed-off-by: Carlo Caione <[email protected]>
1 parent a8d56c4 commit 09fd6b6

File tree

5 files changed

+269
-0
lines changed

5 files changed

+269
-0
lines changed
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/*
2+
* Copyright (c) 2023 Carlo Caione <[email protected]>
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_MEM_ATTR_SW_H_
7+
#define ZEPHYR_INCLUDE_DT_BINDINGS_MEM_ATTR_SW_H_
8+
9+
#include <zephyr/sys/util_macro.h>
10+
#include <zephyr/dt-bindings/memory-attr/memory-attr.h>
11+
12+
/*
13+
* Software specific memory attributes.
14+
*/
15+
#define DT_MEM_SW_MASK DT_MEM_SW_ATTR_MASK
16+
#define DT_MEM_SW_GET(x) ((x) & DT_MEM_SW_ATTR_MASK)
17+
#define DT_MEM_SW(x) ((x) << DT_MEM_SW_ATTR_SHIFT)
18+
19+
#define ATTR_SW_ALLOC_CACHE BIT(0)
20+
#define ATTR_SW_ALLOC_NON_CACHE BIT(1)
21+
#define ATTR_SW_ALLOC_DMA BIT(2)
22+
23+
#define DT_MEM_SW_ALLOC_CACHE DT_MEM_SW(ATTR_SW_ALLOC_CACHE)
24+
#define DT_MEM_SW_ALLOC_NON_CACHE DT_MEM_SW(ATTR_SW_ALLOC_NON_CACHE)
25+
#define DT_MEM_SW_ALLOC_DMA DT_MEM_SW(ATTR_SW_ALLOC_DMA)
26+
27+
#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_MEM_ATTR_SW_H_ */
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
/*
2+
* Copyright (c) 2023 Carlo Caione, <[email protected]>
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#ifndef ZEPHYR_INCLUDE_MEM_ATTR_HEAP_H_
8+
#define ZEPHYR_INCLUDE_MEM_ATTR_HEAP_H_
9+
10+
/**
11+
* @brief Memory heaps based on memory attributes
12+
* @defgroup memory_attr_heap Memory heaps based on memory attributes
13+
* @ingroup mem_mgmt
14+
* @{
15+
*/
16+
17+
#include <zephyr/mem_mgmt/mem_attr.h>
18+
19+
#ifdef __cplusplus
20+
extern "C" {
21+
#endif
22+
23+
/**
24+
* @brief Init the memory pool
25+
*
26+
* This must be the first function to be called to initialize the memory pools
27+
* from all the memory regions with the a software attribute.
28+
*
29+
* @retval 0 on success.
30+
* @retval -EALREADY if the pool was already initialized.
31+
* @retval -ENOMEM too many regions already allocated.
32+
*/
33+
int mem_attr_heap_pool_init(void);
34+
35+
/**
36+
* @brief Allocate memory with a specified attribute and size.
37+
*
38+
* Allocates a block of memory of the specified size in bytes and with a
39+
* specified capability / attribute. The attribute is used to select the
40+
* correct memory heap to allocate memory from.
41+
*
42+
* @param attr capability / attribute requested for the memory block.
43+
* @param bytes requested size of the allocation in bytes.
44+
*
45+
* @retval ptr a valid pointer to the allocated memory.
46+
* @retval NULL if no memory is available with that attribute and size.
47+
*/
48+
void *mem_attr_heap_alloc(uint32_t attr, size_t bytes);
49+
50+
/**
51+
* @brief Allocate aligned memory with a specified attribute, size and alignment.
52+
*
53+
* Allocates a block of memory of the specified size in bytes and with a
54+
* specified capability / attribute. Takes an additional parameter specifying a
55+
* power of two alignment in bytes.
56+
*
57+
* @param attr capability / attribute requested for the memory block.
58+
* @param align power of two alignment for the returned pointer in bytes.
59+
* @param bytes requested size of the allocation in bytes.
60+
*
61+
* @retval ptr a valid pointer to the allocated memory.
62+
* @retval NULL if no memory is available with that attribute and size.
63+
*/
64+
void *mem_attr_heap_aligned_alloc(uint32_t attr, size_t align, size_t bytes);
65+
66+
/**
67+
* @brief Free the allocated memory
68+
*
69+
* Used to free the passed block of memory that must be the return value of a
70+
* previously call to @ref mem_attr_heap_alloc or @ref
71+
* mem_attr_heap_aligned_alloc.
72+
*
73+
* @param block block to free, must be a pointer to a block allocated by
74+
* @ref mem_attr_heap_alloc or @ref mem_attr_heap_aligned_alloc.
75+
*/
76+
void mem_attr_heap_free(void *block);
77+
78+
/**
79+
* @brief Get a specific memory region descriptor for a provided address
80+
*
81+
* Finds the memory region descriptor struct controlling the provided pointer.
82+
*
83+
* @param addr address to be found, must be a pointer to a block allocated by
84+
* @ref mem_attr_heap_alloc or @ref mem_attr_heap_aligned_alloc.
85+
*
86+
* @retval str pointer to a memory region structure the address belongs to.
87+
*/
88+
const struct mem_attr_region_t *mem_attr_heap_get_region(void *addr);
89+
90+
#ifdef __cplusplus
91+
}
92+
#endif
93+
94+
/**
95+
* @}
96+
*/
97+
98+
#endif /* ZEPHYR_INCLUDE_MEM_ATTR_HEAP_H_ */

subsys/mem_mgmt/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
# SPDX-License-Identifier: Apache-2.0
22

33
zephyr_sources_ifdef(CONFIG_MEM_ATTR mem_attr.c)
4+
zephyr_sources_ifdef(CONFIG_MEM_ATTR_HEAP mem_attr_heap.c)

subsys/mem_mgmt/Kconfig

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,10 @@ config MEM_ATTR
1010
time an array of the memory regions defined in the DT that can be
1111
probed at run-time using several helper functions. Set to `N` if
1212
unsure to save RODATA space.
13+
14+
config MEM_ATTR_HEAP
15+
bool "Memory Attributes heap allocator"
16+
depends on MEM_ATTR
17+
help
18+
Enable an heap allocator based on memory attributes to dynamically
19+
allocate memory from DeviceTree defined memory regions.

subsys/mem_mgmt/mem_attr_heap.c

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
/*
2+
* Copyright (c) 2021 Carlo Caione, <[email protected]>
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#include <zephyr/kernel.h>
8+
#include <zephyr/device.h>
9+
#include <zephyr/sys/sys_heap.h>
10+
#include <zephyr/mem_mgmt/mem_attr.h>
11+
#include <zephyr/sys/multi_heap.h>
12+
#include <zephyr/dt-bindings/memory-attr/memory-attr.h>
13+
#include <zephyr/dt-bindings/memory-attr/memory-attr-sw.h>
14+
15+
struct ma_heap {
16+
struct sys_heap heap;
17+
uint32_t attr;
18+
};
19+
20+
struct {
21+
struct ma_heap ma_heaps[MAX_MULTI_HEAPS];
22+
struct sys_multi_heap multi_heap;
23+
int nheaps;
24+
} mah_data;
25+
26+
static void *mah_choice(struct sys_multi_heap *m_heap, void *cfg, size_t align, size_t size)
27+
{
28+
uint32_t attr;
29+
void *block;
30+
31+
if (size == 0) {
32+
return NULL;
33+
}
34+
35+
attr = (uint32_t)(long) cfg;
36+
37+
/* Set in case the user requested a non-existing attr */
38+
block = NULL;
39+
40+
for (size_t hdx = 0; hdx < mah_data.nheaps; hdx++) {
41+
struct ma_heap *h;
42+
43+
h = &mah_data.ma_heaps[hdx];
44+
45+
if (h->attr != attr) {
46+
continue;
47+
}
48+
49+
block = sys_heap_aligned_alloc(&h->heap, align, size);
50+
if (block != NULL) {
51+
break;
52+
}
53+
}
54+
55+
return block;
56+
}
57+
58+
void mem_attr_heap_free(void *block)
59+
{
60+
sys_multi_heap_free(&mah_data.multi_heap, block);
61+
}
62+
63+
void *mem_attr_heap_alloc(uint32_t attr, size_t bytes)
64+
{
65+
return sys_multi_heap_alloc(&mah_data.multi_heap,
66+
(void *)(long) attr, bytes);
67+
}
68+
69+
void *mem_attr_heap_aligned_alloc(uint32_t attr, size_t align, size_t bytes)
70+
{
71+
return sys_multi_heap_aligned_alloc(&mah_data.multi_heap,
72+
(void *)(long) attr, align, bytes);
73+
}
74+
75+
const struct mem_attr_region_t *mem_attr_heap_get_region(void *addr)
76+
{
77+
const struct sys_multi_heap_rec *heap_rec;
78+
79+
heap_rec = sys_multi_heap_get_heap(&mah_data.multi_heap, addr);
80+
81+
return (const struct mem_attr_region_t *) heap_rec->user_data;
82+
}
83+
84+
static int ma_heap_add(const struct mem_attr_region_t *region, uint32_t attr)
85+
{
86+
struct ma_heap *mh;
87+
struct sys_heap *h;
88+
89+
/* No more heaps available */
90+
if (mah_data.nheaps >= MAX_MULTI_HEAPS) {
91+
return -ENOMEM;
92+
}
93+
94+
mh = &mah_data.ma_heaps[mah_data.nheaps++];
95+
h = &mh->heap;
96+
97+
mh->attr = attr;
98+
99+
sys_heap_init(h, (void *) region->dt_addr, region->dt_size);
100+
sys_multi_heap_add_heap(&mah_data.multi_heap, h, (void *) region);
101+
102+
return 0;
103+
}
104+
105+
106+
int mem_attr_heap_pool_init(void)
107+
{
108+
const struct mem_attr_region_t *regions;
109+
static atomic_t state;
110+
size_t num_regions;
111+
112+
if (!atomic_cas(&state, 0, 1)) {
113+
return -EALREADY;
114+
}
115+
116+
sys_multi_heap_init(&mah_data.multi_heap, mah_choice);
117+
118+
num_regions = mem_attr_get_regions(&regions);
119+
120+
for (size_t idx = 0; idx < num_regions; idx++) {
121+
uint32_t sw_attr;
122+
123+
sw_attr = DT_MEM_SW_ATTR_GET(regions[idx].dt_attr);
124+
125+
/* No SW attribute is present */
126+
if (!sw_attr) {
127+
continue;
128+
}
129+
130+
if (ma_heap_add(&regions[idx], sw_attr)) {
131+
return -ENOMEM;
132+
}
133+
}
134+
135+
return 0;
136+
}

0 commit comments

Comments
 (0)