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