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