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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22/* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27#pragma ident "%Z%%M% %I% %E% SMI" 28 29#if defined(lint) || defined(__lint) 30#include <sys/dtrace_impl.h> 31#else 32#include <sys/asm_linkage.h> 33#include <sys/privregs.h> 34#include <sys/fsr.h> 35#include <sys/asi.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{} 322 323#else 324 325 ENTRY(dtrace_copyin) 326 tst %o2 327 bz 1f 328 clr %g1 329 lduba [%o0 + %g1]ASI_USER, %g2 3300: 331 stub %g2, [%o1 + %g1] 332 inc %g1 333 cmp %g1, %o2 334 bl,a 0b 335 lduba [%o0 + %g1]ASI_USER, %g2 3361: 337 retl 338 nop 339 340 SET_SIZE(dtrace_copyin) 341 342#endif 343 344#if defined(lint) 345 346/*ARGSUSED*/ 347void 348dtrace_copyinstr(uintptr_t uaddr, uintptr_t kaddr, size_t size) 349{} 350 351#else 352 353 ENTRY(dtrace_copyinstr) 354 tst %o2 355 bz 1f 356 clr %g1 357 lduba [%o0 + %g1]ASI_USER, %g2 3580: 359 stub %g2, [%o1 + %g1] ! Store byte 360 cmp %g2, 0 ! Was that '\0'? 361 be 1f ! If so, we're done 362 inc %g1 ! Increment offset 363 cmp %g1, %o2 ! Compare to limit 364 bl,a 0b ! If less, take another lap 365 lduba [%o0 + %g1]ASI_USER, %g2 ! delay: load user byte 3661: 367 retl 368 nop 369 370 SET_SIZE(dtrace_copyinstr) 371 372#endif 373 374#if defined(lint) 375 376/*ARGSUSED*/ 377void 378dtrace_copyout(uintptr_t kaddr, uintptr_t uaddr, size_t size) 379{} 380 381#else 382 383 ENTRY(dtrace_copyout) 384 tst %o2 385 bz 1f 386 clr %g1 387 ldub [%o0 + %g1], %g2 3880: 389 stba %g2, [%o1 + %g1]ASI_USER 390 inc %g1 391 cmp %g1, %o2 392 bl,a 0b 393 ldub [%o0 + %g1], %g2 3941: 395 retl 396 nop 397 SET_SIZE(dtrace_copyout) 398 399#endif 400 401#if defined(lint) 402 403/*ARGSUSED*/ 404void 405dtrace_copyoutstr(uintptr_t kaddr, uintptr_t uaddr, size_t size) 406{} 407 408#else 409 410 ENTRY(dtrace_copyoutstr) 411 tst %o2 412 bz 1f 413 clr %g1 414 ldub [%o0 + %g1], %g2 4150: 416 stba %g2, [%o1 + %g1]ASI_USER 417 cmp %g2, 0 418 be 1f 419 inc %g1 420 cmp %g1, %o2 421 bl,a 0b 422 ldub [%o0 + %g1], %g2 4231: 424 retl 425 nop 426 SET_SIZE(dtrace_copyoutstr) 427 428#endif 429 430#if defined(lint) 431 432/*ARGSUSED*/ 433uintptr_t 434dtrace_fulword(void *addr) 435{ return (0); } 436 437#else 438 439 ENTRY(dtrace_fulword) 440 clr %o1 441 ldna [%o0]ASI_USER, %o1 442 retl 443 mov %o1, %o0 444 SET_SIZE(dtrace_fulword) 445 446#endif 447 448#if defined(lint) 449 450/*ARGSUSED*/ 451uint8_t 452dtrace_fuword8(void *addr) 453{ return (0); } 454 455#else 456 457 ENTRY(dtrace_fuword8) 458 clr %o1 459 lduba [%o0]ASI_USER, %o1 460 retl 461 mov %o1, %o0 462 SET_SIZE(dtrace_fuword8) 463 464#endif 465 466#if defined(lint) 467 468/*ARGSUSED*/ 469uint16_t 470dtrace_fuword16(void *addr) 471{ return (0); } 472 473#else 474 475 ENTRY(dtrace_fuword16) 476 clr %o1 477 lduha [%o0]ASI_USER, %o1 478 retl 479 mov %o1, %o0 480 SET_SIZE(dtrace_fuword16) 481 482#endif 483 484#if defined(lint) 485 486/*ARGSUSED*/ 487uint32_t 488dtrace_fuword32(void *addr) 489{ return (0); } 490 491#else 492 493 ENTRY(dtrace_fuword32) 494 clr %o1 495 lda [%o0]ASI_USER, %o1 496 retl 497 mov %o1, %o0 498 SET_SIZE(dtrace_fuword32) 499 500#endif 501 502#if defined(lint) 503 504/*ARGSUSED*/ 505uint64_t 506dtrace_fuword64(void *addr) 507{ return (0); } 508 509#else 510 511 ENTRY(dtrace_fuword64) 512 clr %o1 513 ldxa [%o0]ASI_USER, %o1 514 retl 515 mov %o1, %o0 516 SET_SIZE(dtrace_fuword64) 517 518#endif 519 520#if defined(lint) 521 522/*ARGSUSED*/ 523int 524dtrace_getupcstack_top(uint64_t *pcstack, int pcstack_limit, uintptr_t *sp) 525{ return (0); } 526 527#else 528 529 /* 530 * %g1 pcstack 531 * %g2 current window 532 * %g3 maxwin (nwindows - 1) 533 * %g4 saved %cwp (so we can get back to the original window) 534 * %g5 iteration count 535 * %g6 saved %fp 536 * 537 * %o0 pcstack / return value (iteration count) 538 * %o1 pcstack_limit 539 * %o2 last_fp 540 */ 541 542 ENTRY(dtrace_getupcstack_top) 543 mov %o0, %g1 ! we need the pcstack pointer while 544 ! we're visiting other windows 545 546 rdpr %otherwin, %g5 ! compute the number of iterations 547 cmp %g5, %o1 ! (windows to observe) by taking the 548 movg %icc, %o1, %g5 ! min of %otherwin and pcstack_limit 549 550 brlez,a,pn %g5, 2f ! return 0 if count <= 0 551 clr %o0 552 553 sethi %hi(nwin_minus_one), %g3 ! hang onto maxwin since we'll need 554 ld [%g3 + %lo(nwin_minus_one)], %g3 ! it for our modular arithmetic 555 556 rdpr %cwp, %g4 ! remember our window so we can return 557 rdpr %canrestore, %g2 ! compute the first non-user window 558 subcc %g4, %g2, %g2 ! current = %cwp - %otherwin 559 560 bge,pt %xcc, 1f ! good to go if current is >= 0 561 mov %g5, %o0 ! we need to return the count 562 563 add %g2, %g3, %g2 ! normalize our current window if it's 564 add %g2, 1, %g2 ! less than zero 565 566 ! note that while it's tempting, we can't execute restore to decrement 567 ! the %cwp by one (mod nwindows) because we're in the user's windows 5681: 569 deccc %g2 ! decrement the current window 570 movl %xcc, %g3, %g2 ! normalize if it's negative (-1) 571 572 wrpr %g2, %cwp ! change windows 573 574 stx %i7, [%g1] ! stash the return address in pcstack 575 576 deccc %g5 ! decrement the count 577 bnz,pt %icc, 1b ! we iterate until the count reaches 0 578 add %g1, 8, %g1 ! increment the pcstack pointer 579 580 mov %i6, %g6 ! stash the last frame pointer we 581 ! encounter so the caller can 582 ! continue the stack walk in memory 583 584 wrpr %g4, %cwp ! change back to the original window 585 586 stn %g6, [%o2] ! return the last frame pointer 587 5882: 589 retl 590 nop 591 SET_SIZE(dtrace_getupcstack_top) 592 593#endif 594 595#if defined(lint) || defined(__lint) 596 597/* ARGSUSED */ 598ulong_t 599dtrace_getreg_win(uint_t reg, uint_t depth) 600{ return (0); } 601 602#else /* lint */ 603 604 ENTRY(dtrace_getreg_win) 605 sub %o0, 16, %o0 606 cmp %o0, 16 ! %o0 must begin in the range [16..32) 607 blu,pt %xcc, 1f 608 nop 609 retl 610 clr %o0 611 6121: 613 set dtrace_getreg_win_table, %g3 614 sll %o0, 2, %o0 615 add %g3, %o0, %g3 616 617 rdpr %canrestore, %o3 618 rdpr %cwp, %g2 619 620 ! Set %cwp to be (%cwp - %canrestore - %o1) mod NWINDOWS 621 622 sub %g2, %o3, %o2 ! %o2 is %cwp - %canrestore 623 subcc %o2, %o1, %o4 624 bge,a,pn %xcc, 2f 625 wrpr %o4, %cwp 626 627 sethi %hi(nwin_minus_one), %o3 628 ld [%o3 + %lo(nwin_minus_one)], %o3 629 630 add %o2, %o3, %o4 631 wrpr %o4, %cwp 6322: 633 jmp %g3 634 ba 3f 6353: 636 wrpr %g2, %cwp 637 retl 638 mov %g1, %o0 639 640dtrace_getreg_win_table: 641 mov %l0, %g1 642 mov %l1, %g1 643 mov %l2, %g1 644 mov %l3, %g1 645 mov %l4, %g1 646 mov %l5, %g1 647 mov %l6, %g1 648 mov %l7, %g1 649 mov %i0, %g1 650 mov %i1, %g1 651 mov %i2, %g1 652 mov %i3, %g1 653 mov %i4, %g1 654 mov %i5, %g1 655 mov %i6, %g1 656 mov %i7, %g1 657 SET_SIZE(dtrace_getreg_win) 658 659#endif /* lint */ 660 661#if defined(lint) || defined(__lint) 662 663/* ARGSUSED */ 664void 665dtrace_putreg_win(uint_t reg, ulong_t value) 666{} 667 668#else /* lint */ 669 670 ENTRY(dtrace_putreg_win) 671 sub %o0, 16, %o0 672 cmp %o0, 16 ! %o0 must be in the range [16..32) 673 blu,pt %xcc, 1f 674 nop 675 retl 676 nop 677 6781: 679 mov %o1, %g1 ! move the value into a global register 680 681 set dtrace_putreg_table, %g3 682 sll %o0, 2, %o0 683 add %g3, %o0, %g3 684 685 rdpr %canrestore, %o3 686 rdpr %cwp, %g2 687 688 ! Set %cwp to be (%cwp - %canrestore - 1) mod NWINDOWS 689 690 sub %g2, %o3, %o2 ! %o2 is %cwp - %canrestore 691 subcc %o2, 1, %o4 692 bge,a,pn %xcc, 2f 693 wrpr %o4, %cwp 694 695 sethi %hi(nwin_minus_one), %o3 696 ld [%o3 + %lo(nwin_minus_one)], %o3 697 add %o2, %o3, %o4 698 wrpr %o4, %cwp 6992: 700 jmp %g3 701 ba 3f 7023: 703 wrpr %g2, %cwp 704 retl 705 nop 706 707dtrace_putreg_table: 708 mov %g1, %l0 709 mov %g1, %l1 710 mov %g1, %l2 711 mov %g1, %l3 712 mov %g1, %l4 713 mov %g1, %l5 714 mov %g1, %l6 715 mov %g1, %l7 716 mov %g1, %i0 717 mov %g1, %i1 718 mov %g1, %i2 719 mov %g1, %i3 720 mov %g1, %i4 721 mov %g1, %i5 722 mov %g1, %i6 723 mov %g1, %i7 724 SET_SIZE(dtrace_putreg_win) 725 726#endif /* lint */ 727 728#if defined(lint) || defined(__lint) 729 730/*ARGSUSED*/ 731void 732dtrace_probe_error(dtrace_state_t *state, dtrace_epid_t epid, int which, 733 int fault, int fltoffs, uintptr_t illval) 734{} 735 736#else /* lint */ 737 738 ENTRY(dtrace_probe_error) 739 save %sp, -SA(MINFRAME), %sp 740 sethi %hi(dtrace_probeid_error), %l0 741 ld [%l0 + %lo(dtrace_probeid_error)], %o0 742 mov %i0, %o1 743 mov %i1, %o2 744 mov %i2, %o3 745 mov %i3, %o4 746 call dtrace_probe 747 mov %i4, %o5 748 ret 749 restore 750 SET_SIZE(dtrace_probe_error) 751 752#endif 753