GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: core/src/ux_utility_memory_allocate.c Lines: 65 66 98.5 %
Date: 2024-12-12 17:16:36 Branches: 21 22 95.5 %

Line Branch Exec Source
1
/***************************************************************************
2
 * Copyright (c) 2024 Microsoft Corporation
3
 *
4
 * This program and the accompanying materials are made available under the
5
 * terms of the MIT License which is available at
6
 * https://opensource.org/licenses/MIT.
7
 *
8
 * SPDX-License-Identifier: MIT
9
 **************************************************************************/
10
11
12
/**************************************************************************/
13
/**************************************************************************/
14
/**                                                                       */
15
/** USBX Component                                                        */
16
/**                                                                       */
17
/**   Utility                                                             */
18
/**                                                                       */
19
/**************************************************************************/
20
/**************************************************************************/
21
22
23
/* Include necessary system files.  */
24
25
#define UX_SOURCE_CODE
26
27
#include "ux_api.h"
28
29
/**************************************************************************/
30
/*                                                                        */
31
/*  FUNCTION                                               RELEASE        */
32
/*                                                                        */
33
/*    _ux_utility_memory_allocate                         PORTABLE C      */
34
/*                                                           6.3.0        */
35
/*  AUTHOR                                                                */
36
/*                                                                        */
37
/*    Chaoqiong Xiao, Microsoft Corporation                               */
38
/*                                                                        */
39
/*  DESCRIPTION                                                           */
40
/*                                                                        */
41
/*    This function allocates a block of memory for the specified size    */
42
/*    and alignment.                                                      */
43
/*                                                                        */
44
/*  INPUT                                                                 */
45
/*                                                                        */
46
/*    memory_alignment                      Memory alignment required     */
47
/*    memory_cache_flag                     Memory pool source            */
48
/*    memory_size_requested                 Number of bytes required      */
49
/*                                                                        */
50
/*  OUTPUT                                                                */
51
/*                                                                        */
52
/*    Pointer to block of memory                                          */
53
/*                                                                        */
54
/*  CALLS                                                                 */
55
/*                                                                        */
56
/*    _ux_utility_memory_free_block_best_get Get best fit block of memory */
57
/*    _ux_utility_memory_set                 Set block of memory          */
58
/*                                                                        */
59
/*  CALLED BY                                                             */
60
/*                                                                        */
61
/*    USBX Components                                                     */
62
/*                                                                        */
63
/*  RELEASE HISTORY                                                       */
64
/*                                                                        */
65
/*    DATE              NAME                      DESCRIPTION             */
66
/*                                                                        */
67
/*  05-19-2020     Chaoqiong Xiao           Initial Version 6.0           */
68
/*  09-30-2020     Chaoqiong Xiao           Modified comment(s),          */
69
/*                                            verified memset and memcpy  */
70
/*                                            cases,                      */
71
/*                                            resulting in version 6.1    */
72
/*  01-31-2022     Chaoqiong Xiao           Modified comment(s),          */
73
/*                                            added standalone support,   */
74
/*                                            resulting in version 6.1.10 */
75
/*  04-25-2022     Chaoqiong Xiao           Modified comment(s),          */
76
/*                                            internal clean up,          */
77
/*                                            resulting in version 6.1.11 */
78
/*  10-31-2023     Chaoqiong Xiao           Modified comment(s),          */
79
/*                                            refined memory management,  */
80
/*                                            fixed issue in 64-bit env,  */
81
/*                                            resulting in version 6.3.0  */
82
/*                                                                        */
83
/**************************************************************************/
84
343750
VOID  *_ux_utility_memory_allocate(ULONG memory_alignment, ULONG memory_cache_flag,
85
                                   ULONG memory_size_requested)
86
{
87
UX_MEMORY_BYTE_POOL *pool_ptr;
88
UCHAR               *current_ptr;
89
UCHAR               *work_ptr;
90
UCHAR               *next_ptr;
91
ALIGN_TYPE          *free_ptr;
92
UCHAR               **this_block_link_ptr;
93
UCHAR               **next_block_link_ptr;
94
ULONG               available_bytes;
95
96
ALIGN_TYPE          int_memory_buffer;
97
#ifdef UX_ENABLE_MEMORY_STATISTICS
98
UINT                index;
99
#endif
100
101
    /* Get the pool ptr */
102
343750
    if (memory_cache_flag == UX_REGULAR_MEMORY)
103
    {
104
327660
        pool_ptr = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR];
105
    }
106
16090
    else if (memory_cache_flag == UX_CACHE_SAFE_MEMORY)
107
    {
108
16054
        pool_ptr = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_CACHE_SAFE];
109
    }
110
    else
111
    {
112
36
        return(UX_NULL);
113
    }
114
115
    /* Check if pool_ptr is NX_NULL */
116
343714
    if (pool_ptr == UX_NULL)
117
    {
118
        return(UX_NULL);
119
    }
120
121
    /* Check if the memory size requested is 0.  */
122
343714
    if (memory_size_requested == 0)
123
    {
124
2
        return(UX_NULL);
125
    }
126
127
    /* Get the mutex as this is a critical section.  */
128
343712
    _ux_system_mutex_on(&_ux_system -> ux_system_mutex);
129
130
#ifdef UX_ENFORCE_SAFE_ALIGNMENT
131
132
    /* Check if safe alignment requested, in this case switch to UX_NO_ALIGN.  */
133
    if (memory_alignment == UX_SAFE_ALIGN)
134
    {
135
136
        /* We will use the memory_size_requested for the alignment.
137
           But we check to see if we have a minimum or maximum alignment.  */
138
        if (memory_size_requested < UX_ALIGN_MIN)
139
140
            /* No need to bother about alignment for small packets sizes.  */
141
            memory_alignment = UX_NO_ALIGN;
142
143
        /* Check if we are over the maximum.  */
144
        else if (memory_size_requested > UX_MAX_SCATTER_GATHER_ALIGNMENT)
145
146
            /* We are over the max alignment required. Use the maximum instead.  */
147
            memory_alignment = UX_MAX_SCATTER_GATHER_ALIGNMENT - 1;
148
149
        /* We are not over the maximum, so approximate the alignment according to the size of the memory.
150
            Check range for alignment on 4096 bytes.  */
151
        else if (memory_size_requested >= UX_ALIGN_2048 + 1)
152
            memory_alignment = UX_ALIGN_4096;
153
154
        /* Check range for alignment on 2048 bytes.  */
155
        else if (memory_size_requested >= UX_ALIGN_1024 + 1)
156
            memory_alignment = UX_ALIGN_2048;
157
158
        /* Check range for alignment on 1024 bytes.  */
159
        else if (memory_size_requested >= UX_ALIGN_512 + 1)
160
            memory_alignment = UX_ALIGN_1024;
161
162
        /* Check range for alignment on 512 bytes.  */
163
        else if (memory_size_requested >= UX_ALIGN_256 + 1)
164
            memory_alignment = UX_ALIGN_512;
165
166
        /* Check range for alignment on 256 bytes.  */
167
        else if (memory_size_requested >= UX_ALIGN_128 + 1)
168
            memory_alignment = UX_ALIGN_256;
169
170
        /* Check range for alignment on 128 bytes.  */
171
        else if (memory_size_requested >= UX_ALIGN_64 + 1)
172
            memory_alignment = UX_ALIGN_128;
173
174
        /* Check range for alignment on 64 bytes.  */
175
        else if (memory_size_requested >= UX_ALIGN_32 + 1)
176
            memory_alignment = UX_ALIGN_64;
177
178
        /* Check range for alignment on 32 bytes.  */
179
        else if (memory_size_requested >= UX_ALIGN_16 + 1)
180
            memory_alignment = UX_ALIGN_32;
181
182
        /* Check range for alignment on 16 bytes.  */
183
        else if (memory_size_requested >= UX_ALIGN_8 + 1)
184
            memory_alignment = UX_ALIGN_16;
185
186
        else
187
            memory_alignment = UX_ALIGN_MIN;
188
    }
189
190
#else
191
192
    /* Check if safe alignment requested, in this case switch to UX_NO_ALIGN.  */
193
343712
    if (memory_alignment == UX_SAFE_ALIGN)
194
7260
        memory_alignment = UX_NO_ALIGN;
195
196
#endif
197
198
    /* Ensure the alignment meats the minimum.  */
199
343712
    if (memory_alignment < UX_ALIGN_MIN)
200
342538
        memory_alignment =  UX_ALIGN_MIN;
201
202
    /* We need to make sure that the next memory block buffer is 8-byte aligned too. We
203
       do this by first adjusting the requested memory to be 8-byte aligned. One problem
204
       now is that the memory block might not be a size that is a multiple of 8, so we need
205
       to add the amount of memory required such that the memory buffer after the block has
206
       the correct alignment. For example, if the memory block has a size of 12, then we need
207
       to make sure it is placed on an 8-byte alignment that is after a 8-byte alignment so
208
       that the memory right after the memory block is 8-byte aligned (16).  */
209
343712
    memory_size_requested =  (memory_size_requested + UX_ALIGN_MIN) & (~(ULONG)UX_ALIGN_MIN);
210
343712
    memory_size_requested += (((ULONG)(UX_MEMORY_BLOCK_HEADER_SIZE + UX_ALIGN_MIN) & (~(ULONG)UX_ALIGN_MIN)) - (ULONG)UX_MEMORY_BLOCK_HEADER_SIZE);
211
212
343712
    if (memory_alignment <= UX_ALIGN_MIN)
213
342544
        current_ptr = _ux_utility_memory_byte_pool_search(pool_ptr, memory_size_requested);
214
    else
215
1168
        current_ptr = _ux_utility_memory_byte_pool_search(pool_ptr, memory_size_requested + memory_alignment);
216
217
    /* Check if we found a memory block.  */
218
343712
    if (current_ptr == UX_NULL)
219
    {
220
221
        /* We could not find a memory block.  */
222
15341
        _ux_system_mutex_off(&_ux_system -> ux_system_mutex);
223
224
        UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_MEMORY_INSUFFICIENT, memory_size_requested, 0, 0, UX_TRACE_ERRORS, 0, 0)
225
226
        /* Error trap. */
227
15341
        _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_UTILITY, UX_MEMORY_INSUFFICIENT);
228
229
15341
        return(UX_NULL);
230
    }
231
232
    /* Pickup the next block's pointer.  */
233
328371
    this_block_link_ptr =  UX_UCHAR_TO_INDIRECT_UCHAR_POINTER_CONVERT(current_ptr);
234
328371
    next_ptr =             *this_block_link_ptr;
235
236
    /* Calculate the number of bytes available in this block.  */
237
328371
    available_bytes =   UX_UCHAR_POINTER_DIF(next_ptr, current_ptr);
238
328371
    available_bytes =   available_bytes - UX_MEMORY_BLOCK_HEADER_SIZE;
239
240
    /* Get the memory buffer for this block.  */
241
328371
    int_memory_buffer = (ALIGN_TYPE) (UX_UCHAR_POINTER_ADD(current_ptr, UX_MEMORY_BLOCK_HEADER_SIZE));
242
243
    /* In case we are not aligned  */
244
328371
    if ((int_memory_buffer & memory_alignment) != 0)
245
    {
246
247
        /* No, we need to align the memory buffer.  */
248
870
        int_memory_buffer += (ALIGN_TYPE)UX_MEMORY_BLOCK_HEADER_SIZE;
249
870
        int_memory_buffer += memory_alignment;
250
870
        int_memory_buffer &=  ~((ALIGN_TYPE) memory_alignment);
251
870
        int_memory_buffer -= (ALIGN_TYPE)UX_MEMORY_BLOCK_HEADER_SIZE;
252
253
        /* Setup the new free block.  */
254
870
        next_ptr = (UCHAR *)int_memory_buffer;
255
256
        /* Setup the new free block.  */
257
870
        next_block_link_ptr =   UX_UCHAR_TO_INDIRECT_UCHAR_POINTER_CONVERT(next_ptr);
258
870
        *next_block_link_ptr =  *this_block_link_ptr;
259
870
        work_ptr =              UX_UCHAR_POINTER_ADD(next_ptr, (sizeof(UCHAR *)));
260
870
        free_ptr =              UX_UCHAR_TO_ALIGN_TYPE_POINTER_CONVERT(work_ptr);
261
870
        *free_ptr =             UX_BYTE_BLOCK_FREE;
262
263
        /* Increase the total fragment counter.  */
264
870
        pool_ptr -> ux_byte_pool_fragments++;
265
266
        /* Update the current pointer to point at the newly created block.  */
267
870
        *this_block_link_ptr =  next_ptr;
268
269
        /* Calculate the available bytes.  */
270
870
        available_bytes -=  UX_UCHAR_POINTER_DIF(next_ptr, current_ptr);
271
272
        /* Set Current pointer to the aligned memory buffer.  */
273
870
        current_ptr = next_ptr;
274
    }
275
276
    /* Now we are aligned, determine if we need to split this block.  */
277
328371
    if ((available_bytes - memory_size_requested) >= ((ULONG) UX_BYTE_BLOCK_MIN))
278
    {
279
280
        /* Split the block.  */
281
16363
        next_ptr =  UX_UCHAR_POINTER_ADD(current_ptr, (memory_size_requested + UX_MEMORY_BLOCK_HEADER_SIZE));
282
283
        /* Setup the new free block.  */
284
16363
        next_block_link_ptr =   UX_UCHAR_TO_INDIRECT_UCHAR_POINTER_CONVERT(next_ptr);
285
16363
        this_block_link_ptr =   UX_UCHAR_TO_INDIRECT_UCHAR_POINTER_CONVERT(current_ptr);
286
16363
        *next_block_link_ptr =  *this_block_link_ptr;
287
16363
        work_ptr =              UX_UCHAR_POINTER_ADD(next_ptr, (sizeof(UCHAR *)));
288
16363
        free_ptr =              UX_UCHAR_TO_ALIGN_TYPE_POINTER_CONVERT(work_ptr);
289
16363
        *free_ptr =             UX_BYTE_BLOCK_FREE;
290
291
        /* Increase the total fragment counter.  */
292
16363
        pool_ptr -> ux_byte_pool_fragments++;
293
294
        /* Update the current pointer to point at the newly created block.  */
295
16363
        *this_block_link_ptr =  next_ptr;
296
297
        /* Set available equal to memory size for subsequent calculation.  */
298
16363
        available_bytes =  memory_size_requested;
299
    }
300
301
    /* In any case, mark the current block as allocated.  */
302
328371
    work_ptr =              UX_UCHAR_POINTER_ADD(current_ptr, (sizeof(UCHAR *)));
303
328371
    this_block_link_ptr =   UX_UCHAR_TO_INDIRECT_UCHAR_POINTER_CONVERT(work_ptr);
304
328371
    *this_block_link_ptr =  UX_BYTE_POOL_TO_UCHAR_POINTER_CONVERT(pool_ptr);
305
306
    /* Reduce the number of available bytes in the pool.  */
307
328371
    pool_ptr -> ux_byte_pool_available =  pool_ptr -> ux_byte_pool_available - (available_bytes + UX_MEMORY_BLOCK_HEADER_SIZE);
308
309
    /* Determine if the search pointer needs to be updated. This is only done
310
        if the search pointer matches the block to be returned.  */
311
328371
    if (current_ptr == pool_ptr -> ux_byte_pool_search)
312
    {
313
314
        /* Yes, update the search pointer to the next block.  */
315
17625
        this_block_link_ptr =   UX_UCHAR_TO_INDIRECT_UCHAR_POINTER_CONVERT(current_ptr);
316
17625
        pool_ptr -> ux_byte_pool_search =  *this_block_link_ptr;
317
    }
318
319
    /* Adjust the pointer for the application.  */
320
328371
    work_ptr =  UX_UCHAR_POINTER_ADD(current_ptr, UX_MEMORY_BLOCK_HEADER_SIZE);
321
322
    /* Clear the memory block.  */
323
328371
    _ux_utility_memory_set(work_ptr, 0, available_bytes); /* Use case of memset is verified. */
324
325
#ifdef UX_ENABLE_MEMORY_STATISTICS
326
327
    /* Update allocate count, total size.  */
328
    if (memory_cache_flag == UX_REGULAR_MEMORY)
329
        index = UX_MEMORY_BYTE_POOL_REGULAR;
330
    else
331
        index = UX_MEMORY_BYTE_POOL_CACHE_SAFE;
332
333
    /* Update allocate count, total size.  */
334
    _ux_system -> ux_system_memory_byte_pool[index] -> ux_byte_pool_alloc_count ++;
335
    _ux_system -> ux_system_memory_byte_pool[index] -> ux_byte_pool_alloc_total += (available_bytes + UX_MEMORY_BLOCK_HEADER_SIZE);
336
337
    if (_ux_system -> ux_system_memory_byte_pool[index] -> ux_byte_pool_alloc_max_count < _ux_system -> ux_system_memory_byte_pool[index] -> ux_byte_pool_alloc_count)
338
        _ux_system -> ux_system_memory_byte_pool[index] -> ux_byte_pool_alloc_max_count = _ux_system -> ux_system_memory_byte_pool[index] -> ux_byte_pool_alloc_count;
339
340
    if (_ux_system -> ux_system_memory_byte_pool[index] -> ux_byte_pool_alloc_max_total < _ux_system -> ux_system_memory_byte_pool[index] -> ux_byte_pool_alloc_total)
341
        _ux_system -> ux_system_memory_byte_pool[index] -> ux_byte_pool_alloc_max_total = _ux_system -> ux_system_memory_byte_pool[index] -> ux_byte_pool_alloc_total;
342
343
    /* Log max usage of memory pool.  */
344
    if (_ux_system -> ux_system_memory_byte_pool[index] -> ux_byte_pool_min_free > _ux_system -> ux_system_memory_byte_pool[index] -> ux_byte_pool_available)
345
        _ux_system -> ux_system_memory_byte_pool[index] -> ux_byte_pool_min_free = _ux_system -> ux_system_memory_byte_pool[index] -> ux_byte_pool_available;
346
#endif
347
348
    /* Release the protection.  */
349
328371
    _ux_system_mutex_off(&_ux_system -> ux_system_mutex);
350
351
328371
    return(work_ptr);
352
}