1 /* This test simulator is designed to simulate ux_utility_ APIs for test.  */
2 
3 #include <stdio.h>
4 
5 #include "tx_api.h"
6 #include "ux_test.h"
7 
8 #include "ux_api.h"
9 #include "ux_system.h"
10 #include "ux_utility.h"
11 
12 #include "ux_test_utility_sim.h"
13 
14 #define FAIL_DISABLE (~0x00ul)
15 
16 extern void  test_control_return(UINT status);
17 
18     static UX_MEMORY_BLOCK fail_memory_block_first =
19     {
20         .ux_memory_block_next = UX_NULL,
21         .ux_memory_byte_pool = UX_NULL,
22     };
23 
24 static UX_MEMORY_BLOCK *original_regular_memory_block;
25 static UX_MEMORY_BLOCK *original_cache_safe_memory_block;
26 
27 #define MAX_FLAGGED_MEMORY_ALLOCATION_POINTERS 8*1024
28 static VOID *flagged_memory_allocation_pointers[2][MAX_FLAGGED_MEMORY_ALLOCATION_POINTERS];
29 static ULONG num_flagged_memory_allocation_pointers[2];
30 
ux_test_utility_sim_no_overriding_cleanup(VOID)31 VOID ux_test_utility_sim_no_overriding_cleanup(VOID)
32 {
33 
34     num_flagged_memory_allocation_pointers[0] = 0;
35     num_flagged_memory_allocation_pointers[1] = 0;
36 }
37 
38 /* Memory allocation simulator*/
39 
ux_test_utility_sim_mem_alloc_fail_all_start(VOID)40 VOID ux_test_utility_sim_mem_alloc_fail_all_start(VOID)
41 {
42     original_regular_memory_block = (UX_MEMORY_BLOCK *)_ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_start;
43     original_cache_safe_memory_block = (UX_MEMORY_BLOCK *)_ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_CACHE_SAFE] -> ux_byte_pool_start;
44 
45     _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_start = (UCHAR*)&fail_memory_block_first;
46     _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_CACHE_SAFE] -> ux_byte_pool_start = (UCHAR*)&fail_memory_block_first;
47 }
48 
ux_test_utility_sim_mem_alloc_fail_all_stop(VOID)49 VOID ux_test_utility_sim_mem_alloc_fail_all_stop(VOID)
50 {
51     _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_start = (UCHAR*)original_regular_memory_block;
52     _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_CACHE_SAFE] -> ux_byte_pool_start = (UCHAR*)original_cache_safe_memory_block;
53 }
54 
55 
56 /* When the memory allocator tries to find a block of memory for the requested size, it will add extra stuff to
57    accomodate things like having to align the memory. See the allocator for what it adds. We don't take the requested
58    size alignment into account - we leave it up to the caller.  */
get_amount_added_by_memory_allocator(ULONG memory_alignment,ULONG memory_size_requested)59 static ULONG get_amount_added_by_memory_allocator(ULONG memory_alignment, ULONG memory_size_requested)
60 {
61 
62 ULONG added;
63 
64     if (memory_alignment == UX_SAFE_ALIGN)
65         memory_alignment = UX_NO_ALIGN;
66 
67     if (memory_alignment <= UX_ALIGN_MIN)
68     {
69         added = sizeof(UX_MEMORY_BLOCK) +
70         /* This is the amount of memory required to ensure the next memory block buffer is properly align. */
71         (((sizeof(UX_MEMORY_BLOCK) + UX_ALIGN_MIN) & (~(ULONG)UX_ALIGN_MIN)) - sizeof(UX_MEMORY_BLOCK));
72     }
73     else
74     {
75         added = memory_alignment + sizeof(UX_MEMORY_BLOCK) +
76         /* This is the amount of memory required to ensure the next memory block buffer is properly align. */
77         (((sizeof(UX_MEMORY_BLOCK) + UX_ALIGN_MIN) & (~(ULONG)UX_ALIGN_MIN)) - sizeof(UX_MEMORY_BLOCK));
78     }
79 
80     return added;
81 }
82 
83 /* Returns the amount of memory that should be passed to ux_utility_memory_allocate
84    to allocate a specific memory block of the given size. */
memory_requested_size_for_block(ULONG memory_alignment,ULONG block_size)85 static ULONG memory_requested_size_for_block(ULONG memory_alignment, ULONG block_size)
86 {
87 
88 ULONG result;
89 ULONG added;
90 
91     added = get_amount_added_by_memory_allocator(memory_alignment, block_size);
92     if (added > block_size)
93     {
94         return 0;
95     }
96 
97     /* Now subtract everything we added. */
98     result = block_size - added;
99 
100     /* The allocator will align the requested size to 16 bytes, so if we don't do any alignment now, the allocator
101        might add to the size. We can avoid this by just aligning to 16 bytes now. */
102     result &= ~(UX_ALIGN_MIN);
103 
104     // /* _ux_utility_memory_free_block_best_get does a '>' check, not '>='. */
105     // result--;
106 
107     return(result);
108 }
109 
add_memory_allocation_pointer(ULONG memory_cache_flag,VOID * allocation_ptr)110 static void add_memory_allocation_pointer(ULONG memory_cache_flag, VOID *allocation_ptr)
111 {
112     UX_TEST_ASSERT(num_flagged_memory_allocation_pointers[memory_cache_flag] < MAX_FLAGGED_MEMORY_ALLOCATION_POINTERS);
113     flagged_memory_allocation_pointers[memory_cache_flag][num_flagged_memory_allocation_pointers[memory_cache_flag]++] = allocation_ptr;
114 }
115 
116 /* This function simply allocates everything. */
allocate_everything(ULONG memory_cache_flag)117 VOID allocate_everything(ULONG memory_cache_flag)
118 {
119 
120 // UX_MEMORY_BLOCK *first_memory_block;
121 UX_MEMORY_BLOCK *memory_block;
122 ULONG memory_block_size;
123 ULONG memory_block_requested_size;
124 VOID *tmp_allocation_ptr;
125 UX_MEMORY_BYTE_POOL *pool_ptr;
126 
127     if (memory_cache_flag == UX_REGULAR_MEMORY)
128     {
129         pool_ptr = (UX_MEMORY_BYTE_POOL *)_ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR];
130     }
131     else
132     {
133         pool_ptr = (UX_MEMORY_BYTE_POOL *)_ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_CACHE_SAFE];
134     }
135 
136     /* Try to allocate all the blocks according to their size - this is faster than repeatedly allocating 1 byte. */
137     memory_block = (UX_MEMORY_BLOCK *)pool_ptr -> ux_byte_pool_start;
138     while (memory_block -> ux_memory_block_next > memory_block)
139     {
140         if ((ULONG)memory_block->ux_memory_byte_pool == UX_BYTE_BLOCK_FREE)
141         {
142             memory_block_size = (UCHAR *)memory_block->ux_memory_block_next - (UCHAR*)memory_block;
143             memory_block_requested_size = memory_requested_size_for_block(UX_NO_ALIGN, memory_block_size);
144             if (memory_block_requested_size > 0)
145             {
146                 tmp_allocation_ptr = ux_utility_memory_allocate(UX_NO_ALIGN, memory_cache_flag, memory_block_requested_size);
147                 UX_TEST_ASSERT(tmp_allocation_ptr != UX_NULL);
148                 add_memory_allocation_pointer(memory_cache_flag, tmp_allocation_ptr);
149 
150                 /* memory_block is now the block we just allocated. */
151                 memory_block = (UX_MEMORY_BLOCK *)UX_UCHAR_POINTER_SUB(tmp_allocation_ptr, sizeof(UX_MEMORY_BLOCK));
152             }
153         }
154         memory_block = memory_block->ux_memory_block_next;
155     }
156 
157     /* Now allocate everything else. */
158     while (1)
159     {
160         tmp_allocation_ptr = ux_utility_memory_allocate(UX_NO_ALIGN, memory_cache_flag, 1);
161         if (tmp_allocation_ptr == NULL)
162         {
163             break;
164         }
165         add_memory_allocation_pointer(memory_cache_flag, tmp_allocation_ptr);
166     }
167 }
168 
169 /* The goal of this function is to ensure that allocating 'target_fail_level' amount of memory fails, and to ensure
170    any allocations below 'target_fail_level' succeeds. An example usage is trying to get some allocation to fail in USBX
171    where the allocation follows other allocations i.e. you want allocations X and Y to succeed, but Z to fail; by passing
172    the sum of the sizes of X, Y, and Z to this function, it ensures X and Y will success and Z to fail.
173 
174    The gist of how we do this is to allocate memory for 'target_fail_level - 1', then allocate all other memory, then free
175    the 'target_fail_level - 1' allocation. While that's the gist, it's quite oversimplified and there are nuances in the
176    allocator that makes this a little more difficult, as is explained throughout. */
ux_test_utility_sim_mem_allocate_until_align_flagged(ULONG target_fail_level,ULONG memory_alignment,ULONG memory_cache_flag)177 VOID  ux_test_utility_sim_mem_allocate_until_align_flagged(ULONG target_fail_level, ULONG memory_alignment, ULONG memory_cache_flag)
178 {
179 
180 ULONG amount_added_by_allocator;
181 ULONG amount_added_by_alignment;
182 ULONG total_allocation_size;
183 ULONG memory_used;
184 UX_MEMORY_BLOCK *cur_memory_block;
185 UX_MEMORY_BLOCK *next_memory_block;
186 VOID *next_memory_block_buffer;
187 VOID *main_allocation_ptr;
188 UX_MEMORY_BYTE_POOL *pool_ptr;
189 
190     // printf("alloc_until(%ld, %ld, %ld)\n", target_fail_level, memory_alignment, memory_cache_flag);
191     if (memory_cache_flag == UX_REGULAR_MEMORY)
192     {
193         pool_ptr = (UX_MEMORY_BYTE_POOL *)_ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR];
194     }
195     else
196     {
197         pool_ptr = (UX_MEMORY_BYTE_POOL *)_ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_CACHE_SAFE];
198     }
199     /* Since we're going to generate at least one error, we need to ignore it. */
200     ux_test_ignore_all_errors();
201 
202     /* Adjust level if invalid. */
203     if (target_fail_level == 0)
204         target_fail_level++;
205 
206     /* The allocator will align the requested size to a 16-byte boundary. This means that, instead of allocating 'target_fail_level - 1',
207         we instead allocate 'target_fail_level - 16'. If the target_fail_level is less than 16, then we simply allocate everything. */
208     if (target_fail_level <= (UX_ALIGN_MIN + 1))
209     {
210         allocate_everything(memory_cache_flag);
211     }
212     else
213     {
214 
215         /* As previously said, we subtract 16 since the allocator aligns sizes to 16-bytes. */
216         target_fail_level -= (UX_ALIGN_MIN + 1);
217 
218         /* As The header and the alignment is considered in ux_utility_memory_allocate function, we just need to allocate the request size here */
219 #if 0
220         /* We have to figure out the size we need to allocate for the 'target_fail_level - 1' block. This is tricky because the allocator will
221            find a memory block that fits the requested size plus some extra stuff. If the extra stuff isn't used, the allocator will create another
222            memory block for it, so when we try to allocate the 'target_fail_level - 1 ' again, the memory block won't be big enough (remember, we allocate
223            everything after doing this allocate, so the block of extra stuff will be allocated). So, we need to allocate 'target_fail_level - 1' plus
224            the extra stuff so that when it's freed, the memory block will be big enough for 'target_fail_level - 1' to be allocated. */
225         amount_added_by_allocator = get_amount_added_by_memory_allocator(memory_alignment, target_fail_level);
226         amount_added_by_alignment = ((target_fail_level + UX_ALIGN_MIN) & (~(ULONG)UX_ALIGN_MIN)) - target_fail_level; /* The allocator aligns the requested size i.e. it adds some stuff. Take that into account now. */
227         total_allocation_size = (target_fail_level) + amount_added_by_allocator + amount_added_by_alignment;
228 #else
229         total_allocation_size = target_fail_level;
230 #endif
231         main_allocation_ptr = ux_utility_memory_allocate(memory_alignment, memory_cache_flag, total_allocation_size);
232         if (main_allocation_ptr != NULL)
233         {
234             allocate_everything(memory_cache_flag);
235 
236             /* The next memory block _must_ be USED so that we don't merge with it, since it will cause the 'target_fail_level - 1' block to become
237                larger. The next memory block can be UNUSED if it's too small to be allocated by even a requested size of 1. */
238             cur_memory_block = (UX_MEMORY_BLOCK *) main_allocation_ptr - 1;
239             next_memory_block = cur_memory_block->ux_memory_block_next;
240             if ((ULONG)next_memory_block->ux_memory_byte_pool == UX_BYTE_BLOCK_FREE)
241             {
242                 next_memory_block->ux_memory_byte_pool = pool_ptr;
243                 next_memory_block_buffer = (VOID *) (next_memory_block + 1);
244                 add_memory_allocation_pointer(memory_cache_flag, next_memory_block_buffer);
245 
246                 memory_used = (UCHAR *)next_memory_block->ux_memory_block_next - (UCHAR*)next_memory_block;
247                 if (_ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_CACHE_SAFE] -> ux_byte_pool_start == _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_start)
248                 {
249                     _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available -= memory_used;
250                 }
251                 else
252                 {
253                     switch (memory_cache_flag)
254                     {
255                         case UX_CACHE_SAFE_MEMORY:
256                             _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_CACHE_SAFE] -> ux_byte_pool_available -= memory_used;
257                             break;
258                         default:
259                             _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available -= memory_used;
260                             break;
261                     }
262                 }
263             }
264 
265             /* Now free the 'target_fail_level - 1' block. */
266             ux_utility_memory_free(main_allocation_ptr);
267         }
268     }
269 
270     ux_test_unignore_all_errors();
271 }
272 
ux_test_utility_sim_mem_free_all_flagged(ULONG memory_cache_flag)273 VOID  ux_test_utility_sim_mem_free_all_flagged(ULONG memory_cache_flag)
274 {
275 
276 ULONG i;
277 
278     for (i = 0; i < num_flagged_memory_allocation_pointers[memory_cache_flag]; i++)
279     {
280         ux_utility_memory_free(flagged_memory_allocation_pointers[memory_cache_flag][i]);
281     }
282     num_flagged_memory_allocation_pointers[memory_cache_flag] = 0;
283 }
284 
ux_test_utility_sim_mem_test(VOID)285 VOID ux_test_utility_sim_mem_test(VOID)
286 {
287 ULONG mem_level = 400;
288 ULONG alloc_size;
289 VOID* tmp_alloc;
290 
291     printf("Test memory level: %ld\n", mem_level);
292     ux_test_utility_sim_mem_allocate_until(mem_level);
293 
294     alloc_size = mem_level;
295     tmp_alloc = ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, alloc_size);
296     printf("Allocate size %ld: %p\n", alloc_size, tmp_alloc);
297     if (tmp_alloc) ux_utility_memory_free(tmp_alloc);
298 
299     alloc_size = mem_level >> 1;
300     tmp_alloc = ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, alloc_size);
301     printf("Allocate size %ld: %p\n", alloc_size, tmp_alloc);
302     if (tmp_alloc) ux_utility_memory_free(tmp_alloc);
303 
304     alloc_size = mem_level - 4;
305     tmp_alloc = ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, alloc_size);
306     printf("Allocate size -%ld(%ld): %p\n", mem_level - alloc_size, alloc_size, tmp_alloc);
307     if (tmp_alloc) ux_utility_memory_free(tmp_alloc);
308 
309     alloc_size = mem_level - 8;
310     tmp_alloc = ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, alloc_size);
311     printf("Allocate size -%ld(%ld): %p\n", mem_level - alloc_size, alloc_size, tmp_alloc);
312     if (tmp_alloc) ux_utility_memory_free(tmp_alloc);
313 
314     alloc_size = mem_level - 16;
315     tmp_alloc = ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, alloc_size);
316     printf("Allocate size -%ld(%ld): %p\n", mem_level - alloc_size, alloc_size, tmp_alloc);
317     if (tmp_alloc) ux_utility_memory_free(tmp_alloc);
318 
319     alloc_size = mem_level - 32;
320     tmp_alloc = ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, alloc_size);
321     printf("Allocate size -%ld(%ld): %p\n", mem_level - alloc_size, alloc_size, tmp_alloc);
322     if (tmp_alloc) ux_utility_memory_free(tmp_alloc);
323 
324     alloc_size = mem_level - 64;
325     tmp_alloc = ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, alloc_size);
326     printf("Allocate size -%ld(%ld): %p\n", mem_level - alloc_size, alloc_size, tmp_alloc);
327     if (tmp_alloc) ux_utility_memory_free(tmp_alloc);
328 
329     alloc_size = mem_level - 128;
330     tmp_alloc = ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, alloc_size);
331     printf("Allocate size -%ld(%ld): %p\n", mem_level - alloc_size, alloc_size, tmp_alloc);
332     if (tmp_alloc) ux_utility_memory_free(tmp_alloc);
333 
334     alloc_size = mem_level - 256;
335     tmp_alloc = ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, alloc_size);
336     printf("Allocate size -%ld(%ld): %p\n", mem_level - alloc_size, alloc_size, tmp_alloc);
337     if (tmp_alloc) ux_utility_memory_free(tmp_alloc);
338 
339     ux_test_utility_sim_mem_free_all();
340 
341     printf("alloc resolution:\n");
342     mem_level = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available;
343     tmp_alloc = ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, 4);
344     printf("alloc 4 bytes: %ld -> %ld (%ld)\n", mem_level, _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available, mem_level - _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available);
345     ux_utility_memory_free(tmp_alloc);
346 
347     mem_level = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available;
348     tmp_alloc = ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, 16);
349     printf("alloc 16 bytes: %ld -> %ld (%ld)\n", mem_level, _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available, mem_level - _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available);
350     ux_utility_memory_free(tmp_alloc);
351 
352     mem_level = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available;
353     tmp_alloc = ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, 64);
354     printf("alloc 64 bytes: %ld -> %ld (%ld)\n", mem_level, _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available, mem_level - _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available);
355     ux_utility_memory_free(tmp_alloc);
356 
357     mem_level = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available;
358     tmp_alloc = ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, 100);
359     printf("alloc 100 bytes: %ld -> %ld (%ld)\n", mem_level, _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available, mem_level - _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available);
360     ux_utility_memory_free(tmp_alloc);
361 
362     mem_level = _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available;
363     tmp_alloc = ux_utility_memory_allocate(UX_NO_ALIGN, UX_REGULAR_MEMORY, 200);
364     printf("alloc 200 bytes: %ld -> %ld (%ld)\n", mem_level, _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available, mem_level - _ux_system -> ux_system_memory_byte_pool[UX_MEMORY_BYTE_POOL_REGULAR] -> ux_byte_pool_available);
365     ux_utility_memory_free(tmp_alloc);
366 
367     printf("Halt this thread!\n");
368     while(1)
369     {
370 
371         tx_thread_sleep(10);
372     }
373 }
374