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