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