1 /*
2 * Copyright (c) 2018 Intel Corporation
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/kernel.h>
8 #include <zephyr/portability/cmsis_types.h>
9 #include <string.h>
10 #include "wrapper.h"
11
12 #define TIME_OUT_TICKS 10
13
14 K_MEM_SLAB_DEFINE(cv2_mem_slab, sizeof(struct cmsis_rtos_mempool_cb),
15 CONFIG_CMSIS_V2_MEM_SLAB_MAX_COUNT, 4);
16
17 static const osMemoryPoolAttr_t init_mslab_attrs = {
18 .name = "ZephyrMemPool",
19 .attr_bits = 0,
20 .cb_mem = NULL,
21 .cb_size = 0,
22 .mp_mem = NULL,
23 .mp_size = 0,
24 };
25
26 /**
27 * @brief Create and Initialize a memory pool.
28 */
osMemoryPoolNew(uint32_t block_count,uint32_t block_size,const osMemoryPoolAttr_t * attr)29 osMemoryPoolId_t osMemoryPoolNew(uint32_t block_count, uint32_t block_size,
30 const osMemoryPoolAttr_t *attr)
31 {
32 struct cmsis_rtos_mempool_cb *mslab;
33
34 BUILD_ASSERT(K_HEAP_MEM_POOL_SIZE >= CONFIG_CMSIS_V2_MEM_SLAB_MAX_DYNAMIC_SIZE,
35 "heap must be configured to be at least the max dynamic size");
36
37 if (k_is_in_isr()) {
38 return NULL;
39 }
40
41 if ((attr != NULL) && (attr->mp_size < block_count * block_size)) {
42 return NULL;
43 }
44
45 if (attr == NULL) {
46 attr = &init_mslab_attrs;
47 }
48
49 if (attr->cb_mem != NULL) {
50 __ASSERT(attr->cb_size == sizeof(struct cmsis_rtos_mempool_cb),
51 "Invalid cb_size\n");
52 mslab = (struct cmsis_rtos_mempool_cb *)attr->cb_mem;
53 } else if (k_mem_slab_alloc(&cv2_mem_slab, (void **)&mslab, K_MSEC(100)) != 0) {
54 return NULL;
55 }
56 (void)memset(mslab, 0, sizeof(struct cmsis_rtos_mempool_cb));
57 mslab->is_cb_dynamic_allocation = attr->cb_mem == NULL;
58
59 if (attr->mp_mem == NULL) {
60 __ASSERT((block_count * block_size) <= CONFIG_CMSIS_V2_MEM_SLAB_MAX_DYNAMIC_SIZE,
61 "memory slab/pool size exceeds dynamic maximum");
62
63 mslab->pool = k_calloc(block_count, block_size);
64 if (mslab->pool == NULL) {
65 if (mslab->is_cb_dynamic_allocation) {
66 k_mem_slab_free(&cv2_mem_slab, (void *)mslab);
67 }
68 return NULL;
69 }
70 mslab->is_dynamic_allocation = TRUE;
71 } else {
72 mslab->pool = attr->mp_mem;
73 mslab->is_dynamic_allocation = FALSE;
74 }
75
76 int rc = k_mem_slab_init(&mslab->z_mslab, mslab->pool, block_size, block_count);
77 if (rc != 0) {
78 if (mslab->is_cb_dynamic_allocation) {
79 k_mem_slab_free(&cv2_mem_slab, (void *)mslab);
80 }
81 if (attr->mp_mem == NULL) {
82 k_free(mslab->pool);
83 }
84 return NULL;
85 }
86
87 mslab->name = (attr->name == NULL) ? init_mslab_attrs.name : attr->name;
88
89 return (osMemoryPoolId_t)mslab;
90 }
91
92 /**
93 * @brief Allocate a memory block from a memory pool.
94 */
osMemoryPoolAlloc(osMemoryPoolId_t mp_id,uint32_t timeout)95 void *osMemoryPoolAlloc(osMemoryPoolId_t mp_id, uint32_t timeout)
96 {
97 struct cmsis_rtos_mempool_cb *mslab = (struct cmsis_rtos_mempool_cb *)mp_id;
98 int retval;
99 void *ptr;
100
101 if (mslab == NULL) {
102 return NULL;
103 }
104
105 /* Can be called from ISRs only if timeout is set to 0 */
106 if (timeout > 0 && k_is_in_isr()) {
107 return NULL;
108 }
109
110 if (timeout == 0U) {
111 retval = k_mem_slab_alloc((struct k_mem_slab *)(&mslab->z_mslab), (void **)&ptr,
112 K_NO_WAIT);
113 } else if (timeout == osWaitForever) {
114 retval = k_mem_slab_alloc((struct k_mem_slab *)(&mslab->z_mslab), (void **)&ptr,
115 K_FOREVER);
116 } else {
117 retval = k_mem_slab_alloc((struct k_mem_slab *)(&mslab->z_mslab), (void **)&ptr,
118 K_TICKS(timeout));
119 }
120
121 if (retval == 0) {
122 return ptr;
123 } else {
124 return NULL;
125 }
126 }
127
128 /**
129 * @brief Return an allocated memory block back to a specific memory pool.
130 */
osMemoryPoolFree(osMemoryPoolId_t mp_id,void * block)131 osStatus_t osMemoryPoolFree(osMemoryPoolId_t mp_id, void *block)
132 {
133 struct cmsis_rtos_mempool_cb *mslab = (struct cmsis_rtos_mempool_cb *)mp_id;
134
135 if (mslab == NULL) {
136 return osErrorParameter;
137 }
138
139 /* Note: Below error code is not supported.
140 * osErrorResource: the memory pool specified by parameter mp_id
141 * is in an invalid memory pool state.
142 */
143 if (mslab->is_cb_dynamic_allocation) {
144 k_mem_slab_free((struct k_mem_slab *)(&mslab->z_mslab), (void *)block);
145 }
146 return osOK;
147 }
148
149 /**
150 * @brief Get name of a Memory Pool object.
151 * This function may be called from Interrupt Service Routines.
152 */
osMemoryPoolGetName(osMemoryPoolId_t mp_id)153 const char *osMemoryPoolGetName(osMemoryPoolId_t mp_id)
154 {
155 struct cmsis_rtos_mempool_cb *mslab = (struct cmsis_rtos_mempool_cb *)mp_id;
156
157 if (mslab == NULL) {
158 return NULL;
159 }
160 return mslab->name;
161 }
162
163 /**
164 * @brief Get maximum number of memory blocks in a Memory Pool.
165 */
osMemoryPoolGetCapacity(osMemoryPoolId_t mp_id)166 uint32_t osMemoryPoolGetCapacity(osMemoryPoolId_t mp_id)
167 {
168 struct cmsis_rtos_mempool_cb *mslab = (struct cmsis_rtos_mempool_cb *)mp_id;
169
170 if (mslab == NULL) {
171 return 0;
172 } else {
173 return mslab->z_mslab.info.num_blocks;
174 }
175 }
176
177 /**
178 * @brief Get memory block size in a Memory Pool.
179 */
osMemoryPoolGetBlockSize(osMemoryPoolId_t mp_id)180 uint32_t osMemoryPoolGetBlockSize(osMemoryPoolId_t mp_id)
181 {
182 struct cmsis_rtos_mempool_cb *mslab = (struct cmsis_rtos_mempool_cb *)mp_id;
183
184 if (mslab == NULL) {
185 return 0;
186 } else {
187 return mslab->z_mslab.info.block_size;
188 }
189 }
190
191 /**
192 * @brief Get number of memory blocks used in a Memory Pool.
193 */
osMemoryPoolGetCount(osMemoryPoolId_t mp_id)194 uint32_t osMemoryPoolGetCount(osMemoryPoolId_t mp_id)
195 {
196 struct cmsis_rtos_mempool_cb *mslab = (struct cmsis_rtos_mempool_cb *)mp_id;
197
198 if (mslab == NULL) {
199 return 0;
200 } else {
201 return k_mem_slab_num_used_get(&mslab->z_mslab);
202 }
203 }
204
205 /**
206 * @brief Get number of memory blocks available in a Memory Pool.
207 */
osMemoryPoolGetSpace(osMemoryPoolId_t mp_id)208 uint32_t osMemoryPoolGetSpace(osMemoryPoolId_t mp_id)
209 {
210 struct cmsis_rtos_mempool_cb *mslab = (struct cmsis_rtos_mempool_cb *)mp_id;
211
212 if (mslab == NULL) {
213 return 0;
214 } else {
215 return k_mem_slab_num_free_get(&mslab->z_mslab);
216 }
217 }
218
219 /**
220 * @brief Delete a Memory Pool object.
221 */
osMemoryPoolDelete(osMemoryPoolId_t mp_id)222 osStatus_t osMemoryPoolDelete(osMemoryPoolId_t mp_id)
223 {
224 struct cmsis_rtos_mempool_cb *mslab = (struct cmsis_rtos_mempool_cb *)mp_id;
225
226 if (mslab == NULL) {
227 return osErrorParameter;
228 }
229
230 if (k_is_in_isr()) {
231 return osErrorISR;
232 }
233
234 /* The status code "osErrorResource" (the memory pool specified by
235 * parameter mp_id is in an invalid memory pool state) is not
236 * supported in Zephyr.
237 */
238
239 if (mslab->is_dynamic_allocation) {
240 k_free(mslab->pool);
241 }
242 if (mslab->is_cb_dynamic_allocation) {
243 k_mem_slab_free(&cv2_mem_slab, (void *)mslab);
244 }
245 return osOK;
246 }
247