174fe6c29SRuslan Bukin /*
285f87cf4SRuslan Bukin * Copyright (c) 2013-2019, Intel Corporation
374fe6c29SRuslan Bukin *
474fe6c29SRuslan Bukin * Redistribution and use in source and binary forms, with or without
574fe6c29SRuslan Bukin * modification, are permitted provided that the following conditions are met:
674fe6c29SRuslan Bukin *
774fe6c29SRuslan Bukin * * Redistributions of source code must retain the above copyright notice,
874fe6c29SRuslan Bukin * this list of conditions and the following disclaimer.
974fe6c29SRuslan Bukin * * Redistributions in binary form must reproduce the above copyright notice,
1074fe6c29SRuslan Bukin * this list of conditions and the following disclaimer in the documentation
1174fe6c29SRuslan Bukin * and/or other materials provided with the distribution.
1274fe6c29SRuslan Bukin * * Neither the name of Intel Corporation nor the names of its contributors
1374fe6c29SRuslan Bukin * may be used to endorse or promote products derived from this software
1474fe6c29SRuslan Bukin * without specific prior written permission.
1574fe6c29SRuslan Bukin *
1674fe6c29SRuslan Bukin * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
1774fe6c29SRuslan Bukin * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1874fe6c29SRuslan Bukin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1974fe6c29SRuslan Bukin * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
2074fe6c29SRuslan Bukin * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2174fe6c29SRuslan Bukin * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2274fe6c29SRuslan Bukin * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2374fe6c29SRuslan Bukin * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2474fe6c29SRuslan Bukin * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2574fe6c29SRuslan Bukin * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2674fe6c29SRuslan Bukin * POSSIBILITY OF SUCH DAMAGE.
2774fe6c29SRuslan Bukin */
2874fe6c29SRuslan Bukin
2974fe6c29SRuslan Bukin #include "pt_image.h"
3074fe6c29SRuslan Bukin #include "pt_section.h"
3174fe6c29SRuslan Bukin #include "pt_asid.h"
3274fe6c29SRuslan Bukin #include "pt_image_section_cache.h"
3374fe6c29SRuslan Bukin
3474fe6c29SRuslan Bukin #include <stdlib.h>
3574fe6c29SRuslan Bukin #include <string.h>
3674fe6c29SRuslan Bukin
3774fe6c29SRuslan Bukin
dupstr(const char * str)3874fe6c29SRuslan Bukin static char *dupstr(const char *str)
3974fe6c29SRuslan Bukin {
4074fe6c29SRuslan Bukin char *dup;
4174fe6c29SRuslan Bukin size_t len;
4274fe6c29SRuslan Bukin
4374fe6c29SRuslan Bukin if (!str)
4474fe6c29SRuslan Bukin return NULL;
4574fe6c29SRuslan Bukin
4685f87cf4SRuslan Bukin /* Silently truncate the name if it gets too big. */
4785f87cf4SRuslan Bukin len = strnlen(str, 4096ul);
4885f87cf4SRuslan Bukin
4974fe6c29SRuslan Bukin dup = malloc(len + 1);
5074fe6c29SRuslan Bukin if (!dup)
5174fe6c29SRuslan Bukin return NULL;
5274fe6c29SRuslan Bukin
5385f87cf4SRuslan Bukin dup[len] = 0;
5485f87cf4SRuslan Bukin
5585f87cf4SRuslan Bukin return memcpy(dup, str, len);
5674fe6c29SRuslan Bukin }
5774fe6c29SRuslan Bukin
pt_mk_section_list(struct pt_section * section,const struct pt_asid * asid,uint64_t vaddr,uint64_t offset,uint64_t size,int isid)5874fe6c29SRuslan Bukin static struct pt_section_list *pt_mk_section_list(struct pt_section *section,
5974fe6c29SRuslan Bukin const struct pt_asid *asid,
6074fe6c29SRuslan Bukin uint64_t vaddr,
6174fe6c29SRuslan Bukin uint64_t offset,
6274fe6c29SRuslan Bukin uint64_t size, int isid)
6374fe6c29SRuslan Bukin {
6474fe6c29SRuslan Bukin struct pt_section_list *list;
6574fe6c29SRuslan Bukin int errcode;
6674fe6c29SRuslan Bukin
6774fe6c29SRuslan Bukin list = malloc(sizeof(*list));
6874fe6c29SRuslan Bukin if (!list)
6974fe6c29SRuslan Bukin return NULL;
7074fe6c29SRuslan Bukin
7174fe6c29SRuslan Bukin memset(list, 0, sizeof(*list));
7274fe6c29SRuslan Bukin
7374fe6c29SRuslan Bukin errcode = pt_section_get(section);
7474fe6c29SRuslan Bukin if (errcode < 0)
7574fe6c29SRuslan Bukin goto out_mem;
7674fe6c29SRuslan Bukin
7774fe6c29SRuslan Bukin pt_msec_init(&list->section, section, asid, vaddr, offset, size);
7874fe6c29SRuslan Bukin list->isid = isid;
7974fe6c29SRuslan Bukin
8074fe6c29SRuslan Bukin return list;
8174fe6c29SRuslan Bukin
8274fe6c29SRuslan Bukin out_mem:
8374fe6c29SRuslan Bukin free(list);
8474fe6c29SRuslan Bukin return NULL;
8574fe6c29SRuslan Bukin }
8674fe6c29SRuslan Bukin
pt_section_list_free(struct pt_section_list * list)8774fe6c29SRuslan Bukin static void pt_section_list_free(struct pt_section_list *list)
8874fe6c29SRuslan Bukin {
8974fe6c29SRuslan Bukin if (!list)
9074fe6c29SRuslan Bukin return;
9174fe6c29SRuslan Bukin
9274fe6c29SRuslan Bukin pt_section_put(list->section.section);
9374fe6c29SRuslan Bukin pt_msec_fini(&list->section);
9474fe6c29SRuslan Bukin free(list);
9574fe6c29SRuslan Bukin }
9674fe6c29SRuslan Bukin
pt_section_list_free_tail(struct pt_section_list * list)9774fe6c29SRuslan Bukin static void pt_section_list_free_tail(struct pt_section_list *list)
9874fe6c29SRuslan Bukin {
9974fe6c29SRuslan Bukin while (list) {
10074fe6c29SRuslan Bukin struct pt_section_list *trash;
10174fe6c29SRuslan Bukin
10274fe6c29SRuslan Bukin trash = list;
10374fe6c29SRuslan Bukin list = list->next;
10474fe6c29SRuslan Bukin
10574fe6c29SRuslan Bukin pt_section_list_free(trash);
10674fe6c29SRuslan Bukin }
10774fe6c29SRuslan Bukin }
10874fe6c29SRuslan Bukin
pt_image_init(struct pt_image * image,const char * name)10974fe6c29SRuslan Bukin void pt_image_init(struct pt_image *image, const char *name)
11074fe6c29SRuslan Bukin {
11174fe6c29SRuslan Bukin if (!image)
11274fe6c29SRuslan Bukin return;
11374fe6c29SRuslan Bukin
11474fe6c29SRuslan Bukin memset(image, 0, sizeof(*image));
11574fe6c29SRuslan Bukin
11674fe6c29SRuslan Bukin image->name = dupstr(name);
11774fe6c29SRuslan Bukin }
11874fe6c29SRuslan Bukin
pt_image_fini(struct pt_image * image)11974fe6c29SRuslan Bukin void pt_image_fini(struct pt_image *image)
12074fe6c29SRuslan Bukin {
12174fe6c29SRuslan Bukin if (!image)
12274fe6c29SRuslan Bukin return;
12374fe6c29SRuslan Bukin
12474fe6c29SRuslan Bukin pt_section_list_free_tail(image->sections);
12574fe6c29SRuslan Bukin free(image->name);
12674fe6c29SRuslan Bukin
12774fe6c29SRuslan Bukin memset(image, 0, sizeof(*image));
12874fe6c29SRuslan Bukin }
12974fe6c29SRuslan Bukin
pt_image_alloc(const char * name)13074fe6c29SRuslan Bukin struct pt_image *pt_image_alloc(const char *name)
13174fe6c29SRuslan Bukin {
13274fe6c29SRuslan Bukin struct pt_image *image;
13374fe6c29SRuslan Bukin
13474fe6c29SRuslan Bukin image = malloc(sizeof(*image));
13574fe6c29SRuslan Bukin if (image)
13674fe6c29SRuslan Bukin pt_image_init(image, name);
13774fe6c29SRuslan Bukin
13874fe6c29SRuslan Bukin return image;
13974fe6c29SRuslan Bukin }
14074fe6c29SRuslan Bukin
pt_image_free(struct pt_image * image)14174fe6c29SRuslan Bukin void pt_image_free(struct pt_image *image)
14274fe6c29SRuslan Bukin {
14374fe6c29SRuslan Bukin pt_image_fini(image);
14474fe6c29SRuslan Bukin free(image);
14574fe6c29SRuslan Bukin }
14674fe6c29SRuslan Bukin
pt_image_name(const struct pt_image * image)14774fe6c29SRuslan Bukin const char *pt_image_name(const struct pt_image *image)
14874fe6c29SRuslan Bukin {
14974fe6c29SRuslan Bukin if (!image)
15074fe6c29SRuslan Bukin return NULL;
15174fe6c29SRuslan Bukin
15274fe6c29SRuslan Bukin return image->name;
15374fe6c29SRuslan Bukin }
15474fe6c29SRuslan Bukin
pt_image_add(struct pt_image * image,struct pt_section * section,const struct pt_asid * asid,uint64_t vaddr,int isid)15574fe6c29SRuslan Bukin int pt_image_add(struct pt_image *image, struct pt_section *section,
15674fe6c29SRuslan Bukin const struct pt_asid *asid, uint64_t vaddr, int isid)
15774fe6c29SRuslan Bukin {
15874fe6c29SRuslan Bukin struct pt_section_list **list, *next, *removed, *new;
15974fe6c29SRuslan Bukin uint64_t size, begin, end;
16074fe6c29SRuslan Bukin int errcode;
16174fe6c29SRuslan Bukin
16274fe6c29SRuslan Bukin if (!image || !section)
16374fe6c29SRuslan Bukin return -pte_internal;
16474fe6c29SRuslan Bukin
16574fe6c29SRuslan Bukin size = pt_section_size(section);
16674fe6c29SRuslan Bukin begin = vaddr;
16774fe6c29SRuslan Bukin end = begin + size;
16874fe6c29SRuslan Bukin
16974fe6c29SRuslan Bukin next = pt_mk_section_list(section, asid, begin, 0ull, size, isid);
17074fe6c29SRuslan Bukin if (!next)
17174fe6c29SRuslan Bukin return -pte_nomem;
17274fe6c29SRuslan Bukin
17374fe6c29SRuslan Bukin removed = NULL;
17474fe6c29SRuslan Bukin errcode = 0;
17574fe6c29SRuslan Bukin
17674fe6c29SRuslan Bukin /* Check for overlaps while we move to the end of the list. */
17774fe6c29SRuslan Bukin list = &(image->sections);
17874fe6c29SRuslan Bukin while (*list) {
17974fe6c29SRuslan Bukin const struct pt_mapped_section *msec;
18074fe6c29SRuslan Bukin const struct pt_asid *masid;
18174fe6c29SRuslan Bukin struct pt_section_list *current;
18274fe6c29SRuslan Bukin struct pt_section *lsec;
18374fe6c29SRuslan Bukin uint64_t lbegin, lend, loff;
18474fe6c29SRuslan Bukin
18574fe6c29SRuslan Bukin current = *list;
18674fe6c29SRuslan Bukin msec = ¤t->section;
18774fe6c29SRuslan Bukin masid = pt_msec_asid(msec);
18874fe6c29SRuslan Bukin
18974fe6c29SRuslan Bukin errcode = pt_asid_match(masid, asid);
19074fe6c29SRuslan Bukin if (errcode < 0)
19174fe6c29SRuslan Bukin break;
19274fe6c29SRuslan Bukin
19374fe6c29SRuslan Bukin if (!errcode) {
19474fe6c29SRuslan Bukin list = &((*list)->next);
19574fe6c29SRuslan Bukin continue;
19674fe6c29SRuslan Bukin }
19774fe6c29SRuslan Bukin
19874fe6c29SRuslan Bukin lbegin = pt_msec_begin(msec);
19974fe6c29SRuslan Bukin lend = pt_msec_end(msec);
20074fe6c29SRuslan Bukin
20174fe6c29SRuslan Bukin if ((end <= lbegin) || (lend <= begin)) {
20274fe6c29SRuslan Bukin list = &((*list)->next);
20374fe6c29SRuslan Bukin continue;
20474fe6c29SRuslan Bukin }
20574fe6c29SRuslan Bukin
20674fe6c29SRuslan Bukin /* The new section overlaps with @msec's section. */
20774fe6c29SRuslan Bukin lsec = pt_msec_section(msec);
20874fe6c29SRuslan Bukin loff = pt_msec_offset(msec);
20974fe6c29SRuslan Bukin
21074fe6c29SRuslan Bukin /* We remove @msec and insert new sections for the remaining
21174fe6c29SRuslan Bukin * parts, if any. Those new sections are not mapped initially
21274fe6c29SRuslan Bukin * and need to be added to the end of the section list.
21374fe6c29SRuslan Bukin */
21474fe6c29SRuslan Bukin *list = current->next;
21574fe6c29SRuslan Bukin
21674fe6c29SRuslan Bukin /* Keep a list of removed sections so we can re-add them in case
21774fe6c29SRuslan Bukin * of errors.
21874fe6c29SRuslan Bukin */
21974fe6c29SRuslan Bukin current->next = removed;
22074fe6c29SRuslan Bukin removed = current;
22174fe6c29SRuslan Bukin
22274fe6c29SRuslan Bukin /* Add a section covering the remaining bytes at the front. */
22374fe6c29SRuslan Bukin if (lbegin < begin) {
22474fe6c29SRuslan Bukin new = pt_mk_section_list(lsec, masid, lbegin, loff,
22574fe6c29SRuslan Bukin begin - lbegin, current->isid);
22674fe6c29SRuslan Bukin if (!new) {
22774fe6c29SRuslan Bukin errcode = -pte_nomem;
22874fe6c29SRuslan Bukin break;
22974fe6c29SRuslan Bukin }
23074fe6c29SRuslan Bukin
23174fe6c29SRuslan Bukin new->next = next;
23274fe6c29SRuslan Bukin next = new;
23374fe6c29SRuslan Bukin }
23474fe6c29SRuslan Bukin
23574fe6c29SRuslan Bukin /* Add a section covering the remaining bytes at the back. */
23674fe6c29SRuslan Bukin if (end < lend) {
23774fe6c29SRuslan Bukin new = pt_mk_section_list(lsec, masid, end,
23874fe6c29SRuslan Bukin loff + (end - lbegin),
23974fe6c29SRuslan Bukin lend - end, current->isid);
24074fe6c29SRuslan Bukin if (!new) {
24174fe6c29SRuslan Bukin errcode = -pte_nomem;
24274fe6c29SRuslan Bukin break;
24374fe6c29SRuslan Bukin }
24474fe6c29SRuslan Bukin
24574fe6c29SRuslan Bukin new->next = next;
24674fe6c29SRuslan Bukin next = new;
24774fe6c29SRuslan Bukin }
24874fe6c29SRuslan Bukin }
24974fe6c29SRuslan Bukin
25074fe6c29SRuslan Bukin if (errcode < 0) {
25174fe6c29SRuslan Bukin pt_section_list_free_tail(next);
25274fe6c29SRuslan Bukin
25374fe6c29SRuslan Bukin /* Re-add removed sections to the tail of the section list. */
25474fe6c29SRuslan Bukin for (; *list; list = &((*list)->next))
25574fe6c29SRuslan Bukin ;
25674fe6c29SRuslan Bukin
25774fe6c29SRuslan Bukin *list = removed;
25874fe6c29SRuslan Bukin return errcode;
25974fe6c29SRuslan Bukin }
26074fe6c29SRuslan Bukin
26174fe6c29SRuslan Bukin pt_section_list_free_tail(removed);
26274fe6c29SRuslan Bukin
26374fe6c29SRuslan Bukin *list = next;
26474fe6c29SRuslan Bukin return 0;
26574fe6c29SRuslan Bukin }
26674fe6c29SRuslan Bukin
pt_image_remove(struct pt_image * image,struct pt_section * section,const struct pt_asid * asid,uint64_t vaddr)26774fe6c29SRuslan Bukin int pt_image_remove(struct pt_image *image, struct pt_section *section,
26874fe6c29SRuslan Bukin const struct pt_asid *asid, uint64_t vaddr)
26974fe6c29SRuslan Bukin {
27074fe6c29SRuslan Bukin struct pt_section_list **list;
27174fe6c29SRuslan Bukin
27274fe6c29SRuslan Bukin if (!image || !section)
27374fe6c29SRuslan Bukin return -pte_internal;
27474fe6c29SRuslan Bukin
27574fe6c29SRuslan Bukin for (list = &image->sections; *list; list = &((*list)->next)) {
27674fe6c29SRuslan Bukin struct pt_mapped_section *msec;
27774fe6c29SRuslan Bukin const struct pt_section *sec;
27874fe6c29SRuslan Bukin const struct pt_asid *masid;
27974fe6c29SRuslan Bukin struct pt_section_list *trash;
28074fe6c29SRuslan Bukin uint64_t begin;
28174fe6c29SRuslan Bukin int errcode;
28274fe6c29SRuslan Bukin
28374fe6c29SRuslan Bukin trash = *list;
28474fe6c29SRuslan Bukin msec = &trash->section;
28574fe6c29SRuslan Bukin masid = pt_msec_asid(msec);
28674fe6c29SRuslan Bukin
28774fe6c29SRuslan Bukin errcode = pt_asid_match(masid, asid);
28874fe6c29SRuslan Bukin if (errcode < 0)
28974fe6c29SRuslan Bukin return errcode;
29074fe6c29SRuslan Bukin
29174fe6c29SRuslan Bukin if (!errcode)
29274fe6c29SRuslan Bukin continue;
29374fe6c29SRuslan Bukin
29474fe6c29SRuslan Bukin begin = pt_msec_begin(msec);
29574fe6c29SRuslan Bukin sec = pt_msec_section(msec);
29674fe6c29SRuslan Bukin if (sec == section && begin == vaddr) {
29774fe6c29SRuslan Bukin *list = trash->next;
29874fe6c29SRuslan Bukin pt_section_list_free(trash);
29974fe6c29SRuslan Bukin
30074fe6c29SRuslan Bukin return 0;
30174fe6c29SRuslan Bukin }
30274fe6c29SRuslan Bukin }
30374fe6c29SRuslan Bukin
30474fe6c29SRuslan Bukin return -pte_bad_image;
30574fe6c29SRuslan Bukin }
30674fe6c29SRuslan Bukin
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)30774fe6c29SRuslan Bukin int pt_image_add_file(struct pt_image *image, const char *filename,
30874fe6c29SRuslan Bukin uint64_t offset, uint64_t size,
30974fe6c29SRuslan Bukin const struct pt_asid *uasid, uint64_t vaddr)
31074fe6c29SRuslan Bukin {
31174fe6c29SRuslan Bukin struct pt_section *section;
31274fe6c29SRuslan Bukin struct pt_asid asid;
31374fe6c29SRuslan Bukin int errcode;
31474fe6c29SRuslan Bukin
31574fe6c29SRuslan Bukin if (!image || !filename)
31674fe6c29SRuslan Bukin return -pte_invalid;
31774fe6c29SRuslan Bukin
31874fe6c29SRuslan Bukin errcode = pt_asid_from_user(&asid, uasid);
31974fe6c29SRuslan Bukin if (errcode < 0)
32074fe6c29SRuslan Bukin return errcode;
32174fe6c29SRuslan Bukin
32285f87cf4SRuslan Bukin section = NULL;
32385f87cf4SRuslan Bukin errcode = pt_mk_section(§ion, filename, offset, size);
32485f87cf4SRuslan Bukin if (errcode < 0)
32585f87cf4SRuslan Bukin return errcode;
32674fe6c29SRuslan Bukin
32774fe6c29SRuslan Bukin errcode = pt_image_add(image, section, &asid, vaddr, 0);
32874fe6c29SRuslan Bukin if (errcode < 0) {
32974fe6c29SRuslan Bukin (void) pt_section_put(section);
33074fe6c29SRuslan Bukin return errcode;
33174fe6c29SRuslan Bukin }
33274fe6c29SRuslan Bukin
33374fe6c29SRuslan Bukin /* The image list got its own reference; let's drop ours. */
33474fe6c29SRuslan Bukin errcode = pt_section_put(section);
33574fe6c29SRuslan Bukin if (errcode < 0)
33674fe6c29SRuslan Bukin return errcode;
33774fe6c29SRuslan Bukin
33874fe6c29SRuslan Bukin return 0;
33974fe6c29SRuslan Bukin }
34074fe6c29SRuslan Bukin
pt_image_copy(struct pt_image * image,const struct pt_image * src)34174fe6c29SRuslan Bukin int pt_image_copy(struct pt_image *image, const struct pt_image *src)
34274fe6c29SRuslan Bukin {
34374fe6c29SRuslan Bukin struct pt_section_list *list;
34474fe6c29SRuslan Bukin int ignored;
34574fe6c29SRuslan Bukin
34674fe6c29SRuslan Bukin if (!image || !src)
34774fe6c29SRuslan Bukin return -pte_invalid;
34874fe6c29SRuslan Bukin
34974fe6c29SRuslan Bukin /* There is nothing to do if we copy an image to itself.
35074fe6c29SRuslan Bukin *
35174fe6c29SRuslan Bukin * Besides, pt_image_add() may move sections around, which would
35274fe6c29SRuslan Bukin * interfere with our section iteration.
35374fe6c29SRuslan Bukin */
35474fe6c29SRuslan Bukin if (image == src)
35574fe6c29SRuslan Bukin return 0;
35674fe6c29SRuslan Bukin
35774fe6c29SRuslan Bukin ignored = 0;
35874fe6c29SRuslan Bukin for (list = src->sections; list; list = list->next) {
35974fe6c29SRuslan Bukin int errcode;
36074fe6c29SRuslan Bukin
36174fe6c29SRuslan Bukin errcode = pt_image_add(image, list->section.section,
36274fe6c29SRuslan Bukin &list->section.asid,
36374fe6c29SRuslan Bukin list->section.vaddr,
36474fe6c29SRuslan Bukin list->isid);
36574fe6c29SRuslan Bukin if (errcode < 0)
36674fe6c29SRuslan Bukin ignored += 1;
36774fe6c29SRuslan Bukin }
36874fe6c29SRuslan Bukin
36974fe6c29SRuslan Bukin return ignored;
37074fe6c29SRuslan Bukin }
37174fe6c29SRuslan Bukin
pt_image_remove_by_filename(struct pt_image * image,const char * filename,const struct pt_asid * uasid)37274fe6c29SRuslan Bukin int pt_image_remove_by_filename(struct pt_image *image, const char *filename,
37374fe6c29SRuslan Bukin const struct pt_asid *uasid)
37474fe6c29SRuslan Bukin {
37574fe6c29SRuslan Bukin struct pt_section_list **list;
37674fe6c29SRuslan Bukin struct pt_asid asid;
37774fe6c29SRuslan Bukin int errcode, removed;
37874fe6c29SRuslan Bukin
37974fe6c29SRuslan Bukin if (!image || !filename)
38074fe6c29SRuslan Bukin return -pte_invalid;
38174fe6c29SRuslan Bukin
38274fe6c29SRuslan Bukin errcode = pt_asid_from_user(&asid, uasid);
38374fe6c29SRuslan Bukin if (errcode < 0)
38474fe6c29SRuslan Bukin return errcode;
38574fe6c29SRuslan Bukin
38674fe6c29SRuslan Bukin removed = 0;
38774fe6c29SRuslan Bukin for (list = &image->sections; *list;) {
38874fe6c29SRuslan Bukin struct pt_mapped_section *msec;
38974fe6c29SRuslan Bukin const struct pt_section *sec;
39074fe6c29SRuslan Bukin const struct pt_asid *masid;
39174fe6c29SRuslan Bukin struct pt_section_list *trash;
39274fe6c29SRuslan Bukin const char *tname;
39374fe6c29SRuslan Bukin
39474fe6c29SRuslan Bukin trash = *list;
39574fe6c29SRuslan Bukin msec = &trash->section;
39674fe6c29SRuslan Bukin masid = pt_msec_asid(msec);
39774fe6c29SRuslan Bukin
39874fe6c29SRuslan Bukin errcode = pt_asid_match(masid, &asid);
39974fe6c29SRuslan Bukin if (errcode < 0)
40074fe6c29SRuslan Bukin return errcode;
40174fe6c29SRuslan Bukin
40274fe6c29SRuslan Bukin if (!errcode) {
40374fe6c29SRuslan Bukin list = &trash->next;
40474fe6c29SRuslan Bukin continue;
40574fe6c29SRuslan Bukin }
40674fe6c29SRuslan Bukin
40774fe6c29SRuslan Bukin sec = pt_msec_section(msec);
40874fe6c29SRuslan Bukin tname = pt_section_filename(sec);
40974fe6c29SRuslan Bukin
41074fe6c29SRuslan Bukin if (tname && (strcmp(tname, filename) == 0)) {
41174fe6c29SRuslan Bukin *list = trash->next;
41274fe6c29SRuslan Bukin pt_section_list_free(trash);
41374fe6c29SRuslan Bukin
41474fe6c29SRuslan Bukin removed += 1;
41574fe6c29SRuslan Bukin } else
41674fe6c29SRuslan Bukin list = &trash->next;
41774fe6c29SRuslan Bukin }
41874fe6c29SRuslan Bukin
41974fe6c29SRuslan Bukin return removed;
42074fe6c29SRuslan Bukin }
42174fe6c29SRuslan Bukin
pt_image_remove_by_asid(struct pt_image * image,const struct pt_asid * uasid)42274fe6c29SRuslan Bukin int pt_image_remove_by_asid(struct pt_image *image,
42374fe6c29SRuslan Bukin const struct pt_asid *uasid)
42474fe6c29SRuslan Bukin {
42574fe6c29SRuslan Bukin struct pt_section_list **list;
42674fe6c29SRuslan Bukin struct pt_asid asid;
42774fe6c29SRuslan Bukin int errcode, removed;
42874fe6c29SRuslan Bukin
42974fe6c29SRuslan Bukin if (!image)
43074fe6c29SRuslan Bukin return -pte_invalid;
43174fe6c29SRuslan Bukin
43274fe6c29SRuslan Bukin errcode = pt_asid_from_user(&asid, uasid);
43374fe6c29SRuslan Bukin if (errcode < 0)
43474fe6c29SRuslan Bukin return errcode;
43574fe6c29SRuslan Bukin
43674fe6c29SRuslan Bukin removed = 0;
43774fe6c29SRuslan Bukin for (list = &image->sections; *list;) {
43874fe6c29SRuslan Bukin struct pt_mapped_section *msec;
43974fe6c29SRuslan Bukin const struct pt_asid *masid;
44074fe6c29SRuslan Bukin struct pt_section_list *trash;
44174fe6c29SRuslan Bukin
44274fe6c29SRuslan Bukin trash = *list;
44374fe6c29SRuslan Bukin msec = &trash->section;
44474fe6c29SRuslan Bukin masid = pt_msec_asid(msec);
44574fe6c29SRuslan Bukin
44674fe6c29SRuslan Bukin errcode = pt_asid_match(masid, &asid);
44774fe6c29SRuslan Bukin if (errcode < 0)
44874fe6c29SRuslan Bukin return errcode;
44974fe6c29SRuslan Bukin
45074fe6c29SRuslan Bukin if (!errcode) {
45174fe6c29SRuslan Bukin list = &trash->next;
45274fe6c29SRuslan Bukin continue;
45374fe6c29SRuslan Bukin }
45474fe6c29SRuslan Bukin
45574fe6c29SRuslan Bukin *list = trash->next;
45674fe6c29SRuslan Bukin pt_section_list_free(trash);
45774fe6c29SRuslan Bukin
45874fe6c29SRuslan Bukin removed += 1;
45974fe6c29SRuslan Bukin }
46074fe6c29SRuslan Bukin
46174fe6c29SRuslan Bukin return removed;
46274fe6c29SRuslan Bukin }
46374fe6c29SRuslan Bukin
pt_image_set_callback(struct pt_image * image,read_memory_callback_t * callback,void * context)46474fe6c29SRuslan Bukin int pt_image_set_callback(struct pt_image *image,
46574fe6c29SRuslan Bukin read_memory_callback_t *callback, void *context)
46674fe6c29SRuslan Bukin {
46774fe6c29SRuslan Bukin if (!image)
46874fe6c29SRuslan Bukin return -pte_invalid;
46974fe6c29SRuslan Bukin
47074fe6c29SRuslan Bukin image->readmem.callback = callback;
47174fe6c29SRuslan Bukin image->readmem.context = context;
47274fe6c29SRuslan Bukin
47374fe6c29SRuslan Bukin return 0;
47474fe6c29SRuslan Bukin }
47574fe6c29SRuslan Bukin
pt_image_read_callback(struct pt_image * image,int * isid,uint8_t * buffer,uint16_t size,const struct pt_asid * asid,uint64_t addr)47674fe6c29SRuslan Bukin static int pt_image_read_callback(struct pt_image *image, int *isid,
47774fe6c29SRuslan Bukin uint8_t *buffer, uint16_t size,
47874fe6c29SRuslan Bukin const struct pt_asid *asid, uint64_t addr)
47974fe6c29SRuslan Bukin {
48074fe6c29SRuslan Bukin read_memory_callback_t *callback;
48174fe6c29SRuslan Bukin
48274fe6c29SRuslan Bukin if (!image || !isid)
48374fe6c29SRuslan Bukin return -pte_internal;
48474fe6c29SRuslan Bukin
48574fe6c29SRuslan Bukin callback = image->readmem.callback;
48674fe6c29SRuslan Bukin if (!callback)
48774fe6c29SRuslan Bukin return -pte_nomap;
48874fe6c29SRuslan Bukin
48974fe6c29SRuslan Bukin *isid = 0;
49074fe6c29SRuslan Bukin
49174fe6c29SRuslan Bukin return callback(buffer, size, asid, addr, image->readmem.context);
49274fe6c29SRuslan Bukin }
49374fe6c29SRuslan Bukin
49474fe6c29SRuslan Bukin /* Check whether a mapped section contains an address.
49574fe6c29SRuslan Bukin *
49674fe6c29SRuslan Bukin * Returns zero if @msec contains @vaddr.
49774fe6c29SRuslan Bukin * Returns a negative error code otherwise.
49874fe6c29SRuslan Bukin * Returns -pte_nomap if @msec does not contain @vaddr.
49974fe6c29SRuslan Bukin */
pt_image_check_msec(const struct pt_mapped_section * msec,const struct pt_asid * asid,uint64_t vaddr)50074fe6c29SRuslan Bukin static inline int pt_image_check_msec(const struct pt_mapped_section *msec,
50174fe6c29SRuslan Bukin const struct pt_asid *asid,
50274fe6c29SRuslan Bukin uint64_t vaddr)
50374fe6c29SRuslan Bukin {
50474fe6c29SRuslan Bukin const struct pt_asid *masid;
50574fe6c29SRuslan Bukin uint64_t begin, end;
50674fe6c29SRuslan Bukin int errcode;
50774fe6c29SRuslan Bukin
50874fe6c29SRuslan Bukin if (!msec)
50974fe6c29SRuslan Bukin return -pte_internal;
51074fe6c29SRuslan Bukin
51174fe6c29SRuslan Bukin begin = pt_msec_begin(msec);
51274fe6c29SRuslan Bukin end = pt_msec_end(msec);
51374fe6c29SRuslan Bukin if (vaddr < begin || end <= vaddr)
51474fe6c29SRuslan Bukin return -pte_nomap;
51574fe6c29SRuslan Bukin
51674fe6c29SRuslan Bukin masid = pt_msec_asid(msec);
51774fe6c29SRuslan Bukin errcode = pt_asid_match(masid, asid);
51874fe6c29SRuslan Bukin if (errcode <= 0) {
51974fe6c29SRuslan Bukin if (!errcode)
52074fe6c29SRuslan Bukin errcode = -pte_nomap;
52174fe6c29SRuslan Bukin
52274fe6c29SRuslan Bukin return errcode;
52374fe6c29SRuslan Bukin }
52474fe6c29SRuslan Bukin
52574fe6c29SRuslan Bukin return 0;
52674fe6c29SRuslan Bukin }
52774fe6c29SRuslan Bukin
52874fe6c29SRuslan Bukin /* Find the section containing a given address in a given address space.
52974fe6c29SRuslan Bukin *
53074fe6c29SRuslan Bukin * On success, the found section is moved to the front of the section list.
53174fe6c29SRuslan Bukin * If caching is enabled, maps the section.
53274fe6c29SRuslan Bukin *
53374fe6c29SRuslan Bukin * Returns zero on success, a negative error code otherwise.
53474fe6c29SRuslan Bukin */
pt_image_fetch_section(struct pt_image * image,const struct pt_asid * asid,uint64_t vaddr)53574fe6c29SRuslan Bukin static int pt_image_fetch_section(struct pt_image *image,
53674fe6c29SRuslan Bukin const struct pt_asid *asid, uint64_t vaddr)
53774fe6c29SRuslan Bukin {
53874fe6c29SRuslan Bukin struct pt_section_list **start, **list;
53974fe6c29SRuslan Bukin
54074fe6c29SRuslan Bukin if (!image)
54174fe6c29SRuslan Bukin return -pte_internal;
54274fe6c29SRuslan Bukin
54374fe6c29SRuslan Bukin start = &image->sections;
54474fe6c29SRuslan Bukin for (list = start; *list;) {
54574fe6c29SRuslan Bukin struct pt_mapped_section *msec;
54674fe6c29SRuslan Bukin struct pt_section_list *elem;
54774fe6c29SRuslan Bukin int errcode;
54874fe6c29SRuslan Bukin
54974fe6c29SRuslan Bukin elem = *list;
55074fe6c29SRuslan Bukin msec = &elem->section;
55174fe6c29SRuslan Bukin
55274fe6c29SRuslan Bukin errcode = pt_image_check_msec(msec, asid, vaddr);
55374fe6c29SRuslan Bukin if (errcode < 0) {
55474fe6c29SRuslan Bukin if (errcode != -pte_nomap)
55574fe6c29SRuslan Bukin return errcode;
55674fe6c29SRuslan Bukin
55774fe6c29SRuslan Bukin list = &elem->next;
55874fe6c29SRuslan Bukin continue;
55974fe6c29SRuslan Bukin }
56074fe6c29SRuslan Bukin
56174fe6c29SRuslan Bukin /* Move the section to the front if it isn't already. */
56274fe6c29SRuslan Bukin if (list != start) {
56374fe6c29SRuslan Bukin *list = elem->next;
56474fe6c29SRuslan Bukin elem->next = *start;
56574fe6c29SRuslan Bukin *start = elem;
56674fe6c29SRuslan Bukin }
56774fe6c29SRuslan Bukin
56874fe6c29SRuslan Bukin return 0;
56974fe6c29SRuslan Bukin }
57074fe6c29SRuslan Bukin
57174fe6c29SRuslan Bukin return -pte_nomap;
57274fe6c29SRuslan Bukin }
57374fe6c29SRuslan Bukin
pt_image_read(struct pt_image * image,int * isid,uint8_t * buffer,uint16_t size,const struct pt_asid * asid,uint64_t addr)57474fe6c29SRuslan Bukin int pt_image_read(struct pt_image *image, int *isid, uint8_t *buffer,
57574fe6c29SRuslan Bukin uint16_t size, const struct pt_asid *asid, uint64_t addr)
57674fe6c29SRuslan Bukin {
57774fe6c29SRuslan Bukin struct pt_mapped_section *msec;
57874fe6c29SRuslan Bukin struct pt_section_list *slist;
57974fe6c29SRuslan Bukin struct pt_section *section;
58074fe6c29SRuslan Bukin int errcode, status;
58174fe6c29SRuslan Bukin
58274fe6c29SRuslan Bukin if (!image || !isid)
58374fe6c29SRuslan Bukin return -pte_internal;
58474fe6c29SRuslan Bukin
58574fe6c29SRuslan Bukin errcode = pt_image_fetch_section(image, asid, addr);
58674fe6c29SRuslan Bukin if (errcode < 0) {
58774fe6c29SRuslan Bukin if (errcode != -pte_nomap)
58874fe6c29SRuslan Bukin return errcode;
58974fe6c29SRuslan Bukin
59074fe6c29SRuslan Bukin return pt_image_read_callback(image, isid, buffer, size, asid,
59174fe6c29SRuslan Bukin addr);
59274fe6c29SRuslan Bukin }
59374fe6c29SRuslan Bukin
59474fe6c29SRuslan Bukin slist = image->sections;
59574fe6c29SRuslan Bukin if (!slist)
59674fe6c29SRuslan Bukin return -pte_internal;
59774fe6c29SRuslan Bukin
59874fe6c29SRuslan Bukin *isid = slist->isid;
59974fe6c29SRuslan Bukin msec = &slist->section;
60074fe6c29SRuslan Bukin
60174fe6c29SRuslan Bukin section = pt_msec_section(msec);
60274fe6c29SRuslan Bukin
60374fe6c29SRuslan Bukin errcode = pt_section_map(section);
60474fe6c29SRuslan Bukin if (errcode < 0)
60574fe6c29SRuslan Bukin return errcode;
60674fe6c29SRuslan Bukin
60774fe6c29SRuslan Bukin status = pt_msec_read(msec, buffer, size, addr);
60874fe6c29SRuslan Bukin
60974fe6c29SRuslan Bukin errcode = pt_section_unmap(section);
61074fe6c29SRuslan Bukin if (errcode < 0)
61174fe6c29SRuslan Bukin return errcode;
61274fe6c29SRuslan Bukin
61374fe6c29SRuslan Bukin if (status < 0) {
61474fe6c29SRuslan Bukin if (status != -pte_nomap)
61574fe6c29SRuslan Bukin return status;
61674fe6c29SRuslan Bukin
61774fe6c29SRuslan Bukin return pt_image_read_callback(image, isid, buffer, size, asid,
61874fe6c29SRuslan Bukin addr);
61974fe6c29SRuslan Bukin }
62074fe6c29SRuslan Bukin
62174fe6c29SRuslan Bukin return status;
62274fe6c29SRuslan Bukin }
62374fe6c29SRuslan Bukin
pt_image_add_cached(struct pt_image * image,struct pt_image_section_cache * iscache,int isid,const struct pt_asid * uasid)62474fe6c29SRuslan Bukin int pt_image_add_cached(struct pt_image *image,
62574fe6c29SRuslan Bukin struct pt_image_section_cache *iscache, int isid,
62674fe6c29SRuslan Bukin const struct pt_asid *uasid)
62774fe6c29SRuslan Bukin {
62874fe6c29SRuslan Bukin struct pt_section *section;
62974fe6c29SRuslan Bukin struct pt_asid asid;
63074fe6c29SRuslan Bukin uint64_t vaddr;
63174fe6c29SRuslan Bukin int errcode, status;
63274fe6c29SRuslan Bukin
63374fe6c29SRuslan Bukin if (!image || !iscache)
63474fe6c29SRuslan Bukin return -pte_invalid;
63574fe6c29SRuslan Bukin
63674fe6c29SRuslan Bukin errcode = pt_iscache_lookup(iscache, §ion, &vaddr, isid);
63774fe6c29SRuslan Bukin if (errcode < 0)
63874fe6c29SRuslan Bukin return errcode;
63974fe6c29SRuslan Bukin
64074fe6c29SRuslan Bukin errcode = pt_asid_from_user(&asid, uasid);
64174fe6c29SRuslan Bukin if (errcode < 0)
64274fe6c29SRuslan Bukin return errcode;
64374fe6c29SRuslan Bukin
64474fe6c29SRuslan Bukin status = pt_image_add(image, section, &asid, vaddr, isid);
64574fe6c29SRuslan Bukin
64674fe6c29SRuslan Bukin /* We grab a reference when we add the section. Drop the one we
64774fe6c29SRuslan Bukin * obtained from cache lookup.
64874fe6c29SRuslan Bukin */
64974fe6c29SRuslan Bukin errcode = pt_section_put(section);
65074fe6c29SRuslan Bukin if (errcode < 0)
65174fe6c29SRuslan Bukin return errcode;
65274fe6c29SRuslan Bukin
65374fe6c29SRuslan Bukin return status;
65474fe6c29SRuslan Bukin }
65574fe6c29SRuslan Bukin
pt_image_find(struct pt_image * image,struct pt_mapped_section * usec,const struct pt_asid * asid,uint64_t vaddr)65674fe6c29SRuslan Bukin int pt_image_find(struct pt_image *image, struct pt_mapped_section *usec,
65774fe6c29SRuslan Bukin const struct pt_asid *asid, uint64_t vaddr)
65874fe6c29SRuslan Bukin {
65974fe6c29SRuslan Bukin struct pt_mapped_section *msec;
66074fe6c29SRuslan Bukin struct pt_section_list *slist;
66174fe6c29SRuslan Bukin struct pt_section *section;
66274fe6c29SRuslan Bukin int errcode;
66374fe6c29SRuslan Bukin
66474fe6c29SRuslan Bukin if (!image || !usec)
66574fe6c29SRuslan Bukin return -pte_internal;
66674fe6c29SRuslan Bukin
66774fe6c29SRuslan Bukin errcode = pt_image_fetch_section(image, asid, vaddr);
66874fe6c29SRuslan Bukin if (errcode < 0)
66974fe6c29SRuslan Bukin return errcode;
67074fe6c29SRuslan Bukin
67174fe6c29SRuslan Bukin slist = image->sections;
67274fe6c29SRuslan Bukin if (!slist)
67374fe6c29SRuslan Bukin return -pte_internal;
67474fe6c29SRuslan Bukin
67574fe6c29SRuslan Bukin msec = &slist->section;
67674fe6c29SRuslan Bukin section = pt_msec_section(msec);
67774fe6c29SRuslan Bukin
67874fe6c29SRuslan Bukin errcode = pt_section_get(section);
67974fe6c29SRuslan Bukin if (errcode < 0)
68074fe6c29SRuslan Bukin return errcode;
68174fe6c29SRuslan Bukin
68274fe6c29SRuslan Bukin *usec = *msec;
68374fe6c29SRuslan Bukin
68474fe6c29SRuslan Bukin return slist->isid;
68574fe6c29SRuslan Bukin }
68674fe6c29SRuslan Bukin
pt_image_validate(const struct pt_image * image,const struct pt_mapped_section * usec,uint64_t vaddr,int isid)68774fe6c29SRuslan Bukin int pt_image_validate(const struct pt_image *image,
68874fe6c29SRuslan Bukin const struct pt_mapped_section *usec, uint64_t vaddr,
68974fe6c29SRuslan Bukin int isid)
69074fe6c29SRuslan Bukin {
69174fe6c29SRuslan Bukin const struct pt_section_list *slist;
69274fe6c29SRuslan Bukin uint64_t begin, end;
69374fe6c29SRuslan Bukin int status;
69474fe6c29SRuslan Bukin
69574fe6c29SRuslan Bukin if (!image || !usec)
69674fe6c29SRuslan Bukin return -pte_internal;
69774fe6c29SRuslan Bukin
69874fe6c29SRuslan Bukin /* Check that @vaddr lies within @usec. */
69974fe6c29SRuslan Bukin begin = pt_msec_begin(usec);
70074fe6c29SRuslan Bukin end = pt_msec_end(usec);
70174fe6c29SRuslan Bukin if (vaddr < begin || end <= vaddr)
70274fe6c29SRuslan Bukin return -pte_nomap;
70374fe6c29SRuslan Bukin
70474fe6c29SRuslan Bukin /* We assume that @usec is a copy of the top of our stack and accept
70574fe6c29SRuslan Bukin * sporadic validation fails if it isn't, e.g. because it has moved
70674fe6c29SRuslan Bukin * down.
70774fe6c29SRuslan Bukin *
70874fe6c29SRuslan Bukin * A failed validation requires decoders to re-fetch the section so it
70974fe6c29SRuslan Bukin * only results in a (relatively small) performance loss.
71074fe6c29SRuslan Bukin */
71174fe6c29SRuslan Bukin slist = image->sections;
71274fe6c29SRuslan Bukin if (!slist)
71374fe6c29SRuslan Bukin return -pte_nomap;
71474fe6c29SRuslan Bukin
71574fe6c29SRuslan Bukin if (slist->isid != isid)
71674fe6c29SRuslan Bukin return -pte_nomap;
71774fe6c29SRuslan Bukin
71874fe6c29SRuslan Bukin status = memcmp(&slist->section, usec, sizeof(*usec));
71974fe6c29SRuslan Bukin if (status)
72074fe6c29SRuslan Bukin return -pte_nomap;
72174fe6c29SRuslan Bukin
72274fe6c29SRuslan Bukin return 0;
72374fe6c29SRuslan Bukin }
724