1 /*
2 * Copyright (c) 2016-2018, Intel Corporation
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * * Redistributions of source code must retain the above copyright notice,
8 * this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright notice,
10 * this list of conditions and the following disclaimer in the documentation
11 * and/or other materials provided with the distribution.
12 * * Neither the name of Intel Corporation nor the names of its contributors
13 * may be used to endorse or promote products derived from this software
14 * without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #include "pt_image_section_cache.h"
30
31 #include "ptunit_threads.h"
32
33 #include "intel-pt.h"
34
35 #include <stdlib.h>
36
37
38 struct pt_section {
39 /* The filename. We only support string literals for testing. */
40 const char *filename;
41
42 /* The file offset and size. */
43 uint64_t offset;
44 uint64_t size;
45
46 /* The bcache size. */
47 uint64_t bcsize;
48
49 /* The iscache back link. */
50 struct pt_image_section_cache *iscache;
51
52 /* The file content. */
53 uint8_t content[0x10];
54
55 /* The use count. */
56 int ucount;
57
58 /* The attach count. */
59 int acount;
60
61 /* The map count. */
62 int mcount;
63
64 #if defined(FEATURE_THREADS)
65 /* A lock protecting this section. */
66 mtx_t lock;
67 /* A lock protecting the iscache and acount fields. */
68 mtx_t alock;
69 #endif /* defined(FEATURE_THREADS) */
70 };
71
72 extern struct pt_section *pt_mk_section(const char *filename, uint64_t offset,
73 uint64_t size);
74
75 extern int pt_section_get(struct pt_section *section);
76 extern int pt_section_put(struct pt_section *section);
77 extern int pt_section_attach(struct pt_section *section,
78 struct pt_image_section_cache *iscache);
79 extern int pt_section_detach(struct pt_section *section,
80 struct pt_image_section_cache *iscache);
81
82 extern int pt_section_map(struct pt_section *section);
83 extern int pt_section_map_share(struct pt_section *section);
84 extern int pt_section_unmap(struct pt_section *section);
85 extern int pt_section_request_bcache(struct pt_section *section);
86
87 extern const char *pt_section_filename(const struct pt_section *section);
88 extern uint64_t pt_section_offset(const struct pt_section *section);
89 extern uint64_t pt_section_size(const struct pt_section *section);
90 extern int pt_section_memsize(struct pt_section *section, uint64_t *size);
91
92 extern int pt_section_read(const struct pt_section *section, uint8_t *buffer,
93 uint16_t size, uint64_t offset);
94
95
pt_mk_section(const char * filename,uint64_t offset,uint64_t size)96 struct pt_section *pt_mk_section(const char *filename, uint64_t offset,
97 uint64_t size)
98 {
99 struct pt_section *section;
100
101 section = malloc(sizeof(*section));
102 if (section) {
103 uint8_t idx;
104
105 memset(section, 0, sizeof(*section));
106 section->filename = filename;
107 section->offset = offset;
108 section->size = size;
109 section->ucount = 1;
110
111 for (idx = 0; idx < sizeof(section->content); ++idx)
112 section->content[idx] = idx;
113
114 #if defined(FEATURE_THREADS)
115 {
116 int errcode;
117
118 errcode = mtx_init(§ion->lock, mtx_plain);
119 if (errcode != thrd_success) {
120 free(section);
121 section = NULL;
122 }
123
124 errcode = mtx_init(§ion->alock, mtx_plain);
125 if (errcode != thrd_success) {
126 mtx_destroy(§ion->lock);
127 free(section);
128 section = NULL;
129 }
130 }
131 #endif /* defined(FEATURE_THREADS) */
132 }
133
134 return section;
135 }
136
pt_section_lock(struct pt_section * section)137 static int pt_section_lock(struct pt_section *section)
138 {
139 if (!section)
140 return -pte_internal;
141
142 #if defined(FEATURE_THREADS)
143 {
144 int errcode;
145
146 errcode = mtx_lock(§ion->lock);
147 if (errcode != thrd_success)
148 return -pte_bad_lock;
149 }
150 #endif /* defined(FEATURE_THREADS) */
151
152 return 0;
153 }
154
pt_section_unlock(struct pt_section * section)155 static int pt_section_unlock(struct pt_section *section)
156 {
157 if (!section)
158 return -pte_internal;
159
160 #if defined(FEATURE_THREADS)
161 {
162 int errcode;
163
164 errcode = mtx_unlock(§ion->lock);
165 if (errcode != thrd_success)
166 return -pte_bad_lock;
167 }
168 #endif /* defined(FEATURE_THREADS) */
169
170 return 0;
171 }
172
pt_section_lock_attach(struct pt_section * section)173 static int pt_section_lock_attach(struct pt_section *section)
174 {
175 if (!section)
176 return -pte_internal;
177
178 #if defined(FEATURE_THREADS)
179 {
180 int errcode;
181
182 errcode = mtx_lock(§ion->alock);
183 if (errcode != thrd_success)
184 return -pte_bad_lock;
185 }
186 #endif /* defined(FEATURE_THREADS) */
187
188 return 0;
189 }
190
pt_section_unlock_attach(struct pt_section * section)191 static int pt_section_unlock_attach(struct pt_section *section)
192 {
193 if (!section)
194 return -pte_internal;
195
196 #if defined(FEATURE_THREADS)
197 {
198 int errcode;
199
200 errcode = mtx_unlock(§ion->alock);
201 if (errcode != thrd_success)
202 return -pte_bad_lock;
203 }
204 #endif /* defined(FEATURE_THREADS) */
205
206 return 0;
207 }
208
pt_section_get(struct pt_section * section)209 int pt_section_get(struct pt_section *section)
210 {
211 int errcode, ucount;
212
213 if (!section)
214 return -pte_internal;
215
216 errcode = pt_section_lock(section);
217 if (errcode < 0)
218 return errcode;
219
220 ucount = ++section->ucount;
221
222 errcode = pt_section_unlock(section);
223 if (errcode < 0)
224 return errcode;
225
226 if (!ucount)
227 return -pte_internal;
228
229 return 0;
230 }
231
pt_section_put(struct pt_section * section)232 int pt_section_put(struct pt_section *section)
233 {
234 int errcode, ucount;
235
236 if (!section)
237 return -pte_internal;
238
239 errcode = pt_section_lock(section);
240 if (errcode < 0)
241 return errcode;
242
243 ucount = --section->ucount;
244
245 errcode = pt_section_unlock(section);
246 if (errcode < 0)
247 return errcode;
248
249 if (!ucount) {
250 #if defined(FEATURE_THREADS)
251 mtx_destroy(§ion->alock);
252 mtx_destroy(§ion->lock);
253 #endif /* defined(FEATURE_THREADS) */
254 free(section);
255 }
256
257 return 0;
258 }
259
pt_section_attach(struct pt_section * section,struct pt_image_section_cache * iscache)260 int pt_section_attach(struct pt_section *section,
261 struct pt_image_section_cache *iscache)
262 {
263 int errcode, ucount, acount;
264
265 if (!section || !iscache)
266 return -pte_internal;
267
268 errcode = pt_section_lock_attach(section);
269 if (errcode < 0)
270 return errcode;
271
272 ucount = section->ucount;
273 acount = section->acount;
274 if (!acount) {
275 if (section->iscache || !ucount)
276 goto out_unlock;
277
278 section->iscache = iscache;
279 section->acount = 1;
280
281 return pt_section_unlock_attach(section);
282 }
283
284 acount += 1;
285 if (!acount) {
286 (void) pt_section_unlock_attach(section);
287 return -pte_overflow;
288 }
289
290 if (ucount < acount)
291 goto out_unlock;
292
293 if (section->iscache != iscache)
294 goto out_unlock;
295
296 section->acount = acount;
297
298 return pt_section_unlock_attach(section);
299
300 out_unlock:
301 (void) pt_section_unlock_attach(section);
302 return -pte_internal;
303 }
304
pt_section_detach(struct pt_section * section,struct pt_image_section_cache * iscache)305 int pt_section_detach(struct pt_section *section,
306 struct pt_image_section_cache *iscache)
307 {
308 int errcode, ucount, acount;
309
310 if (!section || !iscache)
311 return -pte_internal;
312
313 errcode = pt_section_lock_attach(section);
314 if (errcode < 0)
315 return errcode;
316
317 if (section->iscache != iscache)
318 goto out_unlock;
319
320 acount = section->acount;
321 if (!acount)
322 goto out_unlock;
323
324 acount -= 1;
325 ucount = section->ucount;
326 if (ucount < acount)
327 goto out_unlock;
328
329 section->acount = acount;
330 if (!acount)
331 section->iscache = NULL;
332
333 return pt_section_unlock_attach(section);
334
335 out_unlock:
336 (void) pt_section_unlock_attach(section);
337 return -pte_internal;
338 }
339
pt_section_map(struct pt_section * section)340 int pt_section_map(struct pt_section *section)
341 {
342 struct pt_image_section_cache *iscache;
343 int errcode, status;
344
345 if (!section)
346 return -pte_internal;
347
348 errcode = pt_section_map_share(section);
349 if (errcode < 0)
350 return errcode;
351
352 errcode = pt_section_lock_attach(section);
353 if (errcode < 0)
354 return errcode;
355
356 status = 0;
357 iscache = section->iscache;
358 if (iscache)
359 status = pt_iscache_notify_map(iscache, section);
360
361 errcode = pt_section_unlock_attach(section);
362
363 return (status < 0) ? status : errcode;
364 }
365
pt_section_map_share(struct pt_section * section)366 int pt_section_map_share(struct pt_section *section)
367 {
368 int errcode, mcount;
369
370 if (!section)
371 return -pte_internal;
372
373 errcode = pt_section_lock(section);
374 if (errcode < 0)
375 return errcode;
376
377 mcount = ++section->mcount;
378
379 errcode = pt_section_unlock(section);
380 if (errcode < 0)
381 return errcode;
382
383 if (mcount <= 0)
384 return -pte_internal;
385
386 return 0;
387 }
388
pt_section_unmap(struct pt_section * section)389 int pt_section_unmap(struct pt_section *section)
390 {
391 int errcode, mcount;
392
393 if (!section)
394 return -pte_internal;
395
396 errcode = pt_section_lock(section);
397 if (errcode < 0)
398 return errcode;
399
400 section->bcsize = 0ull;
401 mcount = --section->mcount;
402
403 errcode = pt_section_unlock(section);
404 if (errcode < 0)
405 return errcode;
406
407 if (mcount < 0)
408 return -pte_internal;
409
410 return 0;
411 }
412
pt_section_request_bcache(struct pt_section * section)413 int pt_section_request_bcache(struct pt_section *section)
414 {
415 struct pt_image_section_cache *iscache;
416 uint64_t memsize;
417 int errcode;
418
419 if (!section)
420 return -pte_internal;
421
422 errcode = pt_section_lock_attach(section);
423 if (errcode < 0)
424 return errcode;
425
426 errcode = pt_section_lock(section);
427 if (errcode < 0)
428 goto out_alock;
429
430 if (section->bcsize)
431 goto out_lock;
432
433 section->bcsize = section->size * 3;
434 memsize = section->size + section->bcsize;
435
436 errcode = pt_section_unlock(section);
437 if (errcode < 0)
438 goto out_alock;
439
440 iscache = section->iscache;
441 if (iscache) {
442 errcode = pt_iscache_notify_resize(iscache, section, memsize);
443 if (errcode < 0)
444 goto out_alock;
445 }
446
447 return pt_section_unlock_attach(section);
448
449
450 out_lock:
451 (void) pt_section_unlock(section);
452
453 out_alock:
454 (void) pt_section_unlock_attach(section);
455 return errcode;
456 }
457
pt_section_filename(const struct pt_section * section)458 const char *pt_section_filename(const struct pt_section *section)
459 {
460 if (!section)
461 return NULL;
462
463 return section->filename;
464 }
465
pt_section_offset(const struct pt_section * section)466 uint64_t pt_section_offset(const struct pt_section *section)
467 {
468 if (!section)
469 return 0ull;
470
471 return section->offset;
472 }
473
pt_section_size(const struct pt_section * section)474 uint64_t pt_section_size(const struct pt_section *section)
475 {
476 if (!section)
477 return 0ull;
478
479 return section->size;
480 }
481
pt_section_memsize(struct pt_section * section,uint64_t * size)482 int pt_section_memsize(struct pt_section *section, uint64_t *size)
483 {
484 if (!section || !size)
485 return -pte_internal;
486
487 *size = section->mcount ? section->size + section->bcsize : 0ull;
488
489 return 0;
490 }
491
pt_section_read(const struct pt_section * section,uint8_t * buffer,uint16_t size,uint64_t offset)492 int pt_section_read(const struct pt_section *section, uint8_t *buffer,
493 uint16_t size, uint64_t offset)
494 {
495 uint64_t begin, end, max;
496
497 if (!section || !buffer)
498 return -pte_internal;
499
500 begin = offset;
501 end = begin + size;
502 max = sizeof(section->content);
503
504 if (max <= begin)
505 return -pte_nomap;
506
507 if (max < end)
508 end = max;
509
510 if (end <= begin)
511 return -pte_invalid;
512
513 memcpy(buffer, §ion->content[begin], (size_t) (end - begin));
514 return (int) (end - begin);
515 }
516
517 enum {
518 /* The number of test sections. */
519 num_sections = 8,
520
521 #if defined(FEATURE_THREADS)
522
523 num_threads = 8,
524
525 #endif /* defined(FEATURE_THREADS) */
526
527 num_iterations = 0x1000
528 };
529
530 struct iscache_fixture {
531 /* Threading support. */
532 struct ptunit_thrd_fixture thrd;
533
534 /* The image section cache under test. */
535 struct pt_image_section_cache iscache;
536
537 /* A bunch of test sections. */
538 struct pt_section *section[num_sections];
539
540 /* The test fixture initialization and finalization functions. */
541 struct ptunit_result (*init)(struct iscache_fixture *);
542 struct ptunit_result (*fini)(struct iscache_fixture *);
543 };
544
dfix_init(struct iscache_fixture * cfix)545 static struct ptunit_result dfix_init(struct iscache_fixture *cfix)
546 {
547 int idx;
548
549 ptu_test(ptunit_thrd_init, &cfix->thrd);
550
551 memset(cfix->section, 0, sizeof(cfix->section));
552
553 for (idx = 0; idx < num_sections; ++idx) {
554 struct pt_section *section;
555
556 section = pt_mk_section("some-filename",
557 idx % 3 == 0 ? 0x1000 : 0x2000,
558 idx % 2 == 0 ? 0x1000 : 0x2000);
559 ptu_ptr(section);
560
561 cfix->section[idx] = section;
562 }
563
564 return ptu_passed();
565 }
566
cfix_init(struct iscache_fixture * cfix)567 static struct ptunit_result cfix_init(struct iscache_fixture *cfix)
568 {
569 int errcode;
570
571 ptu_test(dfix_init, cfix);
572
573 errcode = pt_iscache_init(&cfix->iscache, NULL);
574 ptu_int_eq(errcode, 0);
575
576 return ptu_passed();
577 }
578
sfix_init(struct iscache_fixture * cfix)579 static struct ptunit_result sfix_init(struct iscache_fixture *cfix)
580 {
581 int status, idx;
582
583 ptu_test(cfix_init, cfix);
584
585 cfix->iscache.limit = 0x7800;
586
587 for (idx = 0; idx < num_sections; ++idx) {
588 status = pt_iscache_add(&cfix->iscache, cfix->section[idx],
589 0ull);
590 ptu_int_ge(status, 0);
591 }
592
593 return ptu_passed();
594 }
595
cfix_fini(struct iscache_fixture * cfix)596 static struct ptunit_result cfix_fini(struct iscache_fixture *cfix)
597 {
598 int idx, errcode;
599
600 ptu_test(ptunit_thrd_fini, &cfix->thrd);
601
602 for (idx = 0; idx < cfix->thrd.nthreads; ++idx)
603 ptu_int_eq(cfix->thrd.result[idx], 0);
604
605 pt_iscache_fini(&cfix->iscache);
606
607 for (idx = 0; idx < num_sections; ++idx) {
608 ptu_int_eq(cfix->section[idx]->ucount, 1);
609 ptu_int_eq(cfix->section[idx]->acount, 0);
610 ptu_int_eq(cfix->section[idx]->mcount, 0);
611 ptu_null(cfix->section[idx]->iscache);
612
613 errcode = pt_section_put(cfix->section[idx]);
614 ptu_int_eq(errcode, 0);
615 }
616
617 return ptu_passed();
618 }
619
620
init_null(void)621 static struct ptunit_result init_null(void)
622 {
623 int errcode;
624
625 errcode = pt_iscache_init(NULL, NULL);
626 ptu_int_eq(errcode, -pte_internal);
627
628 return ptu_passed();
629 }
630
fini_null(void)631 static struct ptunit_result fini_null(void)
632 {
633 pt_iscache_fini(NULL);
634
635 return ptu_passed();
636 }
637
name_null(void)638 static struct ptunit_result name_null(void)
639 {
640 const char *name;
641
642 name = pt_iscache_name(NULL);
643 ptu_null(name);
644
645 return ptu_passed();
646 }
647
add_null(void)648 static struct ptunit_result add_null(void)
649 {
650 struct pt_image_section_cache iscache;
651 struct pt_section section;
652 int errcode;
653
654 errcode = pt_iscache_add(NULL, §ion, 0ull);
655 ptu_int_eq(errcode, -pte_internal);
656
657 errcode = pt_iscache_add(&iscache, NULL, 0ull);
658 ptu_int_eq(errcode, -pte_internal);
659
660 return ptu_passed();
661 }
662
find_null(void)663 static struct ptunit_result find_null(void)
664 {
665 int errcode;
666
667 errcode = pt_iscache_find(NULL, "filename", 0ull, 0ull, 0ull);
668 ptu_int_eq(errcode, -pte_internal);
669
670 return ptu_passed();
671 }
672
lookup_null(void)673 static struct ptunit_result lookup_null(void)
674 {
675 struct pt_image_section_cache iscache;
676 struct pt_section *section;
677 uint64_t laddr;
678 int errcode;
679
680 errcode = pt_iscache_lookup(NULL, §ion, &laddr, 0);
681 ptu_int_eq(errcode, -pte_internal);
682
683 errcode = pt_iscache_lookup(&iscache, NULL, &laddr, 0);
684 ptu_int_eq(errcode, -pte_internal);
685
686 errcode = pt_iscache_lookup(&iscache, §ion, NULL, 0);
687 ptu_int_eq(errcode, -pte_internal);
688
689 return ptu_passed();
690 }
691
clear_null(void)692 static struct ptunit_result clear_null(void)
693 {
694 int errcode;
695
696 errcode = pt_iscache_clear(NULL);
697 ptu_int_eq(errcode, -pte_internal);
698
699 return ptu_passed();
700 }
701
free_null(void)702 static struct ptunit_result free_null(void)
703 {
704 pt_iscache_free(NULL);
705
706 return ptu_passed();
707 }
708
add_file_null(void)709 static struct ptunit_result add_file_null(void)
710 {
711 struct pt_image_section_cache iscache;
712 int errcode;
713
714 errcode = pt_iscache_add_file(NULL, "filename", 0ull, 0ull, 0ull);
715 ptu_int_eq(errcode, -pte_invalid);
716
717 errcode = pt_iscache_add_file(&iscache, NULL, 0ull, 0ull, 0ull);
718 ptu_int_eq(errcode, -pte_invalid);
719
720 return ptu_passed();
721 }
722
read_null(void)723 static struct ptunit_result read_null(void)
724 {
725 struct pt_image_section_cache iscache;
726 uint8_t buffer;
727 int errcode;
728
729 errcode = pt_iscache_read(NULL, &buffer, sizeof(buffer), 1ull, 0ull);
730 ptu_int_eq(errcode, -pte_invalid);
731
732 errcode = pt_iscache_read(&iscache, NULL, sizeof(buffer), 1ull, 0ull);
733 ptu_int_eq(errcode, -pte_invalid);
734
735 errcode = pt_iscache_read(&iscache, &buffer, 0ull, 1, 0ull);
736 ptu_int_eq(errcode, -pte_invalid);
737
738 return ptu_passed();
739 }
740
init_fini(struct iscache_fixture * cfix)741 static struct ptunit_result init_fini(struct iscache_fixture *cfix)
742 {
743 (void) cfix;
744
745 /* The actual init and fini calls are in cfix_init() and cfix_fini(). */
746 return ptu_passed();
747 }
748
name(struct iscache_fixture * cfix)749 static struct ptunit_result name(struct iscache_fixture *cfix)
750 {
751 const char *name;
752
753 pt_iscache_init(&cfix->iscache, "iscache-name");
754
755 name = pt_iscache_name(&cfix->iscache);
756 ptu_str_eq(name, "iscache-name");
757
758 return ptu_passed();
759 }
760
name_none(struct iscache_fixture * cfix)761 static struct ptunit_result name_none(struct iscache_fixture *cfix)
762 {
763 const char *name;
764
765 pt_iscache_init(&cfix->iscache, NULL);
766
767 name = pt_iscache_name(&cfix->iscache);
768 ptu_null(name);
769
770 return ptu_passed();
771 }
772
add(struct iscache_fixture * cfix)773 static struct ptunit_result add(struct iscache_fixture *cfix)
774 {
775 int isid;
776
777 isid = pt_iscache_add(&cfix->iscache, cfix->section[0], 0ull);
778 ptu_int_gt(isid, 0);
779
780 /* The cache attaches and gets a reference on success. */
781 ptu_int_eq(cfix->section[0]->ucount, 2);
782 ptu_int_eq(cfix->section[0]->acount, 1);
783
784 /* The added section must be implicitly put in pt_iscache_fini. */
785 return ptu_passed();
786 }
787
add_no_name(struct iscache_fixture * cfix)788 static struct ptunit_result add_no_name(struct iscache_fixture *cfix)
789 {
790 struct pt_section section;
791 int errcode;
792
793 memset(§ion, 0, sizeof(section));
794
795 errcode = pt_iscache_add(&cfix->iscache, §ion, 0ull);
796 ptu_int_eq(errcode, -pte_internal);
797
798 return ptu_passed();
799 }
800
add_file(struct iscache_fixture * cfix)801 static struct ptunit_result add_file(struct iscache_fixture *cfix)
802 {
803 int isid;
804
805 isid = pt_iscache_add_file(&cfix->iscache, "name", 0ull, 1ull, 0ull);
806 ptu_int_gt(isid, 0);
807
808 return ptu_passed();
809 }
810
find(struct iscache_fixture * cfix)811 static struct ptunit_result find(struct iscache_fixture *cfix)
812 {
813 struct pt_section *section;
814 int found, isid;
815
816 section = cfix->section[0];
817 ptu_ptr(section);
818
819 isid = pt_iscache_add(&cfix->iscache, section, 0ull);
820 ptu_int_gt(isid, 0);
821
822 found = pt_iscache_find(&cfix->iscache, section->filename,
823 section->offset, section->size, 0ull);
824 ptu_int_eq(found, isid);
825
826 return ptu_passed();
827 }
828
find_empty(struct iscache_fixture * cfix)829 static struct ptunit_result find_empty(struct iscache_fixture *cfix)
830 {
831 struct pt_section *section;
832 int found;
833
834 section = cfix->section[0];
835 ptu_ptr(section);
836
837 found = pt_iscache_find(&cfix->iscache, section->filename,
838 section->offset, section->size, 0ull);
839 ptu_int_eq(found, 0);
840
841 return ptu_passed();
842 }
843
find_bad_filename(struct iscache_fixture * cfix)844 static struct ptunit_result find_bad_filename(struct iscache_fixture *cfix)
845 {
846 struct pt_section *section;
847 int found, isid;
848
849 section = cfix->section[0];
850 ptu_ptr(section);
851
852 isid = pt_iscache_add(&cfix->iscache, section, 0ull);
853 ptu_int_gt(isid, 0);
854
855 found = pt_iscache_find(&cfix->iscache, "bad-filename",
856 section->offset, section->size, 0ull);
857 ptu_int_eq(found, 0);
858
859 return ptu_passed();
860 }
861
find_null_filename(struct iscache_fixture * cfix)862 static struct ptunit_result find_null_filename(struct iscache_fixture *cfix)
863 {
864 int errcode;
865
866 errcode = pt_iscache_find(&cfix->iscache, NULL, 0ull, 0ull, 0ull);
867 ptu_int_eq(errcode, -pte_internal);
868
869 return ptu_passed();
870 }
871
find_bad_offset(struct iscache_fixture * cfix)872 static struct ptunit_result find_bad_offset(struct iscache_fixture *cfix)
873 {
874 struct pt_section *section;
875 int found, isid;
876
877 section = cfix->section[0];
878 ptu_ptr(section);
879
880 isid = pt_iscache_add(&cfix->iscache, section, 0ull);
881 ptu_int_gt(isid, 0);
882
883 found = pt_iscache_find(&cfix->iscache, section->filename, 0ull,
884 section->size, 0ull);
885 ptu_int_eq(found, 0);
886
887 return ptu_passed();
888 }
889
find_bad_size(struct iscache_fixture * cfix)890 static struct ptunit_result find_bad_size(struct iscache_fixture *cfix)
891 {
892 struct pt_section *section;
893 int found, isid;
894
895 section = cfix->section[0];
896 ptu_ptr(section);
897
898 isid = pt_iscache_add(&cfix->iscache, section, 0ull);
899 ptu_int_gt(isid, 0);
900
901 found = pt_iscache_find(&cfix->iscache, section->filename,
902 section->offset, 0ull, 0ull);
903 ptu_int_eq(found, 0);
904
905 return ptu_passed();
906 }
907
find_bad_laddr(struct iscache_fixture * cfix)908 static struct ptunit_result find_bad_laddr(struct iscache_fixture *cfix)
909 {
910 struct pt_section *section;
911 int found, isid;
912
913 section = cfix->section[0];
914 ptu_ptr(section);
915
916 isid = pt_iscache_add(&cfix->iscache, section, 0ull);
917 ptu_int_gt(isid, 0);
918
919 found = pt_iscache_find(&cfix->iscache, section->filename,
920 section->offset, section->size, 1ull);
921 ptu_int_eq(found, 0);
922
923 return ptu_passed();
924 }
925
lookup(struct iscache_fixture * cfix)926 static struct ptunit_result lookup(struct iscache_fixture *cfix)
927 {
928 struct pt_section *section;
929 uint64_t laddr;
930 int errcode, isid;
931
932 isid = pt_iscache_add(&cfix->iscache, cfix->section[0], 0ull);
933 ptu_int_gt(isid, 0);
934
935 errcode = pt_iscache_lookup(&cfix->iscache, §ion, &laddr, isid);
936 ptu_int_eq(errcode, 0);
937 ptu_ptr_eq(section, cfix->section[0]);
938 ptu_uint_eq(laddr, 0ull);
939
940 errcode = pt_section_put(section);
941 ptu_int_eq(errcode, 0);
942
943 return ptu_passed();
944 }
945
lookup_bad_isid(struct iscache_fixture * cfix)946 static struct ptunit_result lookup_bad_isid(struct iscache_fixture *cfix)
947 {
948 struct pt_section *section;
949 uint64_t laddr;
950 int errcode, isid;
951
952 isid = pt_iscache_add(&cfix->iscache, cfix->section[0], 0ull);
953 ptu_int_gt(isid, 0);
954
955 errcode = pt_iscache_lookup(&cfix->iscache, §ion, &laddr, 0);
956 ptu_int_eq(errcode, -pte_bad_image);
957
958 errcode = pt_iscache_lookup(&cfix->iscache, §ion, &laddr, -isid);
959 ptu_int_eq(errcode, -pte_bad_image);
960
961 errcode = pt_iscache_lookup(&cfix->iscache, §ion, &laddr, isid + 1);
962 ptu_int_eq(errcode, -pte_bad_image);
963
964 return ptu_passed();
965 }
966
clear_empty(struct iscache_fixture * cfix)967 static struct ptunit_result clear_empty(struct iscache_fixture *cfix)
968 {
969 int errcode;
970
971 errcode = pt_iscache_clear(&cfix->iscache);
972 ptu_int_eq(errcode, 0);
973
974 return ptu_passed();
975 }
976
clear_find(struct iscache_fixture * cfix)977 static struct ptunit_result clear_find(struct iscache_fixture *cfix)
978 {
979 struct pt_section *section;
980 int errcode, found, isid;
981
982 section = cfix->section[0];
983 ptu_ptr(section);
984
985 isid = pt_iscache_add(&cfix->iscache, section, 0ull);
986 ptu_int_gt(isid, 0);
987
988 errcode = pt_iscache_clear(&cfix->iscache);
989 ptu_int_eq(errcode, 0);
990
991
992 found = pt_iscache_find(&cfix->iscache, section->filename,
993 section->offset, section->size, 0ull);
994 ptu_int_eq(found, 0);
995
996 return ptu_passed();
997 }
998
clear_lookup(struct iscache_fixture * cfix)999 static struct ptunit_result clear_lookup(struct iscache_fixture *cfix)
1000 {
1001 struct pt_section *section;
1002 uint64_t laddr;
1003 int errcode, isid;
1004
1005 isid = pt_iscache_add(&cfix->iscache, cfix->section[0], 0ull);
1006 ptu_int_gt(isid, 0);
1007
1008 errcode = pt_iscache_clear(&cfix->iscache);
1009 ptu_int_eq(errcode, 0);
1010
1011 errcode = pt_iscache_lookup(&cfix->iscache, §ion, &laddr, isid);
1012 ptu_int_eq(errcode, -pte_bad_image);
1013
1014 return ptu_passed();
1015 }
1016
add_twice(struct iscache_fixture * cfix)1017 static struct ptunit_result add_twice(struct iscache_fixture *cfix)
1018 {
1019 int isid[2];
1020
1021 isid[0] = pt_iscache_add(&cfix->iscache, cfix->section[0], 0ull);
1022 ptu_int_gt(isid[0], 0);
1023
1024 isid[1] = pt_iscache_add(&cfix->iscache, cfix->section[0], 0ull);
1025 ptu_int_gt(isid[1], 0);
1026
1027 /* The second add should be ignored. */
1028 ptu_int_eq(isid[1], isid[0]);
1029
1030 return ptu_passed();
1031 }
1032
add_same(struct iscache_fixture * cfix)1033 static struct ptunit_result add_same(struct iscache_fixture *cfix)
1034 {
1035 int isid[2];
1036
1037 isid[0] = pt_iscache_add(&cfix->iscache, cfix->section[0], 0ull);
1038 ptu_int_gt(isid[0], 0);
1039
1040 cfix->section[1]->offset = cfix->section[0]->offset;
1041 cfix->section[1]->size = cfix->section[0]->size;
1042
1043 isid[1] = pt_iscache_add(&cfix->iscache, cfix->section[1], 0ull);
1044 ptu_int_gt(isid[1], 0);
1045
1046 /* The second add should be ignored. */
1047 ptu_int_eq(isid[1], isid[0]);
1048
1049 return ptu_passed();
1050 }
1051
1052 static struct ptunit_result
add_twice_different_laddr(struct iscache_fixture * cfix)1053 add_twice_different_laddr(struct iscache_fixture *cfix)
1054 {
1055 int isid[2];
1056
1057 isid[0] = pt_iscache_add(&cfix->iscache, cfix->section[0], 0ull);
1058 ptu_int_gt(isid[0], 0);
1059
1060 isid[1] = pt_iscache_add(&cfix->iscache, cfix->section[0], 1ull);
1061 ptu_int_gt(isid[1], 0);
1062
1063 /* We must get different identifiers. */
1064 ptu_int_ne(isid[1], isid[0]);
1065
1066 /* We attach twice and take two references - one for each entry. */
1067 ptu_int_eq(cfix->section[0]->ucount, 3);
1068 ptu_int_eq(cfix->section[0]->acount, 2);
1069
1070 return ptu_passed();
1071 }
1072
1073 static struct ptunit_result
add_same_different_laddr(struct iscache_fixture * cfix)1074 add_same_different_laddr(struct iscache_fixture *cfix)
1075 {
1076 int isid[2];
1077
1078 isid[0] = pt_iscache_add(&cfix->iscache, cfix->section[0], 0ull);
1079 ptu_int_gt(isid[0], 0);
1080
1081 cfix->section[1]->offset = cfix->section[0]->offset;
1082 cfix->section[1]->size = cfix->section[0]->size;
1083
1084 isid[1] = pt_iscache_add(&cfix->iscache, cfix->section[1], 1ull);
1085 ptu_int_gt(isid[1], 0);
1086
1087 /* We must get different identifiers. */
1088 ptu_int_ne(isid[1], isid[0]);
1089
1090 return ptu_passed();
1091 }
1092
1093 static struct ptunit_result
add_different_same_laddr(struct iscache_fixture * cfix)1094 add_different_same_laddr(struct iscache_fixture *cfix)
1095 {
1096 int isid[2];
1097
1098 isid[0] = pt_iscache_add(&cfix->iscache, cfix->section[0], 0ull);
1099 ptu_int_gt(isid[0], 0);
1100
1101 isid[1] = pt_iscache_add(&cfix->iscache, cfix->section[1], 0ull);
1102 ptu_int_gt(isid[1], 0);
1103
1104 /* We must get different identifiers. */
1105 ptu_int_ne(isid[1], isid[0]);
1106
1107 return ptu_passed();
1108 }
1109
add_file_same(struct iscache_fixture * cfix)1110 static struct ptunit_result add_file_same(struct iscache_fixture *cfix)
1111 {
1112 int isid[2];
1113
1114 isid[0] = pt_iscache_add_file(&cfix->iscache, "name", 0ull, 1ull, 0ull);
1115 ptu_int_gt(isid[0], 0);
1116
1117 isid[1] = pt_iscache_add_file(&cfix->iscache, "name", 0ull, 1ull, 0ull);
1118 ptu_int_gt(isid[1], 0);
1119
1120 /* The second add should be ignored. */
1121 ptu_int_eq(isid[1], isid[0]);
1122
1123 return ptu_passed();
1124 }
1125
1126 static struct ptunit_result
add_file_same_different_laddr(struct iscache_fixture * cfix)1127 add_file_same_different_laddr(struct iscache_fixture *cfix)
1128 {
1129 int isid[2];
1130
1131 isid[0] = pt_iscache_add_file(&cfix->iscache, "name", 0ull, 1ull, 0ull);
1132 ptu_int_gt(isid[0], 0);
1133
1134 isid[1] = pt_iscache_add_file(&cfix->iscache, "name", 0ull, 1ull, 1ull);
1135 ptu_int_gt(isid[1], 0);
1136
1137 /* We must get different identifiers. */
1138 ptu_int_ne(isid[1], isid[0]);
1139
1140 return ptu_passed();
1141 }
1142
1143 static struct ptunit_result
add_file_different_same_laddr(struct iscache_fixture * cfix)1144 add_file_different_same_laddr(struct iscache_fixture *cfix)
1145 {
1146 int isid[2];
1147
1148 isid[0] = pt_iscache_add_file(&cfix->iscache, "name", 0ull, 1ull, 0ull);
1149 ptu_int_gt(isid[0], 0);
1150
1151 isid[1] = pt_iscache_add_file(&cfix->iscache, "name", 1ull, 1ull, 0ull);
1152 ptu_int_gt(isid[1], 0);
1153
1154 /* We must get different identifiers. */
1155 ptu_int_ne(isid[1], isid[0]);
1156
1157 return ptu_passed();
1158 }
1159
read(struct iscache_fixture * cfix)1160 static struct ptunit_result read(struct iscache_fixture *cfix)
1161 {
1162 uint8_t buffer[] = { 0xcc, 0xcc, 0xcc };
1163 int status, isid;
1164
1165 isid = pt_iscache_add(&cfix->iscache, cfix->section[0], 0xa000ull);
1166 ptu_int_gt(isid, 0);
1167
1168 status = pt_iscache_read(&cfix->iscache, buffer, 2ull, isid, 0xa008ull);
1169 ptu_int_eq(status, 2);
1170 ptu_uint_eq(buffer[0], 0x8);
1171 ptu_uint_eq(buffer[1], 0x9);
1172 ptu_uint_eq(buffer[2], 0xcc);
1173
1174 return ptu_passed();
1175 }
1176
read_truncate(struct iscache_fixture * cfix)1177 static struct ptunit_result read_truncate(struct iscache_fixture *cfix)
1178 {
1179 uint8_t buffer[] = { 0xcc, 0xcc };
1180 int status, isid;
1181
1182 isid = pt_iscache_add(&cfix->iscache, cfix->section[0], 0xa000ull);
1183 ptu_int_gt(isid, 0);
1184
1185 status = pt_iscache_read(&cfix->iscache, buffer, sizeof(buffer), isid,
1186 0xa00full);
1187 ptu_int_eq(status, 1);
1188 ptu_uint_eq(buffer[0], 0xf);
1189 ptu_uint_eq(buffer[1], 0xcc);
1190
1191 return ptu_passed();
1192 }
1193
read_bad_vaddr(struct iscache_fixture * cfix)1194 static struct ptunit_result read_bad_vaddr(struct iscache_fixture *cfix)
1195 {
1196 uint8_t buffer[] = { 0xcc };
1197 int status, isid;
1198
1199 isid = pt_iscache_add(&cfix->iscache, cfix->section[0], 0xa000ull);
1200 ptu_int_gt(isid, 0);
1201
1202 status = pt_iscache_read(&cfix->iscache, buffer, 1ull, isid, 0xb000ull);
1203 ptu_int_eq(status, -pte_nomap);
1204 ptu_uint_eq(buffer[0], 0xcc);
1205
1206 return ptu_passed();
1207 }
1208
read_bad_isid(struct iscache_fixture * cfix)1209 static struct ptunit_result read_bad_isid(struct iscache_fixture *cfix)
1210 {
1211 uint8_t buffer[] = { 0xcc };
1212 int status, isid;
1213
1214 isid = pt_iscache_add(&cfix->iscache, cfix->section[0], 0xa000ull);
1215 ptu_int_gt(isid, 0);
1216
1217 status = pt_iscache_read(&cfix->iscache, buffer, 1ull, isid + 1,
1218 0xa000ull);
1219 ptu_int_eq(status, -pte_bad_image);
1220 ptu_uint_eq(buffer[0], 0xcc);
1221
1222 return ptu_passed();
1223 }
1224
lru_map(struct iscache_fixture * cfix)1225 static struct ptunit_result lru_map(struct iscache_fixture *cfix)
1226 {
1227 int status, isid;
1228
1229 cfix->iscache.limit = cfix->section[0]->size;
1230 ptu_uint_eq(cfix->iscache.used, 0ull);
1231 ptu_null(cfix->iscache.lru);
1232
1233 isid = pt_iscache_add(&cfix->iscache, cfix->section[0], 0xa000ull);
1234 ptu_int_gt(isid, 0);
1235
1236 status = pt_section_map(cfix->section[0]);
1237 ptu_int_eq(status, 0);
1238
1239 status = pt_section_unmap(cfix->section[0]);
1240 ptu_int_eq(status, 0);
1241
1242 ptu_ptr(cfix->iscache.lru);
1243 ptu_ptr_eq(cfix->iscache.lru->section, cfix->section[0]);
1244 ptu_null(cfix->iscache.lru->next);
1245 ptu_uint_eq(cfix->iscache.used, cfix->section[0]->size);
1246
1247 return ptu_passed();
1248 }
1249
lru_read(struct iscache_fixture * cfix)1250 static struct ptunit_result lru_read(struct iscache_fixture *cfix)
1251 {
1252 uint8_t buffer[] = { 0xcc, 0xcc, 0xcc };
1253 int status, isid;
1254
1255 cfix->iscache.limit = cfix->section[0]->size;
1256 ptu_uint_eq(cfix->iscache.used, 0ull);
1257 ptu_null(cfix->iscache.lru);
1258
1259 isid = pt_iscache_add(&cfix->iscache, cfix->section[0], 0xa000ull);
1260 ptu_int_gt(isid, 0);
1261
1262 status = pt_iscache_read(&cfix->iscache, buffer, 2ull, isid, 0xa008ull);
1263 ptu_int_eq(status, 2);
1264
1265 ptu_ptr(cfix->iscache.lru);
1266 ptu_ptr_eq(cfix->iscache.lru->section, cfix->section[0]);
1267 ptu_null(cfix->iscache.lru->next);
1268 ptu_uint_eq(cfix->iscache.used, cfix->section[0]->size);
1269
1270 return ptu_passed();
1271 }
1272
lru_map_nodup(struct iscache_fixture * cfix)1273 static struct ptunit_result lru_map_nodup(struct iscache_fixture *cfix)
1274 {
1275 int status, isid;
1276
1277 cfix->iscache.limit = 2 * cfix->section[0]->size;
1278 ptu_uint_eq(cfix->iscache.used, 0ull);
1279 ptu_null(cfix->iscache.lru);
1280
1281 isid = pt_iscache_add(&cfix->iscache, cfix->section[0], 0xa000ull);
1282 ptu_int_gt(isid, 0);
1283
1284 status = pt_section_map(cfix->section[0]);
1285 ptu_int_eq(status, 0);
1286
1287 status = pt_section_unmap(cfix->section[0]);
1288 ptu_int_eq(status, 0);
1289
1290 status = pt_section_map(cfix->section[0]);
1291 ptu_int_eq(status, 0);
1292
1293 status = pt_section_unmap(cfix->section[0]);
1294 ptu_int_eq(status, 0);
1295
1296 ptu_ptr(cfix->iscache.lru);
1297 ptu_ptr_eq(cfix->iscache.lru->section, cfix->section[0]);
1298 ptu_null(cfix->iscache.lru->next);
1299 ptu_uint_eq(cfix->iscache.used, cfix->section[0]->size);
1300
1301 return ptu_passed();
1302 }
1303
lru_map_too_big(struct iscache_fixture * cfix)1304 static struct ptunit_result lru_map_too_big(struct iscache_fixture *cfix)
1305 {
1306 int status, isid;
1307
1308 cfix->iscache.limit = cfix->section[0]->size - 1;
1309 ptu_uint_eq(cfix->iscache.used, 0ull);
1310 ptu_null(cfix->iscache.lru);
1311
1312 isid = pt_iscache_add(&cfix->iscache, cfix->section[0], 0xa000ull);
1313 ptu_int_gt(isid, 0);
1314
1315 status = pt_section_map(cfix->section[0]);
1316 ptu_int_eq(status, 0);
1317
1318 status = pt_section_unmap(cfix->section[0]);
1319 ptu_int_eq(status, 0);
1320
1321 ptu_null(cfix->iscache.lru);
1322 ptu_uint_eq(cfix->iscache.used, 0ull);
1323
1324 return ptu_passed();
1325 }
1326
lru_map_add_front(struct iscache_fixture * cfix)1327 static struct ptunit_result lru_map_add_front(struct iscache_fixture *cfix)
1328 {
1329 int status, isid;
1330
1331 cfix->iscache.limit = cfix->section[0]->size + cfix->section[1]->size;
1332 ptu_uint_eq(cfix->iscache.used, 0ull);
1333 ptu_null(cfix->iscache.lru);
1334
1335 isid = pt_iscache_add(&cfix->iscache, cfix->section[0], 0xa000ull);
1336 ptu_int_gt(isid, 0);
1337
1338 isid = pt_iscache_add(&cfix->iscache, cfix->section[1], 0xa000ull);
1339 ptu_int_gt(isid, 0);
1340
1341 status = pt_section_map(cfix->section[0]);
1342 ptu_int_eq(status, 0);
1343
1344 status = pt_section_unmap(cfix->section[0]);
1345 ptu_int_eq(status, 0);
1346
1347 status = pt_section_map(cfix->section[1]);
1348 ptu_int_eq(status, 0);
1349
1350 status = pt_section_unmap(cfix->section[1]);
1351 ptu_int_eq(status, 0);
1352
1353 ptu_ptr(cfix->iscache.lru);
1354 ptu_ptr_eq(cfix->iscache.lru->section, cfix->section[1]);
1355 ptu_ptr(cfix->iscache.lru->next);
1356 ptu_ptr_eq(cfix->iscache.lru->next->section, cfix->section[0]);
1357 ptu_null(cfix->iscache.lru->next->next);
1358 ptu_uint_eq(cfix->iscache.used,
1359 cfix->section[0]->size + cfix->section[1]->size);
1360
1361 return ptu_passed();
1362 }
1363
lru_map_move_front(struct iscache_fixture * cfix)1364 static struct ptunit_result lru_map_move_front(struct iscache_fixture *cfix)
1365 {
1366 int status, isid;
1367
1368 cfix->iscache.limit = cfix->section[0]->size + cfix->section[1]->size;
1369 ptu_uint_eq(cfix->iscache.used, 0ull);
1370 ptu_null(cfix->iscache.lru);
1371
1372 isid = pt_iscache_add(&cfix->iscache, cfix->section[0], 0xa000ull);
1373 ptu_int_gt(isid, 0);
1374
1375 isid = pt_iscache_add(&cfix->iscache, cfix->section[1], 0xa000ull);
1376 ptu_int_gt(isid, 0);
1377
1378 status = pt_section_map(cfix->section[0]);
1379 ptu_int_eq(status, 0);
1380
1381 status = pt_section_unmap(cfix->section[0]);
1382 ptu_int_eq(status, 0);
1383
1384 status = pt_section_map(cfix->section[1]);
1385 ptu_int_eq(status, 0);
1386
1387 status = pt_section_unmap(cfix->section[1]);
1388 ptu_int_eq(status, 0);
1389
1390 status = pt_section_map(cfix->section[0]);
1391 ptu_int_eq(status, 0);
1392
1393 status = pt_section_unmap(cfix->section[0]);
1394 ptu_int_eq(status, 0);
1395
1396 ptu_ptr(cfix->iscache.lru);
1397 ptu_ptr_eq(cfix->iscache.lru->section, cfix->section[0]);
1398 ptu_ptr(cfix->iscache.lru->next);
1399 ptu_ptr_eq(cfix->iscache.lru->next->section, cfix->section[1]);
1400 ptu_null(cfix->iscache.lru->next->next);
1401 ptu_uint_eq(cfix->iscache.used,
1402 cfix->section[0]->size + cfix->section[1]->size);
1403
1404 return ptu_passed();
1405 }
1406
lru_map_evict(struct iscache_fixture * cfix)1407 static struct ptunit_result lru_map_evict(struct iscache_fixture *cfix)
1408 {
1409 int status, isid;
1410
1411 cfix->iscache.limit = cfix->section[0]->size +
1412 cfix->section[1]->size - 1;
1413 ptu_uint_eq(cfix->iscache.used, 0ull);
1414 ptu_null(cfix->iscache.lru);
1415
1416 isid = pt_iscache_add(&cfix->iscache, cfix->section[0], 0xa000ull);
1417 ptu_int_gt(isid, 0);
1418
1419 isid = pt_iscache_add(&cfix->iscache, cfix->section[1], 0xa000ull);
1420 ptu_int_gt(isid, 0);
1421
1422 status = pt_section_map(cfix->section[0]);
1423 ptu_int_eq(status, 0);
1424
1425 status = pt_section_unmap(cfix->section[0]);
1426 ptu_int_eq(status, 0);
1427
1428 status = pt_section_map(cfix->section[1]);
1429 ptu_int_eq(status, 0);
1430
1431 status = pt_section_unmap(cfix->section[1]);
1432 ptu_int_eq(status, 0);
1433
1434 ptu_ptr(cfix->iscache.lru);
1435 ptu_ptr_eq(cfix->iscache.lru->section, cfix->section[1]);
1436 ptu_null(cfix->iscache.lru->next);
1437 ptu_uint_eq(cfix->iscache.used, cfix->section[1]->size);
1438
1439 return ptu_passed();
1440 }
1441
lru_bcache_evict(struct iscache_fixture * cfix)1442 static struct ptunit_result lru_bcache_evict(struct iscache_fixture *cfix)
1443 {
1444 int status, isid;
1445
1446 cfix->iscache.limit = 4 * cfix->section[0]->size +
1447 cfix->section[1]->size - 1;
1448 ptu_uint_eq(cfix->iscache.used, 0ull);
1449 ptu_null(cfix->iscache.lru);
1450
1451 isid = pt_iscache_add(&cfix->iscache, cfix->section[0], 0xa000ull);
1452 ptu_int_gt(isid, 0);
1453
1454 isid = pt_iscache_add(&cfix->iscache, cfix->section[1], 0xa000ull);
1455 ptu_int_gt(isid, 0);
1456
1457 status = pt_section_map(cfix->section[0]);
1458 ptu_int_eq(status, 0);
1459
1460 status = pt_section_unmap(cfix->section[0]);
1461 ptu_int_eq(status, 0);
1462
1463 status = pt_section_map(cfix->section[1]);
1464 ptu_int_eq(status, 0);
1465
1466 status = pt_section_unmap(cfix->section[1]);
1467 ptu_int_eq(status, 0);
1468
1469 status = pt_section_request_bcache(cfix->section[0]);
1470 ptu_int_eq(status, 0);
1471
1472 ptu_ptr(cfix->iscache.lru);
1473 ptu_ptr_eq(cfix->iscache.lru->section, cfix->section[0]);
1474 ptu_null(cfix->iscache.lru->next);
1475 ptu_uint_eq(cfix->iscache.used, 4 * cfix->section[0]->size);
1476
1477 return ptu_passed();
1478 }
1479
lru_bcache_clear(struct iscache_fixture * cfix)1480 static struct ptunit_result lru_bcache_clear(struct iscache_fixture *cfix)
1481 {
1482 int status, isid;
1483
1484 cfix->iscache.limit = cfix->section[0]->size + cfix->section[1]->size;
1485 ptu_uint_eq(cfix->iscache.used, 0ull);
1486 ptu_null(cfix->iscache.lru);
1487
1488 isid = pt_iscache_add(&cfix->iscache, cfix->section[0], 0xa000ull);
1489 ptu_int_gt(isid, 0);
1490
1491 isid = pt_iscache_add(&cfix->iscache, cfix->section[1], 0xa000ull);
1492 ptu_int_gt(isid, 0);
1493
1494 status = pt_section_map(cfix->section[0]);
1495 ptu_int_eq(status, 0);
1496
1497 status = pt_section_unmap(cfix->section[0]);
1498 ptu_int_eq(status, 0);
1499
1500 status = pt_section_map(cfix->section[1]);
1501 ptu_int_eq(status, 0);
1502
1503 status = pt_section_unmap(cfix->section[1]);
1504 ptu_int_eq(status, 0);
1505
1506 status = pt_section_request_bcache(cfix->section[0]);
1507 ptu_int_eq(status, 0);
1508
1509 ptu_null(cfix->iscache.lru);
1510 ptu_uint_eq(cfix->iscache.used, 0ull);
1511
1512 return ptu_passed();
1513 }
1514
lru_limit_evict(struct iscache_fixture * cfix)1515 static struct ptunit_result lru_limit_evict(struct iscache_fixture *cfix)
1516 {
1517 int status, isid;
1518
1519 cfix->iscache.limit = cfix->section[0]->size + cfix->section[1]->size;
1520 ptu_uint_eq(cfix->iscache.used, 0ull);
1521 ptu_null(cfix->iscache.lru);
1522
1523 isid = pt_iscache_add(&cfix->iscache, cfix->section[0], 0xa000ull);
1524 ptu_int_gt(isid, 0);
1525
1526 isid = pt_iscache_add(&cfix->iscache, cfix->section[1], 0xa000ull);
1527 ptu_int_gt(isid, 0);
1528
1529 status = pt_section_map(cfix->section[0]);
1530 ptu_int_eq(status, 0);
1531
1532 status = pt_section_unmap(cfix->section[0]);
1533 ptu_int_eq(status, 0);
1534
1535 status = pt_section_map(cfix->section[1]);
1536 ptu_int_eq(status, 0);
1537
1538 status = pt_section_unmap(cfix->section[1]);
1539 ptu_int_eq(status, 0);
1540
1541 status = pt_iscache_set_limit(&cfix->iscache,
1542 cfix->section[0]->size +
1543 cfix->section[1]->size - 1);
1544 ptu_int_eq(status, 0);
1545
1546 ptu_ptr(cfix->iscache.lru);
1547 ptu_ptr_eq(cfix->iscache.lru->section, cfix->section[1]);
1548 ptu_null(cfix->iscache.lru->next);
1549 ptu_uint_eq(cfix->iscache.used, cfix->section[1]->size);
1550
1551 return ptu_passed();
1552 }
1553
lru_clear(struct iscache_fixture * cfix)1554 static struct ptunit_result lru_clear(struct iscache_fixture *cfix)
1555 {
1556 int status, isid;
1557
1558 cfix->iscache.limit = cfix->section[0]->size;
1559 ptu_uint_eq(cfix->iscache.used, 0ull);
1560 ptu_null(cfix->iscache.lru);
1561
1562 isid = pt_iscache_add(&cfix->iscache, cfix->section[0], 0xa000ull);
1563 ptu_int_gt(isid, 0);
1564
1565 status = pt_section_map(cfix->section[0]);
1566 ptu_int_eq(status, 0);
1567
1568 status = pt_section_unmap(cfix->section[0]);
1569 ptu_int_eq(status, 0);
1570
1571 status = pt_iscache_clear(&cfix->iscache);
1572 ptu_int_eq(status, 0);
1573
1574 ptu_null(cfix->iscache.lru);
1575 ptu_uint_eq(cfix->iscache.used, 0ull);
1576
1577 return ptu_passed();
1578 }
1579
worker_add(void * arg)1580 static int worker_add(void *arg)
1581 {
1582 struct iscache_fixture *cfix;
1583 int it;
1584
1585 cfix = arg;
1586 if (!cfix)
1587 return -pte_internal;
1588
1589 for (it = 0; it < num_iterations; ++it) {
1590 uint64_t laddr;
1591 int sec;
1592
1593 laddr = 0x1000ull * (it % 23);
1594
1595 for (sec = 0; sec < num_sections; ++sec) {
1596 struct pt_section *section;
1597 uint64_t addr;
1598 int isid, errcode;
1599
1600 isid = pt_iscache_add(&cfix->iscache,
1601 cfix->section[sec], laddr);
1602 if (isid < 0)
1603 return isid;
1604
1605 errcode = pt_iscache_lookup(&cfix->iscache, §ion,
1606 &addr, isid);
1607 if (errcode < 0)
1608 return errcode;
1609
1610 if (laddr != addr)
1611 return -pte_noip;
1612
1613 /* We may not get the image we added but the image we
1614 * get must have similar attributes.
1615 *
1616 * We're using the same filename string literal for all
1617 * sections, though.
1618 */
1619 if (section->offset != cfix->section[sec]->offset)
1620 return -pte_bad_image;
1621
1622 if (section->size != cfix->section[sec]->size)
1623 return -pte_bad_image;
1624
1625 errcode = pt_section_put(section);
1626 if (errcode < 0)
1627 return errcode;
1628 }
1629 }
1630
1631 return 0;
1632 }
1633
worker_add_file(void * arg)1634 static int worker_add_file(void *arg)
1635 {
1636 struct iscache_fixture *cfix;
1637 int it;
1638
1639 cfix = arg;
1640 if (!cfix)
1641 return -pte_internal;
1642
1643 for (it = 0; it < num_iterations; ++it) {
1644 uint64_t offset, size, laddr;
1645 int sec;
1646
1647 offset = it % 7 == 0 ? 0x1000 : 0x2000;
1648 size = it % 5 == 0 ? 0x1000 : 0x2000;
1649 laddr = it % 3 == 0 ? 0x1000 : 0x2000;
1650
1651 for (sec = 0; sec < num_sections; ++sec) {
1652 struct pt_section *section;
1653 uint64_t addr;
1654 int isid, errcode;
1655
1656 isid = pt_iscache_add_file(&cfix->iscache, "name",
1657 offset, size, laddr);
1658 if (isid < 0)
1659 return isid;
1660
1661 errcode = pt_iscache_lookup(&cfix->iscache, §ion,
1662 &addr, isid);
1663 if (errcode < 0)
1664 return errcode;
1665
1666 if (laddr != addr)
1667 return -pte_noip;
1668
1669 if (section->offset != offset)
1670 return -pte_bad_image;
1671
1672 if (section->size != size)
1673 return -pte_bad_image;
1674
1675 errcode = pt_section_put(section);
1676 if (errcode < 0)
1677 return errcode;
1678 }
1679 }
1680
1681 return 0;
1682 }
1683
worker_map(void * arg)1684 static int worker_map(void *arg)
1685 {
1686 struct iscache_fixture *cfix;
1687 int it, sec, status;
1688
1689 cfix = arg;
1690 if (!cfix)
1691 return -pte_internal;
1692
1693 for (it = 0; it < num_iterations; ++it) {
1694 for (sec = 0; sec < num_sections; ++sec) {
1695
1696 status = pt_section_map(cfix->section[sec]);
1697 if (status < 0)
1698 return status;
1699
1700 status = pt_section_unmap(cfix->section[sec]);
1701 if (status < 0)
1702 return status;
1703 }
1704 }
1705
1706 return 0;
1707 }
1708
worker_map_limit(void * arg)1709 static int worker_map_limit(void *arg)
1710 {
1711 struct iscache_fixture *cfix;
1712 uint64_t limits[] = { 0x8000, 0x3000, 0x12000, 0x0 }, limit;
1713 int it, sec, errcode, lim;
1714
1715 cfix = arg;
1716 if (!cfix)
1717 return -pte_internal;
1718
1719 lim = 0;
1720 for (it = 0; it < num_iterations; ++it) {
1721 for (sec = 0; sec < num_sections; ++sec) {
1722
1723 errcode = pt_section_map(cfix->section[sec]);
1724 if (errcode < 0)
1725 return errcode;
1726
1727 errcode = pt_section_unmap(cfix->section[sec]);
1728 if (errcode < 0)
1729 return errcode;
1730 }
1731
1732 if (it % 23 != 0)
1733 continue;
1734
1735 limit = limits[lim++];
1736 lim %= sizeof(limits) / sizeof(*limits);
1737
1738 errcode = pt_iscache_set_limit(&cfix->iscache, limit);
1739 if (errcode < 0)
1740 return errcode;
1741 }
1742
1743 return 0;
1744 }
1745
worker_map_bcache(void * arg)1746 static int worker_map_bcache(void *arg)
1747 {
1748 struct iscache_fixture *cfix;
1749 int it, sec, status;
1750
1751 cfix = arg;
1752 if (!cfix)
1753 return -pte_internal;
1754
1755 for (it = 0; it < num_iterations; ++it) {
1756 for (sec = 0; sec < num_sections; ++sec) {
1757 struct pt_section *section;
1758
1759 section = cfix->section[sec];
1760
1761 status = pt_section_map(section);
1762 if (status < 0)
1763 return status;
1764
1765 if (it % 13 == 0) {
1766 status = pt_section_request_bcache(section);
1767 if (status < 0) {
1768 (void) pt_section_unmap(section);
1769 return status;
1770 }
1771 }
1772
1773 status = pt_section_unmap(section);
1774 if (status < 0)
1775 return status;
1776 }
1777 }
1778
1779 return 0;
1780 }
1781
worker_add_map(void * arg)1782 static int worker_add_map(void *arg)
1783 {
1784 struct iscache_fixture *cfix;
1785 struct pt_section *section;
1786 int it;
1787
1788 cfix = arg;
1789 if (!cfix)
1790 return -pte_internal;
1791
1792 section = cfix->section[0];
1793 for (it = 0; it < num_iterations; ++it) {
1794 uint64_t laddr;
1795 int isid, errcode;
1796
1797 laddr = (uint64_t) it << 3;
1798
1799 isid = pt_iscache_add(&cfix->iscache, section, laddr);
1800 if (isid < 0)
1801 return isid;
1802
1803 errcode = pt_section_map(section);
1804 if (errcode < 0)
1805 return errcode;
1806
1807 errcode = pt_section_unmap(section);
1808 if (errcode < 0)
1809 return errcode;
1810 }
1811
1812 return 0;
1813 }
1814
worker_add_clear(void * arg)1815 static int worker_add_clear(void *arg)
1816 {
1817 struct iscache_fixture *cfix;
1818 struct pt_section *section;
1819 int it;
1820
1821 cfix = arg;
1822 if (!cfix)
1823 return -pte_internal;
1824
1825 section = cfix->section[0];
1826 for (it = 0; it < num_iterations; ++it) {
1827 uint64_t laddr;
1828 int isid, errcode;
1829
1830 laddr = (uint64_t) it << 3;
1831
1832 isid = pt_iscache_add(&cfix->iscache, section, laddr);
1833 if (isid < 0)
1834 return isid;
1835
1836 errcode = pt_iscache_clear(&cfix->iscache);
1837 if (errcode < 0)
1838 return errcode;
1839 }
1840
1841 return 0;
1842 }
1843
worker_add_file_map(void * arg)1844 static int worker_add_file_map(void *arg)
1845 {
1846 struct iscache_fixture *cfix;
1847 int it;
1848
1849 cfix = arg;
1850 if (!cfix)
1851 return -pte_internal;
1852
1853 for (it = 0; it < num_iterations; ++it) {
1854 struct pt_section *section;
1855 uint64_t offset, size, laddr, addr;
1856 int isid, errcode;
1857
1858 offset = it % 7 < 4 ? 0x1000 : 0x2000;
1859 size = it % 5 < 3 ? 0x1000 : 0x2000;
1860 laddr = it % 3 < 2 ? 0x1000 : 0x2000;
1861
1862 isid = pt_iscache_add_file(&cfix->iscache, "name",
1863 offset, size, laddr);
1864 if (isid < 0)
1865 return isid;
1866
1867 errcode = pt_iscache_lookup(&cfix->iscache, §ion,
1868 &addr, isid);
1869 if (errcode < 0)
1870 return errcode;
1871
1872 if (addr != laddr)
1873 return -pte_internal;
1874
1875 errcode = pt_section_map(section);
1876 if (errcode < 0)
1877 return errcode;
1878
1879 errcode = pt_section_unmap(section);
1880 if (errcode < 0)
1881 return errcode;
1882 }
1883
1884 return 0;
1885 }
1886
worker_add_file_clear(void * arg)1887 static int worker_add_file_clear(void *arg)
1888 {
1889 struct iscache_fixture *cfix;
1890 int it;
1891
1892 cfix = arg;
1893 if (!cfix)
1894 return -pte_internal;
1895
1896 for (it = 0; it < num_iterations; ++it) {
1897 uint64_t offset, size, laddr;
1898 int isid, errcode;
1899
1900 offset = it % 7 < 4 ? 0x1000 : 0x2000;
1901 size = it % 5 < 3 ? 0x1000 : 0x2000;
1902 laddr = it % 3 < 2 ? 0x1000 : 0x2000;
1903
1904 isid = pt_iscache_add_file(&cfix->iscache, "name",
1905 offset, size, laddr);
1906 if (isid < 0)
1907 return isid;
1908
1909 if (it % 11 < 9)
1910 continue;
1911
1912 errcode = pt_iscache_clear(&cfix->iscache);
1913 if (errcode < 0)
1914 return errcode;
1915 }
1916
1917 return 0;
1918 }
1919
stress(struct iscache_fixture * cfix,int (* worker)(void *))1920 static struct ptunit_result stress(struct iscache_fixture *cfix,
1921 int (*worker)(void *))
1922 {
1923 int errcode;
1924
1925 #if defined(FEATURE_THREADS)
1926 {
1927 int thrd;
1928
1929 for (thrd = 0; thrd < num_threads; ++thrd)
1930 ptu_test(ptunit_thrd_create, &cfix->thrd, worker, cfix);
1931 }
1932 #endif /* defined(FEATURE_THREADS) */
1933
1934 errcode = worker(cfix);
1935 ptu_int_eq(errcode, 0);
1936
1937 return ptu_passed();
1938 }
main(int argc,char ** argv)1939 int main(int argc, char **argv)
1940 {
1941 struct iscache_fixture cfix, dfix, sfix;
1942 struct ptunit_suite suite;
1943
1944 cfix.init = cfix_init;
1945 cfix.fini = cfix_fini;
1946
1947 dfix.init = dfix_init;
1948 dfix.fini = cfix_fini;
1949
1950 sfix.init = sfix_init;
1951 sfix.fini = cfix_fini;
1952
1953 suite = ptunit_mk_suite(argc, argv);
1954
1955 ptu_run(suite, init_null);
1956 ptu_run(suite, fini_null);
1957 ptu_run(suite, name_null);
1958 ptu_run(suite, add_null);
1959 ptu_run(suite, find_null);
1960 ptu_run(suite, lookup_null);
1961 ptu_run(suite, clear_null);
1962 ptu_run(suite, free_null);
1963 ptu_run(suite, add_file_null);
1964 ptu_run(suite, read_null);
1965
1966 ptu_run_f(suite, name, dfix);
1967 ptu_run_f(suite, name_none, dfix);
1968
1969 ptu_run_f(suite, init_fini, cfix);
1970 ptu_run_f(suite, add, cfix);
1971 ptu_run_f(suite, add_no_name, cfix);
1972 ptu_run_f(suite, add_file, cfix);
1973
1974 ptu_run_f(suite, find, cfix);
1975 ptu_run_f(suite, find_empty, cfix);
1976 ptu_run_f(suite, find_bad_filename, cfix);
1977 ptu_run_f(suite, find_null_filename, cfix);
1978 ptu_run_f(suite, find_bad_offset, cfix);
1979 ptu_run_f(suite, find_bad_size, cfix);
1980 ptu_run_f(suite, find_bad_laddr, cfix);
1981
1982 ptu_run_f(suite, lookup, cfix);
1983 ptu_run_f(suite, lookup_bad_isid, cfix);
1984
1985 ptu_run_f(suite, clear_empty, cfix);
1986 ptu_run_f(suite, clear_find, cfix);
1987 ptu_run_f(suite, clear_lookup, cfix);
1988
1989 ptu_run_f(suite, add_twice, cfix);
1990 ptu_run_f(suite, add_same, cfix);
1991 ptu_run_f(suite, add_twice_different_laddr, cfix);
1992 ptu_run_f(suite, add_same_different_laddr, cfix);
1993 ptu_run_f(suite, add_different_same_laddr, cfix);
1994
1995 ptu_run_f(suite, add_file_same, cfix);
1996 ptu_run_f(suite, add_file_same_different_laddr, cfix);
1997 ptu_run_f(suite, add_file_different_same_laddr, cfix);
1998
1999 ptu_run_f(suite, read, cfix);
2000 ptu_run_f(suite, read_truncate, cfix);
2001 ptu_run_f(suite, read_bad_vaddr, cfix);
2002 ptu_run_f(suite, read_bad_isid, cfix);
2003
2004 ptu_run_f(suite, lru_map, cfix);
2005 ptu_run_f(suite, lru_read, cfix);
2006 ptu_run_f(suite, lru_map_nodup, cfix);
2007 ptu_run_f(suite, lru_map_too_big, cfix);
2008 ptu_run_f(suite, lru_map_add_front, cfix);
2009 ptu_run_f(suite, lru_map_move_front, cfix);
2010 ptu_run_f(suite, lru_map_evict, cfix);
2011 ptu_run_f(suite, lru_limit_evict, cfix);
2012 ptu_run_f(suite, lru_bcache_evict, cfix);
2013 ptu_run_f(suite, lru_bcache_clear, cfix);
2014 ptu_run_f(suite, lru_clear, cfix);
2015
2016 ptu_run_fp(suite, stress, cfix, worker_add);
2017 ptu_run_fp(suite, stress, cfix, worker_add_file);
2018 ptu_run_fp(suite, stress, sfix, worker_map);
2019 ptu_run_fp(suite, stress, sfix, worker_map_limit);
2020 ptu_run_fp(suite, stress, sfix, worker_map_bcache);
2021 ptu_run_fp(suite, stress, cfix, worker_add_map);
2022 ptu_run_fp(suite, stress, cfix, worker_add_clear);
2023 ptu_run_fp(suite, stress, cfix, worker_add_file_map);
2024 ptu_run_fp(suite, stress, cfix, worker_add_file_clear);
2025
2026 return ptunit_report(&suite);
2027 }
2028