xref: /titanic_51/usr/src/uts/sparc/dtrace/dtrace_asm.s (revision 5d54f3d8999eac1762fe0a8c7177d20f1f201fae)
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 - %canrestore
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)
596
597/*ARGSUSED*/
598int
599dtrace_getustackdepth_top(uintptr_t *sp)
600{ return (0); }
601
602#else
603
604	ENTRY(dtrace_getustackdepth_top)
605	mov	%o0, %o2
606	rdpr	%otherwin, %o0
607
608	brlez,a,pn %o0, 2f		! return 0 if there are no user wins
609	clr	%o0
610
611	rdpr	%cwp, %g4		! remember our window so we can return
612	rdpr	%canrestore, %g2	! compute the first user window
613	sub	%g4, %g2, %g2		! current = %cwp - %canrestore -
614	subcc	%g2, %o0, %g2		!     %otherwin
615
616	bge,pt	%xcc, 1f		! normalize the window if necessary
617	sethi	%hi(nwin_minus_one), %g3
618	ld	[%g3 + %lo(nwin_minus_one)], %g3
619	add	%g2, %g3, %g2
620	add	%g2, 1, %g2
621
6221:
623	wrpr	%g2, %cwp		! change to the first user window
624	mov	%i6, %g6		! stash the frame pointer
625	wrpr	%g4, %cwp		! change back to the original window
626
627	stn	%g6, [%o2]		! return the frame pointer
628
6292:
630	retl
631	nop
632	SET_SIZE(dtrace_getustackdepth_top)
633
634#endif
635
636#if defined(lint) || defined(__lint)
637
638/* ARGSUSED */
639ulong_t
640dtrace_getreg_win(uint_t reg, uint_t depth)
641{ return (0); }
642
643#else	/* lint */
644
645	ENTRY(dtrace_getreg_win)
646	sub	%o0, 16, %o0
647	cmp	%o0, 16			! %o0 must begin in the range [16..32)
648	blu,pt	%xcc, 1f
649	nop
650	retl
651	clr	%o0
652
6531:
654	set	dtrace_getreg_win_table, %g3
655	sll	%o0, 2, %o0
656	add	%g3, %o0, %g3
657
658	rdpr	%canrestore, %o3
659	rdpr	%cwp, %g2
660
661	! Set %cwp to be (%cwp - %canrestore - %o1) mod NWINDOWS
662
663	sub	%g2, %o3, %o2		! %o2 is %cwp - %canrestore
664	subcc	%o2, %o1, %o4
665	bge,a,pn %xcc, 2f
666	wrpr	%o4, %cwp
667
668	sethi	%hi(nwin_minus_one), %o3
669	ld	[%o3 + %lo(nwin_minus_one)], %o3
670
671	add	%o2, %o3, %o4
672	wrpr	%o4, %cwp
6732:
674	jmp	%g3
675	ba	3f
6763:
677	wrpr	%g2, %cwp
678	retl
679	mov	%g1, %o0
680
681dtrace_getreg_win_table:
682	mov	%l0, %g1
683	mov	%l1, %g1
684	mov	%l2, %g1
685	mov	%l3, %g1
686	mov	%l4, %g1
687	mov	%l5, %g1
688	mov	%l6, %g1
689	mov	%l7, %g1
690	mov	%i0, %g1
691	mov	%i1, %g1
692	mov	%i2, %g1
693	mov	%i3, %g1
694	mov	%i4, %g1
695	mov	%i5, %g1
696	mov	%i6, %g1
697	mov	%i7, %g1
698	SET_SIZE(dtrace_getreg_win)
699
700#endif	/* lint */
701
702#if defined(lint) || defined(__lint)
703
704/* ARGSUSED */
705void
706dtrace_putreg_win(uint_t reg, ulong_t value)
707{}
708
709#else	/* lint */
710
711	ENTRY(dtrace_putreg_win)
712	sub	%o0, 16, %o0
713	cmp	%o0, 16			! %o0 must be in the range [16..32)
714	blu,pt	%xcc, 1f
715	nop
716	retl
717	nop
718
7191:
720	mov	%o1, %g1		! move the value into a global register
721
722	set	dtrace_putreg_table, %g3
723	sll	%o0, 2, %o0
724	add	%g3, %o0, %g3
725
726	rdpr	%canrestore, %o3
727	rdpr	%cwp, %g2
728
729	! Set %cwp to be (%cwp - %canrestore - 1) mod NWINDOWS
730
731	sub	%g2, %o3, %o2		! %o2 is %cwp - %canrestore
732	subcc	%o2, 1, %o4
733	bge,a,pn %xcc, 2f
734	wrpr	%o4, %cwp
735
736	sethi	%hi(nwin_minus_one), %o3
737	ld	[%o3 + %lo(nwin_minus_one)], %o3
738	add	%o2, %o3, %o4
739	wrpr	%o4, %cwp
7402:
741	jmp	%g3
742	ba	3f
7433:
744	wrpr	%g2, %cwp
745	retl
746	nop
747
748dtrace_putreg_table:
749	mov	%g1, %l0
750	mov	%g1, %l1
751	mov	%g1, %l2
752	mov	%g1, %l3
753	mov	%g1, %l4
754	mov	%g1, %l5
755	mov	%g1, %l6
756	mov	%g1, %l7
757	mov	%g1, %i0
758	mov	%g1, %i1
759	mov	%g1, %i2
760	mov	%g1, %i3
761	mov	%g1, %i4
762	mov	%g1, %i5
763	mov	%g1, %i6
764	mov	%g1, %i7
765	SET_SIZE(dtrace_putreg_win)
766
767#endif	/* lint */
768
769#if defined(lint) || defined(__lint)
770
771/*ARGSUSED*/
772void
773dtrace_probe_error(dtrace_state_t *state, dtrace_epid_t epid, int which,
774    int fault, int fltoffs, uintptr_t illval)
775{}
776
777#else	/* lint */
778
779	ENTRY(dtrace_probe_error)
780	save	%sp, -SA(MINFRAME), %sp
781	sethi	%hi(dtrace_probeid_error), %l0
782	ld	[%l0 + %lo(dtrace_probeid_error)], %o0
783	mov	%i0, %o1
784	mov	%i1, %o2
785	mov	%i2, %o3
786	mov	%i3, %o4
787	call	dtrace_probe
788	mov	%i4, %o5
789	ret
790	restore
791	SET_SIZE(dtrace_probe_error)
792
793#endif
794