/* Check whether a mapped section contains an address. * * Returns zero if @msec contains @vaddr. * Returns a negative error code otherwise. * Returns -pte_nomap if @msec does not contain @vaddr. */ static inline int pt_image_check_msec(const struct pt_mapped_section *msec, const struct pt_asid *asid, uint64_t vaddr) { const struct pt_asid *masid; uint64_t begin, end; int errcode; if (!msec) return -pte_internal; begin = pt_msec_begin(msec); end = pt_msec_end(msec); if (vaddr < begin || end <= vaddr) return -pte_nomap; masid = pt_msec_asid(msec); errcode = pt_asid_match(masid, asid); if (errcode <= 0) { if (!errcode) errcode = -pte_nomap; return errcode; } return 0; }
int pt_image_validate(const struct pt_image *image, const struct pt_asid *asid, uint64_t vaddr, const struct pt_section *section, uint64_t laddr, int isid) { struct pt_mapped_section *msec; struct pt_section_list *slist; if (!image) return -pte_internal; /* We only look at the top of our LRU stack and accept sporadic * validation fails if @section moved down in the LRU stack or has been * evicted. * * A failed validation requires decoders to re-fetch the section so it * only results in a (relatively small) performance loss. */ slist = image->sections; if (!slist) return -pte_nomap; if (slist->isid != isid) return -pte_nomap; msec = &slist->section; if (pt_msec_section(msec) != section) return -pte_nomap; if (pt_msec_begin(msec) != laddr) return -pte_nomap; return pt_image_check_msec(msec, asid, vaddr); }
static struct ptunit_result begin(struct section_fixture *sfix) { uint64_t begin; begin = pt_msec_begin(&sfix->msec); ptu_uint_eq(begin, sfix->vaddr); return ptu_passed(); }
static struct ptunit_result begin_null(void) { uint64_t begin; begin = pt_msec_begin(NULL); ptu_uint_eq(begin, 0ull); return ptu_passed(); }
static int pt_image_clone(struct pt_section_list **list, const struct pt_mapped_section *msec, uint64_t begin, uint64_t end, int isid) { const struct pt_asid *masid; struct pt_section_list *next; struct pt_section *section, *sec; uint64_t mbegin, sbegin, offset, size; int errcode; if (!list || !msec) return -pte_internal; sec = pt_msec_section(msec); masid = pt_msec_asid(msec); mbegin = pt_msec_begin(msec); sbegin = pt_section_offset(sec); if (end <= begin) return -pte_internal; if (begin < mbegin) return -pte_internal; offset = begin - mbegin; size = end - begin; errcode = pt_section_clone(§ion, sec, sbegin + offset, size); if (errcode < 0) return errcode; next = pt_mk_section_list(section, masid, begin, isid); if (!next) { (void) pt_section_put(section); return -pte_nomem; } /* The image list got its own reference; let's drop ours. */ errcode = pt_section_put(section); if (errcode < 0) { pt_section_list_free(next); return errcode; } /* Add the new section. */ next->next = *list; *list = next; return 0; }
int pt_image_add(struct pt_image *image, struct pt_section *section, const struct pt_asid *asid, uint64_t vaddr) { struct pt_section_list **list, *next; uint64_t begin, end; int errcode; if (!image || !section) return -pte_internal; begin = vaddr; end = begin + pt_section_size(section); /* Check for overlaps while we move to the end of the list. */ for (list = &(image->sections); *list; list = &((*list)->next)) { const struct pt_mapped_section *msec; uint64_t lbegin, lend; msec = &(*list)->section; errcode = pt_msec_matches_asid(msec, asid); if (errcode < 0) return errcode; if (!errcode) continue; lbegin = pt_msec_begin(msec); lend = pt_msec_end(msec); if (end <= lbegin) continue; if (lend <= begin) continue; return -pte_bad_image; } next = pt_mk_section_list(section, asid, vaddr); if (!next) return -pte_nomap; *list = next; return 0; }
int pt_image_find(struct pt_image *image, struct pt_section **psection, uint64_t *laddr, const struct pt_asid *asid, uint64_t vaddr) { struct pt_mapped_section *msec; struct pt_section_list *slist; struct pt_section *section; int errcode; if (!image || !psection || !laddr) return -pte_internal; slist = image->sections; if (!slist) return -pte_nomap; if (!slist->mapped) return pt_image_find_cold(image, psection, laddr, asid, vaddr); msec = &slist->section; errcode = pt_image_check_msec(msec, asid, vaddr); if (errcode < 0) { if (errcode != -pte_nomap) return errcode; return pt_image_find_cold(image, psection, laddr, asid, vaddr); } section = pt_msec_section(msec); errcode = pt_section_get(section); if (errcode < 0) return errcode; *psection = section; *laddr = pt_msec_begin(msec); return slist->isid; }
int pt_image_remove(struct pt_image *image, struct pt_section *section, const struct pt_asid *asid, uint64_t vaddr) { struct pt_section_list **list; if (!image || !section) return -pte_internal; for (list = &image->sections; *list; list = &((*list)->next)) { struct pt_mapped_section *msec; const struct pt_section *sec; const struct pt_asid *masid; struct pt_section_list *trash; uint64_t begin; int errcode; trash = *list; msec = &trash->section; masid = pt_msec_asid(msec); errcode = pt_asid_match(masid, asid); if (errcode < 0) return errcode; if (!errcode) continue; begin = pt_msec_begin(msec); sec = pt_msec_section(msec); if (sec == section && begin == vaddr) { *list = trash->next; pt_section_list_free(trash); return 0; } } return -pte_bad_image; }
int pt_image_add(struct pt_image *image, struct pt_section *section, const struct pt_asid *asid, uint64_t vaddr, int isid) { struct pt_section_list **list, *next, *removed; uint64_t begin, end; int errcode; if (!image || !section) return -pte_internal; next = pt_mk_section_list(section, asid, vaddr, isid); if (!next) return -pte_nomem; removed = NULL; errcode = 0; begin = vaddr; end = begin + pt_section_size(section); /* Check for overlaps while we move to the end of the list. */ list = &(image->sections); while (*list) { const struct pt_mapped_section *msec; const struct pt_asid *masid; struct pt_section_list *current; struct pt_section *lsec; uint64_t lbegin, lend; current = *list; msec = ¤t->section; masid = pt_msec_asid(msec); errcode = pt_asid_match(masid, asid); if (errcode < 0) break; if (!errcode) { list = &((*list)->next); continue; } lbegin = pt_msec_begin(msec); lend = pt_msec_end(msec); if ((end <= lbegin) || (lend <= begin)) { list = &((*list)->next); continue; } /* The new section overlaps with @msec's section. */ lsec = pt_msec_section(msec); /* Let's check for an identical overlap that may be the result * of repeatedly copying images or repeatedly adding the same * file. */ if ((begin == lbegin) && (end == lend) && (isid == current->isid)) { const char *fname, *lfname; fname = pt_section_filename(section); lfname = pt_section_filename(lsec); if (!fname || !lfname) { errcode = -pte_internal; break; } if (strcmp(fname, lfname) == 0) { /* There should not have been any removals or * additions. */ if (removed || next->next) { errcode = -pte_internal; break; } pt_section_list_free(next); return 0; } } /* We remove @msec and insert new sections for the remaining * parts, if any. Those new sections are not mapped initially * and need to be added to the end of the section list. */ *list = current->next; /* Keep a list of removed sections so we can re-add them in case * of errors. */ current->next = removed; removed = current; /* Unmap the removed section. If we need to re-add it, it will * be moved to the end of the section list where the unmapped * sections are. */ if (current->mapped) { pt_section_unmap(lsec); current->mapped = 0; } /* Add a section covering the remaining bytes at the front. * * We preserve the section identifier to indicate that the new * section originated from the original section. */ if (lbegin < begin) { errcode = pt_image_clone(&next, msec, lbegin, begin, current->isid); if (errcode < 0) break; } /* Add a section covering the remaining bytes at the back. * * We preserve the section identifier to indicate that the new * section originated from the original section. */ if (end < lend) { errcode = pt_image_clone(&next, msec, end, lend, current->isid); if (errcode < 0) break; } } if (errcode < 0) { pt_section_list_free_tail(next); /* Re-add removed sections to the tail of the section list. */ for (; *list; list = &((*list)->next)) ; *list = removed; return errcode; } pt_section_list_free_tail(removed); *list = next; return 0; }