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#include <sys/asm_linkage.h>
27#include <sys/privregs.h>
28#include <sys/fsr.h>
29#include <sys/asi.h>
30#include "assym.h"
31
32	ENTRY_NP(dtrace_getipl)
33	retl
34	rdpr	%pil, %o0
35	SET_SIZE(dtrace_getipl)
36
37	ENTRY_NP(dtrace_getotherwin)
38	retl
39	rdpr	%otherwin, %o0
40	SET_SIZE(dtrace_getotherwin)
41
42	ENTRY_NP(dtrace_getfprs)
43	retl
44	rd	%fprs, %o0
45	SET_SIZE(dtrace_getfprs)
46
47	ENTRY_NP(dtrace_getfsr)
48	rdpr	%pstate, %o1
49	andcc	%o1, PSTATE_PEF, %g0
50	bz,pn	%xcc, 1f
51	nop
52	rd	%fprs, %o1
53	andcc	%o1, FPRS_FEF, %g0
54	bz,pn	%xcc, 1f
55	nop
56	retl
57	stx	%fsr, [%o0]
581:
59	retl
60	stx	%g0, [%o0]
61	SET_SIZE(dtrace_getfsr)
62
63	ENTRY_NP(dtrace_getfp)
64	retl
65	mov	%fp, %o0
66	SET_SIZE(dtrace_getfp)
67
68	ENTRY_NP(dtrace_flush_user_windows)
69	rdpr	%otherwin, %g1
70	brz	%g1, 3f
71	clr	%g2
721:
73	save	%sp, -WINDOWSIZE, %sp
74	rdpr	%otherwin, %g1
75	brnz	%g1, 1b
76	add	%g2, 1, %g2
772:
78	sub	%g2, 1, %g2		! restore back to orig window
79	brnz	%g2, 2b
80	restore
813:
82	retl
83	nop
84	SET_SIZE(dtrace_flush_user_windows)
85
86	ENTRY(dtrace_cas32)
87	cas	[%o0], %o1, %o2
88	retl
89	mov	%o2, %o0
90	SET_SIZE(dtrace_cas32)
91
92	ENTRY(dtrace_casptr)
93	casn	[%o0], %o1, %o2
94	retl
95	mov	%o2, %o0
96	SET_SIZE(dtrace_casptr)
97
98	ENTRY(dtrace_caller)
99	sethi	%hi(nwin_minus_one), %g4
100	ld	[%g4 + %lo(nwin_minus_one)], %g4
101	rdpr	%canrestore, %g2
102	cmp	%g2, %o0
103	bl	%icc, 1f
104	rdpr	%cwp, %g1
105	sub	%g1, %o0, %g3
106	brgez,a,pt %g3, 0f
107	wrpr	%g3, %cwp
108
109	!
110	! CWP minus the number of frames is negative; we must perform the
111	! arithmetic modulo MAXWIN.
112	!
113	add	%g4, %g3, %g3
114	inc	%g3
115	wrpr	%g3, %cwp
1160:
117	mov	%i7, %g4
118	wrpr	%g1, %cwp
119	retl
120	mov	%g4, %o0
1211:
122	!
123	! The caller has been flushed to the stack.  This is unlikely
124	! (interrupts are disabled in dtrace_probe()), but possible (the
125	! interrupt inducing the spill may have been taken before the
126	! call to dtrace_probe()).
127	!
128	retl
129	mov	-1, %o0
130	SET_SIZE(dtrace_caller)
131
132	ENTRY(dtrace_fish)
133
134	rd	%pc, %g5
135	ba	0f
136	add	%g5, 12, %g5
137	mov	%l0, %g4
138	mov	%l1, %g4
139	mov	%l2, %g4
140	mov	%l3, %g4
141	mov	%l4, %g4
142	mov	%l5, %g4
143	mov	%l6, %g4
144	mov	%l7, %g4
145	mov	%i0, %g4
146	mov	%i1, %g4
147	mov	%i2, %g4
148	mov	%i3, %g4
149	mov	%i4, %g4
150	mov	%i5, %g4
151	mov	%i6, %g4
152	mov	%i7, %g4
1530:
154	sub	%o1, 16, %o1		! Can only retrieve %l's and %i's
155	sll	%o1, 2, %o1		! Multiply by instruction size
156	add	%g5, %o1, %g5		! %g5 now contains the instr. to pick
157
158	sethi	%hi(nwin_minus_one), %g4
159	ld	[%g4 + %lo(nwin_minus_one)], %g4
160
161	!
162	! First we need to see if the frame that we're fishing in is still
163	! contained in the register windows.
164	!
165	rdpr	%canrestore, %g2
166	cmp	%g2, %o0
167	bl	%icc, 2f
168	rdpr	%cwp, %g1
169	sub	%g1, %o0, %g3
170	brgez,a,pt %g3, 0f
171	wrpr	%g3, %cwp
172
173	!
174	! CWP minus the number of frames is negative; we must perform the
175	! arithmetic modulo MAXWIN.
176	!
177	add	%g4, %g3, %g3
178	inc	%g3
179	wrpr	%g3, %cwp
1800:
181	jmp	%g5
182	ba	1f
1831:
184	wrpr	%g1, %cwp
185	stn	%g4, [%o2]
186	retl
187	clr	%o0			! Success; return 0.
1882:
189	!
190	! The frame that we're looking for has been flushed to the stack; the
191	! caller will be forced to
192	!
193	retl
194	add	%g2, 1, %o0		! Failure; return deepest frame + 1
195	SET_SIZE(dtrace_fish)
196
197	ENTRY(dtrace_copyin)
198	tst	%o2
199	bz	2f
200	clr	%g1
201	lduba	[%o0 + %g1]ASI_USER, %g2
2020:
203	! check for an error if the count is 4k-aligned
204	andcc	%g1, 0xfff, %g0
205	bnz,pt	%icc, 1f
206	stub	%g2, [%o1 + %g1]
207	lduh	[%o3], %g3
208	andcc	%g3, CPU_DTRACE_BADADDR, %g0
209	bnz,pn	%icc, 2f
210	nop
2111:
212	inc	%g1
213	cmp	%g1, %o2
214	bl,a	0b
215	lduba	[%o0 + %g1]ASI_USER, %g2
2162:
217	retl
218	nop
219
220	SET_SIZE(dtrace_copyin)
221
222	ENTRY(dtrace_copyinstr)
223	tst	%o2
224	bz	2f
225	clr	%g1
226	lduba	[%o0 + %g1]ASI_USER, %g2
2270:
228	stub	%g2, [%o1 + %g1]		! Store byte
229
230	! check for an error if the count is 4k-aligned
231	andcc	%g1, 0xfff, %g0
232	bnz,pt	%icc, 1f
233	inc	%g1
234	lduh	[%o3], %g3
235	andcc	%g3, CPU_DTRACE_BADADDR, %g0
236	bnz,pn	%icc, 2f
237	nop
2381:
239	cmp	%g2, 0				! Was that '\0'?
240	be	2f				! If so, we're done
241	cmp	%g1, %o2			! Compare to limit
242	bl,a	0b				! If less, take another lap
243	lduba	[%o0 + %g1]ASI_USER, %g2	!   delay: load user byte
2442:
245	retl
246	nop
247
248	SET_SIZE(dtrace_copyinstr)
249
250	ENTRY(dtrace_copyout)
251	tst	%o2
252	bz	2f
253	clr	%g1
254	ldub	[%o0 + %g1], %g2
2550:
256	! check for an error if the count is 4k-aligned
257	andcc	%g1, 0xfff, %g0
258	bnz,pt	%icc, 1f
259	stba	%g2, [%o1 + %g1]ASI_USER
260	lduh	[%o3], %g3
261	andcc	%g3, CPU_DTRACE_BADADDR, %g0
262	bnz,pn	%icc, 2f
263	nop
2641:
265	inc	%g1
266	cmp	%g1, %o2
267	bl,a	0b
268	ldub	[%o0 + %g1], %g2
2692:
270	retl
271	nop
272	SET_SIZE(dtrace_copyout)
273
274	ENTRY(dtrace_copyoutstr)
275	tst	%o2
276	bz	2f
277	clr	%g1
278	ldub	[%o0 + %g1], %g2
2790:
280	stba	%g2, [%o1 + %g1]ASI_USER
281
282	! check for an error if the count is 4k-aligned
283	andcc	%g1, 0xfff, %g0
284	bnz,pt  %icc, 1f
285	inc	%g1
286	lduh	[%o3], %g3
287	andcc	%g3, CPU_DTRACE_BADADDR, %g0
288	bnz,pn	%icc, 2f
289	nop
2901:
291	cmp	%g2, 0
292	be	2f
293	cmp	%g1, %o2
294	bl,a	0b
295	ldub	[%o0 + %g1], %g2
2962:
297	retl
298	nop
299	SET_SIZE(dtrace_copyoutstr)
300
301	ENTRY(dtrace_fulword)
302	clr	%o1
303	ldna	[%o0]ASI_USER, %o1
304	retl
305	mov	%o1, %o0
306	SET_SIZE(dtrace_fulword)
307
308	ENTRY(dtrace_fuword8)
309	clr	%o1
310	lduba	[%o0]ASI_USER, %o1
311	retl
312	mov	%o1, %o0
313	SET_SIZE(dtrace_fuword8)
314
315	ENTRY(dtrace_fuword16)
316	clr	%o1
317	lduha	[%o0]ASI_USER, %o1
318	retl
319	mov	%o1, %o0
320	SET_SIZE(dtrace_fuword16)
321
322	ENTRY(dtrace_fuword32)
323	clr	%o1
324	lda	[%o0]ASI_USER, %o1
325	retl
326	mov	%o1, %o0
327	SET_SIZE(dtrace_fuword32)
328
329	ENTRY(dtrace_fuword64)
330	clr	%o1
331	ldxa	[%o0]ASI_USER, %o1
332	retl
333	mov	%o1, %o0
334	SET_SIZE(dtrace_fuword64)
335
336	/*
337	 * %g1	pcstack
338	 * %g2	current window
339	 * %g3	maxwin (nwindows - 1)
340	 * %g4	saved %cwp (so we can get back to the original window)
341	 * %g5	iteration count
342	 * %g6	saved %fp
343	 *
344	 * %o0	pcstack / return value (iteration count)
345	 * %o1	pcstack_limit
346	 * %o2	last_fp
347	 */
348
349	ENTRY(dtrace_getupcstack_top)
350	mov	%o0, %g1		! we need the pcstack pointer while
351					! we're visiting other windows
352
353	rdpr	%otherwin, %g5		! compute the number of iterations
354	cmp	%g5, %o1		! (windows to observe) by taking the
355	movg	%icc, %o1, %g5		! min of %otherwin and pcstack_limit
356
357	brlez,a,pn %g5, 2f		! return 0 if count <= 0
358	clr	%o0
359
360	sethi	%hi(nwin_minus_one), %g3 ! hang onto maxwin since we'll need
361	ld	[%g3 + %lo(nwin_minus_one)], %g3 ! it for our modular arithmetic
362
363	rdpr	%cwp, %g4		! remember our window so we can return
364	rdpr	%canrestore, %g2	! compute the first non-user window
365	subcc	%g4, %g2, %g2		! current = %cwp - %canrestore
366
367	bge,pt	%xcc, 1f		! good to go if current is >= 0
368	mov	%g5, %o0		! we need to return the count
369
370	add	%g2, %g3, %g2		! normalize our current window if it's
371	add	%g2, 1, %g2		! less than zero
372
373	! note that while it's tempting, we can't execute restore to decrement
374	! the %cwp by one (mod nwindows) because we're in the user's windows
3751:
376	deccc	%g2			! decrement the current window
377	movl	%xcc, %g3, %g2		! normalize if it's negative (-1)
378
379	wrpr	%g2, %cwp		! change windows
380
381	stx	%i7, [%g1]		! stash the return address in pcstack
382
383	deccc	%g5			! decrement the count
384	bnz,pt	%icc, 1b		! we iterate until the count reaches 0
385	add	%g1, 8, %g1		! increment the pcstack pointer
386
387	mov	%i6, %g6		! stash the last frame pointer we
388					! encounter so the caller can
389					! continue the stack walk in memory
390
391	wrpr	%g4, %cwp		! change back to the original window
392
393	stn	%g6, [%o2]		! return the last frame pointer
394
3952:
396	retl
397	nop
398	SET_SIZE(dtrace_getupcstack_top)
399
400	ENTRY(dtrace_getustackdepth_top)
401	mov	%o0, %o2
402	rdpr	%otherwin, %o0
403
404	brlez,a,pn %o0, 2f		! return 0 if there are no user wins
405	clr	%o0
406
407	rdpr	%cwp, %g4		! remember our window so we can return
408	rdpr	%canrestore, %g2	! compute the first user window
409	sub	%g4, %g2, %g2		! current = %cwp - %canrestore -
410	subcc	%g2, %o0, %g2		!     %otherwin
411
412	bge,pt	%xcc, 1f		! normalize the window if necessary
413	sethi	%hi(nwin_minus_one), %g3
414	ld	[%g3 + %lo(nwin_minus_one)], %g3
415	add	%g2, %g3, %g2
416	add	%g2, 1, %g2
417
4181:
419	wrpr	%g2, %cwp		! change to the first user window
420	mov	%i6, %g6		! stash the frame pointer
421	wrpr	%g4, %cwp		! change back to the original window
422
423	stn	%g6, [%o2]		! return the frame pointer
424
4252:
426	retl
427	nop
428	SET_SIZE(dtrace_getustackdepth_top)
429
430	ENTRY(dtrace_getreg_win)
431	sub	%o0, 16, %o0
432	cmp	%o0, 16			! %o0 must begin in the range [16..32)
433	blu,pt	%xcc, 1f
434	nop
435	retl
436	clr	%o0
437
4381:
439	set	dtrace_getreg_win_table, %g3
440	sll	%o0, 2, %o0
441	add	%g3, %o0, %g3
442
443	rdpr	%canrestore, %o3
444	rdpr	%cwp, %g2
445
446	! Set %cwp to be (%cwp - %canrestore - %o1) mod NWINDOWS
447
448	sub	%g2, %o3, %o2		! %o2 is %cwp - %canrestore
449	subcc	%o2, %o1, %o4
450	bge,a,pn %xcc, 2f
451	wrpr	%o4, %cwp
452
453	sethi	%hi(nwin_minus_one), %o3
454	ld	[%o3 + %lo(nwin_minus_one)], %o3
455
456	add	%o2, %o3, %o4
457	wrpr	%o4, %cwp
4582:
459	jmp	%g3
460	ba	3f
4613:
462	wrpr	%g2, %cwp
463	retl
464	mov	%g1, %o0
465
466dtrace_getreg_win_table:
467	mov	%l0, %g1
468	mov	%l1, %g1
469	mov	%l2, %g1
470	mov	%l3, %g1
471	mov	%l4, %g1
472	mov	%l5, %g1
473	mov	%l6, %g1
474	mov	%l7, %g1
475	mov	%i0, %g1
476	mov	%i1, %g1
477	mov	%i2, %g1
478	mov	%i3, %g1
479	mov	%i4, %g1
480	mov	%i5, %g1
481	mov	%i6, %g1
482	mov	%i7, %g1
483	SET_SIZE(dtrace_getreg_win)
484
485	ENTRY(dtrace_putreg_win)
486	sub	%o0, 16, %o0
487	cmp	%o0, 16			! %o0 must be in the range [16..32)
488	blu,pt	%xcc, 1f
489	nop
490	retl
491	nop
492
4931:
494	mov	%o1, %g1		! move the value into a global register
495
496	set	dtrace_putreg_table, %g3
497	sll	%o0, 2, %o0
498	add	%g3, %o0, %g3
499
500	rdpr	%canrestore, %o3
501	rdpr	%cwp, %g2
502
503	! Set %cwp to be (%cwp - %canrestore - 1) mod NWINDOWS
504
505	sub	%g2, %o3, %o2		! %o2 is %cwp - %canrestore
506	subcc	%o2, 1, %o4
507	bge,a,pn %xcc, 2f
508	wrpr	%o4, %cwp
509
510	sethi	%hi(nwin_minus_one), %o3
511	ld	[%o3 + %lo(nwin_minus_one)], %o3
512	add	%o2, %o3, %o4
513	wrpr	%o4, %cwp
5142:
515	jmp	%g3
516	ba	3f
5173:
518	wrpr	%g2, %cwp
519	retl
520	nop
521
522dtrace_putreg_table:
523	mov	%g1, %l0
524	mov	%g1, %l1
525	mov	%g1, %l2
526	mov	%g1, %l3
527	mov	%g1, %l4
528	mov	%g1, %l5
529	mov	%g1, %l6
530	mov	%g1, %l7
531	mov	%g1, %i0
532	mov	%g1, %i1
533	mov	%g1, %i2
534	mov	%g1, %i3
535	mov	%g1, %i4
536	mov	%g1, %i5
537	mov	%g1, %i6
538	mov	%g1, %i7
539	SET_SIZE(dtrace_putreg_win)
540
541	ENTRY(dtrace_probe_error)
542	save	%sp, -SA(MINFRAME), %sp
543	sethi	%hi(dtrace_probeid_error), %l0
544	ld	[%l0 + %lo(dtrace_probeid_error)], %o0
545	mov	%i0, %o1
546	mov	%i1, %o2
547	mov	%i2, %o3
548	mov	%i3, %o4
549	call	dtrace_probe
550	mov	%i4, %o5
551	ret
552	restore
553	SET_SIZE(dtrace_probe_error)
554
555