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 40int 41dtrace_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 55uint_t 56dtrace_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 70uint_t 71dtrace_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*/ 86void 87dtrace_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] 1031: 104 retl 105 stx %g0, [%o0] 106 SET_SIZE(dtrace_getfsr) 107 108#endif /* lint */ 109 110#if defined(lint) || defined(__lint) 111 112greg_t 113dtrace_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 127void 128dtrace_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 1371: 138 save %sp, -WINDOWSIZE, %sp 139 rdpr %otherwin, %g1 140 brnz %g1, 1b 141 add %g2, 1, %g2 1422: 143 sub %g2, 1, %g2 ! restore back to orig window 144 brnz %g2, 2b 145 restore 1463: 147 retl 148 nop 149 SET_SIZE(dtrace_flush_user_windows) 150 151#endif /* lint */ 152 153#if defined(lint) || defined(__lint) 154 155uint32_t 156dtrace_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 165void * 166dtrace_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*/ 194uintptr_t 195dtrace_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 2200: 221 mov %i7, %g4 222 wrpr %g1, %cwp 223 retl 224 mov %g4, %o0 2251: 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*/ 241int 242dtrace_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 2700: 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 2970: 298 jmp %g5 299 ba 1f 3001: 301 wrpr %g1, %cwp 302 stn %g4, [%o2] 303 retl 304 clr %o0 ! Success; return 0. 3052: 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*/ 319void 320dtrace_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 3310: 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 3401: 341 inc %g1 342 cmp %g1, %o2 343 bl,a 0b 344 lduba [%o0 + %g1]ASI_USER, %g2 3452: 346 retl 347 nop 348 349 SET_SIZE(dtrace_copyin) 350 351#endif 352 353#if defined(lint) 354 355/*ARGSUSED*/ 356void 357dtrace_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 3680: 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 3791: 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 3852: 386 retl 387 nop 388 389 SET_SIZE(dtrace_copyinstr) 390 391#endif 392 393#if defined(lint) 394 395/*ARGSUSED*/ 396void 397dtrace_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 4080: 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 4171: 418 inc %g1 419 cmp %g1, %o2 420 bl,a 0b 421 ldub [%o0 + %g1], %g2 4222: 423 retl 424 nop 425 SET_SIZE(dtrace_copyout) 426 427#endif 428 429#if defined(lint) 430 431/*ARGSUSED*/ 432void 433dtrace_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 4440: 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 4551: 456 cmp %g2, 0 457 be 2f 458 cmp %g1, %o2 459 bl,a 0b 460 ldub [%o0 + %g1], %g2 4612: 462 retl 463 nop 464 SET_SIZE(dtrace_copyoutstr) 465 466#endif 467 468#if defined(lint) 469 470/*ARGSUSED*/ 471uintptr_t 472dtrace_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*/ 489uint8_t 490dtrace_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*/ 507uint16_t 508dtrace_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*/ 525uint32_t 526dtrace_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*/ 543uint64_t 544dtrace_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*/ 561int 562dtrace_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 6061: 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 6262: 627 retl 628 nop 629 SET_SIZE(dtrace_getupcstack_top) 630 631#endif 632 633#if defined(lint) 634 635/*ARGSUSED*/ 636int 637dtrace_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 6601: 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 6672: 668 retl 669 nop 670 SET_SIZE(dtrace_getustackdepth_top) 671 672#endif 673 674#if defined(lint) || defined(__lint) 675 676/* ARGSUSED */ 677ulong_t 678dtrace_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 6911: 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 7112: 712 jmp %g3 713 ba 3f 7143: 715 wrpr %g2, %cwp 716 retl 717 mov %g1, %o0 718 719dtrace_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 */ 743void 744dtrace_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 7571: 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 7782: 779 jmp %g3 780 ba 3f 7813: 782 wrpr %g2, %cwp 783 retl 784 nop 785 786dtrace_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*/ 810void 811dtrace_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 832