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