1 /**************************************************************************/
2 /* */
3 /* Copyright (c) Microsoft Corporation. All rights reserved. */
4 /* */
5 /* This software is licensed under the Microsoft Software License */
6 /* Terms for Microsoft Azure RTOS. Full text of the license can be */
7 /* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
8 /* and in the root directory of this software. */
9 /* */
10 /**************************************************************************/
11
12
13 /**************************************************************************/
14 /**************************************************************************/
15 /** */
16 /** USBX Component */
17 /** */
18 /** Utility */
19 /** */
20 /**************************************************************************/
21 /**************************************************************************/
22
23
24 /* Include necessary system files. */
25
26 #define UX_SOURCE_CODE
27
28 #include "ux_api.h"
29
30
31 /**************************************************************************/
32 /* */
33 /* FUNCTION RELEASE */
34 /* */
35 /* _ux_utility_memory_allocate PORTABLE C */
36 /* 6.1.11 */
37 /* AUTHOR */
38 /* */
39 /* Chaoqiong Xiao, Microsoft Corporation */
40 /* */
41 /* DESCRIPTION */
42 /* */
43 /* This function allocates a block of memory for the specified size */
44 /* and alignment. */
45 /* */
46 /* INPUT */
47 /* */
48 /* memory_alignment Memory alignment required */
49 /* memory_cache_flag Memory pool source */
50 /* memory_size_requested Number of bytes required */
51 /* */
52 /* OUTPUT */
53 /* */
54 /* Pointer to block of memory */
55 /* */
56 /* CALLS */
57 /* */
58 /* _ux_utility_memory_free_block_best_get Get best fit block of memory */
59 /* _ux_utility_memory_set Set block of memory */
60 /* */
61 /* CALLED BY */
62 /* */
63 /* USBX Components */
64 /* */
65 /* RELEASE HISTORY */
66 /* */
67 /* DATE NAME DESCRIPTION */
68 /* */
69 /* 05-19-2020 Chaoqiong Xiao Initial Version 6.0 */
70 /* 09-30-2020 Chaoqiong Xiao Modified comment(s), */
71 /* verified memset and memcpy */
72 /* cases, */
73 /* resulting in version 6.1 */
74 /* 01-31-2022 Chaoqiong Xiao Modified comment(s), */
75 /* added standalone support, */
76 /* resulting in version 6.1.10 */
77 /* 04-25-2022 Chaoqiong Xiao Modified comment(s), */
78 /* internal clean up, */
79 /* resulting in version 6.1.11 */
80 /* */
81 /**************************************************************************/
_ux_utility_memory_allocate(ULONG memory_alignment,ULONG memory_cache_flag,ULONG memory_size_requested)82 VOID *_ux_utility_memory_allocate(ULONG memory_alignment, ULONG memory_cache_flag,
83 ULONG memory_size_requested)
84 {
85
86 UX_MEMORY_BLOCK *memory_block;
87 UX_MEMORY_BLOCK *new_memory_block;
88 UX_MEMORY_BLOCK *leftover_memory_block;
89 ULONG memory_for_alignment;
90 ULONG memory_removed_from_pool;
91 ULONG leftover;
92 UCHAR *memory_buffer;
93 ALIGN_TYPE int_memory_buffer;
94
95
96 /* Get the mutex as this is a critical section. */
97 _ux_system_mutex_on(&_ux_system -> ux_system_mutex);
98
99 #ifdef UX_ENFORCE_SAFE_ALIGNMENT
100
101 /* Check if safe alignment requested, in this case switch to UX_NO_ALIGN. */
102 if (memory_alignment == UX_SAFE_ALIGN)
103 {
104
105 /* We will use the memory_size_requested for the alignment.
106 But we check to see if we have a minimum or maximum alignment. */
107 if (memory_size_requested < UX_ALIGN_MIN)
108
109 /* No need to bother about alignment for small packets sizes. */
110 memory_alignment = UX_NO_ALIGN;
111
112 else
113 {
114
115 /* Check if we are over the maximum. */
116 if (memory_size_requested > UX_MAX_SCATTER_GATHER_ALIGNMENT)
117
118 /* We are over the max alignment required. Use the maximum instead. */
119 memory_alignment = UX_MAX_SCATTER_GATHER_ALIGNMENT - 1;
120
121 else
122 {
123 /* We are not over the maximum, so approximate the alignment according to the size of the memory.
124 Check range for alignment on 4096 bytes. */
125 if (memory_size_requested >= UX_ALIGN_2048 + 1)
126 memory_alignment = UX_ALIGN_4096;
127
128 else
129 {
130
131 /* Check range for alignment on 2048 bytes. */
132 if (memory_size_requested >= UX_ALIGN_1024 + 1)
133 memory_alignment = UX_ALIGN_2048;
134
135 else
136 {
137
138 /* Check range for alignment on 1024 bytes. */
139 if (memory_size_requested >= UX_ALIGN_512 + 1)
140 memory_alignment = UX_ALIGN_1024;
141
142 else
143 {
144
145 /* Check range for alignment on 512 bytes. */
146 if (memory_size_requested >= UX_ALIGN_256 + 1)
147 memory_alignment = UX_ALIGN_512;
148
149 else
150 {
151
152 /* Check range for alignment on 256 bytes. */
153 if (memory_size_requested >= UX_ALIGN_128 + 1)
154 memory_alignment = UX_ALIGN_256;
155
156 else
157 {
158
159 /* Check range for alignment on 128 bytes. */
160 if (memory_size_requested >= UX_ALIGN_64 + 1)
161 memory_alignment = UX_ALIGN_128;
162
163 else
164 {
165
166 /* Check range for alignment on 128 bytes. */
167 if (memory_size_requested >= UX_ALIGN_64 + 1)
168 memory_alignment = UX_ALIGN_128;
169
170 else
171 {
172
173 /* Check range for alignment on 64 bytes. */
174 if (memory_size_requested >= UX_ALIGN_32 + 1)
175 memory_alignment = UX_ALIGN_64;
176
177 else
178 {
179
180 /* Check range for alignment on 32 bytes. */
181 if (memory_size_requested >= UX_ALIGN_16 + 1)
182 memory_alignment = UX_ALIGN_32;
183
184 else
185 memory_alignment = UX_ALIGN_MIN;
186
187
188 }
189 }
190 }
191 }
192 }
193 }
194 }
195 }
196 }
197 }
198 }
199
200 #else
201
202 /* Check if safe alignment requested, in this case switch to UX_NO_ALIGN. */
203 if (memory_alignment == UX_SAFE_ALIGN)
204 memory_alignment = UX_NO_ALIGN;
205
206 #endif
207
208 /* Ensure the alignment meats the minimum. */
209 if (memory_alignment < UX_ALIGN_MIN)
210 memory_alignment = UX_ALIGN_MIN;
211
212 /* Adjust the memory alignment since our macros are one minus the desired alignment.
213 Also determine the amount of extra memory we need for the alignment, which is one
214 minus the actual alignment. */
215 memory_for_alignment = memory_alignment;
216 memory_alignment++;
217
218 /* We need to make sure that the next memory block buffer is 16-byte aligned too. We
219 do this by first adjusting the requested memory to be 16-byte aligned. One problem
220 now is that the memory block might not be a size that is a multiple of 16, so we need
221 to add the amount of memory required such that the memory buffer after the block has
222 the correct alignment. For example, if the memory block has a size of 24, then we need
223 to make sure it is placed on an 8-byte alignment that is after a 16-byte alignment so
224 that the memory right after the memory block is 16-byte aligned (8 + 24 = 32). */
225 memory_size_requested = (memory_size_requested + UX_ALIGN_MIN) & (~(ULONG)UX_ALIGN_MIN);
226 memory_size_requested += (((ULONG)sizeof(UX_MEMORY_BLOCK) + UX_ALIGN_MIN) & (~(ULONG)UX_ALIGN_MIN)) - (ULONG)sizeof(UX_MEMORY_BLOCK);
227
228 /* Try to find the best block for this memory by requesting the maximum amount of
229 memory we'll need which is calculated as follows: the amount memory requested by
230 the caller plus the maximum amount of memory wasted due to alignment plus 2 memory
231 blocks structs - one for the new memory block we'll create for the user block and one
232 that we might create if there is extra memory after doing the alignment. */
233 memory_block = _ux_utility_memory_free_block_best_get(memory_cache_flag, memory_size_requested + memory_for_alignment + (ULONG)sizeof(UX_MEMORY_BLOCK));
234
235 /* If the block returned is NULL, there is no free memory in the pool
236 for that size. */
237 if (memory_block == UX_NULL)
238 {
239
240 /* Release the protection. */
241 _ux_system_mutex_off(&_ux_system -> ux_system_mutex);
242
243 /* If trace is enabled, insert this event into the trace buffer. */
244 UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_MEMORY_INSUFFICIENT, memory_size_requested, 0, 0, UX_TRACE_ERRORS, 0, 0)
245
246 /* Error trap. */
247 _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_UTILITY, UX_MEMORY_INSUFFICIENT);
248
249 /* Return NULL to indicate no block was found. */
250 return(UX_NULL);
251 }
252
253 /* Get the memory buffer for this block. */
254 int_memory_buffer = (ALIGN_TYPE) ((UCHAR *) memory_block + sizeof(UX_MEMORY_BLOCK));
255
256 /* Are we already aligned? */
257 if ((int_memory_buffer & (memory_alignment - 1)) == 0)
258 {
259
260 /* Setup the new memory block. */
261 new_memory_block = (UX_MEMORY_BLOCK *) ((UCHAR *) memory_block + sizeof(UX_MEMORY_BLOCK) + memory_size_requested);
262 new_memory_block -> ux_memory_block_next = memory_block -> ux_memory_block_next;
263 new_memory_block -> ux_memory_block_previous = memory_block;
264 new_memory_block -> ux_memory_block_size = memory_block -> ux_memory_block_size - memory_size_requested - (ULONG)sizeof(UX_MEMORY_BLOCK);
265 new_memory_block -> ux_memory_block_status = UX_MEMORY_UNUSED;
266
267 /* Update the current memory block. */
268 memory_block -> ux_memory_block_size = memory_size_requested;
269 memory_block -> ux_memory_block_next = new_memory_block;
270 memory_block -> ux_memory_block_status = UX_MEMORY_USED | memory_cache_flag;
271
272 /* Declare how much memory we removed from the pool. */
273 memory_removed_from_pool = memory_block -> ux_memory_block_size + (ULONG)sizeof(UX_MEMORY_BLOCK);
274 }
275 else
276 {
277
278 /* Align the buffer. The first thing we do is increment by the size of a
279 memory block because we have to make sure we have enough memory for at
280 least that. */
281 int_memory_buffer += (ULONG)sizeof(UX_MEMORY_BLOCK);
282 int_memory_buffer += memory_alignment - 1;
283 int_memory_buffer &= ~(((ALIGN_TYPE) memory_alignment) - 1);
284
285 /* Setup the new memory block. Note that its size is updated again later. */
286 new_memory_block = (UX_MEMORY_BLOCK *) (int_memory_buffer - (ULONG)sizeof(UX_MEMORY_BLOCK));
287 new_memory_block -> ux_memory_block_previous = memory_block;
288 new_memory_block -> ux_memory_block_next = memory_block -> ux_memory_block_next;
289 new_memory_block -> ux_memory_block_size = memory_block -> ux_memory_block_size;
290 new_memory_block -> ux_memory_block_status = UX_MEMORY_USED | memory_cache_flag;
291
292 /* Update the current memory block. */
293 int_memory_buffer = (ALIGN_TYPE) ((UCHAR *) memory_block + sizeof(UX_MEMORY_BLOCK));
294 memory_block -> ux_memory_block_next = new_memory_block;
295 memory_block -> ux_memory_block_size = (ULONG) ((ALIGN_TYPE) new_memory_block - int_memory_buffer);
296
297 /* Update the new memory block's size. */
298 new_memory_block -> ux_memory_block_size -= (memory_block -> ux_memory_block_size + (ULONG)sizeof(UX_MEMORY_BLOCK));
299
300 /* Calculate how much memory is leftover in the new memory block after doing
301 the alignment. */
302 leftover = new_memory_block -> ux_memory_block_size - memory_size_requested;
303
304 /* Can we fit another block after the new block? */
305 if (leftover > sizeof(UX_MEMORY_BLOCK))
306 {
307
308 /* Setup the leftover memory block. */
309 leftover_memory_block = (UX_MEMORY_BLOCK *) (((ALIGN_TYPE) new_memory_block + sizeof(UX_MEMORY_BLOCK) + memory_size_requested) & 0xFFFFFFFFu);
310 leftover_memory_block -> ux_memory_block_next = new_memory_block -> ux_memory_block_next;
311 leftover_memory_block -> ux_memory_block_previous = new_memory_block;
312 leftover_memory_block -> ux_memory_block_size = leftover - (ULONG)sizeof(UX_MEMORY_BLOCK);
313 leftover_memory_block -> ux_memory_block_status = UX_MEMORY_UNUSED;
314
315 new_memory_block -> ux_memory_block_next = leftover_memory_block;
316 new_memory_block -> ux_memory_block_size -= leftover;
317 }
318
319 /* Declare how much memory we removed from the pool. */
320 memory_removed_from_pool = new_memory_block -> ux_memory_block_size + (ULONG)sizeof(UX_MEMORY_BLOCK);
321
322 /* The new memory block is the one we give to the user. */
323 memory_block = new_memory_block;
324 }
325
326 /* The memory to be returned is after the block header. */
327 memory_buffer = ((UCHAR *) memory_block) + sizeof(UX_MEMORY_BLOCK);
328
329 /* Clear the memory block. */
330 _ux_utility_memory_set(memory_buffer, 0, memory_size_requested); /* Use case of memset is verified. */
331
332 /* Update the memory free in the pool. */
333 if (_ux_system -> ux_system_cache_safe_memory_pool_start == _ux_system -> ux_system_regular_memory_pool_start)
334 {
335
336 /* There is only one memory pool. */
337 _ux_system -> ux_system_regular_memory_pool_free -= memory_removed_from_pool;
338 }
339 else
340 {
341
342 switch (memory_cache_flag)
343 {
344
345 case UX_CACHE_SAFE_MEMORY:
346 /* Update the amount of free memory in the cache safe memory pool. */
347 _ux_system -> ux_system_cache_safe_memory_pool_free -= memory_removed_from_pool;
348
349 break;
350
351 default:
352 /* Update the amount of free memory in the regular memory pool. */
353 _ux_system -> ux_system_regular_memory_pool_free -= memory_removed_from_pool;
354 break;
355
356 }
357 }
358
359 #ifdef UX_ENABLE_MEMORY_STATISTICS
360
361 /* Update allocate count, total size. */
362 if (memory_cache_flag == UX_REGULAR_MEMORY)
363 {
364 _ux_system -> ux_system_regular_memory_pool_alloc_count ++;
365 _ux_system -> ux_system_regular_memory_pool_alloc_total += memory_size_requested;
366 if (_ux_system -> ux_system_regular_memory_pool_alloc_max_count < _ux_system -> ux_system_regular_memory_pool_alloc_count)
367 _ux_system -> ux_system_regular_memory_pool_alloc_max_count = _ux_system -> ux_system_regular_memory_pool_alloc_count;
368 if (_ux_system -> ux_system_regular_memory_pool_alloc_max_total < _ux_system -> ux_system_regular_memory_pool_alloc_total)
369 _ux_system -> ux_system_regular_memory_pool_alloc_max_total = _ux_system -> ux_system_regular_memory_pool_alloc_total;
370 }
371 else
372 {
373 _ux_system -> ux_system_cache_safe_memory_pool_alloc_count ++;
374 _ux_system -> ux_system_cache_safe_memory_pool_alloc_total += memory_size_requested;
375 if (_ux_system -> ux_system_cache_safe_memory_pool_alloc_max_count < _ux_system -> ux_system_cache_safe_memory_pool_alloc_count)
376 _ux_system -> ux_system_cache_safe_memory_pool_alloc_max_count = _ux_system -> ux_system_cache_safe_memory_pool_alloc_count;
377 if (_ux_system -> ux_system_cache_safe_memory_pool_alloc_max_total < _ux_system -> ux_system_cache_safe_memory_pool_alloc_total)
378 _ux_system -> ux_system_cache_safe_memory_pool_alloc_max_total = _ux_system -> ux_system_cache_safe_memory_pool_alloc_total;
379 }
380
381 /* Log max usage of regular memory pool. */
382 memory_removed_from_pool = (ALIGN_TYPE)_ux_system -> ux_system_regular_memory_pool_start -
383 (ALIGN_TYPE)_ux_system -> ux_system_regular_memory_pool_base;
384 if (memory_removed_from_pool > _ux_system -> ux_system_regular_memory_pool_max_start_offset)
385 _ux_system -> ux_system_regular_memory_pool_max_start_offset = memory_removed_from_pool;
386 if (_ux_system -> ux_system_regular_memory_pool_min_free > _ux_system -> ux_system_regular_memory_pool_free)
387 _ux_system -> ux_system_regular_memory_pool_min_free = _ux_system -> ux_system_regular_memory_pool_free;
388
389 /* Log max usage of cache safe memory pool. */
390 memory_removed_from_pool = (ALIGN_TYPE)_ux_system -> ux_system_cache_safe_memory_pool_start -
391 (ALIGN_TYPE)_ux_system -> ux_system_cache_safe_memory_pool_base;
392 if (memory_removed_from_pool > _ux_system -> ux_system_cache_safe_memory_pool_max_start_offset)
393 _ux_system -> ux_system_cache_safe_memory_pool_max_start_offset = memory_removed_from_pool;
394 if (_ux_system -> ux_system_cache_safe_memory_pool_min_free > _ux_system -> ux_system_cache_safe_memory_pool_free)
395 _ux_system -> ux_system_cache_safe_memory_pool_min_free = _ux_system -> ux_system_cache_safe_memory_pool_free;
396
397 #endif
398
399 /* Release the protection. */
400 _ux_system_mutex_off(&_ux_system -> ux_system_mutex);
401
402 /* The memory block pointer contains a memory area properly
403 aligned. */
404 return(memory_buffer);
405 }
406