1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate #include <sys/dtrace.h>
30*0Sstevel@tonic-gate #include <sys/fasttrap.h>
31*0Sstevel@tonic-gate #include <sys/x_call.h>
32*0Sstevel@tonic-gate #include <sys/atomic.h>
33*0Sstevel@tonic-gate #include <sys/machsystm.h>
34*0Sstevel@tonic-gate 
35*0Sstevel@tonic-gate static void
36*0Sstevel@tonic-gate dtrace_xcall_func(uint64_t arg1, uint64_t arg2)
37*0Sstevel@tonic-gate {
38*0Sstevel@tonic-gate 	(*(dtrace_xcall_t)arg1)((void *)(arg2));
39*0Sstevel@tonic-gate }
40*0Sstevel@tonic-gate 
41*0Sstevel@tonic-gate void
42*0Sstevel@tonic-gate dtrace_xcall(processorid_t cpu, dtrace_xcall_t func, void *arg)
43*0Sstevel@tonic-gate {
44*0Sstevel@tonic-gate 	if (cpu == DTRACE_CPUALL) {
45*0Sstevel@tonic-gate 		xc_all(dtrace_xcall_func, (uint64_t)func, (uint64_t)arg);
46*0Sstevel@tonic-gate 	} else {
47*0Sstevel@tonic-gate 		xc_one(cpu, dtrace_xcall_func, (uint64_t)func, (uint64_t)arg);
48*0Sstevel@tonic-gate 	}
49*0Sstevel@tonic-gate }
50*0Sstevel@tonic-gate 
51*0Sstevel@tonic-gate /*ARGSUSED*/
52*0Sstevel@tonic-gate static void
53*0Sstevel@tonic-gate dtrace_sync_func(uint64_t arg1, uint64_t arg2)
54*0Sstevel@tonic-gate {
55*0Sstevel@tonic-gate 	membar_consumer();
56*0Sstevel@tonic-gate }
57*0Sstevel@tonic-gate 
58*0Sstevel@tonic-gate void
59*0Sstevel@tonic-gate dtrace_sync(void)
60*0Sstevel@tonic-gate {
61*0Sstevel@tonic-gate 	membar_producer();
62*0Sstevel@tonic-gate 	xc_all(dtrace_sync_func, 0, 0);
63*0Sstevel@tonic-gate }
64*0Sstevel@tonic-gate 
65*0Sstevel@tonic-gate void
66*0Sstevel@tonic-gate dtrace_toxic_ranges(void (*func)(uintptr_t base, uintptr_t limit))
67*0Sstevel@tonic-gate {
68*0Sstevel@tonic-gate 	(*func)(PIOMAPBASE, PIOMAPBASE + PIOMAPSIZE);
69*0Sstevel@tonic-gate 	(*func)(OFW_START_ADDR, OFW_END_ADDR);
70*0Sstevel@tonic-gate 
71*0Sstevel@tonic-gate 	if (hole_end > hole_start)
72*0Sstevel@tonic-gate 		(*func)((uintptr_t)hole_start, (uintptr_t)hole_end);
73*0Sstevel@tonic-gate }
74*0Sstevel@tonic-gate 
75*0Sstevel@tonic-gate int (*dtrace_fasttrap_probe_ptr)(struct regs *);
76*0Sstevel@tonic-gate 
77*0Sstevel@tonic-gate void
78*0Sstevel@tonic-gate dtrace_fasttrap_probe(struct regs *rp)
79*0Sstevel@tonic-gate {
80*0Sstevel@tonic-gate 	krwlock_t *rwp = &CPU->cpu_ft_lock;
81*0Sstevel@tonic-gate 
82*0Sstevel@tonic-gate 	rw_enter(rwp, RW_READER);
83*0Sstevel@tonic-gate 	if (dtrace_fasttrap_probe_ptr == NULL) {
84*0Sstevel@tonic-gate 		rw_exit(rwp);
85*0Sstevel@tonic-gate 		rp->r_pc = rp->r_npc;
86*0Sstevel@tonic-gate 		rp->r_npc = rp->r_pc + 4;
87*0Sstevel@tonic-gate 	} else {
88*0Sstevel@tonic-gate 		(void) (*dtrace_fasttrap_probe_ptr)(rp);
89*0Sstevel@tonic-gate 		rw_exit(rwp);
90*0Sstevel@tonic-gate 	}
91*0Sstevel@tonic-gate }
92*0Sstevel@tonic-gate 
93*0Sstevel@tonic-gate int (*dtrace_pid_probe_ptr)(struct regs *);
94*0Sstevel@tonic-gate 
95*0Sstevel@tonic-gate void
96*0Sstevel@tonic-gate dtrace_pid_probe(struct regs *rp)
97*0Sstevel@tonic-gate {
98*0Sstevel@tonic-gate 	krwlock_t *rwp = &CPU->cpu_ft_lock;
99*0Sstevel@tonic-gate 	uint32_t instr;
100*0Sstevel@tonic-gate 
101*0Sstevel@tonic-gate 	/*
102*0Sstevel@tonic-gate 	 * This trap should only be invoked if there's a corresponding
103*0Sstevel@tonic-gate 	 * enabled dtrace probe. If there isn't, send SIGILL as though
104*0Sstevel@tonic-gate 	 * the process had executed an invalid trap instruction.
105*0Sstevel@tonic-gate 	 */
106*0Sstevel@tonic-gate 	rw_enter(rwp, RW_READER);
107*0Sstevel@tonic-gate 	if (dtrace_pid_probe_ptr != NULL && (*dtrace_pid_probe_ptr)(rp) == 0) {
108*0Sstevel@tonic-gate 		rw_exit(rwp);
109*0Sstevel@tonic-gate 		return;
110*0Sstevel@tonic-gate 	}
111*0Sstevel@tonic-gate 	rw_exit(rwp);
112*0Sstevel@tonic-gate 
113*0Sstevel@tonic-gate 	/*
114*0Sstevel@tonic-gate 	 * It is possible that we were preempted after entering the kernel,
115*0Sstevel@tonic-gate 	 * and the tracepoint was removed. If it appears that the process hit
116*0Sstevel@tonic-gate 	 * our reserved trap instruction, we call send SIGILL just as though
117*0Sstevel@tonic-gate 	 * the user had executed an unused trap instruction.
118*0Sstevel@tonic-gate 	 */
119*0Sstevel@tonic-gate 	if (fuword32((void *)rp->r_pc, &instr) != 0 ||
120*0Sstevel@tonic-gate 	    instr == FASTTRAP_INSTR) {
121*0Sstevel@tonic-gate 		sigqueue_t *sqp = kmem_zalloc(sizeof (sigqueue_t), KM_SLEEP);
122*0Sstevel@tonic-gate 		proc_t *p = curproc;
123*0Sstevel@tonic-gate 
124*0Sstevel@tonic-gate 		sqp->sq_info.si_signo = SIGILL;
125*0Sstevel@tonic-gate 		sqp->sq_info.si_code = ILL_ILLTRP;
126*0Sstevel@tonic-gate 		sqp->sq_info.si_addr = (caddr_t)rp->r_pc;
127*0Sstevel@tonic-gate 		sqp->sq_info.si_trapno = 0x38;
128*0Sstevel@tonic-gate 
129*0Sstevel@tonic-gate 		mutex_enter(&p->p_lock);
130*0Sstevel@tonic-gate 		sigaddqa(p, curthread, sqp);
131*0Sstevel@tonic-gate 		mutex_exit(&p->p_lock);
132*0Sstevel@tonic-gate 		aston(curthread);
133*0Sstevel@tonic-gate 	}
134*0Sstevel@tonic-gate }
135*0Sstevel@tonic-gate 
136*0Sstevel@tonic-gate int (*dtrace_return_probe_ptr)(struct regs *);
137*0Sstevel@tonic-gate 
138*0Sstevel@tonic-gate void
139*0Sstevel@tonic-gate dtrace_return_probe(struct regs *rp)
140*0Sstevel@tonic-gate {
141*0Sstevel@tonic-gate 	krwlock_t *rwp;
142*0Sstevel@tonic-gate 	uintptr_t npc = curthread->t_dtrace_npc;
143*0Sstevel@tonic-gate 	uint8_t on = curthread->t_dtrace_on;
144*0Sstevel@tonic-gate 	uint8_t step = curthread->t_dtrace_step;
145*0Sstevel@tonic-gate 	uint8_t ret = curthread->t_dtrace_ret;
146*0Sstevel@tonic-gate 
147*0Sstevel@tonic-gate 	if (curthread->t_dtrace_ast) {
148*0Sstevel@tonic-gate 		aston(curthread);
149*0Sstevel@tonic-gate 		curthread->t_sig_check = 1;
150*0Sstevel@tonic-gate 	}
151*0Sstevel@tonic-gate 
152*0Sstevel@tonic-gate 	/*
153*0Sstevel@tonic-gate 	 * Clear all user tracing flags.
154*0Sstevel@tonic-gate 	 */
155*0Sstevel@tonic-gate 	curthread->t_dtrace_ft = 0;
156*0Sstevel@tonic-gate 
157*0Sstevel@tonic-gate 	/*
158*0Sstevel@tonic-gate 	 * If we weren't expecting to take a return probe trap, kill the
159*0Sstevel@tonic-gate 	 * process as though it had just executed an unassigned trap
160*0Sstevel@tonic-gate 	 * instruction.
161*0Sstevel@tonic-gate 	 */
162*0Sstevel@tonic-gate 	if (step == 0) {
163*0Sstevel@tonic-gate 		ASSERT(on != 0);
164*0Sstevel@tonic-gate 		tsignal(curthread, SIGILL);
165*0Sstevel@tonic-gate 		return;
166*0Sstevel@tonic-gate 	}
167*0Sstevel@tonic-gate 
168*0Sstevel@tonic-gate 	ASSERT(rp->r_npc == rp->r_pc + 4);
169*0Sstevel@tonic-gate 
170*0Sstevel@tonic-gate 	/*
171*0Sstevel@tonic-gate 	 * If we hit this trap unrelated to a return probe, we're just here
172*0Sstevel@tonic-gate 	 * to reset the AST flag since we deferred a signal until after we
173*0Sstevel@tonic-gate 	 * logically single-stepped the instruction we copied out.
174*0Sstevel@tonic-gate 	 */
175*0Sstevel@tonic-gate 	if (ret == 0) {
176*0Sstevel@tonic-gate 		rp->r_pc = npc;
177*0Sstevel@tonic-gate 		rp->r_npc = npc + 4;
178*0Sstevel@tonic-gate 		return;
179*0Sstevel@tonic-gate 	}
180*0Sstevel@tonic-gate 
181*0Sstevel@tonic-gate 	/*
182*0Sstevel@tonic-gate 	 * We need to wait until after we've called the dtrace_return_probe_ptr
183*0Sstevel@tonic-gate 	 * function pointer to set %pc and %npc.
184*0Sstevel@tonic-gate 	 */
185*0Sstevel@tonic-gate 	rwp = &CPU->cpu_ft_lock;
186*0Sstevel@tonic-gate 	rw_enter(rwp, RW_READER);
187*0Sstevel@tonic-gate 	if (dtrace_return_probe_ptr != NULL)
188*0Sstevel@tonic-gate 		(void) (*dtrace_return_probe_ptr)(rp);
189*0Sstevel@tonic-gate 	rw_exit(rwp);
190*0Sstevel@tonic-gate 	rp->r_pc = npc;
191*0Sstevel@tonic-gate 	rp->r_npc = npc + 4;
192*0Sstevel@tonic-gate }
193*0Sstevel@tonic-gate 
194*0Sstevel@tonic-gate void
195*0Sstevel@tonic-gate dtrace_safe_synchronous_signal(void)
196*0Sstevel@tonic-gate {
197*0Sstevel@tonic-gate 	kthread_t *t = curthread;
198*0Sstevel@tonic-gate 	struct regs *rp = lwptoregs(ttolwp(t));
199*0Sstevel@tonic-gate 
200*0Sstevel@tonic-gate 	ASSERT(t->t_dtrace_on);
201*0Sstevel@tonic-gate 
202*0Sstevel@tonic-gate 	/*
203*0Sstevel@tonic-gate 	 * If we're not actively tracing an instruction, turn off tracing
204*0Sstevel@tonic-gate 	 * flags. If the instruction we copied out caused a synchronous
205*0Sstevel@tonic-gate 	 * trap, reset the pc and npc back to their original values and turn
206*0Sstevel@tonic-gate 	 * off the flags.
207*0Sstevel@tonic-gate 	 */
208*0Sstevel@tonic-gate 	if (rp->r_pc != t->t_dtrace_scrpc && rp->r_pc != t->t_dtrace_astpc &&
209*0Sstevel@tonic-gate 	    rp->r_npc != t->t_dtrace_astpc) {
210*0Sstevel@tonic-gate 		t->t_dtrace_ft = 0;
211*0Sstevel@tonic-gate 	} else if (rp->r_pc == t->t_dtrace_scrpc) {
212*0Sstevel@tonic-gate 		rp->r_pc = t->t_dtrace_pc;
213*0Sstevel@tonic-gate 		rp->r_npc = t->t_dtrace_npc;
214*0Sstevel@tonic-gate 		t->t_dtrace_ft = 0;
215*0Sstevel@tonic-gate 	}
216*0Sstevel@tonic-gate }
217*0Sstevel@tonic-gate 
218*0Sstevel@tonic-gate int
219*0Sstevel@tonic-gate dtrace_safe_defer_signal(void)
220*0Sstevel@tonic-gate {
221*0Sstevel@tonic-gate 	kthread_t *t = curthread;
222*0Sstevel@tonic-gate 	struct regs *rp = lwptoregs(ttolwp(t));
223*0Sstevel@tonic-gate 
224*0Sstevel@tonic-gate 	ASSERT(t->t_dtrace_on);
225*0Sstevel@tonic-gate 
226*0Sstevel@tonic-gate 	/*
227*0Sstevel@tonic-gate 	 * If we're not actively tracing an instruction, turn off tracing
228*0Sstevel@tonic-gate 	 * flags.
229*0Sstevel@tonic-gate 	 */
230*0Sstevel@tonic-gate 	if (rp->r_pc != t->t_dtrace_scrpc && rp->r_pc != t->t_dtrace_astpc &&
231*0Sstevel@tonic-gate 	    rp->r_npc != t->t_dtrace_astpc) {
232*0Sstevel@tonic-gate 		t->t_dtrace_ft = 0;
233*0Sstevel@tonic-gate 		return (0);
234*0Sstevel@tonic-gate 	}
235*0Sstevel@tonic-gate 
236*0Sstevel@tonic-gate 	/*
237*0Sstevel@tonic-gate 	 * Otherwise, make sure we'll return to the kernel after executing
238*0Sstevel@tonic-gate 	 * the instruction we copied out.
239*0Sstevel@tonic-gate 	 */
240*0Sstevel@tonic-gate 	if (!t->t_dtrace_step) {
241*0Sstevel@tonic-gate 		ASSERT(rp->r_pc == t->t_dtrace_scrpc);
242*0Sstevel@tonic-gate 		rp->r_npc = t->t_dtrace_astpc;
243*0Sstevel@tonic-gate 		t->t_dtrace_step = 1;
244*0Sstevel@tonic-gate 	}
245*0Sstevel@tonic-gate 
246*0Sstevel@tonic-gate 	t->t_dtrace_ast = 1;
247*0Sstevel@tonic-gate 
248*0Sstevel@tonic-gate 	return (1);
249*0Sstevel@tonic-gate }
250