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