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 	if (attr->name == NULL) {
88 		strncpy(mslab->name, init_mslab_attrs.name, sizeof(mslab->name) - 1);
89 	} else {
90 		strncpy(mslab->name, attr->name, sizeof(mslab->name) - 1);
91 	}
92 
93 	return (osMemoryPoolId_t)mslab;
94 }
95 
96 /**
97  * @brief Allocate a memory block from a memory pool.
98  */
osMemoryPoolAlloc(osMemoryPoolId_t mp_id,uint32_t timeout)99 void *osMemoryPoolAlloc(osMemoryPoolId_t mp_id, uint32_t timeout)
100 {
101 	struct cmsis_rtos_mempool_cb *mslab = (struct cmsis_rtos_mempool_cb *)mp_id;
102 	int retval;
103 	void *ptr;
104 
105 	if (mslab == NULL) {
106 		return NULL;
107 	}
108 
109 	/* Can be called from ISRs only if timeout is set to 0 */
110 	if (timeout > 0 && k_is_in_isr()) {
111 		return NULL;
112 	}
113 
114 	if (timeout == 0U) {
115 		retval = k_mem_slab_alloc((struct k_mem_slab *)(&mslab->z_mslab), (void **)&ptr,
116 					  K_NO_WAIT);
117 	} else if (timeout == osWaitForever) {
118 		retval = k_mem_slab_alloc((struct k_mem_slab *)(&mslab->z_mslab), (void **)&ptr,
119 					  K_FOREVER);
120 	} else {
121 		retval = k_mem_slab_alloc((struct k_mem_slab *)(&mslab->z_mslab), (void **)&ptr,
122 					  K_TICKS(timeout));
123 	}
124 
125 	if (retval == 0) {
126 		return ptr;
127 	} else {
128 		return NULL;
129 	}
130 }
131 
132 /**
133  * @brief Return an allocated memory block back to a specific memory pool.
134  */
osMemoryPoolFree(osMemoryPoolId_t mp_id,void * block)135 osStatus_t osMemoryPoolFree(osMemoryPoolId_t mp_id, void *block)
136 {
137 	struct cmsis_rtos_mempool_cb *mslab = (struct cmsis_rtos_mempool_cb *)mp_id;
138 
139 	if (mslab == NULL) {
140 		return osErrorParameter;
141 	}
142 
143 	/* Note: Below error code is not supported.
144 	 *       osErrorResource: the memory pool specified by parameter mp_id
145 	 *       is in an invalid memory pool state.
146 	 */
147 	if (mslab->is_cb_dynamic_allocation) {
148 		k_mem_slab_free((struct k_mem_slab *)(&mslab->z_mslab), (void *)block);
149 	}
150 	return osOK;
151 }
152 
153 /**
154  * @brief Get name of a Memory Pool object.
155  */
osMemoryPoolGetName(osMemoryPoolId_t mp_id)156 const char *osMemoryPoolGetName(osMemoryPoolId_t mp_id)
157 {
158 	struct cmsis_rtos_mempool_cb *mslab = (struct cmsis_rtos_mempool_cb *)mp_id;
159 
160 	if (!k_is_in_isr() && (mslab != NULL)) {
161 		return mslab->name;
162 	} else {
163 		return NULL;
164 	}
165 }
166 
167 /**
168  * @brief Get maximum number of memory blocks in a Memory Pool.
169  */
osMemoryPoolGetCapacity(osMemoryPoolId_t mp_id)170 uint32_t osMemoryPoolGetCapacity(osMemoryPoolId_t mp_id)
171 {
172 	struct cmsis_rtos_mempool_cb *mslab = (struct cmsis_rtos_mempool_cb *)mp_id;
173 
174 	if (mslab == NULL) {
175 		return 0;
176 	} else {
177 		return mslab->z_mslab.info.num_blocks;
178 	}
179 }
180 
181 /**
182  * @brief Get memory block size in a Memory Pool.
183  */
osMemoryPoolGetBlockSize(osMemoryPoolId_t mp_id)184 uint32_t osMemoryPoolGetBlockSize(osMemoryPoolId_t mp_id)
185 {
186 	struct cmsis_rtos_mempool_cb *mslab = (struct cmsis_rtos_mempool_cb *)mp_id;
187 
188 	if (mslab == NULL) {
189 		return 0;
190 	} else {
191 		return mslab->z_mslab.info.block_size;
192 	}
193 }
194 
195 /**
196  * @brief Get number of memory blocks used in a Memory Pool.
197  */
osMemoryPoolGetCount(osMemoryPoolId_t mp_id)198 uint32_t osMemoryPoolGetCount(osMemoryPoolId_t mp_id)
199 {
200 	struct cmsis_rtos_mempool_cb *mslab = (struct cmsis_rtos_mempool_cb *)mp_id;
201 
202 	if (mslab == NULL) {
203 		return 0;
204 	} else {
205 		return k_mem_slab_num_used_get(&mslab->z_mslab);
206 	}
207 }
208 
209 /**
210  * @brief Get number of memory blocks available in a Memory Pool.
211  */
osMemoryPoolGetSpace(osMemoryPoolId_t mp_id)212 uint32_t osMemoryPoolGetSpace(osMemoryPoolId_t mp_id)
213 {
214 	struct cmsis_rtos_mempool_cb *mslab = (struct cmsis_rtos_mempool_cb *)mp_id;
215 
216 	if (mslab == NULL) {
217 		return 0;
218 	} else {
219 		return k_mem_slab_num_free_get(&mslab->z_mslab);
220 	}
221 }
222 
223 /**
224  * @brief Delete a Memory Pool object.
225  */
osMemoryPoolDelete(osMemoryPoolId_t mp_id)226 osStatus_t osMemoryPoolDelete(osMemoryPoolId_t mp_id)
227 {
228 	struct cmsis_rtos_mempool_cb *mslab = (struct cmsis_rtos_mempool_cb *)mp_id;
229 
230 	if (mslab == NULL) {
231 		return osErrorParameter;
232 	}
233 
234 	if (k_is_in_isr()) {
235 		return osErrorISR;
236 	}
237 
238 	/* The status code "osErrorResource" (the memory pool specified by
239 	 * parameter mp_id is in an invalid memory pool state) is not
240 	 * supported in Zephyr.
241 	 */
242 
243 	if (mslab->is_dynamic_allocation) {
244 		k_free(mslab->pool);
245 	}
246 	if (mslab->is_cb_dynamic_allocation) {
247 		k_mem_slab_free(&cv2_mem_slab, (void *)mslab);
248 	}
249 	return osOK;
250 }
251