1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #if defined(lint) || defined(__lint) 29 #include <sys/dtrace_impl.h> 30 #else 31 #include <sys/asm_linkage.h> 32 #include <sys/privregs.h> 33 #include <sys/fsr.h> 34 #include <sys/asi.h> 35 #include "assym.h" 36 #endif 37 38 #if defined(lint) || defined(__lint) 39 40 int 41 dtrace_getipl(void) 42 { return (0); } 43 44 #else /* lint */ 45 46 ENTRY_NP(dtrace_getipl) 47 retl 48 rdpr %pil, %o0 49 SET_SIZE(dtrace_getipl) 50 51 #endif /* lint */ 52 53 #if defined(lint) || defined(__lint) 54 55 uint_t 56 dtrace_getotherwin(void) 57 { return (0); } 58 59 #else /* lint */ 60 61 ENTRY_NP(dtrace_getotherwin) 62 retl 63 rdpr %otherwin, %o0 64 SET_SIZE(dtrace_getotherwin) 65 66 #endif /* lint */ 67 68 #if defined(lint) || defined(__lint) 69 70 uint_t 71 dtrace_getfprs(void) 72 { return (0); } 73 74 #else /* lint */ 75 76 ENTRY_NP(dtrace_getfprs) 77 retl 78 rd %fprs, %o0 79 SET_SIZE(dtrace_getfprs) 80 81 #endif /* lint */ 82 83 #if defined(lint) || defined(__lint) 84 85 /*ARGSUSED*/ 86 void 87 dtrace_getfsr(uint64_t *val) 88 {} 89 90 #else /* lint */ 91 92 ENTRY_NP(dtrace_getfsr) 93 rdpr %pstate, %o1 94 andcc %o1, PSTATE_PEF, %g0 95 bz,pn %xcc, 1f 96 nop 97 rd %fprs, %o1 98 andcc %o1, FPRS_FEF, %g0 99 bz,pn %xcc, 1f 100 nop 101 retl 102 stx %fsr, [%o0] 103 1: 104 retl 105 stx %g0, [%o0] 106 SET_SIZE(dtrace_getfsr) 107 108 #endif /* lint */ 109 110 #if defined(lint) || defined(__lint) 111 112 greg_t 113 dtrace_getfp(void) 114 { return (0); } 115 116 #else /* lint */ 117 118 ENTRY_NP(dtrace_getfp) 119 retl 120 mov %fp, %o0 121 SET_SIZE(dtrace_getfp) 122 123 #endif /* lint */ 124 125 #if defined(lint) || defined(__lint) 126 127 void 128 dtrace_flush_user_windows(void) 129 {} 130 131 #else 132 133 ENTRY_NP(dtrace_flush_user_windows) 134 rdpr %otherwin, %g1 135 brz %g1, 3f 136 clr %g2 137 1: 138 save %sp, -WINDOWSIZE, %sp 139 rdpr %otherwin, %g1 140 brnz %g1, 1b 141 add %g2, 1, %g2 142 2: 143 sub %g2, 1, %g2 ! restore back to orig window 144 brnz %g2, 2b 145 restore 146 3: 147 retl 148 nop 149 SET_SIZE(dtrace_flush_user_windows) 150 151 #endif /* lint */ 152 153 #if defined(lint) || defined(__lint) 154 155 uint32_t 156 dtrace_cas32(uint32_t *target, uint32_t cmp, uint32_t new) 157 { 158 uint32_t old; 159 160 if ((old = *target) == cmp) 161 *target = new; 162 return (old); 163 } 164 165 void * 166 dtrace_casptr(void *target, void *cmp, void *new) 167 { 168 void *old; 169 170 if ((old = *(void **)target) == cmp) 171 *(void **)target = new; 172 return (old); 173 } 174 175 #else /* lint */ 176 177 ENTRY(dtrace_cas32) 178 cas [%o0], %o1, %o2 179 retl 180 mov %o2, %o0 181 SET_SIZE(dtrace_cas32) 182 183 ENTRY(dtrace_casptr) 184 casn [%o0], %o1, %o2 185 retl 186 mov %o2, %o0 187 SET_SIZE(dtrace_casptr) 188 189 #endif /* lint */ 190 191 #if defined(lint) 192 193 /*ARGSUSED*/ 194 uintptr_t 195 dtrace_caller(int aframes) 196 { 197 return (0); 198 } 199 200 #else /* lint */ 201 202 ENTRY(dtrace_caller) 203 sethi %hi(nwin_minus_one), %g4 204 ld [%g4 + %lo(nwin_minus_one)], %g4 205 rdpr %canrestore, %g2 206 cmp %g2, %o0 207 bl %icc, 1f 208 rdpr %cwp, %g1 209 sub %g1, %o0, %g3 210 brgez,a,pt %g3, 0f 211 wrpr %g3, %cwp 212 213 ! 214 ! CWP minus the number of frames is negative; we must perform the 215 ! arithmetic modulo MAXWIN. 216 ! 217 add %g4, %g3, %g3 218 inc %g3 219 wrpr %g3, %cwp 220 0: 221 mov %i7, %g4 222 wrpr %g1, %cwp 223 retl 224 mov %g4, %o0 225 1: 226 ! 227 ! The caller has been flushed to the stack. This is unlikely 228 ! (interrupts are disabled in dtrace_probe()), but possible (the 229 ! interrupt inducing the spill may have been taken before the 230 ! call to dtrace_probe()). 231 ! 232 retl 233 mov -1, %o0 234 SET_SIZE(dtrace_caller) 235 236 #endif 237 238 #if defined(lint) 239 240 /*ARGSUSED*/ 241 int 242 dtrace_fish(int aframes, int reg, uintptr_t *regval) 243 { 244 return (0); 245 } 246 247 #else /* lint */ 248 249 ENTRY(dtrace_fish) 250 251 rd %pc, %g5 252 ba 0f 253 add %g5, 12, %g5 254 mov %l0, %g4 255 mov %l1, %g4 256 mov %l2, %g4 257 mov %l3, %g4 258 mov %l4, %g4 259 mov %l5, %g4 260 mov %l6, %g4 261 mov %l7, %g4 262 mov %i0, %g4 263 mov %i1, %g4 264 mov %i2, %g4 265 mov %i3, %g4 266 mov %i4, %g4 267 mov %i5, %g4 268 mov %i6, %g4 269 mov %i7, %g4 270 0: 271 sub %o1, 16, %o1 ! Can only retrieve %l's and %i's 272 sll %o1, 2, %o1 ! Multiply by instruction size 273 add %g5, %o1, %g5 ! %g5 now contains the instr. to pick 274 275 sethi %hi(nwin_minus_one), %g4 276 ld [%g4 + %lo(nwin_minus_one)], %g4 277 278 ! 279 ! First we need to see if the frame that we're fishing in is still 280 ! contained in the register windows. 281 ! 282 rdpr %canrestore, %g2 283 cmp %g2, %o0 284 bl %icc, 2f 285 rdpr %cwp, %g1 286 sub %g1, %o0, %g3 287 brgez,a,pt %g3, 0f 288 wrpr %g3, %cwp 289 290 ! 291 ! CWP minus the number of frames is negative; we must perform the 292 ! arithmetic modulo MAXWIN. 293 ! 294 add %g4, %g3, %g3 295 inc %g3 296 wrpr %g3, %cwp 297 0: 298 jmp %g5 299 ba 1f 300 1: 301 wrpr %g1, %cwp 302 stn %g4, [%o2] 303 retl 304 clr %o0 ! Success; return 0. 305 2: 306 ! 307 ! The frame that we're looking for has been flushed to the stack; the 308 ! caller will be forced to 309 ! 310 retl 311 add %g2, 1, %o0 ! Failure; return deepest frame + 1 312 SET_SIZE(dtrace_fish) 313 314 #endif 315 316 #if defined(lint) 317 318 /*ARGSUSED*/ 319 void 320 dtrace_copyin(uintptr_t uaddr, uintptr_t kaddr, size_t size, 321 volatile uint16_t *flags) 322 {} 323 324 #else 325 326 ENTRY(dtrace_copyin) 327 tst %o2 328 bz 2f 329 clr %g1 330 lduba [%o0 + %g1]ASI_USER, %g2 331 0: 332 ! check for an error if the count is 4k-aligned 333 andcc %g1, 0xfff, %g0 334 bnz,pt %icc, 1f 335 stub %g2, [%o1 + %g1] 336 lduh [%o3], %g3 337 andcc %g3, CPU_DTRACE_BADADDR, %g0 338 bnz,pn %icc, 2f 339 nop 340 1: 341 inc %g1 342 cmp %g1, %o2 343 bl,a 0b 344 lduba [%o0 + %g1]ASI_USER, %g2 345 2: 346 retl 347 nop 348 349 SET_SIZE(dtrace_copyin) 350 351 #endif 352 353 #if defined(lint) 354 355 /*ARGSUSED*/ 356 void 357 dtrace_copyinstr(uintptr_t uaddr, uintptr_t kaddr, size_t size, 358 volatile uint16_t *flags) 359 {} 360 361 #else 362 363 ENTRY(dtrace_copyinstr) 364 tst %o2 365 bz 2f 366 clr %g1 367 lduba [%o0 + %g1]ASI_USER, %g2 368 0: 369 stub %g2, [%o1 + %g1] ! Store byte 370 371 ! check for an error if the count is 4k-aligned 372 andcc %g1, 0xfff, %g0 373 bnz,pt %icc, 1f 374 inc %g1 375 lduh [%o3], %g3 376 andcc %g3, CPU_DTRACE_BADADDR, %g0 377 bnz,pn %icc, 2f 378 nop 379 1: 380 cmp %g2, 0 ! Was that '\0'? 381 be 2f ! If so, we're done 382 cmp %g1, %o2 ! Compare to limit 383 bl,a 0b ! If less, take another lap 384 lduba [%o0 + %g1]ASI_USER, %g2 ! delay: load user byte 385 2: 386 retl 387 nop 388 389 SET_SIZE(dtrace_copyinstr) 390 391 #endif 392 393 #if defined(lint) 394 395 /*ARGSUSED*/ 396 void 397 dtrace_copyout(uintptr_t kaddr, uintptr_t uaddr, size_t size, 398 volatile uint16_t *flags) 399 {} 400 401 #else 402 403 ENTRY(dtrace_copyout) 404 tst %o2 405 bz 2f 406 clr %g1 407 ldub [%o0 + %g1], %g2 408 0: 409 ! check for an error if the count is 4k-aligned 410 andcc %g1, 0xfff, %g0 411 bnz,pt %icc, 1f 412 stba %g2, [%o1 + %g1]ASI_USER 413 lduh [%o3], %g3 414 andcc %g3, CPU_DTRACE_BADADDR, %g0 415 bnz,pn %icc, 2f 416 nop 417 1: 418 inc %g1 419 cmp %g1, %o2 420 bl,a 0b 421 ldub [%o0 + %g1], %g2 422 2: 423 retl 424 nop 425 SET_SIZE(dtrace_copyout) 426 427 #endif 428 429 #if defined(lint) 430 431 /*ARGSUSED*/ 432 void 433 dtrace_copyoutstr(uintptr_t kaddr, uintptr_t uaddr, size_t size, 434 volatile uint16_t *flags) 435 {} 436 437 #else 438 439 ENTRY(dtrace_copyoutstr) 440 tst %o2 441 bz 2f 442 clr %g1 443 ldub [%o0 + %g1], %g2 444 0: 445 stba %g2, [%o1 + %g1]ASI_USER 446 447 ! check for an error if the count is 4k-aligned 448 andcc %g1, 0xfff, %g0 449 bnz,pt %icc, 1f 450 inc %g1 451 lduh [%o3], %g3 452 andcc %g3, CPU_DTRACE_BADADDR, %g0 453 bnz,pn %icc, 2f 454 nop 455 1: 456 cmp %g2, 0 457 be 2f 458 cmp %g1, %o2 459 bl,a 0b 460 ldub [%o0 + %g1], %g2 461 2: 462 retl 463 nop 464 SET_SIZE(dtrace_copyoutstr) 465 466 #endif 467 468 #if defined(lint) 469 470 /*ARGSUSED*/ 471 uintptr_t 472 dtrace_fulword(void *addr) 473 { return (0); } 474 475 #else 476 477 ENTRY(dtrace_fulword) 478 clr %o1 479 ldna [%o0]ASI_USER, %o1 480 retl 481 mov %o1, %o0 482 SET_SIZE(dtrace_fulword) 483 484 #endif 485 486 #if defined(lint) 487 488 /*ARGSUSED*/ 489 uint8_t 490 dtrace_fuword8(void *addr) 491 { return (0); } 492 493 #else 494 495 ENTRY(dtrace_fuword8) 496 clr %o1 497 lduba [%o0]ASI_USER, %o1 498 retl 499 mov %o1, %o0 500 SET_SIZE(dtrace_fuword8) 501 502 #endif 503 504 #if defined(lint) 505 506 /*ARGSUSED*/ 507 uint16_t 508 dtrace_fuword16(void *addr) 509 { return (0); } 510 511 #else 512 513 ENTRY(dtrace_fuword16) 514 clr %o1 515 lduha [%o0]ASI_USER, %o1 516 retl 517 mov %o1, %o0 518 SET_SIZE(dtrace_fuword16) 519 520 #endif 521 522 #if defined(lint) 523 524 /*ARGSUSED*/ 525 uint32_t 526 dtrace_fuword32(void *addr) 527 { return (0); } 528 529 #else 530 531 ENTRY(dtrace_fuword32) 532 clr %o1 533 lda [%o0]ASI_USER, %o1 534 retl 535 mov %o1, %o0 536 SET_SIZE(dtrace_fuword32) 537 538 #endif 539 540 #if defined(lint) 541 542 /*ARGSUSED*/ 543 uint64_t 544 dtrace_fuword64(void *addr) 545 { return (0); } 546 547 #else 548 549 ENTRY(dtrace_fuword64) 550 clr %o1 551 ldxa [%o0]ASI_USER, %o1 552 retl 553 mov %o1, %o0 554 SET_SIZE(dtrace_fuword64) 555 556 #endif 557 558 #if defined(lint) 559 560 /*ARGSUSED*/ 561 int 562 dtrace_getupcstack_top(uint64_t *pcstack, int pcstack_limit, uintptr_t *sp) 563 { return (0); } 564 565 #else 566 567 /* 568 * %g1 pcstack 569 * %g2 current window 570 * %g3 maxwin (nwindows - 1) 571 * %g4 saved %cwp (so we can get back to the original window) 572 * %g5 iteration count 573 * %g6 saved %fp 574 * 575 * %o0 pcstack / return value (iteration count) 576 * %o1 pcstack_limit 577 * %o2 last_fp 578 */ 579 580 ENTRY(dtrace_getupcstack_top) 581 mov %o0, %g1 ! we need the pcstack pointer while 582 ! we're visiting other windows 583 584 rdpr %otherwin, %g5 ! compute the number of iterations 585 cmp %g5, %o1 ! (windows to observe) by taking the 586 movg %icc, %o1, %g5 ! min of %otherwin and pcstack_limit 587 588 brlez,a,pn %g5, 2f ! return 0 if count <= 0 589 clr %o0 590 591 sethi %hi(nwin_minus_one), %g3 ! hang onto maxwin since we'll need 592 ld [%g3 + %lo(nwin_minus_one)], %g3 ! it for our modular arithmetic 593 594 rdpr %cwp, %g4 ! remember our window so we can return 595 rdpr %canrestore, %g2 ! compute the first non-user window 596 subcc %g4, %g2, %g2 ! current = %cwp - %canrestore 597 598 bge,pt %xcc, 1f ! good to go if current is >= 0 599 mov %g5, %o0 ! we need to return the count 600 601 add %g2, %g3, %g2 ! normalize our current window if it's 602 add %g2, 1, %g2 ! less than zero 603 604 ! note that while it's tempting, we can't execute restore to decrement 605 ! the %cwp by one (mod nwindows) because we're in the user's windows 606 1: 607 deccc %g2 ! decrement the current window 608 movl %xcc, %g3, %g2 ! normalize if it's negative (-1) 609 610 wrpr %g2, %cwp ! change windows 611 612 stx %i7, [%g1] ! stash the return address in pcstack 613 614 deccc %g5 ! decrement the count 615 bnz,pt %icc, 1b ! we iterate until the count reaches 0 616 add %g1, 8, %g1 ! increment the pcstack pointer 617 618 mov %i6, %g6 ! stash the last frame pointer we 619 ! encounter so the caller can 620 ! continue the stack walk in memory 621 622 wrpr %g4, %cwp ! change back to the original window 623 624 stn %g6, [%o2] ! return the last frame pointer 625 626 2: 627 retl 628 nop 629 SET_SIZE(dtrace_getupcstack_top) 630 631 #endif 632 633 #if defined(lint) 634 635 /*ARGSUSED*/ 636 int 637 dtrace_getustackdepth_top(uintptr_t *sp) 638 { return (0); } 639 640 #else 641 642 ENTRY(dtrace_getustackdepth_top) 643 mov %o0, %o2 644 rdpr %otherwin, %o0 645 646 brlez,a,pn %o0, 2f ! return 0 if there are no user wins 647 clr %o0 648 649 rdpr %cwp, %g4 ! remember our window so we can return 650 rdpr %canrestore, %g2 ! compute the first user window 651 sub %g4, %g2, %g2 ! current = %cwp - %canrestore - 652 subcc %g2, %o0, %g2 ! %otherwin 653 654 bge,pt %xcc, 1f ! normalize the window if necessary 655 sethi %hi(nwin_minus_one), %g3 656 ld [%g3 + %lo(nwin_minus_one)], %g3 657 add %g2, %g3, %g2 658 add %g2, 1, %g2 659 660 1: 661 wrpr %g2, %cwp ! change to the first user window 662 mov %i6, %g6 ! stash the frame pointer 663 wrpr %g4, %cwp ! change back to the original window 664 665 stn %g6, [%o2] ! return the frame pointer 666 667 2: 668 retl 669 nop 670 SET_SIZE(dtrace_getustackdepth_top) 671 672 #endif 673 674 #if defined(lint) || defined(__lint) 675 676 /* ARGSUSED */ 677 ulong_t 678 dtrace_getreg_win(uint_t reg, uint_t depth) 679 { return (0); } 680 681 #else /* lint */ 682 683 ENTRY(dtrace_getreg_win) 684 sub %o0, 16, %o0 685 cmp %o0, 16 ! %o0 must begin in the range [16..32) 686 blu,pt %xcc, 1f 687 nop 688 retl 689 clr %o0 690 691 1: 692 set dtrace_getreg_win_table, %g3 693 sll %o0, 2, %o0 694 add %g3, %o0, %g3 695 696 rdpr %canrestore, %o3 697 rdpr %cwp, %g2 698 699 ! Set %cwp to be (%cwp - %canrestore - %o1) mod NWINDOWS 700 701 sub %g2, %o3, %o2 ! %o2 is %cwp - %canrestore 702 subcc %o2, %o1, %o4 703 bge,a,pn %xcc, 2f 704 wrpr %o4, %cwp 705 706 sethi %hi(nwin_minus_one), %o3 707 ld [%o3 + %lo(nwin_minus_one)], %o3 708 709 add %o2, %o3, %o4 710 wrpr %o4, %cwp 711 2: 712 jmp %g3 713 ba 3f 714 3: 715 wrpr %g2, %cwp 716 retl 717 mov %g1, %o0 718 719 dtrace_getreg_win_table: 720 mov %l0, %g1 721 mov %l1, %g1 722 mov %l2, %g1 723 mov %l3, %g1 724 mov %l4, %g1 725 mov %l5, %g1 726 mov %l6, %g1 727 mov %l7, %g1 728 mov %i0, %g1 729 mov %i1, %g1 730 mov %i2, %g1 731 mov %i3, %g1 732 mov %i4, %g1 733 mov %i5, %g1 734 mov %i6, %g1 735 mov %i7, %g1 736 SET_SIZE(dtrace_getreg_win) 737 738 #endif /* lint */ 739 740 #if defined(lint) || defined(__lint) 741 742 /* ARGSUSED */ 743 void 744 dtrace_putreg_win(uint_t reg, ulong_t value) 745 {} 746 747 #else /* lint */ 748 749 ENTRY(dtrace_putreg_win) 750 sub %o0, 16, %o0 751 cmp %o0, 16 ! %o0 must be in the range [16..32) 752 blu,pt %xcc, 1f 753 nop 754 retl 755 nop 756 757 1: 758 mov %o1, %g1 ! move the value into a global register 759 760 set dtrace_putreg_table, %g3 761 sll %o0, 2, %o0 762 add %g3, %o0, %g3 763 764 rdpr %canrestore, %o3 765 rdpr %cwp, %g2 766 767 ! Set %cwp to be (%cwp - %canrestore - 1) mod NWINDOWS 768 769 sub %g2, %o3, %o2 ! %o2 is %cwp - %canrestore 770 subcc %o2, 1, %o4 771 bge,a,pn %xcc, 2f 772 wrpr %o4, %cwp 773 774 sethi %hi(nwin_minus_one), %o3 775 ld [%o3 + %lo(nwin_minus_one)], %o3 776 add %o2, %o3, %o4 777 wrpr %o4, %cwp 778 2: 779 jmp %g3 780 ba 3f 781 3: 782 wrpr %g2, %cwp 783 retl 784 nop 785 786 dtrace_putreg_table: 787 mov %g1, %l0 788 mov %g1, %l1 789 mov %g1, %l2 790 mov %g1, %l3 791 mov %g1, %l4 792 mov %g1, %l5 793 mov %g1, %l6 794 mov %g1, %l7 795 mov %g1, %i0 796 mov %g1, %i1 797 mov %g1, %i2 798 mov %g1, %i3 799 mov %g1, %i4 800 mov %g1, %i5 801 mov %g1, %i6 802 mov %g1, %i7 803 SET_SIZE(dtrace_putreg_win) 804 805 #endif /* lint */ 806 807 #if defined(lint) || defined(__lint) 808 809 /*ARGSUSED*/ 810 void 811 dtrace_probe_error(dtrace_state_t *state, dtrace_epid_t epid, int which, 812 int fault, int fltoffs, uintptr_t illval) 813 {} 814 815 #else /* lint */ 816 817 ENTRY(dtrace_probe_error) 818 save %sp, -SA(MINFRAME), %sp 819 sethi %hi(dtrace_probeid_error), %l0 820 ld [%l0 + %lo(dtrace_probeid_error)], %o0 821 mov %i0, %o1 822 mov %i1, %o2 823 mov %i2, %o3 824 mov %i3, %o4 825 call dtrace_probe 826 mov %i4, %o5 827 ret 828 restore 829 SET_SIZE(dtrace_probe_error) 830 831 #endif