Blame libipt/src/pt_image.c

Packit b1f7ae
/*
Packit b1f7ae
 * Copyright (c) 2013-2017, Intel Corporation
Packit b1f7ae
 *
Packit b1f7ae
 * Redistribution and use in source and binary forms, with or without
Packit b1f7ae
 * modification, are permitted provided that the following conditions are met:
Packit b1f7ae
 *
Packit b1f7ae
 *  * Redistributions of source code must retain the above copyright notice,
Packit b1f7ae
 *    this list of conditions and the following disclaimer.
Packit b1f7ae
 *  * Redistributions in binary form must reproduce the above copyright notice,
Packit b1f7ae
 *    this list of conditions and the following disclaimer in the documentation
Packit b1f7ae
 *    and/or other materials provided with the distribution.
Packit b1f7ae
 *  * Neither the name of Intel Corporation nor the names of its contributors
Packit b1f7ae
 *    may be used to endorse or promote products derived from this software
Packit b1f7ae
 *    without specific prior written permission.
Packit b1f7ae
 *
Packit b1f7ae
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
Packit b1f7ae
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
Packit b1f7ae
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
Packit b1f7ae
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
Packit b1f7ae
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
Packit b1f7ae
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
Packit b1f7ae
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
Packit b1f7ae
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
Packit b1f7ae
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
Packit b1f7ae
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
Packit b1f7ae
 * POSSIBILITY OF SUCH DAMAGE.
Packit b1f7ae
 */
Packit b1f7ae
Packit b1f7ae
#include "pt_image.h"
Packit b1f7ae
#include "pt_section.h"
Packit b1f7ae
#include "pt_asid.h"
Packit b1f7ae
#include "pt_image_section_cache.h"
Packit b1f7ae
Packit b1f7ae
#include <stdlib.h>
Packit b1f7ae
#include <string.h>
Packit b1f7ae
Packit b1f7ae
Packit b1f7ae
static char *dupstr(const char *str)
Packit b1f7ae
{
Packit b1f7ae
	char *dup;
Packit b1f7ae
	size_t len;
Packit b1f7ae
Packit b1f7ae
	if (!str)
Packit b1f7ae
		return NULL;
Packit b1f7ae
Packit b1f7ae
	len = strlen(str);
Packit b1f7ae
	dup = malloc(len + 1);
Packit b1f7ae
	if (!dup)
Packit b1f7ae
		return NULL;
Packit b1f7ae
Packit b1f7ae
	return strcpy(dup, str);
Packit b1f7ae
}
Packit b1f7ae
Packit b1f7ae
static struct pt_section_list *pt_mk_section_list(struct pt_section *section,
Packit b1f7ae
						  const struct pt_asid *asid,
Packit b1f7ae
						  uint64_t vaddr, int isid)
Packit b1f7ae
{
Packit b1f7ae
	struct pt_section_list *list;
Packit b1f7ae
	int errcode;
Packit b1f7ae
Packit b1f7ae
	list = malloc(sizeof(*list));
Packit b1f7ae
	if (!list)
Packit b1f7ae
		return NULL;
Packit b1f7ae
Packit b1f7ae
	memset(list, 0, sizeof(*list));
Packit b1f7ae
Packit b1f7ae
	errcode = pt_section_get(section);
Packit b1f7ae
	if (errcode < 0)
Packit b1f7ae
		goto out_mem;
Packit b1f7ae
Packit b1f7ae
	pt_msec_init(&list->section, section, asid, vaddr);
Packit b1f7ae
	list->isid = isid;
Packit b1f7ae
Packit b1f7ae
	return list;
Packit b1f7ae
Packit b1f7ae
out_mem:
Packit b1f7ae
	free(list);
Packit b1f7ae
	return NULL;
Packit b1f7ae
}
Packit b1f7ae
Packit b1f7ae
static void pt_section_list_free(struct pt_section_list *list)
Packit b1f7ae
{
Packit b1f7ae
	if (!list)
Packit b1f7ae
		return;
Packit b1f7ae
Packit b1f7ae
	if (list->mapped)
Packit b1f7ae
		pt_section_unmap(list->section.section);
Packit b1f7ae
	pt_section_put(list->section.section);
Packit b1f7ae
	pt_msec_fini(&list->section);
Packit b1f7ae
	free(list);
Packit b1f7ae
}
Packit b1f7ae
Packit b1f7ae
static void pt_section_list_free_tail(struct pt_section_list *list)
Packit b1f7ae
{
Packit b1f7ae
	while (list) {
Packit b1f7ae
		struct pt_section_list *trash;
Packit b1f7ae
Packit b1f7ae
		trash = list;
Packit b1f7ae
		list = list->next;
Packit b1f7ae
Packit b1f7ae
		pt_section_list_free(trash);
Packit b1f7ae
	}
Packit b1f7ae
}
Packit b1f7ae
Packit b1f7ae
void pt_image_init(struct pt_image *image, const char *name)
Packit b1f7ae
{
Packit b1f7ae
	if (!image)
Packit b1f7ae
		return;
Packit b1f7ae
Packit b1f7ae
	memset(image, 0, sizeof(*image));
Packit b1f7ae
Packit b1f7ae
	image->name = dupstr(name);
Packit b1f7ae
	image->cache = 10;
Packit b1f7ae
}
Packit b1f7ae
Packit b1f7ae
void pt_image_fini(struct pt_image *image)
Packit b1f7ae
{
Packit b1f7ae
	if (!image)
Packit b1f7ae
		return;
Packit b1f7ae
Packit b1f7ae
	pt_section_list_free_tail(image->sections);
Packit b1f7ae
	free(image->name);
Packit b1f7ae
Packit b1f7ae
	memset(image, 0, sizeof(*image));
Packit b1f7ae
}
Packit b1f7ae
Packit b1f7ae
struct pt_image *pt_image_alloc(const char *name)
Packit b1f7ae
{
Packit b1f7ae
	struct pt_image *image;
Packit b1f7ae
Packit b1f7ae
	image = malloc(sizeof(*image));
Packit b1f7ae
	if (image)
Packit b1f7ae
		pt_image_init(image, name);
Packit b1f7ae
Packit b1f7ae
	return image;
Packit b1f7ae
}
Packit b1f7ae
Packit b1f7ae
void pt_image_free(struct pt_image *image)
Packit b1f7ae
{
Packit b1f7ae
	pt_image_fini(image);
Packit b1f7ae
	free(image);
Packit b1f7ae
}
Packit b1f7ae
Packit b1f7ae
const char *pt_image_name(const struct pt_image *image)
Packit b1f7ae
{
Packit b1f7ae
	if (!image)
Packit b1f7ae
		return NULL;
Packit b1f7ae
Packit b1f7ae
	return image->name;
Packit b1f7ae
}
Packit b1f7ae
Packit b1f7ae
static int pt_image_clone(struct pt_section_list **list,
Packit b1f7ae
			  const struct pt_mapped_section *msec,
Packit b1f7ae
			  uint64_t begin, uint64_t end, int isid)
Packit b1f7ae
{
Packit b1f7ae
	const struct pt_asid *masid;
Packit b1f7ae
	struct pt_section_list *next;
Packit b1f7ae
	struct pt_section *section, *sec;
Packit b1f7ae
	uint64_t mbegin, sbegin, offset, size;
Packit b1f7ae
	int errcode;
Packit b1f7ae
Packit b1f7ae
	if (!list || !msec)
Packit b1f7ae
		return -pte_internal;
Packit b1f7ae
Packit b1f7ae
	sec = pt_msec_section(msec);
Packit b1f7ae
	masid = pt_msec_asid(msec);
Packit b1f7ae
	mbegin = pt_msec_begin(msec);
Packit b1f7ae
	sbegin = pt_section_offset(sec);
Packit b1f7ae
Packit b1f7ae
	if (end <= begin)
Packit b1f7ae
		return -pte_internal;
Packit b1f7ae
Packit b1f7ae
	if (begin < mbegin)
Packit b1f7ae
		return -pte_internal;
Packit b1f7ae
Packit b1f7ae
	offset = begin - mbegin;
Packit b1f7ae
	size = end - begin;
Packit b1f7ae
Packit b1f7ae
	errcode = pt_section_clone(&section, sec, sbegin + offset, size);
Packit b1f7ae
	if (errcode < 0)
Packit b1f7ae
		return errcode;
Packit b1f7ae
Packit b1f7ae
	next = pt_mk_section_list(section, masid, begin, isid);
Packit b1f7ae
	if (!next) {
Packit b1f7ae
		(void) pt_section_put(section);
Packit b1f7ae
Packit b1f7ae
		return -pte_nomem;
Packit b1f7ae
	}
Packit b1f7ae
Packit b1f7ae
	/* The image list got its own reference; let's drop ours. */
Packit b1f7ae
	errcode = pt_section_put(section);
Packit b1f7ae
	if (errcode < 0) {
Packit b1f7ae
		pt_section_list_free(next);
Packit b1f7ae
Packit b1f7ae
		return errcode;
Packit b1f7ae
	}
Packit b1f7ae
Packit b1f7ae
	/* Add the new section. */
Packit b1f7ae
	next->next = *list;
Packit b1f7ae
	*list = next;
Packit b1f7ae
Packit b1f7ae
	return 0;
Packit b1f7ae
}
Packit b1f7ae
Packit b1f7ae
int pt_image_add(struct pt_image *image, struct pt_section *section,
Packit b1f7ae
		 const struct pt_asid *asid, uint64_t vaddr, int isid)
Packit b1f7ae
{
Packit b1f7ae
	struct pt_section_list **list, *next, *removed;
Packit b1f7ae
	uint64_t begin, end;
Packit b1f7ae
	int errcode;
Packit b1f7ae
Packit b1f7ae
	if (!image || !section)
Packit b1f7ae
		return -pte_internal;
Packit b1f7ae
Packit b1f7ae
	next = pt_mk_section_list(section, asid, vaddr, isid);
Packit b1f7ae
	if (!next)
Packit b1f7ae
		return -pte_nomem;
Packit b1f7ae
Packit b1f7ae
	removed = NULL;
Packit b1f7ae
	errcode = 0;
Packit b1f7ae
Packit b1f7ae
	begin = vaddr;
Packit b1f7ae
	end = begin + pt_section_size(section);
Packit b1f7ae
Packit b1f7ae
	/* Check for overlaps while we move to the end of the list. */
Packit b1f7ae
	list = &(image->sections);
Packit b1f7ae
	while (*list) {
Packit b1f7ae
		const struct pt_mapped_section *msec;
Packit b1f7ae
		const struct pt_asid *masid;
Packit b1f7ae
		struct pt_section_list *current;
Packit b1f7ae
		struct pt_section *lsec;
Packit b1f7ae
		uint64_t lbegin, lend;
Packit b1f7ae
Packit b1f7ae
		current = *list;
Packit b1f7ae
		msec = &current->section;
Packit b1f7ae
		masid = pt_msec_asid(msec);
Packit b1f7ae
Packit b1f7ae
		errcode = pt_asid_match(masid, asid);
Packit b1f7ae
		if (errcode < 0)
Packit b1f7ae
			break;
Packit b1f7ae
Packit b1f7ae
		if (!errcode) {
Packit b1f7ae
			list = &((*list)->next);
Packit b1f7ae
			continue;
Packit b1f7ae
		}
Packit b1f7ae
Packit b1f7ae
		lbegin = pt_msec_begin(msec);
Packit b1f7ae
		lend = pt_msec_end(msec);
Packit b1f7ae
Packit b1f7ae
		if ((end <= lbegin) || (lend <= begin)) {
Packit b1f7ae
			list = &((*list)->next);
Packit b1f7ae
			continue;
Packit b1f7ae
		}
Packit b1f7ae
Packit b1f7ae
		/* The new section overlaps with @msec's section. */
Packit b1f7ae
		lsec = pt_msec_section(msec);
Packit b1f7ae
Packit b1f7ae
		/* Let's check for an identical overlap that may be the result
Packit b1f7ae
		 * of repeatedly copying images or repeatedly adding the same
Packit b1f7ae
		 * file.
Packit b1f7ae
		 */
Packit b1f7ae
		if ((begin == lbegin) && (end == lend) &&
Packit b1f7ae
		    (isid == current->isid)) {
Packit b1f7ae
			const char *fname, *lfname;
Packit b1f7ae
Packit b1f7ae
			fname = pt_section_filename(section);
Packit b1f7ae
			lfname = pt_section_filename(lsec);
Packit b1f7ae
Packit b1f7ae
			if (!fname || !lfname) {
Packit b1f7ae
				errcode = -pte_internal;
Packit b1f7ae
				break;
Packit b1f7ae
			}
Packit b1f7ae
Packit b1f7ae
			if (strcmp(fname, lfname) == 0) {
Packit b1f7ae
				/* There should not have been any removals or
Packit b1f7ae
				 * additions.
Packit b1f7ae
				 */
Packit b1f7ae
				if (removed || next->next) {
Packit b1f7ae
					errcode = -pte_internal;
Packit b1f7ae
					break;
Packit b1f7ae
				}
Packit b1f7ae
Packit b1f7ae
				pt_section_list_free(next);
Packit b1f7ae
				return 0;
Packit b1f7ae
			}
Packit b1f7ae
		}
Packit b1f7ae
Packit b1f7ae
		/* We remove @msec and insert new sections for the remaining
Packit b1f7ae
		 * parts, if any.  Those new sections are not mapped initially
Packit b1f7ae
		 * and need to be added to the end of the section list.
Packit b1f7ae
		 */
Packit b1f7ae
		*list = current->next;
Packit b1f7ae
Packit b1f7ae
		/* Keep a list of removed sections so we can re-add them in case
Packit b1f7ae
		 * of errors.
Packit b1f7ae
		 */
Packit b1f7ae
		current->next = removed;
Packit b1f7ae
		removed = current;
Packit b1f7ae
Packit b1f7ae
		/* Unmap the removed section.  If we need to re-add it, it will
Packit b1f7ae
		 * be moved to the end of the section list where the unmapped
Packit b1f7ae
		 * sections are.
Packit b1f7ae
		 */
Packit b1f7ae
		if (current->mapped) {
Packit b1f7ae
			pt_section_unmap(lsec);
Packit b1f7ae
			current->mapped = 0;
Packit b1f7ae
		}
Packit b1f7ae
Packit b1f7ae
		/* Add a section covering the remaining bytes at the front.
Packit b1f7ae
		 *
Packit b1f7ae
		 * We preserve the section identifier to indicate that the new
Packit b1f7ae
		 * section originated from the original section.
Packit b1f7ae
		 */
Packit b1f7ae
		if (lbegin < begin) {
Packit b1f7ae
			errcode = pt_image_clone(&next, msec, lbegin, begin,
Packit b1f7ae
						 current->isid);
Packit b1f7ae
			if (errcode < 0)
Packit b1f7ae
				break;
Packit b1f7ae
		}
Packit b1f7ae
Packit b1f7ae
		/* Add a section covering the remaining bytes at the back.
Packit b1f7ae
		 *
Packit b1f7ae
		 * We preserve the section identifier to indicate that the new
Packit b1f7ae
		 * section originated from the original section.
Packit b1f7ae
		 */
Packit b1f7ae
		if (end < lend) {
Packit b1f7ae
			errcode = pt_image_clone(&next, msec, end, lend,
Packit b1f7ae
						 current->isid);
Packit b1f7ae
			if (errcode < 0)
Packit b1f7ae
				break;
Packit b1f7ae
		}
Packit b1f7ae
	}
Packit b1f7ae
Packit b1f7ae
	if (errcode < 0) {
Packit b1f7ae
		pt_section_list_free_tail(next);
Packit b1f7ae
Packit b1f7ae
		/* Re-add removed sections to the tail of the section list. */
Packit b1f7ae
		for (; *list; list = &((*list)->next))
Packit b1f7ae
			;
Packit b1f7ae
Packit b1f7ae
		*list = removed;
Packit b1f7ae
		return errcode;
Packit b1f7ae
	}
Packit b1f7ae
Packit b1f7ae
	pt_section_list_free_tail(removed);
Packit b1f7ae
Packit b1f7ae
	*list = next;
Packit b1f7ae
	return 0;
Packit b1f7ae
}
Packit b1f7ae
Packit b1f7ae
int pt_image_remove(struct pt_image *image, struct pt_section *section,
Packit b1f7ae
		    const struct pt_asid *asid, uint64_t vaddr)
Packit b1f7ae
{
Packit b1f7ae
	struct pt_section_list **list;
Packit b1f7ae
Packit b1f7ae
	if (!image || !section)
Packit b1f7ae
		return -pte_internal;
Packit b1f7ae
Packit b1f7ae
	for (list = &image->sections; *list; list = &((*list)->next)) {
Packit b1f7ae
		struct pt_mapped_section *msec;
Packit b1f7ae
		const struct pt_section *sec;
Packit b1f7ae
		const struct pt_asid *masid;
Packit b1f7ae
		struct pt_section_list *trash;
Packit b1f7ae
		uint64_t begin;
Packit b1f7ae
		int errcode;
Packit b1f7ae
Packit b1f7ae
		trash = *list;
Packit b1f7ae
		msec = &trash->section;
Packit b1f7ae
		masid = pt_msec_asid(msec);
Packit b1f7ae
Packit b1f7ae
		errcode = pt_asid_match(masid, asid);
Packit b1f7ae
		if (errcode < 0)
Packit b1f7ae
			return errcode;
Packit b1f7ae
Packit b1f7ae
		if (!errcode)
Packit b1f7ae
			continue;
Packit b1f7ae
Packit b1f7ae
		begin = pt_msec_begin(msec);
Packit b1f7ae
		sec = pt_msec_section(msec);
Packit b1f7ae
		if (sec == section && begin == vaddr) {
Packit b1f7ae
			*list = trash->next;
Packit b1f7ae
			pt_section_list_free(trash);
Packit b1f7ae
Packit b1f7ae
			return 0;
Packit b1f7ae
		}
Packit b1f7ae
	}
Packit b1f7ae
Packit b1f7ae
	return -pte_bad_image;
Packit b1f7ae
}
Packit b1f7ae
Packit b1f7ae
int pt_image_add_file(struct pt_image *image, const char *filename,
Packit b1f7ae
		      uint64_t offset, uint64_t size,
Packit b1f7ae
		      const struct pt_asid *uasid, uint64_t vaddr)
Packit b1f7ae
{
Packit b1f7ae
	struct pt_section *section;
Packit b1f7ae
	struct pt_asid asid;
Packit b1f7ae
	int errcode;
Packit b1f7ae
Packit b1f7ae
	if (!image || !filename)
Packit b1f7ae
		return -pte_invalid;
Packit b1f7ae
Packit b1f7ae
	errcode = pt_asid_from_user(&asid, uasid);
Packit b1f7ae
	if (errcode < 0)
Packit b1f7ae
		return errcode;
Packit b1f7ae
Packit b1f7ae
	section = pt_mk_section(filename, offset, size);
Packit b1f7ae
	if (!section)
Packit b1f7ae
		return -pte_invalid;
Packit b1f7ae
Packit b1f7ae
	errcode = pt_image_add(image, section, &asid, vaddr, 0);
Packit b1f7ae
	if (errcode < 0) {
Packit b1f7ae
		(void) pt_section_put(section);
Packit b1f7ae
		return errcode;
Packit b1f7ae
	}
Packit b1f7ae
Packit b1f7ae
	/* The image list got its own reference; let's drop ours. */
Packit b1f7ae
	errcode = pt_section_put(section);
Packit b1f7ae
	if (errcode < 0)
Packit b1f7ae
		return errcode;
Packit b1f7ae
Packit b1f7ae
	return 0;
Packit b1f7ae
}
Packit b1f7ae
Packit b1f7ae
int pt_image_copy(struct pt_image *image, const struct pt_image *src)
Packit b1f7ae
{
Packit b1f7ae
	struct pt_section_list *list;
Packit b1f7ae
	int ignored;
Packit b1f7ae
Packit b1f7ae
	if (!image || !src)
Packit b1f7ae
		return -pte_invalid;
Packit b1f7ae
Packit b1f7ae
	ignored = 0;
Packit b1f7ae
	for (list = src->sections; list; list = list->next) {
Packit b1f7ae
		int errcode;
Packit b1f7ae
Packit b1f7ae
		errcode = pt_image_add(image, list->section.section,
Packit b1f7ae
				       &list->section.asid,
Packit b1f7ae
				       list->section.vaddr,
Packit b1f7ae
				       list->isid);
Packit b1f7ae
		if (errcode < 0)
Packit b1f7ae
			ignored += 1;
Packit b1f7ae
	}
Packit b1f7ae
Packit b1f7ae
	return ignored;
Packit b1f7ae
}
Packit b1f7ae
Packit b1f7ae
int pt_image_remove_by_filename(struct pt_image *image, const char *filename,
Packit b1f7ae
				const struct pt_asid *uasid)
Packit b1f7ae
{
Packit b1f7ae
	struct pt_section_list **list;
Packit b1f7ae
	struct pt_asid asid;
Packit b1f7ae
	int errcode, removed;
Packit b1f7ae
Packit b1f7ae
	if (!image || !filename)
Packit b1f7ae
		return -pte_invalid;
Packit b1f7ae
Packit b1f7ae
	errcode = pt_asid_from_user(&asid, uasid);
Packit b1f7ae
	if (errcode < 0)
Packit b1f7ae
		return errcode;
Packit b1f7ae
Packit b1f7ae
	removed = 0;
Packit b1f7ae
	for (list = &image->sections; *list;) {
Packit b1f7ae
		struct pt_mapped_section *msec;
Packit b1f7ae
		const struct pt_section *sec;
Packit b1f7ae
		const struct pt_asid *masid;
Packit b1f7ae
		struct pt_section_list *trash;
Packit b1f7ae
		const char *tname;
Packit b1f7ae
Packit b1f7ae
		trash = *list;
Packit b1f7ae
		msec = &trash->section;
Packit b1f7ae
		masid = pt_msec_asid(msec);
Packit b1f7ae
Packit b1f7ae
		errcode = pt_asid_match(masid, &asid);
Packit b1f7ae
		if (errcode < 0)
Packit b1f7ae
			return errcode;
Packit b1f7ae
Packit b1f7ae
		if (!errcode) {
Packit b1f7ae
			list = &trash->next;
Packit b1f7ae
			continue;
Packit b1f7ae
		}
Packit b1f7ae
Packit b1f7ae
		sec = pt_msec_section(msec);
Packit b1f7ae
		tname = pt_section_filename(sec);
Packit b1f7ae
Packit b1f7ae
		if (tname && (strcmp(tname, filename) == 0)) {
Packit b1f7ae
			*list = trash->next;
Packit b1f7ae
			pt_section_list_free(trash);
Packit b1f7ae
Packit b1f7ae
			removed += 1;
Packit b1f7ae
		} else
Packit b1f7ae
			list = &trash->next;
Packit b1f7ae
	}
Packit b1f7ae
Packit b1f7ae
	return removed;
Packit b1f7ae
}
Packit b1f7ae
Packit b1f7ae
int pt_image_remove_by_asid(struct pt_image *image,
Packit b1f7ae
			    const struct pt_asid *uasid)
Packit b1f7ae
{
Packit b1f7ae
	struct pt_section_list **list;
Packit b1f7ae
	struct pt_asid asid;
Packit b1f7ae
	int errcode, removed;
Packit b1f7ae
Packit b1f7ae
	if (!image)
Packit b1f7ae
		return -pte_invalid;
Packit b1f7ae
Packit b1f7ae
	errcode = pt_asid_from_user(&asid, uasid);
Packit b1f7ae
	if (errcode < 0)
Packit b1f7ae
		return errcode;
Packit b1f7ae
Packit b1f7ae
	removed = 0;
Packit b1f7ae
	for (list = &image->sections; *list;) {
Packit b1f7ae
		struct pt_mapped_section *msec;
Packit b1f7ae
		const struct pt_asid *masid;
Packit b1f7ae
		struct pt_section_list *trash;
Packit b1f7ae
Packit b1f7ae
		trash = *list;
Packit b1f7ae
		msec = &trash->section;
Packit b1f7ae
		masid = pt_msec_asid(msec);
Packit b1f7ae
Packit b1f7ae
		errcode = pt_asid_match(masid, &asid);
Packit b1f7ae
		if (errcode < 0)
Packit b1f7ae
			return errcode;
Packit b1f7ae
Packit b1f7ae
		if (!errcode) {
Packit b1f7ae
			list = &trash->next;
Packit b1f7ae
			continue;
Packit b1f7ae
		}
Packit b1f7ae
Packit b1f7ae
		*list = trash->next;
Packit b1f7ae
		pt_section_list_free(trash);
Packit b1f7ae
Packit b1f7ae
		removed += 1;
Packit b1f7ae
	}
Packit b1f7ae
Packit b1f7ae
	return removed;
Packit b1f7ae
}
Packit b1f7ae
Packit b1f7ae
int pt_image_set_callback(struct pt_image *image,
Packit b1f7ae
			  read_memory_callback_t *callback, void *context)
Packit b1f7ae
{
Packit b1f7ae
	if (!image)
Packit b1f7ae
		return -pte_invalid;
Packit b1f7ae
Packit b1f7ae
	image->readmem.callback = callback;
Packit b1f7ae
	image->readmem.context = context;
Packit b1f7ae
Packit b1f7ae
	return 0;
Packit b1f7ae
}
Packit b1f7ae
Packit b1f7ae
static int pt_image_prune_cache(struct pt_image *image)
Packit b1f7ae
{
Packit b1f7ae
	struct pt_section_list *list;
Packit b1f7ae
	uint16_t cache, mapped;
Packit b1f7ae
	int status;
Packit b1f7ae
Packit b1f7ae
	if (!image)
Packit b1f7ae
		return -pte_internal;
Packit b1f7ae
Packit b1f7ae
	cache = image->cache;
Packit b1f7ae
	status = 0;
Packit b1f7ae
	mapped = 0;
Packit b1f7ae
	for (list = image->sections; list; list = list->next) {
Packit b1f7ae
		int errcode;
Packit b1f7ae
Packit b1f7ae
		/* Let's traverse the entire list.  It isn't very long and
Packit b1f7ae
		 * this allows us to fix up any previous unmap errors.
Packit b1f7ae
		 */
Packit b1f7ae
		if (!list->mapped)
Packit b1f7ae
			continue;
Packit b1f7ae
Packit b1f7ae
		mapped += 1;
Packit b1f7ae
		if (mapped <= cache)
Packit b1f7ae
			continue;
Packit b1f7ae
Packit b1f7ae
		errcode = pt_section_unmap(list->section.section);
Packit b1f7ae
		if (errcode < 0) {
Packit b1f7ae
			status = errcode;
Packit b1f7ae
			continue;
Packit b1f7ae
		}
Packit b1f7ae
Packit b1f7ae
		list->mapped = 0;
Packit b1f7ae
		mapped -= 1;
Packit b1f7ae
	}
Packit b1f7ae
Packit b1f7ae
	image->mapped = mapped;
Packit b1f7ae
	return status;
Packit b1f7ae
}
Packit b1f7ae
Packit b1f7ae
static int pt_image_read_callback(struct pt_image *image, int *isid,
Packit b1f7ae
				  uint8_t *buffer, uint16_t size,
Packit b1f7ae
				  const struct pt_asid *asid, uint64_t addr)
Packit b1f7ae
{
Packit b1f7ae
	read_memory_callback_t *callback;
Packit b1f7ae
Packit b1f7ae
	if (!image || !isid)
Packit b1f7ae
		return -pte_internal;
Packit b1f7ae
Packit b1f7ae
	callback = image->readmem.callback;
Packit b1f7ae
	if (!callback)
Packit b1f7ae
		return -pte_nomap;
Packit b1f7ae
Packit b1f7ae
	*isid = 0;
Packit b1f7ae
Packit b1f7ae
	return callback(buffer, size, asid, addr, image->readmem.context);
Packit b1f7ae
}
Packit b1f7ae
Packit b1f7ae
/* Check whether a mapped section contains an address.
Packit b1f7ae
 *
Packit b1f7ae
 * Returns zero if @msec contains @vaddr.
Packit b1f7ae
 * Returns a negative error code otherwise.
Packit b1f7ae
 * Returns -pte_nomap if @msec does not contain @vaddr.
Packit b1f7ae
 */
Packit b1f7ae
static inline int pt_image_check_msec(const struct pt_mapped_section *msec,
Packit b1f7ae
				      const struct pt_asid *asid,
Packit b1f7ae
				      uint64_t vaddr)
Packit b1f7ae
{
Packit b1f7ae
	const struct pt_asid *masid;
Packit b1f7ae
	uint64_t begin, end;
Packit b1f7ae
	int errcode;
Packit b1f7ae
Packit b1f7ae
	if (!msec)
Packit b1f7ae
		return -pte_internal;
Packit b1f7ae
Packit b1f7ae
	begin = pt_msec_begin(msec);
Packit b1f7ae
	end = pt_msec_end(msec);
Packit b1f7ae
	if (vaddr < begin || end <= vaddr)
Packit b1f7ae
		return -pte_nomap;
Packit b1f7ae
Packit b1f7ae
	masid = pt_msec_asid(msec);
Packit b1f7ae
	errcode = pt_asid_match(masid, asid);
Packit b1f7ae
	if (errcode <= 0) {
Packit b1f7ae
		if (!errcode)
Packit b1f7ae
			errcode = -pte_nomap;
Packit b1f7ae
Packit b1f7ae
		return errcode;
Packit b1f7ae
	}
Packit b1f7ae
Packit b1f7ae
	return 0;
Packit b1f7ae
}
Packit b1f7ae
Packit b1f7ae
/* Read memory from a mapped section.
Packit b1f7ae
 *
Packit b1f7ae
 * @msec's section must be mapped.
Packit b1f7ae
 *
Packit b1f7ae
 * Returns the number of bytes read on success.
Packit b1f7ae
 * Returns a negative error code otherwise.
Packit b1f7ae
 */
Packit b1f7ae
static int pt_image_read_msec(uint8_t *buffer, uint16_t size,
Packit b1f7ae
			      const struct pt_mapped_section *msec,
Packit b1f7ae
			      uint64_t addr)
Packit b1f7ae
{
Packit b1f7ae
	struct pt_section *section;
Packit b1f7ae
	uint64_t offset;
Packit b1f7ae
Packit b1f7ae
	if (!msec)
Packit b1f7ae
		return -pte_internal;
Packit b1f7ae
Packit b1f7ae
	section = pt_msec_section(msec);
Packit b1f7ae
	offset = pt_msec_unmap(msec, addr);
Packit b1f7ae
Packit b1f7ae
	return pt_section_read(section, buffer, size, offset);
Packit b1f7ae
}
Packit b1f7ae
Packit b1f7ae
/* Find the section containing a given address in a given address space.
Packit b1f7ae
 *
Packit b1f7ae
 * On success, the found section is moved to the front of the section list.
Packit b1f7ae
 * If caching is enabled, maps the section.
Packit b1f7ae
 *
Packit b1f7ae
 * Returns zero on success, a negative error code otherwise.
Packit b1f7ae
 */
Packit b1f7ae
static int pt_image_fetch_section(struct pt_image *image,
Packit b1f7ae
				  const struct pt_asid *asid, uint64_t vaddr)
Packit b1f7ae
{
Packit b1f7ae
	struct pt_section_list **start, **list;
Packit b1f7ae
Packit b1f7ae
	if (!image)
Packit b1f7ae
		return -pte_internal;
Packit b1f7ae
Packit b1f7ae
	start = &image->sections;
Packit b1f7ae
	for (list = start; *list;) {
Packit b1f7ae
		struct pt_mapped_section *msec;
Packit b1f7ae
		struct pt_section_list *elem;
Packit b1f7ae
		int errcode;
Packit b1f7ae
Packit b1f7ae
		elem = *list;
Packit b1f7ae
		msec = &elem->section;
Packit b1f7ae
Packit b1f7ae
		errcode = pt_image_check_msec(msec, asid, vaddr);
Packit b1f7ae
		if (errcode < 0) {
Packit b1f7ae
			if (errcode != -pte_nomap)
Packit b1f7ae
				return errcode;
Packit b1f7ae
Packit b1f7ae
			list = &elem->next;
Packit b1f7ae
			continue;
Packit b1f7ae
		}
Packit b1f7ae
Packit b1f7ae
		/* Move the section to the front if it isn't already. */
Packit b1f7ae
		if (list != start) {
Packit b1f7ae
			*list = elem->next;
Packit b1f7ae
			elem->next = *start;
Packit b1f7ae
			*start = elem;
Packit b1f7ae
		}
Packit b1f7ae
Packit b1f7ae
		/* Map the section if it isn't already - provided we do cache
Packit b1f7ae
		 * recently used sections.
Packit b1f7ae
		 */
Packit b1f7ae
		if (!elem->mapped) {
Packit b1f7ae
			uint16_t cache, already;
Packit b1f7ae
Packit b1f7ae
			already = image->mapped;
Packit b1f7ae
			cache = image->cache;
Packit b1f7ae
			if (cache) {
Packit b1f7ae
				struct pt_section *section;
Packit b1f7ae
Packit b1f7ae
				section = pt_msec_section(msec);
Packit b1f7ae
Packit b1f7ae
				errcode = pt_section_map(section);
Packit b1f7ae
				if (errcode < 0)
Packit b1f7ae
					return errcode;
Packit b1f7ae
Packit b1f7ae
				elem->mapped = 1;
Packit b1f7ae
Packit b1f7ae
				already += 1;
Packit b1f7ae
				image->mapped = already;
Packit b1f7ae
Packit b1f7ae
				if (cache < already)
Packit b1f7ae
					return pt_image_prune_cache(image);
Packit b1f7ae
			}
Packit b1f7ae
		}
Packit b1f7ae
Packit b1f7ae
		return 0;
Packit b1f7ae
	}
Packit b1f7ae
Packit b1f7ae
	return -pte_nomap;
Packit b1f7ae
}
Packit b1f7ae
Packit b1f7ae
static int pt_image_read_cold(struct pt_image *image, int *isid,
Packit b1f7ae
			      uint8_t *buffer, uint16_t size,
Packit b1f7ae
			      const struct pt_asid *asid, uint64_t addr)
Packit b1f7ae
{
Packit b1f7ae
	struct pt_mapped_section *msec;
Packit b1f7ae
	struct pt_section_list *section;
Packit b1f7ae
	int errcode;
Packit b1f7ae
Packit b1f7ae
	if (!image || !isid)
Packit b1f7ae
		return -pte_internal;
Packit b1f7ae
Packit b1f7ae
	errcode = pt_image_fetch_section(image, asid, addr);
Packit b1f7ae
	if (errcode < 0) {
Packit b1f7ae
		if (errcode != -pte_nomap)
Packit b1f7ae
			return errcode;
Packit b1f7ae
	}
Packit b1f7ae
Packit b1f7ae
	section = image->sections;
Packit b1f7ae
	if (!section)
Packit b1f7ae
		return pt_image_read_callback(image, isid, buffer, size, asid,
Packit b1f7ae
					      addr);
Packit b1f7ae
Packit b1f7ae
	msec = &section->section;
Packit b1f7ae
Packit b1f7ae
	errcode = pt_image_check_msec(msec, asid, addr);
Packit b1f7ae
	if (errcode < 0) {
Packit b1f7ae
		if (errcode != -pte_nomap)
Packit b1f7ae
			return errcode;
Packit b1f7ae
Packit b1f7ae
		return pt_image_read_callback(image, isid, buffer, size, asid,
Packit b1f7ae
					      addr);
Packit b1f7ae
	}
Packit b1f7ae
Packit b1f7ae
	*isid = section->isid;
Packit b1f7ae
Packit b1f7ae
	if (section->mapped)
Packit b1f7ae
		return pt_image_read_msec(buffer, size, msec, addr);
Packit b1f7ae
	else {
Packit b1f7ae
		struct pt_section *sec;
Packit b1f7ae
		int status;
Packit b1f7ae
Packit b1f7ae
		sec = pt_msec_section(msec);
Packit b1f7ae
Packit b1f7ae
		errcode = pt_section_map(sec);
Packit b1f7ae
		if (errcode < 0)
Packit b1f7ae
			return errcode;
Packit b1f7ae
Packit b1f7ae
		status = pt_image_read_msec(buffer, size, msec, addr);
Packit b1f7ae
Packit b1f7ae
		errcode = pt_section_unmap(sec);
Packit b1f7ae
		if (errcode < 0)
Packit b1f7ae
			return errcode;
Packit b1f7ae
Packit b1f7ae
		return status;
Packit b1f7ae
	}
Packit b1f7ae
}
Packit b1f7ae
Packit b1f7ae
Packit b1f7ae
int pt_image_read(struct pt_image *image, int *isid, uint8_t *buffer,
Packit b1f7ae
		  uint16_t size, const struct pt_asid *asid, uint64_t addr)
Packit b1f7ae
{
Packit b1f7ae
	struct pt_mapped_section *msec;
Packit b1f7ae
	struct pt_section_list *section;
Packit b1f7ae
	int errcode;
Packit b1f7ae
Packit b1f7ae
	if (!image || !isid)
Packit b1f7ae
		return -pte_internal;
Packit b1f7ae
Packit b1f7ae
	section = image->sections;
Packit b1f7ae
	if (!section)
Packit b1f7ae
		return pt_image_read_callback(image, isid, buffer, size, asid,
Packit b1f7ae
					      addr);
Packit b1f7ae
Packit b1f7ae
	if (!section->mapped)
Packit b1f7ae
		return pt_image_read_cold(image, isid, buffer, size, asid,
Packit b1f7ae
					  addr);
Packit b1f7ae
Packit b1f7ae
	msec = &section->section;
Packit b1f7ae
Packit b1f7ae
	errcode = pt_image_check_msec(msec, asid, addr);
Packit b1f7ae
	if (errcode < 0) {
Packit b1f7ae
		if (errcode != -pte_nomap)
Packit b1f7ae
			return errcode;
Packit b1f7ae
Packit b1f7ae
		return pt_image_read_cold(image, isid, buffer, size, asid,
Packit b1f7ae
					  addr);
Packit b1f7ae
	}
Packit b1f7ae
Packit b1f7ae
	*isid = section->isid;
Packit b1f7ae
Packit b1f7ae
	return pt_image_read_msec(buffer, size, msec, addr);
Packit b1f7ae
}
Packit b1f7ae
Packit b1f7ae
int pt_image_add_cached(struct pt_image *image,
Packit b1f7ae
			struct pt_image_section_cache *iscache, int isid,
Packit b1f7ae
			const struct pt_asid *uasid)
Packit b1f7ae
{
Packit b1f7ae
	struct pt_section *section;
Packit b1f7ae
	struct pt_asid asid;
Packit b1f7ae
	uint64_t vaddr;
Packit b1f7ae
	int errcode, status;
Packit b1f7ae
Packit b1f7ae
	if (!image || !iscache)
Packit b1f7ae
		return -pte_invalid;
Packit b1f7ae
Packit b1f7ae
	errcode = pt_iscache_lookup(iscache, &section, &vaddr, isid);
Packit b1f7ae
	if (errcode < 0)
Packit b1f7ae
		return errcode;
Packit b1f7ae
Packit b1f7ae
	errcode = pt_asid_from_user(&asid, uasid);
Packit b1f7ae
	if (errcode < 0)
Packit b1f7ae
		return errcode;
Packit b1f7ae
Packit b1f7ae
	status = pt_image_add(image, section, &asid, vaddr, isid);
Packit b1f7ae
Packit b1f7ae
	/* We grab a reference when we add the section.  Drop the one we
Packit b1f7ae
	 * obtained from cache lookup.
Packit b1f7ae
	 */
Packit b1f7ae
	errcode = pt_section_put(section);
Packit b1f7ae
	if (errcode < 0)
Packit b1f7ae
		return errcode;
Packit b1f7ae
Packit b1f7ae
	return status;
Packit b1f7ae
}
Packit b1f7ae
Packit b1f7ae
static int pt_image_find_cold(struct pt_image *image,
Packit b1f7ae
			      struct pt_section **psection, uint64_t *laddr,
Packit b1f7ae
			      const struct pt_asid *asid, uint64_t vaddr)
Packit b1f7ae
{
Packit b1f7ae
	struct pt_mapped_section *msec;
Packit b1f7ae
	struct pt_section_list *slist;
Packit b1f7ae
	struct pt_section *section;
Packit b1f7ae
	int errcode;
Packit b1f7ae
Packit b1f7ae
	if (!image || !psection || !laddr)
Packit b1f7ae
		return -pte_internal;
Packit b1f7ae
Packit b1f7ae
	errcode = pt_image_fetch_section(image, asid, vaddr);
Packit b1f7ae
	if (errcode < 0)
Packit b1f7ae
		return errcode;
Packit b1f7ae
Packit b1f7ae
	slist = image->sections;
Packit b1f7ae
	if (!slist)
Packit b1f7ae
		return -pte_nomap;
Packit b1f7ae
Packit b1f7ae
	msec = &slist->section;
Packit b1f7ae
Packit b1f7ae
	errcode = pt_image_check_msec(msec, asid, vaddr);
Packit b1f7ae
	if (errcode < 0)
Packit b1f7ae
		return errcode;
Packit b1f7ae
Packit b1f7ae
	section = pt_msec_section(msec);
Packit b1f7ae
Packit b1f7ae
	errcode = pt_section_get(section);
Packit b1f7ae
	if (errcode < 0)
Packit b1f7ae
		return errcode;
Packit b1f7ae
Packit b1f7ae
	*psection = section;
Packit b1f7ae
	*laddr = pt_msec_begin(msec);
Packit b1f7ae
Packit b1f7ae
	return slist->isid;
Packit b1f7ae
}
Packit b1f7ae
Packit b1f7ae
int pt_image_find(struct pt_image *image, struct pt_section **psection,
Packit b1f7ae
		  uint64_t *laddr, const struct pt_asid *asid, uint64_t vaddr)
Packit b1f7ae
{
Packit b1f7ae
	struct pt_mapped_section *msec;
Packit b1f7ae
	struct pt_section_list *slist;
Packit b1f7ae
	struct pt_section *section;
Packit b1f7ae
	int errcode;
Packit b1f7ae
Packit b1f7ae
	if (!image || !psection || !laddr)
Packit b1f7ae
		return -pte_internal;
Packit b1f7ae
Packit b1f7ae
	slist = image->sections;
Packit b1f7ae
	if (!slist)
Packit b1f7ae
		return -pte_nomap;
Packit b1f7ae
Packit b1f7ae
	if (!slist->mapped)
Packit b1f7ae
		return pt_image_find_cold(image, psection, laddr, asid, vaddr);
Packit b1f7ae
Packit b1f7ae
	msec = &slist->section;
Packit b1f7ae
Packit b1f7ae
	errcode = pt_image_check_msec(msec, asid, vaddr);
Packit b1f7ae
	if (errcode < 0) {
Packit b1f7ae
		if (errcode != -pte_nomap)
Packit b1f7ae
			return errcode;
Packit b1f7ae
Packit b1f7ae
		return pt_image_find_cold(image, psection, laddr, asid, vaddr);
Packit b1f7ae
	}
Packit b1f7ae
Packit b1f7ae
	section = pt_msec_section(msec);
Packit b1f7ae
Packit b1f7ae
	errcode = pt_section_get(section);
Packit b1f7ae
	if (errcode < 0)
Packit b1f7ae
		return errcode;
Packit b1f7ae
Packit b1f7ae
	*psection = section;
Packit b1f7ae
	*laddr = pt_msec_begin(msec);
Packit b1f7ae
Packit b1f7ae
	return slist->isid;
Packit b1f7ae
}
Packit b1f7ae
Packit b1f7ae
int pt_image_validate(const struct pt_image *image, const struct pt_asid *asid,
Packit b1f7ae
		      uint64_t vaddr, const struct pt_section *section,
Packit b1f7ae
		      uint64_t laddr, int isid)
Packit b1f7ae
{
Packit b1f7ae
	struct pt_mapped_section *msec;
Packit b1f7ae
	struct pt_section_list *slist;
Packit b1f7ae
Packit b1f7ae
	if (!image)
Packit b1f7ae
		return -pte_internal;
Packit b1f7ae
Packit b1f7ae
	/* We only look at the top of our LRU stack and accept sporadic
Packit b1f7ae
	 * validation fails if @section moved down in the LRU stack or has been
Packit b1f7ae
	 * evicted.
Packit b1f7ae
	 *
Packit b1f7ae
	 * A failed validation requires decoders to re-fetch the section so it
Packit b1f7ae
	 * only results in a (relatively small) performance loss.
Packit b1f7ae
	 */
Packit b1f7ae
	slist = image->sections;
Packit b1f7ae
	if (!slist)
Packit b1f7ae
		return -pte_nomap;
Packit b1f7ae
Packit b1f7ae
	if (slist->isid != isid)
Packit b1f7ae
		return -pte_nomap;
Packit b1f7ae
Packit b1f7ae
	msec = &slist->section;
Packit b1f7ae
Packit b1f7ae
	if (pt_msec_section(msec) != section)
Packit b1f7ae
		return -pte_nomap;
Packit b1f7ae
Packit b1f7ae
	if (pt_msec_begin(msec) != laddr)
Packit b1f7ae
		return -pte_nomap;
Packit b1f7ae
Packit b1f7ae
	return pt_image_check_msec(msec, asid, vaddr);
Packit b1f7ae
}