blob: 6da1ac926c6ff0a6853fff19bdc9e79acb0fd37f [file] [log] [blame]
Jakub Czapigac1e4c5a2021-07-23 13:35:14 +02001/* SPDX-License-Identifier: GPL-2.0-only */
2
3#include <stdlib.h>
4#include <types.h>
5#include <string.h>
6#include <tests/test.h>
7#include <imd.h>
8#include <imd_private.h>
9#include <cbmem.h>
10#include <commonlib/bsd/helpers.h>
11#include <lib.h>
12
13/* Auxiliary functions and definitions. */
14
15#define LG_ROOT_SIZE align_up_pow2(sizeof(struct imd_root_pointer) +\
16 sizeof(struct imd_root) + 3 * sizeof(struct imd_entry))
17#define LG_ENTRY_ALIGN (2 * sizeof(int32_t))
18#define LG_ENTRY_SIZE (2 * sizeof(int32_t))
19#define LG_ENTRY_ID 0xA001
20
21#define SM_ROOT_SIZE LG_ROOT_SIZE
22#define SM_ENTRY_ALIGN sizeof(uint32_t)
23#define SM_ENTRY_SIZE sizeof(uint32_t)
24#define SM_ENTRY_ID 0xB001
25
26#define INVALID_REGION_ID 0xC001
27
28static uint32_t align_up_pow2(uint32_t x)
29{
30 return (1 << log2_ceil(x));
31}
32
33static size_t max_entries(size_t root_size)
34{
35 return (root_size - sizeof(struct imd_root_pointer) - sizeof(struct imd_root))
36 / sizeof(struct imd_entry);
37}
38
39/*
40 * Mainly, we should check that imd_handle_init() aligns upper_limit properly
41 * for various inputs. Upper limit is the _exclusive_ address, so we expect
42 * ALIGN_DOWN.
43 */
44static void test_imd_handle_init(void **state)
45{
46 int i;
47 void *base;
48 struct imd imd;
49 uintptr_t test_inputs[] = {
50 0, /* Lowest possible address */
51 0xA000, /* Fits in 16 bits, should not get rounded down*/
52 0xDEAA, /* Fits in 16 bits */
53 0xB0B0B000, /* Fits in 32 bits, should not get rounded down */
54 0xF0F0F0F0, /* Fits in 32 bits */
55 ((1ULL << 32) + 4), /* Just above 32-bit limit */
56 0x6666777788889000, /* Fits in 64 bits, should not get rounded down */
57 ((1ULL << 60) - 100) /* Very large address, fitting in 64 bits */
58 };
59
60 for (i = 0; i < ARRAY_SIZE(test_inputs); i++) {
61 base = (void *)test_inputs[i];
62
63 imd_handle_init(&imd, (void *)base);
64
65 assert_int_equal(imd.lg.limit % LIMIT_ALIGN, 0);
66 assert_int_equal(imd.lg.limit, ALIGN_DOWN(test_inputs[i], LIMIT_ALIGN));
67 assert_ptr_equal(imd.lg.r, NULL);
68
69 /* Small allocations not initialized */
70 assert_ptr_equal(imd.sm.limit, NULL);
71 assert_ptr_equal(imd.sm.r, NULL);
72 }
73}
74
75static void test_imd_handle_init_partial_recovery(void **state)
76{
77 void *base;
78 struct imd imd = {0};
79 const struct imd_entry *entry;
80
81 imd_handle_init_partial_recovery(&imd);
82 assert_null(imd.lg.limit);
83 assert_null(imd.sm.limit);
84
85 base = malloc(LIMIT_ALIGN);
86 if (base == NULL)
87 fail_msg("Cannot allocate enough memory - fail test");
88
89 imd_handle_init(&imd, (void *)(LIMIT_ALIGN + (uintptr_t)base));
90 imd_handle_init_partial_recovery(&imd);
91
92 assert_non_null(imd.lg.r);
93 assert_null(imd.sm.limit);
94
95 assert_int_equal(0, imd_create_empty(&imd, LG_ROOT_SIZE, LG_ENTRY_ALIGN));
96 entry = imd_entry_add(&imd, SMALL_REGION_ID, LG_ENTRY_SIZE);
97 assert_non_null(entry);
98
99 imd_handle_init_partial_recovery(&imd);
100
101 assert_non_null(imd.lg.r);
102 assert_non_null(imd.sm.limit);
103 assert_ptr_equal(imd.lg.r + entry->start_offset + LG_ENTRY_SIZE, imd.sm.limit);
104 assert_non_null(imd.sm.r);
105
106 free(base);
107}
108
109static void test_imd_create_empty(void **state)
110{
111 struct imd imd = {0};
112 void *base;
113 struct imd_root *r;
114 struct imd_entry *e;
115
116 /* Expect imd_create_empty to fail, since imd handle is not initialized */
117 assert_int_equal(-1, imd_create_empty(&imd, LG_ROOT_SIZE, LG_ENTRY_ALIGN));
118 base = malloc(sizeof(struct imd_root_pointer) + sizeof(struct imd_root));
119 if (base == NULL)
120 fail_msg("Cannot allocate enough memory - fail test");
121
122 imd_handle_init(&imd, (void *)(LIMIT_ALIGN + (uintptr_t)base));
123
124 /* Try incorrect sizes */
125 assert_int_equal(-1, imd_create_empty(&imd,
126 sizeof(struct imd_root_pointer),
127 LG_ENTRY_ALIGN));
128 assert_int_equal(-1, imd_create_empty(&imd, LG_ROOT_SIZE, 2 * LG_ROOT_SIZE));
129
130 /* Working case */
131 assert_int_equal(0, imd_create_empty(&imd, LG_ROOT_SIZE, LG_ENTRY_ALIGN));
132
133 /* Only large allocation initialized with one entry for the root region */
134 r = (struct imd_root *) (imd.lg.r);
135 assert_non_null(r);
136
137 e = &r->entries[r->num_entries - 1];
138
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);
145
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);
150
151 free(base);
152}
153
154static void test_imd_create_tiered_empty(void **state)
155{
156 void *base;
157 size_t sm_region_size, lg_region_wrong_size;
158 struct imd imd = {0};
159 struct imd_root *r;
160 struct imd_entry *fst_lg_entry, *snd_lg_entry, *sm_entry;
161
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));
165
166 base = malloc(LIMIT_ALIGN);
167 if (base == NULL)
168 fail_msg("Cannot allocate enough memory - fail test");
169
170 imd_handle_init(&imd, (void *)(LIMIT_ALIGN + (uintptr_t)base));
171
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)));
175
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(
180 imd_create_tiered_empty(&imd, lg_region_wrong_size, LG_ENTRY_ALIGN,
181 SM_ROOT_SIZE, SM_ENTRY_ALIGN)
182 );
183
184 assert_int_equal(0, imd_create_tiered_empty(&imd, LG_ROOT_SIZE, LG_ENTRY_ALIGN,
185 SM_ROOT_SIZE, SM_ENTRY_ALIGN));
186
187 r = imd.lg.r;
188
189 /* One entry for root_region and one for small allocations */
190 assert_int_equal(2, r->num_entries);
191
192 fst_lg_entry = &r->entries[0];
193 assert_int_equal(IMD_ENTRY_MAGIC, fst_lg_entry->magic);
194 assert_int_equal(0, fst_lg_entry->start_offset);
195 assert_int_equal(LG_ROOT_SIZE, fst_lg_entry->size);
196 assert_int_equal(CBMEM_ID_IMD_ROOT, fst_lg_entry->id);
197
198 /* Calculated like in imd_create_tiered_empty */
199 sm_region_size = max_entries(SM_ROOT_SIZE) * SM_ENTRY_ALIGN;
200 sm_region_size += SM_ROOT_SIZE;
201 sm_region_size = ALIGN_UP(sm_region_size, LG_ENTRY_ALIGN);
202
203 snd_lg_entry = &r->entries[1];
204 assert_int_equal(IMD_ENTRY_MAGIC, snd_lg_entry->magic);
205 assert_int_equal(-sm_region_size, snd_lg_entry->start_offset);
206 assert_int_equal(CBMEM_ID_IMD_SMALL, snd_lg_entry->id);
207
208 assert_int_equal(sm_region_size, snd_lg_entry->size);
209
210 r = imd.sm.r;
211 assert_int_equal(1, r->num_entries);
212
213 sm_entry = &r->entries[0];
214 assert_int_equal(IMD_ENTRY_MAGIC, sm_entry->magic);
215 assert_int_equal(0, sm_entry->start_offset);
216 assert_int_equal(SM_ROOT_SIZE, sm_entry->size);
217 assert_int_equal(CBMEM_ID_IMD_ROOT, sm_entry->id);
218
219 free(base);
220}
221
222/* Tests for imdr_recover. */
223static void test_imd_recover(void **state)
224{
225 int32_t offset_copy, max_offset_copy;
226 uint32_t rp_magic_copy, num_entries_copy;
227 uint32_t e_align_copy, e_magic_copy, e_id_copy;
228 uint32_t size_copy, diff;
229 void *base;
230 struct imd imd = {0};
231 struct imd_root_pointer *rp;
232 struct imd_root *r;
233 struct imd_entry *lg_root_entry, *sm_root_entry, *ptr;
234 const struct imd_entry *lg_entry;
235
236 /* Fail when the limit for lg was not set. */
237 imd.lg.limit = (uintptr_t) NULL;
238 assert_int_equal(-1, imd_recover(&imd));
239
240 /* Set the limit for lg. */
241 base = malloc(LIMIT_ALIGN);
242 if (base == NULL)
243 fail_msg("Cannot allocate enough memory - fail test");
244
245 imd_handle_init(&imd, (void *)(LIMIT_ALIGN + (uintptr_t)base));
246
247 /* Fail when the root pointer is not valid. */
248 rp = (void *)imd.lg.limit - sizeof(struct imd_root_pointer);
249 assert_non_null(rp);
250 assert_int_equal(IMD_ROOT_PTR_MAGIC, rp->magic);
251
252 rp_magic_copy = rp->magic;
253 rp->magic = 0;
254 assert_int_equal(-1, imd_recover(&imd));
255 rp->magic = rp_magic_copy;
256
257 /* Set the root pointer. */
258 assert_int_equal(0, imd_create_tiered_empty(&imd, LG_ROOT_SIZE, LG_ENTRY_ALIGN,
259 SM_ROOT_SIZE, SM_ENTRY_ALIGN));
260 assert_int_equal(2, ((struct imd_root *)imd.lg.r)->num_entries);
261 assert_int_equal(1, ((struct imd_root *)imd.sm.r)->num_entries);
262
263 /* Fail if the number of entries exceeds the maximum number of entries. */
264 r = imd.lg.r;
265 num_entries_copy = r->num_entries;
266 r->num_entries = r->max_entries + 1;
267 assert_int_equal(-1, imd_recover(&imd));
268 r->num_entries = num_entries_copy;
269
270 /* Fail if entry align is not a power of 2. */
271 e_align_copy = r->entry_align;
272 r->entry_align++;
273 assert_int_equal(-1, imd_recover(&imd));
274 r->entry_align = e_align_copy;
275
276 /* Fail when an entry is not valid. */
277 lg_root_entry = &r->entries[0];
278 e_magic_copy = lg_root_entry->magic;
279 lg_root_entry->magic = 0;
280 assert_int_equal(-1, imd_recover(&imd));
281 lg_root_entry->magic = e_magic_copy;
282
283 /* Add new entries: large and small. */
284 lg_entry = imd_entry_add(&imd, LG_ENTRY_ID, LG_ENTRY_SIZE);
285 assert_non_null(lg_entry);
286 assert_int_equal(3, r->num_entries);
287
288 assert_non_null(imd_entry_add(&imd, SM_ENTRY_ID, SM_ENTRY_SIZE));
289 assert_int_equal(2, ((struct imd_root *)imd.sm.r)->num_entries);
290
291 /* Fail when start_addr is lower than low_limit. */
292 r = imd.lg.r;
293 max_offset_copy = r->max_offset;
294 r->max_offset = lg_entry->start_offset + sizeof(int32_t);
295 assert_int_equal(-1, imd_recover(&imd));
296 r->max_offset = max_offset_copy;
297
298 /* Fail when start_addr is at least imdr->limit. */
299 offset_copy = lg_entry->start_offset;
300 ptr = (struct imd_entry *)lg_entry;
301 ptr->start_offset = (void *)imd.lg.limit - (void *)r;
302 assert_int_equal(-1, imd_recover(&imd));
303 ptr->start_offset = offset_copy;
304
305 /* Fail when (start_addr + e->size) is higher than imdr->limit. */
306 size_copy = lg_entry->size;
307 diff = (void *)imd.lg.limit - ((void *)r + lg_entry->start_offset);
308 ptr->size = diff + 1;
309 assert_int_equal(-1, imd_recover(&imd));
310 ptr->size = size_copy;
311
312 /* Succeed if small region is not present. */
313 sm_root_entry = &r->entries[1];
314 e_id_copy = sm_root_entry->id;
315 sm_root_entry->id = 0;
316 assert_int_equal(0, imd_recover(&imd));
317 sm_root_entry->id = e_id_copy;
318
319 assert_int_equal(0, imd_recover(&imd));
320
321 free(base);
322}
323
324static void test_imd_limit_size(void **state)
325{
326 void *base;
327 struct imd imd = {0};
328 size_t root_size, max_size;
329
330 max_size = align_up_pow2(sizeof(struct imd_root_pointer)
331 + sizeof(struct imd_root) + 3 * sizeof(struct imd_entry));
332
333 assert_int_equal(-1, imd_limit_size(&imd, max_size));
334
335 base = malloc(LIMIT_ALIGN);
336 if (base == NULL)
337 fail_msg("Cannot allocate enough memory - fail test");
338 imd_handle_init(&imd, (void *)(LIMIT_ALIGN + (uintptr_t)base));
339
340 root_size = align_up_pow2(sizeof(struct imd_root_pointer)
341 + sizeof(struct imd_root) + 2 * sizeof(struct imd_entry));
342 imd.lg.r = (void *)imd.lg.limit - root_size;
343
344 imd_create_empty(&imd, root_size, LG_ENTRY_ALIGN);
345 assert_int_equal(-1, imd_limit_size(&imd, root_size - 1));
346 assert_int_equal(0, imd_limit_size(&imd, max_size));
347
348 /* Cannot create such a big entry */
349 assert_null(imd_entry_add(&imd, LG_ENTRY_ID, max_size - root_size + 1));
350
351 free(base);
352}
353
354static void test_imd_lockdown(void **state)
355{
356 struct imd imd = {0};
357 struct imd_root *r_lg, *r_sm;
358
359 assert_int_equal(-1, imd_lockdown(&imd));
360
361 imd.lg.r = malloc(sizeof(struct imd_root));
362 if (imd.lg.r == NULL)
363 fail_msg("Cannot allocate enough memory - fail test");
364
365 r_lg = (struct imd_root *) (imd.lg.r);
366
367 assert_int_equal(0, imd_lockdown(&imd));
368 assert_true(r_lg->flags & IMD_FLAG_LOCKED);
369
370 imd.sm.r = malloc(sizeof(struct imd_root));
371 if (imd.sm.r == NULL)
372 fail_msg("Cannot allocate enough memory - fail test");
373 r_sm = (struct imd_root *) (imd.sm.r);
374
375 assert_int_equal(0, imd_lockdown(&imd));
376 assert_true(r_sm->flags & IMD_FLAG_LOCKED);
377
378 free(imd.lg.r);
379 free(imd.sm.r);
380}
381
382static void test_imd_region_used(void **state)
383{
384 struct imd imd = {0};
385 struct imd_entry *first_entry, *new_entry;
386 struct imd_root *r;
387 size_t size;
388 void *imd_base;
389 void *base;
390
391 assert_int_equal(-1, imd_region_used(&imd, &base, &size));
392
393 imd_base = malloc(LIMIT_ALIGN);
394 if (imd_base == NULL)
395 fail_msg("Cannot allocate enough memory - fail test");
396 imd_handle_init(&imd, (void *)(LIMIT_ALIGN + (uintptr_t)imd_base));
397
398 assert_int_equal(-1, imd_region_used(&imd, &base, &size));
399 assert_int_equal(0, imd_create_empty(&imd, LG_ROOT_SIZE, LG_ENTRY_ALIGN));
400 assert_int_equal(0, imd_region_used(&imd, &base, &size));
401
402 r = (struct imd_root *)imd.lg.r;
403 first_entry = &r->entries[r->num_entries - 1];
404
405 assert_int_equal(r + first_entry->start_offset, (uintptr_t)base);
406 assert_int_equal(first_entry->size, size);
407
408 assert_non_null(imd_entry_add(&imd, LG_ENTRY_ID, LG_ENTRY_SIZE));
409 assert_int_equal(2, r->num_entries);
410
411 assert_int_equal(0, imd_region_used(&imd, &base, &size));
412
413 new_entry = &r->entries[r->num_entries - 1];
414
415 assert_true((void *)r + new_entry->start_offset == base);
416 assert_int_equal(first_entry->size + new_entry->size, size);
417
418 free(imd_base);
419}
420
421static void test_imd_entry_add(void **state)
422{
423 int i;
424 struct imd imd = {0};
425 size_t entry_size = 0;
426 size_t used_size;
427 ssize_t entry_offset;
428 void *base;
429 struct imd_root *r, *sm_r, *lg_r;
430 struct imd_entry *first_entry, *new_entry;
431 uint32_t num_entries_copy;
432 int32_t max_offset_copy;
433
434 /* No small region case. */
435 assert_null(imd_entry_add(&imd, LG_ENTRY_ID, entry_size));
436
437 base = malloc(LIMIT_ALIGN);
438 if (base == NULL)
439 fail_msg("Cannot allocate enough memory - fail test");
440
441 imd_handle_init(&imd, (void *)(LIMIT_ALIGN + (uintptr_t)base));
442
443 assert_int_equal(0, imd_create_empty(&imd, LG_ROOT_SIZE, LG_ENTRY_ALIGN));
444
445 r = (struct imd_root *)imd.lg.r;
446 first_entry = &r->entries[r->num_entries - 1];
447
448 /* Cannot add an entry when root is locked. */
449 r->flags = IMD_FLAG_LOCKED;
450 assert_null(imd_entry_add(&imd, LG_ENTRY_ID, entry_size));
451 r->flags = 0;
452
453 /* Fail when the maximum number of entries has been reached. */
454 num_entries_copy = r->num_entries;
455 r->num_entries = r->max_entries;
456 assert_null(imd_entry_add(&imd, LG_ENTRY_ID, entry_size));
457 r->num_entries = num_entries_copy;
458
459 /* Fail when entry size is 0 */
460 assert_null(imd_entry_add(&imd, LG_ENTRY_ID, 0));
461
462 /* Fail when entry size (after alignment) overflows imd total size. */
463 entry_size = 2049;
464 max_offset_copy = r->max_offset;
465 r->max_offset = -entry_size;
466 assert_null(imd_entry_add(&imd, LG_ENTRY_ID, entry_size));
467 r->max_offset = max_offset_copy;
468
469 /* Finally succeed. */
470 entry_size = 2 * sizeof(int32_t);
471 assert_non_null(imd_entry_add(&imd, LG_ENTRY_ID, entry_size));
472 assert_int_equal(2, r->num_entries);
473
474 new_entry = &r->entries[r->num_entries - 1];
475 assert_int_equal(sizeof(struct imd_entry), (void *)new_entry - (void *)first_entry);
476
477 assert_int_equal(IMD_ENTRY_MAGIC, new_entry->magic);
478 assert_int_equal(LG_ENTRY_ID, new_entry->id);
479 assert_int_equal(entry_size, new_entry->size);
480
481 used_size = ALIGN_UP(entry_size, r->entry_align);
482 entry_offset = first_entry->start_offset - used_size;
483 assert_int_equal(entry_offset, new_entry->start_offset);
484
485 /* Use small region case. */
486 imd_create_tiered_empty(&imd, LG_ROOT_SIZE, LG_ENTRY_ALIGN, SM_ROOT_SIZE,
487 SM_ENTRY_ALIGN);
488
489 lg_r = imd.lg.r;
490 sm_r = imd.sm.r;
491
492 /* All five new entries should be added to small allocations */
493 for (i = 0; i < 5; i++) {
494 assert_non_null(imd_entry_add(&imd, SM_ENTRY_ID, SM_ENTRY_SIZE));
495 assert_int_equal(i+2, sm_r->num_entries);
496 assert_int_equal(2, lg_r->num_entries);
497 }
498
499 /* But next should fall back on large region */
500 assert_non_null(imd_entry_add(&imd, SM_ENTRY_ID, SM_ENTRY_SIZE));
501 assert_int_equal(6, sm_r->num_entries);
502 assert_int_equal(3, lg_r->num_entries);
503
504 /*
505 * Small allocation is created when occupies less than 1/4 of available
506 * small region. Verify this.
507 */
508 imd_create_tiered_empty(&imd, LG_ROOT_SIZE, LG_ENTRY_ALIGN, SM_ROOT_SIZE,
509 SM_ENTRY_ALIGN);
510
511 assert_non_null(imd_entry_add(&imd, SM_ENTRY_ID, -sm_r->max_offset / 4 + 1));
512 assert_int_equal(1, sm_r->num_entries);
513 assert_int_equal(3, lg_r->num_entries);
514
515 /* Next two should go into small region */
516 assert_non_null(imd_entry_add(&imd, SM_ENTRY_ID, -sm_r->max_offset / 4));
517 assert_int_equal(2, sm_r->num_entries);
518 assert_int_equal(3, lg_r->num_entries);
519
520 /* (1/4 * 3/4) */
521 assert_non_null(imd_entry_add(&imd, SM_ENTRY_ID, -sm_r->max_offset / 16 * 3));
522 assert_int_equal(3, sm_r->num_entries);
523 assert_int_equal(3, lg_r->num_entries);
524
525 free(base);
526}
527
528static void test_imd_entry_find(void **state)
529{
530 struct imd imd = {0};
531 void *base;
532
533 base = malloc(LIMIT_ALIGN);
534 if (base == NULL)
535 fail_msg("Cannot allocate enough memory - fail test");
536 imd_handle_init(&imd, (void *)(LIMIT_ALIGN + (uintptr_t)base));
537
538 assert_int_equal(0, imd_create_tiered_empty(&imd, LG_ROOT_SIZE, LG_ENTRY_ALIGN,
539 SM_ROOT_SIZE, SM_ENTRY_ALIGN));
540
541 assert_non_null(imd_entry_add(&imd, LG_ENTRY_ID, LG_ENTRY_SIZE));
542
543 assert_non_null(imd_entry_find(&imd, LG_ENTRY_ID));
544 assert_non_null(imd_entry_find(&imd, SMALL_REGION_ID));
545
546 /* Try invalid id, should fail */
547 assert_null(imd_entry_find(&imd, INVALID_REGION_ID));
548
549 free(base);
550}
551
552static void test_imd_entry_find_or_add(void **state)
553{
554 struct imd imd = {0};
555 const struct imd_entry *entry;
556 struct imd_root *r;
557 void *base;
558
559 base = malloc(LIMIT_ALIGN);
560 if (base == NULL)
561 fail_msg("Cannot allocate enough memory - fail test");
562 imd_handle_init(&imd, (void *)(LIMIT_ALIGN + (uintptr_t)base));
563
564 assert_null(imd_entry_find_or_add(&imd, LG_ENTRY_ID, LG_ENTRY_SIZE));
565
566 assert_int_equal(0, imd_create_empty(&imd, LG_ROOT_SIZE, LG_ENTRY_ALIGN));
567 entry = imd_entry_find_or_add(&imd, LG_ENTRY_ID, LG_ENTRY_SIZE);
568 assert_non_null(entry);
569
570 r = (struct imd_root *)imd.lg.r;
571
572 assert_int_equal(entry->id, LG_ENTRY_ID);
573 assert_int_equal(2, r->num_entries);
574 assert_non_null(imd_entry_find_or_add(&imd, LG_ENTRY_ID, LG_ENTRY_SIZE));
575 assert_int_equal(2, r->num_entries);
576
577 free(base);
578}
579
580static void test_imd_entry_size(void **state)
581{
582 struct imd_entry entry = { .size = LG_ENTRY_SIZE };
583
584 assert_int_equal(LG_ENTRY_SIZE, imd_entry_size(&entry));
585
586 entry.size = 0;
587 assert_int_equal(0, imd_entry_size(&entry));
588}
589
590static void test_imd_entry_at(void **state)
591{
592 struct imd imd = {0};
593 struct imd_root *r;
594 struct imd_entry *e = NULL;
595 const struct imd_entry *entry;
596 void *base;
597
598 base = malloc(LIMIT_ALIGN);
599 if (base == NULL)
600 fail_msg("Cannot allocate enough memory - fail test");
601 imd_handle_init(&imd, (void *)(LIMIT_ALIGN + (uintptr_t)base));
602
603 assert_int_equal(0, imd_create_empty(&imd, LG_ROOT_SIZE, LG_ENTRY_ALIGN));
604
605 /* Fail when entry is NULL */
606 assert_null(imd_entry_at(&imd, e));
607
608 entry = imd_entry_add(&imd, LG_ENTRY_ID, LG_ENTRY_SIZE);
609 assert_non_null(entry);
610
611 r = (struct imd_root *)imd.lg.r;
612 assert_ptr_equal((void *)r + entry->start_offset, imd_entry_at(&imd, entry));
613
614 free(base);
615}
616
617static void test_imd_entry_id(void **state)
618{
619 struct imd_entry entry = { .id = LG_ENTRY_ID };
620
621 assert_int_equal(LG_ENTRY_ID, imd_entry_id(&entry));
622}
623
624static void test_imd_entry_remove(void **state)
625{
626 void *base;
627 struct imd imd = {0};
628 struct imd_root *r;
629 const struct imd_entry *fst_lg_entry, *snd_lg_entry, *fst_sm_entry;
630 const struct imd_entry *e = NULL;
631
632 /* Uninitialized handle */
633 assert_int_equal(-1, imd_entry_remove(&imd, e));
634
635 base = malloc(LIMIT_ALIGN);
636 if (base == NULL)
637 fail_msg("Cannot allocate enough memory - fail test");
638
639 imd_handle_init(&imd, (void *)(LIMIT_ALIGN + (uintptr_t)base));
640
641 assert_int_equal(0, imd_create_tiered_empty(&imd, LG_ROOT_SIZE, LG_ENTRY_ALIGN,
642 SM_ROOT_SIZE, SM_ENTRY_ALIGN));
643
644 r = imd.lg.r;
645 assert_int_equal(2, r->num_entries);
646 fst_lg_entry = &r->entries[0];
647 snd_lg_entry = &r->entries[1];
648
649 /* Only last entry can be removed */
650 assert_int_equal(-1, imd_entry_remove(&imd, fst_lg_entry));
651 r->flags = IMD_FLAG_LOCKED;
652 assert_int_equal(-1, imd_entry_remove(&imd, snd_lg_entry));
653 r->flags = 0;
654
655 r = imd.sm.r;
656 assert_int_equal(1, r->num_entries);
657 fst_sm_entry = &r->entries[0];
658
659 /* Fail trying to remove root entry */
660 assert_int_equal(-1, imd_entry_remove(&imd, fst_sm_entry));
661 assert_int_equal(1, r->num_entries);
662
663 r = imd.lg.r;
664 assert_int_equal(0, imd_entry_remove(&imd, snd_lg_entry));
665 assert_int_equal(1, r->num_entries);
666
667 /* Fail trying to remove root entry */
668 assert_int_equal(-1, imd_entry_remove(&imd, fst_lg_entry));
669 assert_int_equal(1, r->num_entries);
670
671 free(base);
672}
673
674static void test_imd_cursor_init(void **state)
675{
676 struct imd imd = {0};
677 struct imd_cursor cursor;
678
679 assert_int_equal(-1, imd_cursor_init(NULL, NULL));
680 assert_int_equal(-1, imd_cursor_init(NULL, &cursor));
681 assert_int_equal(-1, imd_cursor_init(&imd, NULL));
682 assert_int_equal(0, imd_cursor_init(&imd, &cursor));
683
684 assert_ptr_equal(cursor.imdr[0], &imd.lg);
685 assert_ptr_equal(cursor.imdr[1], &imd.sm);
686}
687
688static void test_imd_cursor_next(void **state)
689{
690 void *base;
691 struct imd imd = {0};
692 struct imd_cursor cursor;
693 struct imd_root *r;
694 const struct imd_entry *entry;
695 struct imd_entry *fst_lg_entry, *snd_lg_entry, *fst_sm_entry;
696 assert_int_equal(0, imd_cursor_init(&imd, &cursor));
697
698 cursor.current_imdr = 3;
699 cursor.current_entry = 0;
700 assert_null(imd_cursor_next(&cursor));
701
702 cursor.current_imdr = 0;
703 assert_null(imd_cursor_next(&cursor));
704
705 base = malloc(LIMIT_ALIGN);
706 if (base == NULL)
707 fail_msg("Cannot allocate enough memory - fail test");
708 imd_handle_init(&imd, (void *)(LIMIT_ALIGN + (uintptr_t)base));
709
710 assert_int_equal(0, imd_create_tiered_empty(&imd, LG_ROOT_SIZE, LG_ENTRY_ALIGN,
711 SM_ROOT_SIZE, SM_ENTRY_ALIGN));
712
713 r = imd.lg.r;
714 entry = imd_cursor_next(&cursor);
715 assert_non_null(entry);
716
717 fst_lg_entry = &r->entries[0];
718 assert_int_equal(fst_lg_entry->id, entry->id);
719 assert_ptr_equal(fst_lg_entry, entry);
720
721 entry = imd_cursor_next(&cursor);
722 assert_non_null(entry);
723
724 snd_lg_entry = &r->entries[1];
725 assert_int_equal(snd_lg_entry->id, entry->id);
726 assert_ptr_equal(snd_lg_entry, entry);
727
728 entry = imd_cursor_next(&cursor);
729 assert_non_null(entry);
730
731 r = imd.sm.r;
732 fst_sm_entry = &r->entries[0];
733 assert_int_equal(fst_sm_entry->id, entry->id);
734 assert_ptr_equal(fst_sm_entry, entry);
735
736 entry = imd_cursor_next(&cursor);
737 assert_null(entry);
738}
739
740int main(void)
741{
742 const struct CMUnitTest tests[] = {
743 cmocka_unit_test(test_imd_handle_init),
744 cmocka_unit_test(test_imd_handle_init_partial_recovery),
745 cmocka_unit_test(test_imd_create_empty),
746 cmocka_unit_test(test_imd_create_tiered_empty),
747 cmocka_unit_test(test_imd_recover),
748 cmocka_unit_test(test_imd_limit_size),
749 cmocka_unit_test(test_imd_lockdown),
750 cmocka_unit_test(test_imd_region_used),
751 cmocka_unit_test(test_imd_entry_add),
752 cmocka_unit_test(test_imd_entry_find),
753 cmocka_unit_test(test_imd_entry_find_or_add),
754 cmocka_unit_test(test_imd_entry_size),
755 cmocka_unit_test(test_imd_entry_at),
756 cmocka_unit_test(test_imd_entry_id),
757 cmocka_unit_test(test_imd_entry_remove),
758 cmocka_unit_test(test_imd_cursor_init),
759 cmocka_unit_test(test_imd_cursor_next),
760 };
761
762 return cb_run_group_tests(tests, NULL, NULL);
763}
764