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 = ¤t->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, §ion, &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