1 /* SPDX-License-Identifier: GPL-2.0-only */
6 #include <tests/test.h>
8 #include <imd_private.h>
10 #include <commonlib/bsd/helpers.h>
13 /* Auxiliary functions and definitions. */
15 #define LG_ROOT_SIZE \
16 align_up_pow2(sizeof(struct imd_root_pointer) + sizeof(struct imd_root) \
17 + 3 * sizeof(struct imd_entry))
18 #define LG_ENTRY_ALIGN (2 * sizeof(int32_t))
19 #define LG_ENTRY_SIZE (2 * sizeof(int32_t))
20 #define LG_ENTRY_ID 0xA001
22 #define SM_ROOT_SIZE LG_ROOT_SIZE
23 #define SM_ENTRY_ALIGN sizeof(uint32_t)
24 #define SM_ENTRY_SIZE sizeof(uint32_t)
25 #define SM_ENTRY_ID 0xB001
27 #define INVALID_REGION_ID 0xC001
29 static uint32_t align_up_pow2(uint32_t x
)
31 return (1 << log2_ceil(x
));
34 static size_t max_entries(size_t root_size
)
36 return (root_size
- sizeof(struct imd_root_pointer
) - sizeof(struct imd_root
))
37 / sizeof(struct imd_entry
);
41 * Mainly, we should check that imd_handle_init() aligns upper_limit properly
42 * for various inputs. Upper limit is the _exclusive_ address, so we expect
45 static void test_imd_handle_init(void **state
)
50 uintptr_t test_inputs
[] = {
51 0, /* Lowest possible address */
52 0xA000, /* Fits in 16 bits, should not get rounded down */
53 0xDEAA, /* Fits in 16 bits */
54 0xB0B0B000, /* Fits in 32 bits, should not get rounded down */
55 0xF0F0F0F0, /* Fits in 32 bits */
56 ((1ULL << 32) + 4), /* Just above 32-bit limit */
57 0x6666777788889000, /* Fits in 64 bits, should not get rounded down */
58 ((1ULL << 60) - 100) /* Very large address, fitting in 64 bits */
61 for (i
= 0; i
< ARRAY_SIZE(test_inputs
); i
++) {
62 base
= (void *)test_inputs
[i
];
64 imd_handle_init(&imd
, (void *)base
);
66 assert_int_equal(imd
.lg
.limit
% LIMIT_ALIGN
, 0);
67 assert_int_equal(imd
.lg
.limit
, ALIGN_DOWN(test_inputs
[i
], LIMIT_ALIGN
));
68 assert_ptr_equal(imd
.lg
.r
, NULL
);
70 /* Small allocations not initialized */
71 assert_ptr_equal(imd
.sm
.limit
, NULL
);
72 assert_ptr_equal(imd
.sm
.r
, NULL
);
76 static void test_imd_handle_init_partial_recovery(void **state
)
80 const struct imd_entry
*entry
;
82 imd_handle_init_partial_recovery(&imd
);
83 assert_null(imd
.lg
.limit
);
84 assert_null(imd
.sm
.limit
);
86 base
= malloc(LIMIT_ALIGN
);
88 fail_msg("Cannot allocate enough memory - fail test");
90 imd_handle_init(&imd
, (void *)(LIMIT_ALIGN
+ (uintptr_t)base
));
91 imd_handle_init_partial_recovery(&imd
);
93 assert_non_null(imd
.lg
.r
);
94 assert_null(imd
.sm
.limit
);
96 assert_int_equal(0, imd_create_empty(&imd
, LG_ROOT_SIZE
, LG_ENTRY_ALIGN
));
97 entry
= imd_entry_add(&imd
, SMALL_REGION_ID
, LG_ENTRY_SIZE
);
98 assert_non_null(entry
);
100 imd_handle_init_partial_recovery(&imd
);
102 assert_non_null(imd
.lg
.r
);
103 assert_non_null(imd
.sm
.limit
);
104 assert_ptr_equal(imd
.lg
.r
+ entry
->start_offset
+ LG_ENTRY_SIZE
, imd
.sm
.limit
);
105 assert_non_null(imd
.sm
.r
);
110 static void test_imd_create_empty(void **state
)
112 struct imd imd
= {0};
117 /* Expect imd_create_empty to fail, since imd handle is not initialized */
118 assert_int_equal(-1, imd_create_empty(&imd
, LG_ROOT_SIZE
, LG_ENTRY_ALIGN
));
119 base
= malloc(sizeof(struct imd_root_pointer
) + sizeof(struct imd_root
));
121 fail_msg("Cannot allocate enough memory - fail test");
123 imd_handle_init(&imd
, (void *)(LIMIT_ALIGN
+ (uintptr_t)base
));
125 /* Try incorrect sizes */
127 -1, imd_create_empty(&imd
, sizeof(struct imd_root_pointer
), LG_ENTRY_ALIGN
));
128 assert_int_equal(-1, imd_create_empty(&imd
, LG_ROOT_SIZE
, 2 * LG_ROOT_SIZE
));
131 assert_int_equal(0, imd_create_empty(&imd
, LG_ROOT_SIZE
, LG_ENTRY_ALIGN
));
133 /* Only large allocation initialized with one entry for the root region */
134 r
= (struct imd_root
*)(imd
.lg
.r
);
137 e
= &r
->entries
[r
->num_entries
- 1];
139 assert_int_equal(max_entries(LG_ROOT_SIZE
), r
->max_entries
);
140 assert_int_equal(1, r
->num_entries
);
141 assert_int_equal(0, r
->flags
);
142 assert_int_equal(LG_ENTRY_ALIGN
, r
->entry_align
);
143 assert_int_equal(0, r
->max_offset
);
144 assert_ptr_equal(e
, &r
->entries
);
146 assert_int_equal(IMD_ENTRY_MAGIC
, e
->magic
);
147 assert_int_equal(0, e
->start_offset
);
148 assert_int_equal(LG_ROOT_SIZE
, e
->size
);
149 assert_int_equal(CBMEM_ID_IMD_ROOT
, e
->id
);
154 static void test_imd_create_tiered_empty(void **state
)
157 size_t sm_region_size
, lg_region_wrong_size
;
158 struct imd imd
= {0};
160 struct imd_entry
*fst_lg_entry
, *snd_lg_entry
, *sm_entry
;
162 /* Uninitialized imd handle */
163 assert_int_equal(-1, imd_create_tiered_empty(&imd
, LG_ROOT_SIZE
, LG_ENTRY_ALIGN
,
164 LG_ROOT_SIZE
, SM_ENTRY_ALIGN
));
166 base
= malloc(LIMIT_ALIGN
);
168 fail_msg("Cannot allocate enough memory - fail test");
170 imd_handle_init(&imd
, (void *)(LIMIT_ALIGN
+ (uintptr_t)base
));
172 /* Too small root_size for small region */
173 assert_int_equal(-1, imd_create_tiered_empty(&imd
, LG_ROOT_SIZE
, LG_ENTRY_ALIGN
,
174 sizeof(int32_t), 2 * sizeof(int32_t)));
176 /* Fail when large region doesn't have capacity for more than 1 entry */
177 lg_region_wrong_size
= sizeof(struct imd_root_pointer
) + sizeof(struct imd_root
)
178 + sizeof(struct imd_entry
);
179 expect_assert_failure(imd_create_tiered_empty(
180 &imd
, lg_region_wrong_size
, LG_ENTRY_ALIGN
, SM_ROOT_SIZE
, SM_ENTRY_ALIGN
));
182 assert_int_equal(0, imd_create_tiered_empty(&imd
, LG_ROOT_SIZE
, LG_ENTRY_ALIGN
,
183 SM_ROOT_SIZE
, SM_ENTRY_ALIGN
));
187 /* One entry for root_region and one for small allocations */
188 assert_int_equal(2, r
->num_entries
);
190 fst_lg_entry
= &r
->entries
[0];
191 assert_int_equal(IMD_ENTRY_MAGIC
, fst_lg_entry
->magic
);
192 assert_int_equal(0, fst_lg_entry
->start_offset
);
193 assert_int_equal(LG_ROOT_SIZE
, fst_lg_entry
->size
);
194 assert_int_equal(CBMEM_ID_IMD_ROOT
, fst_lg_entry
->id
);
196 /* Calculated like in imd_create_tiered_empty */
197 sm_region_size
= max_entries(SM_ROOT_SIZE
) * SM_ENTRY_ALIGN
;
198 sm_region_size
+= SM_ROOT_SIZE
;
199 sm_region_size
= ALIGN_UP(sm_region_size
, LG_ENTRY_ALIGN
);
201 snd_lg_entry
= &r
->entries
[1];
202 assert_int_equal(IMD_ENTRY_MAGIC
, snd_lg_entry
->magic
);
203 assert_int_equal(-sm_region_size
, snd_lg_entry
->start_offset
);
204 assert_int_equal(CBMEM_ID_IMD_SMALL
, snd_lg_entry
->id
);
206 assert_int_equal(sm_region_size
, snd_lg_entry
->size
);
209 assert_int_equal(1, r
->num_entries
);
211 sm_entry
= &r
->entries
[0];
212 assert_int_equal(IMD_ENTRY_MAGIC
, sm_entry
->magic
);
213 assert_int_equal(0, sm_entry
->start_offset
);
214 assert_int_equal(SM_ROOT_SIZE
, sm_entry
->size
);
215 assert_int_equal(CBMEM_ID_IMD_ROOT
, sm_entry
->id
);
220 /* Tests for imdr_recover. */
221 static void test_imd_recover(void **state
)
223 int32_t offset_copy
, max_offset_copy
;
224 uint32_t rp_magic_copy
, num_entries_copy
;
225 uint32_t e_align_copy
, e_magic_copy
, e_id_copy
;
226 uint32_t size_copy
, diff
;
228 struct imd imd
= {0};
229 struct imd_root_pointer
*rp
;
231 struct imd_entry
*lg_root_entry
, *sm_root_entry
, *ptr
;
232 const struct imd_entry
*lg_entry
;
234 /* Fail when the limit for lg was not set. */
235 imd
.lg
.limit
= (uintptr_t)NULL
;
236 assert_int_equal(-1, imd_recover(&imd
));
238 /* Set the limit for lg. */
239 base
= malloc(LIMIT_ALIGN
);
241 fail_msg("Cannot allocate enough memory - fail test");
243 imd_handle_init(&imd
, (void *)(LIMIT_ALIGN
+ (uintptr_t)base
));
245 /* Fail when the root pointer is not valid. */
246 rp
= (void *)imd
.lg
.limit
- sizeof(struct imd_root_pointer
);
248 assert_int_equal(IMD_ROOT_PTR_MAGIC
, rp
->magic
);
250 rp_magic_copy
= rp
->magic
;
252 assert_int_equal(-1, imd_recover(&imd
));
253 rp
->magic
= rp_magic_copy
;
255 /* Set the root pointer. */
256 assert_int_equal(0, imd_create_tiered_empty(&imd
, LG_ROOT_SIZE
, LG_ENTRY_ALIGN
,
257 SM_ROOT_SIZE
, SM_ENTRY_ALIGN
));
258 assert_int_equal(2, ((struct imd_root
*)imd
.lg
.r
)->num_entries
);
259 assert_int_equal(1, ((struct imd_root
*)imd
.sm
.r
)->num_entries
);
261 /* Fail if the number of entries exceeds the maximum number of entries. */
263 num_entries_copy
= r
->num_entries
;
264 r
->num_entries
= r
->max_entries
+ 1;
265 assert_int_equal(-1, imd_recover(&imd
));
266 r
->num_entries
= num_entries_copy
;
268 /* Fail if entry align is not a power of 2. */
269 e_align_copy
= r
->entry_align
;
271 assert_int_equal(-1, imd_recover(&imd
));
272 r
->entry_align
= e_align_copy
;
274 /* Fail when an entry is not valid. */
275 lg_root_entry
= &r
->entries
[0];
276 e_magic_copy
= lg_root_entry
->magic
;
277 lg_root_entry
->magic
= 0;
278 assert_int_equal(-1, imd_recover(&imd
));
279 lg_root_entry
->magic
= e_magic_copy
;
281 /* Add new entries: large and small. */
282 lg_entry
= imd_entry_add(&imd
, LG_ENTRY_ID
, LG_ENTRY_SIZE
);
283 assert_non_null(lg_entry
);
284 assert_int_equal(3, r
->num_entries
);
286 assert_non_null(imd_entry_add(&imd
, SM_ENTRY_ID
, SM_ENTRY_SIZE
));
287 assert_int_equal(2, ((struct imd_root
*)imd
.sm
.r
)->num_entries
);
289 /* Fail when start_addr is lower than low_limit. */
291 max_offset_copy
= r
->max_offset
;
292 r
->max_offset
= lg_entry
->start_offset
+ sizeof(int32_t);
293 assert_int_equal(-1, imd_recover(&imd
));
294 r
->max_offset
= max_offset_copy
;
296 /* Fail when start_addr is at least imdr->limit. */
297 offset_copy
= lg_entry
->start_offset
;
298 ptr
= (struct imd_entry
*)lg_entry
;
299 ptr
->start_offset
= (void *)imd
.lg
.limit
- (void *)r
;
300 assert_int_equal(-1, imd_recover(&imd
));
301 ptr
->start_offset
= offset_copy
;
303 /* Fail when (start_addr + e->size) is higher than imdr->limit. */
304 size_copy
= lg_entry
->size
;
305 diff
= (void *)imd
.lg
.limit
- ((void *)r
+ lg_entry
->start_offset
);
306 ptr
->size
= diff
+ 1;
307 assert_int_equal(-1, imd_recover(&imd
));
308 ptr
->size
= size_copy
;
310 /* Succeed if small region is not present. */
311 sm_root_entry
= &r
->entries
[1];
312 e_id_copy
= sm_root_entry
->id
;
313 sm_root_entry
->id
= 0;
314 assert_int_equal(0, imd_recover(&imd
));
315 sm_root_entry
->id
= e_id_copy
;
317 assert_int_equal(0, imd_recover(&imd
));
322 static void test_imd_limit_size(void **state
)
325 struct imd imd
= {0};
326 size_t root_size
, max_size
;
328 max_size
= align_up_pow2(sizeof(struct imd_root_pointer
) + sizeof(struct imd_root
)
329 + 3 * sizeof(struct imd_entry
));
331 assert_int_equal(-1, imd_limit_size(&imd
, max_size
));
333 base
= malloc(LIMIT_ALIGN
);
335 fail_msg("Cannot allocate enough memory - fail test");
336 imd_handle_init(&imd
, (void *)(LIMIT_ALIGN
+ (uintptr_t)base
));
338 root_size
= align_up_pow2(sizeof(struct imd_root_pointer
) + sizeof(struct imd_root
)
339 + 2 * sizeof(struct imd_entry
));
340 imd
.lg
.r
= (void *)imd
.lg
.limit
- root_size
;
342 imd_create_empty(&imd
, root_size
, LG_ENTRY_ALIGN
);
343 assert_int_equal(-1, imd_limit_size(&imd
, root_size
- 1));
344 assert_int_equal(0, imd_limit_size(&imd
, max_size
));
346 /* Cannot create such a big entry */
347 assert_null(imd_entry_add(&imd
, LG_ENTRY_ID
, max_size
- root_size
+ 1));
352 static void test_imd_lockdown(void **state
)
354 struct imd imd
= {0};
355 struct imd_root
*r_lg
, *r_sm
;
357 assert_int_equal(-1, imd_lockdown(&imd
));
359 imd
.lg
.r
= malloc(sizeof(struct imd_root
));
360 if (imd
.lg
.r
== NULL
)
361 fail_msg("Cannot allocate enough memory - fail test");
363 r_lg
= (struct imd_root
*)(imd
.lg
.r
);
365 assert_int_equal(0, imd_lockdown(&imd
));
366 assert_true(r_lg
->flags
& IMD_FLAG_LOCKED
);
368 imd
.sm
.r
= malloc(sizeof(struct imd_root
));
369 if (imd
.sm
.r
== NULL
)
370 fail_msg("Cannot allocate enough memory - fail test");
371 r_sm
= (struct imd_root
*)(imd
.sm
.r
);
373 assert_int_equal(0, imd_lockdown(&imd
));
374 assert_true(r_sm
->flags
& IMD_FLAG_LOCKED
);
380 static void test_imd_region_used(void **state
)
382 struct imd imd
= {0};
383 struct imd_entry
*first_entry
, *new_entry
;
389 assert_int_equal(-1, imd_region_used(&imd
, &base
, &size
));
391 imd_base
= malloc(LIMIT_ALIGN
);
392 if (imd_base
== NULL
)
393 fail_msg("Cannot allocate enough memory - fail test");
394 imd_handle_init(&imd
, (void *)(LIMIT_ALIGN
+ (uintptr_t)imd_base
));
396 assert_int_equal(-1, imd_region_used(&imd
, &base
, &size
));
397 assert_int_equal(0, imd_create_empty(&imd
, LG_ROOT_SIZE
, LG_ENTRY_ALIGN
));
398 assert_int_equal(0, imd_region_used(&imd
, &base
, &size
));
400 r
= (struct imd_root
*)imd
.lg
.r
;
401 first_entry
= &r
->entries
[r
->num_entries
- 1];
403 assert_int_equal(r
+ first_entry
->start_offset
, (uintptr_t)base
);
404 assert_int_equal(first_entry
->size
, size
);
406 assert_non_null(imd_entry_add(&imd
, LG_ENTRY_ID
, LG_ENTRY_SIZE
));
407 assert_int_equal(2, r
->num_entries
);
409 assert_int_equal(0, imd_region_used(&imd
, &base
, &size
));
411 new_entry
= &r
->entries
[r
->num_entries
- 1];
413 assert_true((void *)r
+ new_entry
->start_offset
== base
);
414 assert_int_equal(first_entry
->size
+ new_entry
->size
, size
);
419 static void test_imd_entry_add(void **state
)
422 struct imd imd
= {0};
423 size_t entry_size
= 0;
425 ssize_t entry_offset
;
427 struct imd_root
*r
, *sm_r
, *lg_r
;
428 struct imd_entry
*first_entry
, *new_entry
;
429 uint32_t num_entries_copy
;
430 int32_t max_offset_copy
;
432 /* No small region case. */
433 assert_null(imd_entry_add(&imd
, LG_ENTRY_ID
, entry_size
));
435 base
= malloc(LIMIT_ALIGN
);
437 fail_msg("Cannot allocate enough memory - fail test");
439 imd_handle_init(&imd
, (void *)(LIMIT_ALIGN
+ (uintptr_t)base
));
441 assert_int_equal(0, imd_create_empty(&imd
, LG_ROOT_SIZE
, LG_ENTRY_ALIGN
));
443 r
= (struct imd_root
*)imd
.lg
.r
;
444 first_entry
= &r
->entries
[r
->num_entries
- 1];
446 /* Cannot add an entry when root is locked. */
447 r
->flags
= IMD_FLAG_LOCKED
;
448 assert_null(imd_entry_add(&imd
, LG_ENTRY_ID
, entry_size
));
451 /* Fail when the maximum number of entries has been reached. */
452 num_entries_copy
= r
->num_entries
;
453 r
->num_entries
= r
->max_entries
;
454 assert_null(imd_entry_add(&imd
, LG_ENTRY_ID
, entry_size
));
455 r
->num_entries
= num_entries_copy
;
457 /* Fail when entry size is 0 */
458 assert_null(imd_entry_add(&imd
, LG_ENTRY_ID
, 0));
460 /* Fail when entry size (after alignment) overflows imd total size. */
462 max_offset_copy
= r
->max_offset
;
463 r
->max_offset
= -entry_size
;
464 assert_null(imd_entry_add(&imd
, LG_ENTRY_ID
, entry_size
));
465 r
->max_offset
= max_offset_copy
;
467 /* Finally succeed. */
468 entry_size
= 2 * sizeof(int32_t);
469 assert_non_null(imd_entry_add(&imd
, LG_ENTRY_ID
, entry_size
));
470 assert_int_equal(2, r
->num_entries
);
472 new_entry
= &r
->entries
[r
->num_entries
- 1];
473 assert_int_equal(sizeof(struct imd_entry
), (void *)new_entry
- (void *)first_entry
);
475 assert_int_equal(IMD_ENTRY_MAGIC
, new_entry
->magic
);
476 assert_int_equal(LG_ENTRY_ID
, new_entry
->id
);
477 assert_int_equal(entry_size
, new_entry
->size
);
479 used_size
= ALIGN_UP(entry_size
, r
->entry_align
);
480 entry_offset
= first_entry
->start_offset
- used_size
;
481 assert_int_equal(entry_offset
, new_entry
->start_offset
);
483 /* Use small region case. */
484 imd_create_tiered_empty(&imd
, LG_ROOT_SIZE
, LG_ENTRY_ALIGN
, SM_ROOT_SIZE
,
490 /* All five new entries should be added to small allocations */
491 for (i
= 0; i
< 5; i
++) {
492 assert_non_null(imd_entry_add(&imd
, SM_ENTRY_ID
, SM_ENTRY_SIZE
));
493 assert_int_equal(i
+ 2, sm_r
->num_entries
);
494 assert_int_equal(2, lg_r
->num_entries
);
497 /* But next should fall back on large region */
498 assert_non_null(imd_entry_add(&imd
, SM_ENTRY_ID
, SM_ENTRY_SIZE
));
499 assert_int_equal(6, sm_r
->num_entries
);
500 assert_int_equal(3, lg_r
->num_entries
);
503 * Small allocation is created when occupies less than 1/4 of available
504 * small region. Verify this.
506 imd_create_tiered_empty(&imd
, LG_ROOT_SIZE
, LG_ENTRY_ALIGN
, SM_ROOT_SIZE
,
509 assert_non_null(imd_entry_add(&imd
, SM_ENTRY_ID
, -sm_r
->max_offset
/ 4 + 1));
510 assert_int_equal(1, sm_r
->num_entries
);
511 assert_int_equal(3, lg_r
->num_entries
);
513 /* Next two should go into small region */
514 assert_non_null(imd_entry_add(&imd
, SM_ENTRY_ID
, -sm_r
->max_offset
/ 4));
515 assert_int_equal(2, sm_r
->num_entries
);
516 assert_int_equal(3, lg_r
->num_entries
);
519 assert_non_null(imd_entry_add(&imd
, SM_ENTRY_ID
, -sm_r
->max_offset
/ 16 * 3));
520 assert_int_equal(3, sm_r
->num_entries
);
521 assert_int_equal(3, lg_r
->num_entries
);
526 static void test_imd_entry_find(void **state
)
528 struct imd imd
= {0};
531 base
= malloc(LIMIT_ALIGN
);
533 fail_msg("Cannot allocate enough memory - fail test");
534 imd_handle_init(&imd
, (void *)(LIMIT_ALIGN
+ (uintptr_t)base
));
536 assert_int_equal(0, imd_create_tiered_empty(&imd
, LG_ROOT_SIZE
, LG_ENTRY_ALIGN
,
537 SM_ROOT_SIZE
, SM_ENTRY_ALIGN
));
539 assert_non_null(imd_entry_add(&imd
, LG_ENTRY_ID
, LG_ENTRY_SIZE
));
541 assert_non_null(imd_entry_find(&imd
, LG_ENTRY_ID
));
542 assert_non_null(imd_entry_find(&imd
, SMALL_REGION_ID
));
544 /* Try invalid id, should fail */
545 assert_null(imd_entry_find(&imd
, INVALID_REGION_ID
));
550 static void test_imd_entry_find_or_add(void **state
)
552 struct imd imd
= {0};
553 const struct imd_entry
*entry
;
557 base
= malloc(LIMIT_ALIGN
);
559 fail_msg("Cannot allocate enough memory - fail test");
560 imd_handle_init(&imd
, (void *)(LIMIT_ALIGN
+ (uintptr_t)base
));
562 assert_null(imd_entry_find_or_add(&imd
, LG_ENTRY_ID
, LG_ENTRY_SIZE
));
564 assert_int_equal(0, imd_create_empty(&imd
, LG_ROOT_SIZE
, LG_ENTRY_ALIGN
));
565 entry
= imd_entry_find_or_add(&imd
, LG_ENTRY_ID
, LG_ENTRY_SIZE
);
566 assert_non_null(entry
);
568 r
= (struct imd_root
*)imd
.lg
.r
;
570 assert_int_equal(entry
->id
, LG_ENTRY_ID
);
571 assert_int_equal(2, r
->num_entries
);
572 assert_non_null(imd_entry_find_or_add(&imd
, LG_ENTRY_ID
, LG_ENTRY_SIZE
));
573 assert_int_equal(2, r
->num_entries
);
578 static void test_imd_entry_size(void **state
)
580 struct imd_entry entry
= {.size
= LG_ENTRY_SIZE
};
582 assert_int_equal(LG_ENTRY_SIZE
, imd_entry_size(&entry
));
585 assert_int_equal(0, imd_entry_size(&entry
));
588 static void test_imd_entry_at(void **state
)
590 struct imd imd
= {0};
592 struct imd_entry
*e
= NULL
;
593 const struct imd_entry
*entry
;
596 base
= malloc(LIMIT_ALIGN
);
598 fail_msg("Cannot allocate enough memory - fail test");
599 imd_handle_init(&imd
, (void *)(LIMIT_ALIGN
+ (uintptr_t)base
));
601 assert_int_equal(0, imd_create_empty(&imd
, LG_ROOT_SIZE
, LG_ENTRY_ALIGN
));
603 /* Fail when entry is NULL */
604 assert_null(imd_entry_at(&imd
, e
));
606 entry
= imd_entry_add(&imd
, LG_ENTRY_ID
, LG_ENTRY_SIZE
);
607 assert_non_null(entry
);
609 r
= (struct imd_root
*)imd
.lg
.r
;
610 assert_ptr_equal((void *)r
+ entry
->start_offset
, imd_entry_at(&imd
, entry
));
615 static void test_imd_entry_id(void **state
)
617 struct imd_entry entry
= {.id
= LG_ENTRY_ID
};
619 assert_int_equal(LG_ENTRY_ID
, imd_entry_id(&entry
));
622 static void test_imd_entry_remove(void **state
)
625 struct imd imd
= {0};
627 const struct imd_entry
*fst_lg_entry
, *snd_lg_entry
, *fst_sm_entry
;
628 const struct imd_entry
*e
= NULL
;
630 /* Uninitialized handle */
631 assert_int_equal(-1, imd_entry_remove(&imd
, e
));
633 base
= malloc(LIMIT_ALIGN
);
635 fail_msg("Cannot allocate enough memory - fail test");
637 imd_handle_init(&imd
, (void *)(LIMIT_ALIGN
+ (uintptr_t)base
));
639 assert_int_equal(0, imd_create_tiered_empty(&imd
, LG_ROOT_SIZE
, LG_ENTRY_ALIGN
,
640 SM_ROOT_SIZE
, SM_ENTRY_ALIGN
));
643 assert_int_equal(2, r
->num_entries
);
644 fst_lg_entry
= &r
->entries
[0];
645 snd_lg_entry
= &r
->entries
[1];
647 /* Only last entry can be removed */
648 assert_int_equal(-1, imd_entry_remove(&imd
, fst_lg_entry
));
649 r
->flags
= IMD_FLAG_LOCKED
;
650 assert_int_equal(-1, imd_entry_remove(&imd
, snd_lg_entry
));
654 assert_int_equal(1, r
->num_entries
);
655 fst_sm_entry
= &r
->entries
[0];
657 /* Fail trying to remove root entry */
658 assert_int_equal(-1, imd_entry_remove(&imd
, fst_sm_entry
));
659 assert_int_equal(1, r
->num_entries
);
662 assert_int_equal(0, imd_entry_remove(&imd
, snd_lg_entry
));
663 assert_int_equal(1, r
->num_entries
);
665 /* Fail trying to remove root entry */
666 assert_int_equal(-1, imd_entry_remove(&imd
, fst_lg_entry
));
667 assert_int_equal(1, r
->num_entries
);
672 static void test_imd_cursor_init(void **state
)
674 struct imd imd
= {0};
675 struct imd_cursor cursor
;
677 assert_int_equal(-1, imd_cursor_init(NULL
, NULL
));
678 assert_int_equal(-1, imd_cursor_init(NULL
, &cursor
));
679 assert_int_equal(-1, imd_cursor_init(&imd
, NULL
));
680 assert_int_equal(0, imd_cursor_init(&imd
, &cursor
));
682 assert_ptr_equal(cursor
.imdr
[0], &imd
.lg
);
683 assert_ptr_equal(cursor
.imdr
[1], &imd
.sm
);
686 static void test_imd_cursor_next(void **state
)
689 struct imd imd
= {0};
690 struct imd_cursor cursor
;
692 const struct imd_entry
*entry
;
693 struct imd_entry
*fst_lg_entry
, *snd_lg_entry
, *fst_sm_entry
;
694 assert_int_equal(0, imd_cursor_init(&imd
, &cursor
));
696 cursor
.current_imdr
= 3;
697 cursor
.current_entry
= 0;
698 assert_null(imd_cursor_next(&cursor
));
700 cursor
.current_imdr
= 0;
701 assert_null(imd_cursor_next(&cursor
));
703 base
= malloc(LIMIT_ALIGN
);
705 fail_msg("Cannot allocate enough memory - fail test");
706 imd_handle_init(&imd
, (void *)(LIMIT_ALIGN
+ (uintptr_t)base
));
708 assert_int_equal(0, imd_create_tiered_empty(&imd
, LG_ROOT_SIZE
, LG_ENTRY_ALIGN
,
709 SM_ROOT_SIZE
, SM_ENTRY_ALIGN
));
712 entry
= imd_cursor_next(&cursor
);
713 assert_non_null(entry
);
715 fst_lg_entry
= &r
->entries
[0];
716 assert_int_equal(fst_lg_entry
->id
, entry
->id
);
717 assert_ptr_equal(fst_lg_entry
, entry
);
719 entry
= imd_cursor_next(&cursor
);
720 assert_non_null(entry
);
722 snd_lg_entry
= &r
->entries
[1];
723 assert_int_equal(snd_lg_entry
->id
, entry
->id
);
724 assert_ptr_equal(snd_lg_entry
, entry
);
726 entry
= imd_cursor_next(&cursor
);
727 assert_non_null(entry
);
730 fst_sm_entry
= &r
->entries
[0];
731 assert_int_equal(fst_sm_entry
->id
, entry
->id
);
732 assert_ptr_equal(fst_sm_entry
, entry
);
734 entry
= imd_cursor_next(&cursor
);
740 const struct CMUnitTest tests
[] = {
741 cmocka_unit_test(test_imd_handle_init
),
742 cmocka_unit_test(test_imd_handle_init_partial_recovery
),
743 cmocka_unit_test(test_imd_create_empty
),
744 cmocka_unit_test(test_imd_create_tiered_empty
),
745 cmocka_unit_test(test_imd_recover
),
746 cmocka_unit_test(test_imd_limit_size
),
747 cmocka_unit_test(test_imd_lockdown
),
748 cmocka_unit_test(test_imd_region_used
),
749 cmocka_unit_test(test_imd_entry_add
),
750 cmocka_unit_test(test_imd_entry_find
),
751 cmocka_unit_test(test_imd_entry_find_or_add
),
752 cmocka_unit_test(test_imd_entry_size
),
753 cmocka_unit_test(test_imd_entry_at
),
754 cmocka_unit_test(test_imd_entry_id
),
755 cmocka_unit_test(test_imd_entry_remove
),
756 cmocka_unit_test(test_imd_cursor_init
),
757 cmocka_unit_test(test_imd_cursor_next
),
760 return cb_run_group_tests(tests
, NULL
, NULL
);