1 /*
2 * Copyright (c) 2013-2019, 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.h"
30 #include "pt_section.h"
31 #include "pt_asid.h"
32 #include "pt_image_section_cache.h"
33
34 #include <stdlib.h>
35 #include <string.h>
36
37
dupstr(const char * str)38 static char *dupstr(const char *str)
39 {
40 char *dup;
41 size_t len;
42
43 if (!str)
44 return NULL;
45
46 /* Silently truncate the name if it gets too big. */
47 len = strnlen(str, 4096ul);
48
49 dup = malloc(len + 1);
50 if (!dup)
51 return NULL;
52
53 dup[len] = 0;
54
55 return memcpy(dup, str, len);
56 }
57
pt_mk_section_list(struct pt_section * section,const struct pt_asid * asid,uint64_t vaddr,uint64_t offset,uint64_t size,int isid)58 static struct pt_section_list *pt_mk_section_list(struct pt_section *section,
59 const struct pt_asid *asid,
60 uint64_t vaddr,
61 uint64_t offset,
62 uint64_t size, int isid)
63 {
64 struct pt_section_list *list;
65 int errcode;
66
67 list = malloc(sizeof(*list));
68 if (!list)
69 return NULL;
70
71 memset(list, 0, sizeof(*list));
72
73 errcode = pt_section_get(section);
74 if (errcode < 0)
75 goto out_mem;
76
77 pt_msec_init(&list->section, section, asid, vaddr, offset, size);
78 list->isid = isid;
79
80 return list;
81
82 out_mem:
83 free(list);
84 return NULL;
85 }
86
pt_section_list_free(struct pt_section_list * list)87 static void pt_section_list_free(struct pt_section_list *list)
88 {
89 if (!list)
90 return;
91
92 pt_section_put(list->section.section);
93 pt_msec_fini(&list->section);
94 free(list);
95 }
96
pt_section_list_free_tail(struct pt_section_list * list)97 static void pt_section_list_free_tail(struct pt_section_list *list)
98 {
99 while (list) {
100 struct pt_section_list *trash;
101
102 trash = list;
103 list = list->next;
104
105 pt_section_list_free(trash);
106 }
107 }
108
pt_image_init(struct pt_image * image,const char * name)109 void pt_image_init(struct pt_image *image, const char *name)
110 {
111 if (!image)
112 return;
113
114 memset(image, 0, sizeof(*image));
115
116 image->name = dupstr(name);
117 }
118
pt_image_fini(struct pt_image * image)119 void pt_image_fini(struct pt_image *image)
120 {
121 if (!image)
122 return;
123
124 pt_section_list_free_tail(image->sections);
125 free(image->name);
126
127 memset(image, 0, sizeof(*image));
128 }
129
pt_image_alloc(const char * name)130 struct pt_image *pt_image_alloc(const char *name)
131 {
132 struct pt_image *image;
133
134 image = malloc(sizeof(*image));
135 if (image)
136 pt_image_init(image, name);
137
138 return image;
139 }
140
pt_image_free(struct pt_image * image)141 void pt_image_free(struct pt_image *image)
142 {
143 pt_image_fini(image);
144 free(image);
145 }
146
pt_image_name(const struct pt_image * image)147 const char *pt_image_name(const struct pt_image *image)
148 {
149 if (!image)
150 return NULL;
151
152 return image->name;
153 }
154
pt_image_add(struct pt_image * image,struct pt_section * section,const struct pt_asid * asid,uint64_t vaddr,int isid)155 int pt_image_add(struct pt_image *image, struct pt_section *section,
156 const struct pt_asid *asid, uint64_t vaddr, int isid)
157 {
158 struct pt_section_list **list, *next, *removed, *new;
159 uint64_t size, begin, end;
160 int errcode;
161
162 if (!image || !section)
163 return -pte_internal;
164
165 size = pt_section_size(section);
166 begin = vaddr;
167 end = begin + size;
168
169 next = pt_mk_section_list(section, asid, begin, 0ull, size, isid);
170 if (!next)
171 return -pte_nomem;
172
173 removed = NULL;
174 errcode = 0;
175
176 /* Check for overlaps while we move to the end of the list. */
177 list = &(image->sections);
178 while (*list) {
179 const struct pt_mapped_section *msec;
180 const struct pt_asid *masid;
181 struct pt_section_list *current;
182 struct pt_section *lsec;
183 uint64_t lbegin, lend, loff;
184
185 current = *list;
186 msec = ¤t->section;
187 masid = pt_msec_asid(msec);
188
189 errcode = pt_asid_match(masid, asid);
190 if (errcode < 0)
191 break;
192
193 if (!errcode) {
194 list = &((*list)->next);
195 continue;
196 }
197
198 lbegin = pt_msec_begin(msec);
199 lend = pt_msec_end(msec);
200
201 if ((end <= lbegin) || (lend <= begin)) {
202 list = &((*list)->next);
203 continue;
204 }
205
206 /* The new section overlaps with @msec's section. */
207 lsec = pt_msec_section(msec);
208 loff = pt_msec_offset(msec);
209
210 /* We remove @msec and insert new sections for the remaining
211 * parts, if any. Those new sections are not mapped initially
212 * and need to be added to the end of the section list.
213 */
214 *list = current->next;
215
216 /* Keep a list of removed sections so we can re-add them in case
217 * of errors.
218 */
219 current->next = removed;
220 removed = current;
221
222 /* Add a section covering the remaining bytes at the front. */
223 if (lbegin < begin) {
224 new = pt_mk_section_list(lsec, masid, lbegin, loff,
225 begin - lbegin, current->isid);
226 if (!new) {
227 errcode = -pte_nomem;
228 break;
229 }
230
231 new->next = next;
232 next = new;
233 }
234
235 /* Add a section covering the remaining bytes at the back. */
236 if (end < lend) {
237 new = pt_mk_section_list(lsec, masid, end,
238 loff + (end - lbegin),
239 lend - end, current->isid);
240 if (!new) {
241 errcode = -pte_nomem;
242 break;
243 }
244
245 new->next = next;
246 next = new;
247 }
248 }
249
250 if (errcode < 0) {
251 pt_section_list_free_tail(next);
252
253 /* Re-add removed sections to the tail of the section list. */
254 for (; *list; list = &((*list)->next))
255 ;
256
257 *list = removed;
258 return errcode;
259 }
260
261 pt_section_list_free_tail(removed);
262
263 *list = next;
264 return 0;
265 }
266
pt_image_remove(struct pt_image * image,struct pt_section * section,const struct pt_asid * asid,uint64_t vaddr)267 int pt_image_remove(struct pt_image *image, struct pt_section *section,
268 const struct pt_asid *asid, uint64_t vaddr)
269 {
270 struct pt_section_list **list;
271
272 if (!image || !section)
273 return -pte_internal;
274
275 for (list = &image->sections; *list; list = &((*list)->next)) {
276 struct pt_mapped_section *msec;
277 const struct pt_section *sec;
278 const struct pt_asid *masid;
279 struct pt_section_list *trash;
280 uint64_t begin;
281 int errcode;
282
283 trash = *list;
284 msec = &trash->section;
285 masid = pt_msec_asid(msec);
286
287 errcode = pt_asid_match(masid, asid);
288 if (errcode < 0)
289 return errcode;
290
291 if (!errcode)
292 continue;
293
294 begin = pt_msec_begin(msec);
295 sec = pt_msec_section(msec);
296 if (sec == section && begin == vaddr) {
297 *list = trash->next;
298 pt_section_list_free(trash);
299
300 return 0;
301 }
302 }
303
304 return -pte_bad_image;
305 }
306
pt_image_add_file(struct pt_image * image,const char * filename,uint64_t offset,uint64_t size,const struct pt_asid * uasid,uint64_t vaddr)307 int pt_image_add_file(struct pt_image *image, const char *filename,
308 uint64_t offset, uint64_t size,
309 const struct pt_asid *uasid, uint64_t vaddr)
310 {
311 struct pt_section *section;
312 struct pt_asid asid;
313 int errcode;
314
315 if (!image || !filename)
316 return -pte_invalid;
317
318 errcode = pt_asid_from_user(&asid, uasid);
319 if (errcode < 0)
320 return errcode;
321
322 section = NULL;
323 errcode = pt_mk_section(§ion, filename, offset, size);
324 if (errcode < 0)
325 return errcode;
326
327 errcode = pt_image_add(image, section, &asid, vaddr, 0);
328 if (errcode < 0) {
329 (void) pt_section_put(section);
330 return errcode;
331 }
332
333 /* The image list got its own reference; let's drop ours. */
334 errcode = pt_section_put(section);
335 if (errcode < 0)
336 return errcode;
337
338 return 0;
339 }
340
pt_image_copy(struct pt_image * image,const struct pt_image * src)341 int pt_image_copy(struct pt_image *image, const struct pt_image *src)
342 {
343 struct pt_section_list *list;
344 int ignored;
345
346 if (!image || !src)
347 return -pte_invalid;
348
349 /* There is nothing to do if we copy an image to itself.
350 *
351 * Besides, pt_image_add() may move sections around, which would
352 * interfere with our section iteration.
353 */
354 if (image == src)
355 return 0;
356
357 ignored = 0;
358 for (list = src->sections; list; list = list->next) {
359 int errcode;
360
361 errcode = pt_image_add(image, list->section.section,
362 &list->section.asid,
363 list->section.vaddr,
364 list->isid);
365 if (errcode < 0)
366 ignored += 1;
367 }
368
369 return ignored;
370 }
371
pt_image_remove_by_filename(struct pt_image * image,const char * filename,const struct pt_asid * uasid)372 int pt_image_remove_by_filename(struct pt_image *image, const char *filename,
373 const struct pt_asid *uasid)
374 {
375 struct pt_section_list **list;
376 struct pt_asid asid;
377 int errcode, removed;
378
379 if (!image || !filename)
380 return -pte_invalid;
381
382 errcode = pt_asid_from_user(&asid, uasid);
383 if (errcode < 0)
384 return errcode;
385
386 removed = 0;
387 for (list = &image->sections; *list;) {
388 struct pt_mapped_section *msec;
389 const struct pt_section *sec;
390 const struct pt_asid *masid;
391 struct pt_section_list *trash;
392 const char *tname;
393
394 trash = *list;
395 msec = &trash->section;
396 masid = pt_msec_asid(msec);
397
398 errcode = pt_asid_match(masid, &asid);
399 if (errcode < 0)
400 return errcode;
401
402 if (!errcode) {
403 list = &trash->next;
404 continue;
405 }
406
407 sec = pt_msec_section(msec);
408 tname = pt_section_filename(sec);
409
410 if (tname && (strcmp(tname, filename) == 0)) {
411 *list = trash->next;
412 pt_section_list_free(trash);
413
414 removed += 1;
415 } else
416 list = &trash->next;
417 }
418
419 return removed;
420 }
421
pt_image_remove_by_asid(struct pt_image * image,const struct pt_asid * uasid)422 int pt_image_remove_by_asid(struct pt_image *image,
423 const struct pt_asid *uasid)
424 {
425 struct pt_section_list **list;
426 struct pt_asid asid;
427 int errcode, removed;
428
429 if (!image)
430 return -pte_invalid;
431
432 errcode = pt_asid_from_user(&asid, uasid);
433 if (errcode < 0)
434 return errcode;
435
436 removed = 0;
437 for (list = &image->sections; *list;) {
438 struct pt_mapped_section *msec;
439 const struct pt_asid *masid;
440 struct pt_section_list *trash;
441
442 trash = *list;
443 msec = &trash->section;
444 masid = pt_msec_asid(msec);
445
446 errcode = pt_asid_match(masid, &asid);
447 if (errcode < 0)
448 return errcode;
449
450 if (!errcode) {
451 list = &trash->next;
452 continue;
453 }
454
455 *list = trash->next;
456 pt_section_list_free(trash);
457
458 removed += 1;
459 }
460
461 return removed;
462 }
463
pt_image_set_callback(struct pt_image * image,read_memory_callback_t * callback,void * context)464 int pt_image_set_callback(struct pt_image *image,
465 read_memory_callback_t *callback, void *context)
466 {
467 if (!image)
468 return -pte_invalid;
469
470 image->readmem.callback = callback;
471 image->readmem.context = context;
472
473 return 0;
474 }
475
pt_image_read_callback(struct pt_image * image,int * isid,uint8_t * buffer,uint16_t size,const struct pt_asid * asid,uint64_t addr)476 static int pt_image_read_callback(struct pt_image *image, int *isid,
477 uint8_t *buffer, uint16_t size,
478 const struct pt_asid *asid, uint64_t addr)
479 {
480 read_memory_callback_t *callback;
481
482 if (!image || !isid)
483 return -pte_internal;
484
485 callback = image->readmem.callback;
486 if (!callback)
487 return -pte_nomap;
488
489 *isid = 0;
490
491 return callback(buffer, size, asid, addr, image->readmem.context);
492 }
493
494 /* Check whether a mapped section contains an address.
495 *
496 * Returns zero if @msec contains @vaddr.
497 * Returns a negative error code otherwise.
498 * Returns -pte_nomap if @msec does not contain @vaddr.
499 */
pt_image_check_msec(const struct pt_mapped_section * msec,const struct pt_asid * asid,uint64_t vaddr)500 static inline int pt_image_check_msec(const struct pt_mapped_section *msec,
501 const struct pt_asid *asid,
502 uint64_t vaddr)
503 {
504 const struct pt_asid *masid;
505 uint64_t begin, end;
506 int errcode;
507
508 if (!msec)
509 return -pte_internal;
510
511 begin = pt_msec_begin(msec);
512 end = pt_msec_end(msec);
513 if (vaddr < begin || end <= vaddr)
514 return -pte_nomap;
515
516 masid = pt_msec_asid(msec);
517 errcode = pt_asid_match(masid, asid);
518 if (errcode <= 0) {
519 if (!errcode)
520 errcode = -pte_nomap;
521
522 return errcode;
523 }
524
525 return 0;
526 }
527
528 /* Find the section containing a given address in a given address space.
529 *
530 * On success, the found section is moved to the front of the section list.
531 * If caching is enabled, maps the section.
532 *
533 * Returns zero on success, a negative error code otherwise.
534 */
pt_image_fetch_section(struct pt_image * image,const struct pt_asid * asid,uint64_t vaddr)535 static int pt_image_fetch_section(struct pt_image *image,
536 const struct pt_asid *asid, uint64_t vaddr)
537 {
538 struct pt_section_list **start, **list;
539
540 if (!image)
541 return -pte_internal;
542
543 start = &image->sections;
544 for (list = start; *list;) {
545 struct pt_mapped_section *msec;
546 struct pt_section_list *elem;
547 int errcode;
548
549 elem = *list;
550 msec = &elem->section;
551
552 errcode = pt_image_check_msec(msec, asid, vaddr);
553 if (errcode < 0) {
554 if (errcode != -pte_nomap)
555 return errcode;
556
557 list = &elem->next;
558 continue;
559 }
560
561 /* Move the section to the front if it isn't already. */
562 if (list != start) {
563 *list = elem->next;
564 elem->next = *start;
565 *start = elem;
566 }
567
568 return 0;
569 }
570
571 return -pte_nomap;
572 }
573
pt_image_read(struct pt_image * image,int * isid,uint8_t * buffer,uint16_t size,const struct pt_asid * asid,uint64_t addr)574 int pt_image_read(struct pt_image *image, int *isid, uint8_t *buffer,
575 uint16_t size, const struct pt_asid *asid, uint64_t addr)
576 {
577 struct pt_mapped_section *msec;
578 struct pt_section_list *slist;
579 struct pt_section *section;
580 int errcode, status;
581
582 if (!image || !isid)
583 return -pte_internal;
584
585 errcode = pt_image_fetch_section(image, asid, addr);
586 if (errcode < 0) {
587 if (errcode != -pte_nomap)
588 return errcode;
589
590 return pt_image_read_callback(image, isid, buffer, size, asid,
591 addr);
592 }
593
594 slist = image->sections;
595 if (!slist)
596 return -pte_internal;
597
598 *isid = slist->isid;
599 msec = &slist->section;
600
601 section = pt_msec_section(msec);
602
603 errcode = pt_section_map(section);
604 if (errcode < 0)
605 return errcode;
606
607 status = pt_msec_read(msec, buffer, size, addr);
608
609 errcode = pt_section_unmap(section);
610 if (errcode < 0)
611 return errcode;
612
613 if (status < 0) {
614 if (status != -pte_nomap)
615 return status;
616
617 return pt_image_read_callback(image, isid, buffer, size, asid,
618 addr);
619 }
620
621 return status;
622 }
623
pt_image_add_cached(struct pt_image * image,struct pt_image_section_cache * iscache,int isid,const struct pt_asid * uasid)624 int pt_image_add_cached(struct pt_image *image,
625 struct pt_image_section_cache *iscache, int isid,
626 const struct pt_asid *uasid)
627 {
628 struct pt_section *section;
629 struct pt_asid asid;
630 uint64_t vaddr;
631 int errcode, status;
632
633 if (!image || !iscache)
634 return -pte_invalid;
635
636 errcode = pt_iscache_lookup(iscache, §ion, &vaddr, isid);
637 if (errcode < 0)
638 return errcode;
639
640 errcode = pt_asid_from_user(&asid, uasid);
641 if (errcode < 0)
642 return errcode;
643
644 status = pt_image_add(image, section, &asid, vaddr, isid);
645
646 /* We grab a reference when we add the section. Drop the one we
647 * obtained from cache lookup.
648 */
649 errcode = pt_section_put(section);
650 if (errcode < 0)
651 return errcode;
652
653 return status;
654 }
655
pt_image_find(struct pt_image * image,struct pt_mapped_section * usec,const struct pt_asid * asid,uint64_t vaddr)656 int pt_image_find(struct pt_image *image, struct pt_mapped_section *usec,
657 const struct pt_asid *asid, uint64_t vaddr)
658 {
659 struct pt_mapped_section *msec;
660 struct pt_section_list *slist;
661 struct pt_section *section;
662 int errcode;
663
664 if (!image || !usec)
665 return -pte_internal;
666
667 errcode = pt_image_fetch_section(image, asid, vaddr);
668 if (errcode < 0)
669 return errcode;
670
671 slist = image->sections;
672 if (!slist)
673 return -pte_internal;
674
675 msec = &slist->section;
676 section = pt_msec_section(msec);
677
678 errcode = pt_section_get(section);
679 if (errcode < 0)
680 return errcode;
681
682 *usec = *msec;
683
684 return slist->isid;
685 }
686
pt_image_validate(const struct pt_image * image,const struct pt_mapped_section * usec,uint64_t vaddr,int isid)687 int pt_image_validate(const struct pt_image *image,
688 const struct pt_mapped_section *usec, uint64_t vaddr,
689 int isid)
690 {
691 const struct pt_section_list *slist;
692 uint64_t begin, end;
693 int status;
694
695 if (!image || !usec)
696 return -pte_internal;
697
698 /* Check that @vaddr lies within @usec. */
699 begin = pt_msec_begin(usec);
700 end = pt_msec_end(usec);
701 if (vaddr < begin || end <= vaddr)
702 return -pte_nomap;
703
704 /* We assume that @usec is a copy of the top of our stack and accept
705 * sporadic validation fails if it isn't, e.g. because it has moved
706 * down.
707 *
708 * A failed validation requires decoders to re-fetch the section so it
709 * only results in a (relatively small) performance loss.
710 */
711 slist = image->sections;
712 if (!slist)
713 return -pte_nomap;
714
715 if (slist->isid != isid)
716 return -pte_nomap;
717
718 status = memcmp(&slist->section, usec, sizeof(*usec));
719 if (status)
720 return -pte_nomap;
721
722 return 0;
723 }
724