2 * Copyright (c) 2013-2018, Intel Corporation
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
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.
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.
30 #include "pt_section.h"
32 #include "pt_image_section_cache.h"
38 static char *dupstr(const char *str)
47 dup = malloc(len + 1);
51 return strcpy(dup, str);
54 static struct pt_section_list *pt_mk_section_list(struct pt_section *section,
55 const struct pt_asid *asid,
58 uint64_t size, int isid)
60 struct pt_section_list *list;
63 list = malloc(sizeof(*list));
67 memset(list, 0, sizeof(*list));
69 errcode = pt_section_get(section);
73 pt_msec_init(&list->section, section, asid, vaddr, offset, size);
83 static void pt_section_list_free(struct pt_section_list *list)
88 pt_section_put(list->section.section);
89 pt_msec_fini(&list->section);
93 static void pt_section_list_free_tail(struct pt_section_list *list)
96 struct pt_section_list *trash;
101 pt_section_list_free(trash);
105 void pt_image_init(struct pt_image *image, const char *name)
110 memset(image, 0, sizeof(*image));
112 image->name = dupstr(name);
115 void pt_image_fini(struct pt_image *image)
120 pt_section_list_free_tail(image->sections);
123 memset(image, 0, sizeof(*image));
126 struct pt_image *pt_image_alloc(const char *name)
128 struct pt_image *image;
130 image = malloc(sizeof(*image));
132 pt_image_init(image, name);
137 void pt_image_free(struct pt_image *image)
139 pt_image_fini(image);
143 const char *pt_image_name(const struct pt_image *image)
151 int pt_image_add(struct pt_image *image, struct pt_section *section,
152 const struct pt_asid *asid, uint64_t vaddr, int isid)
154 struct pt_section_list **list, *next, *removed, *new;
155 uint64_t size, begin, end;
158 if (!image || !section)
159 return -pte_internal;
161 size = pt_section_size(section);
165 next = pt_mk_section_list(section, asid, begin, 0ull, size, isid);
172 /* Check for overlaps while we move to the end of the list. */
173 list = &(image->sections);
175 const struct pt_mapped_section *msec;
176 const struct pt_asid *masid;
177 struct pt_section_list *current;
178 struct pt_section *lsec;
179 uint64_t lbegin, lend, loff;
182 msec = ¤t->section;
183 masid = pt_msec_asid(msec);
185 errcode = pt_asid_match(masid, asid);
190 list = &((*list)->next);
194 lbegin = pt_msec_begin(msec);
195 lend = pt_msec_end(msec);
197 if ((end <= lbegin) || (lend <= begin)) {
198 list = &((*list)->next);
202 /* The new section overlaps with @msec's section. */
203 lsec = pt_msec_section(msec);
204 loff = pt_msec_offset(msec);
206 /* We remove @msec and insert new sections for the remaining
207 * parts, if any. Those new sections are not mapped initially
208 * and need to be added to the end of the section list.
210 *list = current->next;
212 /* Keep a list of removed sections so we can re-add them in case
215 current->next = removed;
218 /* Add a section covering the remaining bytes at the front. */
219 if (lbegin < begin) {
220 new = pt_mk_section_list(lsec, masid, lbegin, loff,
221 begin - lbegin, current->isid);
223 errcode = -pte_nomem;
231 /* Add a section covering the remaining bytes at the back. */
233 new = pt_mk_section_list(lsec, masid, end,
234 loff + (end - lbegin),
235 lend - end, current->isid);
237 errcode = -pte_nomem;
247 pt_section_list_free_tail(next);
249 /* Re-add removed sections to the tail of the section list. */
250 for (; *list; list = &((*list)->next))
257 pt_section_list_free_tail(removed);
263 int pt_image_remove(struct pt_image *image, struct pt_section *section,
264 const struct pt_asid *asid, uint64_t vaddr)
266 struct pt_section_list **list;
268 if (!image || !section)
269 return -pte_internal;
271 for (list = &image->sections; *list; list = &((*list)->next)) {
272 struct pt_mapped_section *msec;
273 const struct pt_section *sec;
274 const struct pt_asid *masid;
275 struct pt_section_list *trash;
280 msec = &trash->section;
281 masid = pt_msec_asid(msec);
283 errcode = pt_asid_match(masid, asid);
290 begin = pt_msec_begin(msec);
291 sec = pt_msec_section(msec);
292 if (sec == section && begin == vaddr) {
294 pt_section_list_free(trash);
300 return -pte_bad_image;
303 int pt_image_add_file(struct pt_image *image, const char *filename,
304 uint64_t offset, uint64_t size,
305 const struct pt_asid *uasid, uint64_t vaddr)
307 struct pt_section *section;
311 if (!image || !filename)
314 errcode = pt_asid_from_user(&asid, uasid);
318 section = pt_mk_section(filename, offset, size);
322 errcode = pt_image_add(image, section, &asid, vaddr, 0);
324 (void) pt_section_put(section);
328 /* The image list got its own reference; let's drop ours. */
329 errcode = pt_section_put(section);
336 int pt_image_copy(struct pt_image *image, const struct pt_image *src)
338 struct pt_section_list *list;
344 /* There is nothing to do if we copy an image to itself.
346 * Besides, pt_image_add() may move sections around, which would
347 * interfere with our section iteration.
353 for (list = src->sections; list; list = list->next) {
356 errcode = pt_image_add(image, list->section.section,
367 int pt_image_remove_by_filename(struct pt_image *image, const char *filename,
368 const struct pt_asid *uasid)
370 struct pt_section_list **list;
372 int errcode, removed;
374 if (!image || !filename)
377 errcode = pt_asid_from_user(&asid, uasid);
382 for (list = &image->sections; *list;) {
383 struct pt_mapped_section *msec;
384 const struct pt_section *sec;
385 const struct pt_asid *masid;
386 struct pt_section_list *trash;
390 msec = &trash->section;
391 masid = pt_msec_asid(msec);
393 errcode = pt_asid_match(masid, &asid);
402 sec = pt_msec_section(msec);
403 tname = pt_section_filename(sec);
405 if (tname && (strcmp(tname, filename) == 0)) {
407 pt_section_list_free(trash);
417 int pt_image_remove_by_asid(struct pt_image *image,
418 const struct pt_asid *uasid)
420 struct pt_section_list **list;
422 int errcode, removed;
427 errcode = pt_asid_from_user(&asid, uasid);
432 for (list = &image->sections; *list;) {
433 struct pt_mapped_section *msec;
434 const struct pt_asid *masid;
435 struct pt_section_list *trash;
438 msec = &trash->section;
439 masid = pt_msec_asid(msec);
441 errcode = pt_asid_match(masid, &asid);
451 pt_section_list_free(trash);
459 int pt_image_set_callback(struct pt_image *image,
460 read_memory_callback_t *callback, void *context)
465 image->readmem.callback = callback;
466 image->readmem.context = context;
471 static int pt_image_read_callback(struct pt_image *image, int *isid,
472 uint8_t *buffer, uint16_t size,
473 const struct pt_asid *asid, uint64_t addr)
475 read_memory_callback_t *callback;
478 return -pte_internal;
480 callback = image->readmem.callback;
486 return callback(buffer, size, asid, addr, image->readmem.context);
489 /* Check whether a mapped section contains an address.
491 * Returns zero if @msec contains @vaddr.
492 * Returns a negative error code otherwise.
493 * Returns -pte_nomap if @msec does not contain @vaddr.
495 static inline int pt_image_check_msec(const struct pt_mapped_section *msec,
496 const struct pt_asid *asid,
499 const struct pt_asid *masid;
504 return -pte_internal;
506 begin = pt_msec_begin(msec);
507 end = pt_msec_end(msec);
508 if (vaddr < begin || end <= vaddr)
511 masid = pt_msec_asid(msec);
512 errcode = pt_asid_match(masid, asid);
515 errcode = -pte_nomap;
523 /* Find the section containing a given address in a given address space.
525 * On success, the found section is moved to the front of the section list.
526 * If caching is enabled, maps the section.
528 * Returns zero on success, a negative error code otherwise.
530 static int pt_image_fetch_section(struct pt_image *image,
531 const struct pt_asid *asid, uint64_t vaddr)
533 struct pt_section_list **start, **list;
536 return -pte_internal;
538 start = &image->sections;
539 for (list = start; *list;) {
540 struct pt_mapped_section *msec;
541 struct pt_section_list *elem;
545 msec = &elem->section;
547 errcode = pt_image_check_msec(msec, asid, vaddr);
549 if (errcode != -pte_nomap)
556 /* Move the section to the front if it isn't already. */
569 int pt_image_read(struct pt_image *image, int *isid, uint8_t *buffer,
570 uint16_t size, const struct pt_asid *asid, uint64_t addr)
572 struct pt_mapped_section *msec;
573 struct pt_section_list *slist;
574 struct pt_section *section;
578 return -pte_internal;
580 errcode = pt_image_fetch_section(image, asid, addr);
582 if (errcode != -pte_nomap)
585 return pt_image_read_callback(image, isid, buffer, size, asid,
589 slist = image->sections;
591 return -pte_internal;
594 msec = &slist->section;
596 section = pt_msec_section(msec);
598 errcode = pt_section_map(section);
602 status = pt_msec_read(msec, buffer, size, addr);
604 errcode = pt_section_unmap(section);
609 if (status != -pte_nomap)
612 return pt_image_read_callback(image, isid, buffer, size, asid,
619 int pt_image_add_cached(struct pt_image *image,
620 struct pt_image_section_cache *iscache, int isid,
621 const struct pt_asid *uasid)
623 struct pt_section *section;
628 if (!image || !iscache)
631 errcode = pt_iscache_lookup(iscache, §ion, &vaddr, isid);
635 errcode = pt_asid_from_user(&asid, uasid);
639 status = pt_image_add(image, section, &asid, vaddr, isid);
641 /* We grab a reference when we add the section. Drop the one we
642 * obtained from cache lookup.
644 errcode = pt_section_put(section);
651 int pt_image_find(struct pt_image *image, struct pt_mapped_section *usec,
652 const struct pt_asid *asid, uint64_t vaddr)
654 struct pt_mapped_section *msec;
655 struct pt_section_list *slist;
656 struct pt_section *section;
660 return -pte_internal;
662 errcode = pt_image_fetch_section(image, asid, vaddr);
666 slist = image->sections;
668 return -pte_internal;
670 msec = &slist->section;
671 section = pt_msec_section(msec);
673 errcode = pt_section_get(section);
682 int pt_image_validate(const struct pt_image *image,
683 const struct pt_mapped_section *usec, uint64_t vaddr,
686 const struct pt_section_list *slist;
691 return -pte_internal;
693 /* Check that @vaddr lies within @usec. */
694 begin = pt_msec_begin(usec);
695 end = pt_msec_end(usec);
696 if (vaddr < begin || end <= vaddr)
699 /* We assume that @usec is a copy of the top of our stack and accept
700 * sporadic validation fails if it isn't, e.g. because it has moved
703 * A failed validation requires decoders to re-fetch the section so it
704 * only results in a (relatively small) performance loss.
706 slist = image->sections;
710 if (slist->isid != isid)
713 status = memcmp(&slist->section, usec, sizeof(*usec));