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