1 /*
2 * Copyright (c) 2016 Nordic Semiconductor ASA
3 * Copyright (c) 2016 Vinayak Kariappa Chettimada
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 */
7
8 #include <zephyr/types.h>
9 #include <string.h>
10
11 #include "util.h"
12
13 #include "mem.h"
14
mem_init(void * mem_pool,uint16_t mem_size,uint16_t mem_count,void ** mem_head)15 void mem_init(void *mem_pool, uint16_t mem_size, uint16_t mem_count,
16 void **mem_head)
17 {
18 *mem_head = mem_pool;
19
20 /* Store free mem_count after the list's next pointer at an 32-bit
21 * aligned memory location to ensure atomic read/write (in ARM for now).
22 */
23 *((uint16_t *)MROUND((uint8_t *)mem_pool + sizeof(mem_pool))) = mem_count;
24
25 /* Initialize next pointers to form a free list,
26 * next pointer is stored in the first 32-bit of each block
27 */
28 (void)memset(((uint8_t *)mem_pool + (mem_size * (--mem_count))), 0,
29 sizeof(mem_pool));
30 while (mem_count--) {
31 uint32_t next;
32
33 next = (uint32_t)((uint8_t *) mem_pool +
34 (mem_size * (mem_count + 1)));
35 memcpy(((uint8_t *)mem_pool + (mem_size * mem_count)),
36 (void *)&next, sizeof(next));
37 }
38 }
39
mem_acquire(void ** mem_head)40 void *mem_acquire(void **mem_head)
41 {
42 if (*mem_head) {
43 uint16_t free_count;
44 void *head;
45 void *mem;
46
47 /* Get the free count from the list and decrement it */
48 free_count = *((uint16_t *)MROUND((uint8_t *)*mem_head +
49 sizeof(mem_head)));
50 free_count--;
51
52 mem = *mem_head;
53 memcpy(&head, mem, sizeof(head));
54
55 /* Store free mem_count after the list's next pointer */
56 if (head) {
57 *((uint16_t *)MROUND((uint8_t *)head + sizeof(head))) =
58 free_count;
59 }
60
61 *mem_head = head;
62 return mem;
63 }
64
65 return NULL;
66 }
67
mem_release(void * mem,void ** mem_head)68 void mem_release(void *mem, void **mem_head)
69 {
70 uint16_t free_count = 0U;
71
72 /* Get the free count from the list and increment it */
73 if (*mem_head) {
74 free_count = *((uint16_t *)MROUND((uint8_t *)*mem_head +
75 sizeof(mem_head)));
76 }
77 free_count++;
78
79 memcpy(mem, mem_head, sizeof(mem));
80
81 /* Store free mem_count after the list's next pointer */
82 *((uint16_t *)MROUND((uint8_t *)mem + sizeof(mem))) = free_count;
83
84 *mem_head = mem;
85 }
86
mem_free_count_get(void * mem_head)87 uint16_t mem_free_count_get(void *mem_head)
88 {
89 uint16_t free_count = 0U;
90
91 /* Get the free count from the list */
92 if (mem_head) {
93 free_count = *((uint16_t *)MROUND((uint8_t *)mem_head +
94 sizeof(mem_head)));
95 }
96
97 return free_count;
98 }
99
mem_get(void * mem_pool,uint16_t mem_size,uint16_t index)100 void *mem_get(void *mem_pool, uint16_t mem_size, uint16_t index)
101 {
102 return ((void *)((uint8_t *)mem_pool + (mem_size * index)));
103 }
104
mem_index_get(void * mem,void * mem_pool,uint16_t mem_size)105 uint16_t mem_index_get(void *mem, void *mem_pool, uint16_t mem_size)
106 {
107 return ((uint16_t)((uint8_t *)mem - (uint8_t *)mem_pool) / mem_size);
108 }
109
110 /**
111 * @brief Copy bytes in reverse
112 * @details Example: [ 0x11 0x22 0x33 ] -> [ 0x33 0x22 0x11 ]
113 */
mem_rcopy(uint8_t * dst,uint8_t const * src,uint16_t len)114 void mem_rcopy(uint8_t *dst, uint8_t const *src, uint16_t len)
115 {
116 src += len;
117 while (len--) {
118 *dst++ = *--src;
119 }
120 }
121
122 /**
123 * @brief Determine if src[0..len-1] contains one or more non-zero bytes
124 * @return 0 if all bytes are zero; otherwise 1
125 */
mem_nz(uint8_t * src,uint16_t len)126 uint8_t mem_nz(uint8_t *src, uint16_t len)
127 {
128 while (len--) {
129 if (*src++) {
130 return 1;
131 }
132 }
133
134 return 0;
135 }
136
137 /**
138 * @brief Unit test
139 */
mem_ut(void)140 uint32_t mem_ut(void)
141 {
142 #define BLOCK_SIZE MROUND(10)
143 #define BLOCK_COUNT 10
144 uint8_t MALIGN(4) pool[BLOCK_COUNT][BLOCK_SIZE];
145 void *mem_free;
146 void *mem_used;
147 uint16_t mem_free_count;
148 void *mem;
149
150 mem_init(pool, BLOCK_SIZE, BLOCK_COUNT, &mem_free);
151
152 mem_free_count = mem_free_count_get(mem_free);
153 if (mem_free_count != BLOCK_COUNT) {
154 return 1;
155 }
156
157 mem_used = 0;
158 while (mem_free_count--) {
159 uint16_t mem_free_count_current;
160
161 mem = mem_acquire(&mem_free);
162 mem_free_count_current = mem_free_count_get(mem_free);
163 if (mem_free_count != mem_free_count_current) {
164 return 2;
165 }
166
167 memcpy(mem, &mem_used, sizeof(mem));
168 mem_used = mem;
169 }
170
171 mem = mem_acquire(&mem_free);
172 if (mem) {
173 return 3;
174 }
175
176 while (++mem_free_count < BLOCK_COUNT) {
177 uint16_t mem_free_count_current;
178
179 mem = mem_used;
180 memcpy(&mem_used, mem, sizeof(void *));
181 mem_release(mem, &mem_free);
182
183 mem_free_count_current = mem_free_count_get(mem_free);
184 if ((mem_free_count + 1) != mem_free_count_current) {
185 return 4;
186 }
187 }
188
189 if (mem != mem_free) {
190 return 5;
191 }
192
193 if (mem_free_count_get(mem_free) != BLOCK_COUNT) {
194 return 6;
195 }
196
197 return 0;
198 }
199