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