xref: /freebsd-src/sys/cddl/dev/dtrace/arm/dtrace_subr.c (revision 95ee2897e98f5d444f26ed2334cc7c439f9c16c6)
1fcb56067SGeorge V. Neville-Neil /*
2fcb56067SGeorge V. Neville-Neil  * CDDL HEADER START
3fcb56067SGeorge V. Neville-Neil  *
4fcb56067SGeorge V. Neville-Neil  * The contents of this file are subject to the terms of the
5fcb56067SGeorge V. Neville-Neil  * Common Development and Distribution License, Version 1.0 only
6fcb56067SGeorge V. Neville-Neil  * (the "License").  You may not use this file except in compliance
7fcb56067SGeorge V. Neville-Neil  * with the License.
8fcb56067SGeorge V. Neville-Neil  *
9fcb56067SGeorge V. Neville-Neil  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10fcb56067SGeorge V. Neville-Neil  * or http://www.opensolaris.org/os/licensing.
11fcb56067SGeorge V. Neville-Neil  * See the License for the specific language governing permissions
12fcb56067SGeorge V. Neville-Neil  * and limitations under the License.
13fcb56067SGeorge V. Neville-Neil  *
14fcb56067SGeorge V. Neville-Neil  * When distributing Covered Code, include this CDDL HEADER in each
15fcb56067SGeorge V. Neville-Neil  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16fcb56067SGeorge V. Neville-Neil  * If applicable, add the following below this CDDL HEADER, with the
17fcb56067SGeorge V. Neville-Neil  * fields enclosed by brackets "[]" replaced with your own identifying
18fcb56067SGeorge V. Neville-Neil  * information: Portions Copyright [yyyy] [name of copyright owner]
19fcb56067SGeorge V. Neville-Neil  *
20fcb56067SGeorge V. Neville-Neil  * CDDL HEADER END
21fcb56067SGeorge V. Neville-Neil  *
22fcb56067SGeorge V. Neville-Neil  */
23fcb56067SGeorge V. Neville-Neil /*
24fcb56067SGeorge V. Neville-Neil  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
25fcb56067SGeorge V. Neville-Neil  * Use is subject to license terms.
26fcb56067SGeorge V. Neville-Neil  */
27fcb56067SGeorge V. Neville-Neil 
28fcb56067SGeorge V. Neville-Neil #include <sys/param.h>
29fcb56067SGeorge V. Neville-Neil #include <sys/systm.h>
30fcb56067SGeorge V. Neville-Neil #include <sys/kernel.h>
31fcb56067SGeorge V. Neville-Neil #include <sys/malloc.h>
32fcb56067SGeorge V. Neville-Neil #include <sys/kmem.h>
33*bdd101c4SMark Johnston #include <sys/proc.h>
34fcb56067SGeorge V. Neville-Neil #include <sys/smp.h>
35fcb56067SGeorge V. Neville-Neil #include <sys/dtrace_impl.h>
36fcb56067SGeorge V. Neville-Neil #include <sys/dtrace_bsd.h>
37*bdd101c4SMark Johnston #include <cddl/dev/dtrace/dtrace_cddl.h>
38fcb56067SGeorge V. Neville-Neil #include <machine/armreg.h>
39fcb56067SGeorge V. Neville-Neil #include <machine/clock.h>
40fcb56067SGeorge V. Neville-Neil #include <machine/frame.h>
41fcb56067SGeorge V. Neville-Neil #include <machine/trap.h>
42fcb56067SGeorge V. Neville-Neil #include <vm/pmap.h>
43fcb56067SGeorge V. Neville-Neil 
44fcb56067SGeorge V. Neville-Neil #define	DELAYBRANCH(x)	((int)(x) < 0)
45fcb56067SGeorge V. Neville-Neil 
464a8169d9SAndrew Turner #define	BIT_PC		15
474a8169d9SAndrew Turner #define	BIT_LR		14
484a8169d9SAndrew Turner #define	BIT_SP		13
494a8169d9SAndrew Turner 
50fcb56067SGeorge V. Neville-Neil extern dtrace_id_t	dtrace_probeid_error;
51fcb56067SGeorge V. Neville-Neil extern int (*dtrace_invop_jump_addr)(struct trapframe *);
52a340dc53SGeorge V. Neville-Neil extern void dtrace_getnanotime(struct timespec *tsp);
5330b68ecdSRobert Watson extern void dtrace_getnanouptime(struct timespec *tsp);
54fcb56067SGeorge V. Neville-Neil 
556c280659SMark Johnston int dtrace_invop(uintptr_t, struct trapframe *, uintptr_t);
56fcb56067SGeorge V. Neville-Neil void dtrace_invop_init(void);
57fcb56067SGeorge V. Neville-Neil void dtrace_invop_uninit(void);
58fcb56067SGeorge V. Neville-Neil 
59fcb56067SGeorge V. Neville-Neil typedef struct dtrace_invop_hdlr {
606c280659SMark Johnston 	int (*dtih_func)(uintptr_t, struct trapframe *, uintptr_t);
61fcb56067SGeorge V. Neville-Neil 	struct dtrace_invop_hdlr *dtih_next;
62fcb56067SGeorge V. Neville-Neil } dtrace_invop_hdlr_t;
63fcb56067SGeorge V. Neville-Neil 
64fcb56067SGeorge V. Neville-Neil dtrace_invop_hdlr_t *dtrace_invop_hdlr;
65fcb56067SGeorge V. Neville-Neil 
66fcb56067SGeorge V. Neville-Neil int
dtrace_invop(uintptr_t addr,struct trapframe * frame,uintptr_t eax)676c280659SMark Johnston dtrace_invop(uintptr_t addr, struct trapframe *frame, uintptr_t eax)
68fcb56067SGeorge V. Neville-Neil {
69*bdd101c4SMark Johnston 	struct thread *td;
70fcb56067SGeorge V. Neville-Neil 	dtrace_invop_hdlr_t *hdlr;
71fcb56067SGeorge V. Neville-Neil 	int rval;
72fcb56067SGeorge V. Neville-Neil 
73*bdd101c4SMark Johnston 	rval = 0;
74*bdd101c4SMark Johnston 	td = curthread;
75*bdd101c4SMark Johnston 	td->t_dtrace_trapframe = frame;
76fcb56067SGeorge V. Neville-Neil 	for (hdlr = dtrace_invop_hdlr; hdlr != NULL; hdlr = hdlr->dtih_next)
776c280659SMark Johnston 		if ((rval = hdlr->dtih_func(addr, frame, eax)) != 0)
78*bdd101c4SMark Johnston 			break;
79*bdd101c4SMark Johnston 	td->t_dtrace_trapframe = NULL;
80fcb56067SGeorge V. Neville-Neil 	return (rval);
81fcb56067SGeorge V. Neville-Neil }
82fcb56067SGeorge V. Neville-Neil 
83fcb56067SGeorge V. Neville-Neil 
84fcb56067SGeorge V. Neville-Neil void
dtrace_invop_add(int (* func)(uintptr_t,struct trapframe *,uintptr_t))856c280659SMark Johnston dtrace_invop_add(int (*func)(uintptr_t, struct trapframe *, uintptr_t))
86fcb56067SGeorge V. Neville-Neil {
87fcb56067SGeorge V. Neville-Neil 	dtrace_invop_hdlr_t *hdlr;
88fcb56067SGeorge V. Neville-Neil 
89fcb56067SGeorge V. Neville-Neil 	hdlr = kmem_alloc(sizeof (dtrace_invop_hdlr_t), KM_SLEEP);
90fcb56067SGeorge V. Neville-Neil 	hdlr->dtih_func = func;
91fcb56067SGeorge V. Neville-Neil 	hdlr->dtih_next = dtrace_invop_hdlr;
92fcb56067SGeorge V. Neville-Neil 	dtrace_invop_hdlr = hdlr;
93fcb56067SGeorge V. Neville-Neil }
94fcb56067SGeorge V. Neville-Neil 
95fcb56067SGeorge V. Neville-Neil void
dtrace_invop_remove(int (* func)(uintptr_t,struct trapframe *,uintptr_t))966c280659SMark Johnston dtrace_invop_remove(int (*func)(uintptr_t, struct trapframe *, uintptr_t))
97fcb56067SGeorge V. Neville-Neil {
98fcb56067SGeorge V. Neville-Neil 	dtrace_invop_hdlr_t *hdlr = dtrace_invop_hdlr, *prev = NULL;
99fcb56067SGeorge V. Neville-Neil 
100fcb56067SGeorge V. Neville-Neil 	for (;;) {
101fcb56067SGeorge V. Neville-Neil 		if (hdlr == NULL)
102fcb56067SGeorge V. Neville-Neil 			panic("attempt to remove non-existent invop handler");
103fcb56067SGeorge V. Neville-Neil 
104fcb56067SGeorge V. Neville-Neil 		if (hdlr->dtih_func == func)
105fcb56067SGeorge V. Neville-Neil 			break;
106fcb56067SGeorge V. Neville-Neil 
107fcb56067SGeorge V. Neville-Neil 		prev = hdlr;
108fcb56067SGeorge V. Neville-Neil 		hdlr = hdlr->dtih_next;
109fcb56067SGeorge V. Neville-Neil 	}
110fcb56067SGeorge V. Neville-Neil 
111fcb56067SGeorge V. Neville-Neil 	if (prev == NULL) {
112fcb56067SGeorge V. Neville-Neil 		ASSERT(dtrace_invop_hdlr == hdlr);
113fcb56067SGeorge V. Neville-Neil 		dtrace_invop_hdlr = hdlr->dtih_next;
114fcb56067SGeorge V. Neville-Neil 	} else {
115fcb56067SGeorge V. Neville-Neil 		ASSERT(dtrace_invop_hdlr != hdlr);
116fcb56067SGeorge V. Neville-Neil 		prev->dtih_next = hdlr->dtih_next;
117fcb56067SGeorge V. Neville-Neil 	}
118fcb56067SGeorge V. Neville-Neil 
119fcb56067SGeorge V. Neville-Neil 	kmem_free(hdlr, 0);
120fcb56067SGeorge V. Neville-Neil }
121fcb56067SGeorge V. Neville-Neil 
122fcb56067SGeorge V. Neville-Neil 
123fcb56067SGeorge V. Neville-Neil /*ARGSUSED*/
124fcb56067SGeorge V. Neville-Neil void
dtrace_toxic_ranges(void (* func)(uintptr_t base,uintptr_t limit))125fcb56067SGeorge V. Neville-Neil dtrace_toxic_ranges(void (*func)(uintptr_t base, uintptr_t limit))
126fcb56067SGeorge V. Neville-Neil {
1278bfc473cSIan Lepore 
1288bfc473cSIan Lepore 	/*
1298bfc473cSIan Lepore 	 * There are no ranges to exclude that are common to all 32-bit arm
1308bfc473cSIan Lepore 	 * platforms.  This function only needs to exclude ranges "... in
1318bfc473cSIan Lepore 	 * which it is impossible to recover from such a load after it has been
1328bfc473cSIan Lepore 	 * attempted." -- i.e., accessing within the range causes some sort
1338bfc473cSIan Lepore 	 * fault in the system which is not handled by the normal arm
1348bfc473cSIan Lepore 	 * exception-handling mechanisms.  If systems exist where that is the
1358bfc473cSIan Lepore 	 * case, a method to handle this functionality would have to be added to
1368bfc473cSIan Lepore 	 * the platform_if interface so that those systems could provide their
1378bfc473cSIan Lepore 	 * specific toxic range(s).
1388bfc473cSIan Lepore 	 */
139fcb56067SGeorge V. Neville-Neil }
140fcb56067SGeorge V. Neville-Neil 
141fcb56067SGeorge V. Neville-Neil void
dtrace_xcall(processorid_t cpu,dtrace_xcall_t func,void * arg)142fcb56067SGeorge V. Neville-Neil dtrace_xcall(processorid_t cpu, dtrace_xcall_t func, void *arg)
143fcb56067SGeorge V. Neville-Neil {
144fcb56067SGeorge V. Neville-Neil 	cpuset_t cpus;
145fcb56067SGeorge V. Neville-Neil 
146fcb56067SGeorge V. Neville-Neil 	if (cpu == DTRACE_CPUALL)
147fcb56067SGeorge V. Neville-Neil 		cpus = all_cpus;
148fcb56067SGeorge V. Neville-Neil 	else
149fcb56067SGeorge V. Neville-Neil 		CPU_SETOF(cpu, &cpus);
150fcb56067SGeorge V. Neville-Neil 
15167d955aaSPatrick Kelsey 	smp_rendezvous_cpus(cpus, smp_no_rendezvous_barrier, func,
15267d955aaSPatrick Kelsey 	    smp_no_rendezvous_barrier, arg);
153fcb56067SGeorge V. Neville-Neil }
154fcb56067SGeorge V. Neville-Neil 
155fcb56067SGeorge V. Neville-Neil static void
dtrace_sync_func(void)156fcb56067SGeorge V. Neville-Neil dtrace_sync_func(void)
157fcb56067SGeorge V. Neville-Neil {
158fcb56067SGeorge V. Neville-Neil }
159fcb56067SGeorge V. Neville-Neil 
160fcb56067SGeorge V. Neville-Neil void
dtrace_sync(void)161fcb56067SGeorge V. Neville-Neil dtrace_sync(void)
162fcb56067SGeorge V. Neville-Neil {
163fcb56067SGeorge V. Neville-Neil 	dtrace_xcall(DTRACE_CPUALL, (dtrace_xcall_t)dtrace_sync_func, NULL);
164fcb56067SGeorge V. Neville-Neil }
165fcb56067SGeorge V. Neville-Neil 
166fcb56067SGeorge V. Neville-Neil /*
167fcb56067SGeorge V. Neville-Neil  * DTrace needs a high resolution time function which can
168fcb56067SGeorge V. Neville-Neil  * be called from a probe context and guaranteed not to have
169fcb56067SGeorge V. Neville-Neil  * instrumented with probes itself.
170fcb56067SGeorge V. Neville-Neil  *
171fcb56067SGeorge V. Neville-Neil  * Returns nanoseconds since boot.
172fcb56067SGeorge V. Neville-Neil  */
173fcb56067SGeorge V. Neville-Neil uint64_t
dtrace_gethrtime(void)1747357c2e5SDimitry Andric dtrace_gethrtime(void)
175fcb56067SGeorge V. Neville-Neil {
176fcb56067SGeorge V. Neville-Neil 	struct	timespec curtime;
177fcb56067SGeorge V. Neville-Neil 
17830b68ecdSRobert Watson 	dtrace_getnanouptime(&curtime);
179fcb56067SGeorge V. Neville-Neil 
180fcb56067SGeorge V. Neville-Neil 	return (curtime.tv_sec * 1000000000UL + curtime.tv_nsec);
181fcb56067SGeorge V. Neville-Neil 
182fcb56067SGeorge V. Neville-Neil }
183fcb56067SGeorge V. Neville-Neil 
184fcb56067SGeorge V. Neville-Neil uint64_t
dtrace_gethrestime(void)185fcb56067SGeorge V. Neville-Neil dtrace_gethrestime(void)
186fcb56067SGeorge V. Neville-Neil {
187a340dc53SGeorge V. Neville-Neil 	struct timespec current_time;
188fcb56067SGeorge V. Neville-Neil 
189a340dc53SGeorge V. Neville-Neil 	dtrace_getnanotime(&current_time);
190fcb56067SGeorge V. Neville-Neil 
191a340dc53SGeorge V. Neville-Neil 	return (current_time.tv_sec * 1000000000UL + current_time.tv_nsec);
192fcb56067SGeorge V. Neville-Neil }
193fcb56067SGeorge V. Neville-Neil 
194fcb56067SGeorge V. Neville-Neil /* Function to handle DTrace traps during probes. See amd64/amd64/trap.c */
195fcb56067SGeorge V. Neville-Neil int
dtrace_trap(struct trapframe * frame,u_int type)196fcb56067SGeorge V. Neville-Neil dtrace_trap(struct trapframe *frame, u_int type)
197fcb56067SGeorge V. Neville-Neil {
198fcb56067SGeorge V. Neville-Neil 	/*
199fcb56067SGeorge V. Neville-Neil 	 * A trap can occur while DTrace executes a probe. Before
200fcb56067SGeorge V. Neville-Neil 	 * executing the probe, DTrace blocks re-scheduling and sets
20128323addSBryan Drewery 	 * a flag in its per-cpu flags to indicate that it doesn't
202fcb56067SGeorge V. Neville-Neil 	 * want to fault. On returning from the probe, the no-fault
203fcb56067SGeorge V. Neville-Neil 	 * flag is cleared and finally re-scheduling is enabled.
204fcb56067SGeorge V. Neville-Neil 	 *
205fcb56067SGeorge V. Neville-Neil 	 * Check if DTrace has enabled 'no-fault' mode:
206fcb56067SGeorge V. Neville-Neil 	 *
207fcb56067SGeorge V. Neville-Neil 	 */
208fcb56067SGeorge V. Neville-Neil 	if ((cpu_core[curcpu].cpuc_dtrace_flags & CPU_DTRACE_NOFAULT) != 0) {
209fcb56067SGeorge V. Neville-Neil 		/*
210fcb56067SGeorge V. Neville-Neil 		 * There are only a couple of trap types that are expected.
211fcb56067SGeorge V. Neville-Neil 		 * All the rest will be handled in the usual way.
212fcb56067SGeorge V. Neville-Neil 		 */
213fcb56067SGeorge V. Neville-Neil 		switch (type) {
214fcb56067SGeorge V. Neville-Neil 		/* Page fault. */
215fcb56067SGeorge V. Neville-Neil 		case FAULT_ALIGN:
216fcb56067SGeorge V. Neville-Neil 			/* Flag a bad address. */
217fcb56067SGeorge V. Neville-Neil 			cpu_core[curcpu].cpuc_dtrace_flags |= CPU_DTRACE_BADADDR;
218fcb56067SGeorge V. Neville-Neil 			cpu_core[curcpu].cpuc_dtrace_illval = 0;
219fcb56067SGeorge V. Neville-Neil 
220fcb56067SGeorge V. Neville-Neil 			/*
221fcb56067SGeorge V. Neville-Neil 			 * Offset the instruction pointer to the instruction
222fcb56067SGeorge V. Neville-Neil 			 * following the one causing the fault.
223fcb56067SGeorge V. Neville-Neil 			 */
224fcb56067SGeorge V. Neville-Neil 			frame->tf_pc += sizeof(int);
225fcb56067SGeorge V. Neville-Neil 			return (1);
226fcb56067SGeorge V. Neville-Neil 		default:
227fcb56067SGeorge V. Neville-Neil 			/* Handle all other traps in the usual way. */
228fcb56067SGeorge V. Neville-Neil 			break;
229fcb56067SGeorge V. Neville-Neil 		}
230fcb56067SGeorge V. Neville-Neil 	}
231fcb56067SGeorge V. Neville-Neil 
232fcb56067SGeorge V. Neville-Neil 	/* Handle the trap in the usual way. */
233fcb56067SGeorge V. Neville-Neil 	return (0);
234fcb56067SGeorge V. Neville-Neil }
235fcb56067SGeorge V. Neville-Neil 
236fcb56067SGeorge V. Neville-Neil void
dtrace_probe_error(dtrace_state_t * state,dtrace_epid_t epid,int which,int fault,int fltoffs,uintptr_t illval)237fcb56067SGeorge V. Neville-Neil dtrace_probe_error(dtrace_state_t *state, dtrace_epid_t epid, int which,
238fcb56067SGeorge V. Neville-Neil     int fault, int fltoffs, uintptr_t illval)
239fcb56067SGeorge V. Neville-Neil {
240fcb56067SGeorge V. Neville-Neil 
241fcb56067SGeorge V. Neville-Neil 	dtrace_probe(dtrace_probeid_error, (uint64_t)(uintptr_t)state,
242fcb56067SGeorge V. Neville-Neil 	    (uintptr_t)epid,
243fcb56067SGeorge V. Neville-Neil 	    (uintptr_t)which, (uintptr_t)fault, (uintptr_t)fltoffs);
244fcb56067SGeorge V. Neville-Neil }
245fcb56067SGeorge V. Neville-Neil 
246fcb56067SGeorge V. Neville-Neil static int
dtrace_invop_start(struct trapframe * frame)247fcb56067SGeorge V. Neville-Neil dtrace_invop_start(struct trapframe *frame)
248fcb56067SGeorge V. Neville-Neil {
2494a8169d9SAndrew Turner 	register_t *r0, *sp;
2504a8169d9SAndrew Turner 	int data, invop, reg, update_sp;
2514a8169d9SAndrew Turner 
2522032c532SAndriy Gapon 	invop = dtrace_invop(frame->tf_pc, frame, frame->tf_r0);
2534a8169d9SAndrew Turner 	switch (invop & DTRACE_INVOP_MASK) {
254fcb56067SGeorge V. Neville-Neil 	case DTRACE_INVOP_PUSHM:
2554a8169d9SAndrew Turner 		sp = (register_t *)frame->tf_svc_sp;
2564a8169d9SAndrew Turner 		r0 = &frame->tf_r0;
2574a8169d9SAndrew Turner 		data = DTRACE_INVOP_DATA(invop);
2584a8169d9SAndrew Turner 
2594a8169d9SAndrew Turner 		/*
2604a8169d9SAndrew Turner 		 * Store the pc, lr, and sp. These have their own
2614a8169d9SAndrew Turner 		 * entries in the struct.
2624a8169d9SAndrew Turner 		 */
2634a8169d9SAndrew Turner 		if (data & (1 << BIT_PC)) {
2644a8169d9SAndrew Turner 			sp--;
2654a8169d9SAndrew Turner 			*sp = frame->tf_pc;
2664a8169d9SAndrew Turner 		}
2674a8169d9SAndrew Turner 		if (data & (1 << BIT_LR)) {
2684a8169d9SAndrew Turner 			sp--;
2694a8169d9SAndrew Turner 			*sp = frame->tf_svc_lr;
2704a8169d9SAndrew Turner 		}
2714a8169d9SAndrew Turner 		if (data & (1 << BIT_SP)) {
2724a8169d9SAndrew Turner 			sp--;
2734a8169d9SAndrew Turner 			*sp = frame->tf_svc_sp;
2744a8169d9SAndrew Turner 		}
2754a8169d9SAndrew Turner 
2764a8169d9SAndrew Turner 		/* Store the general registers */
2774a8169d9SAndrew Turner 		for (reg = 12; reg >= 0; reg--) {
2784a8169d9SAndrew Turner 			if (data & (1 << reg)) {
2794a8169d9SAndrew Turner 				sp--;
2804a8169d9SAndrew Turner 				*sp = r0[reg];
2814a8169d9SAndrew Turner 			}
2824a8169d9SAndrew Turner 		}
2834a8169d9SAndrew Turner 
2844a8169d9SAndrew Turner 		/* Update the stack pointer and program counter to continue */
2854a8169d9SAndrew Turner 		frame->tf_svc_sp = (register_t)sp;
2864a8169d9SAndrew Turner 		frame->tf_pc += 4;
287fcb56067SGeorge V. Neville-Neil 		break;
288fcb56067SGeorge V. Neville-Neil 	case DTRACE_INVOP_POPM:
2894a8169d9SAndrew Turner 		sp = (register_t *)frame->tf_svc_sp;
2904a8169d9SAndrew Turner 		r0 = &frame->tf_r0;
2914a8169d9SAndrew Turner 		data = DTRACE_INVOP_DATA(invop);
2924a8169d9SAndrew Turner 
2934a8169d9SAndrew Turner 		/* Read the general registers */
2944a8169d9SAndrew Turner 		for (reg = 0; reg <= 12; reg++) {
2954a8169d9SAndrew Turner 			if (data & (1 << reg)) {
2964a8169d9SAndrew Turner 				r0[reg] = *sp;
2974a8169d9SAndrew Turner 				sp++;
2984a8169d9SAndrew Turner 			}
2994a8169d9SAndrew Turner 		}
3004a8169d9SAndrew Turner 
3014a8169d9SAndrew Turner 		/*
3024a8169d9SAndrew Turner 		 * Set the stack pointer. If we don't update it here we will
3034a8169d9SAndrew Turner 		 * need to update it at the end as the instruction would do
3044a8169d9SAndrew Turner 		 */
3054a8169d9SAndrew Turner 		update_sp = 1;
3064a8169d9SAndrew Turner 		if (data & (1 << BIT_SP)) {
3074a8169d9SAndrew Turner 			frame->tf_svc_sp = *sp;
3084a8169d9SAndrew Turner 			*sp++;
3094a8169d9SAndrew Turner 			update_sp = 0;
3104a8169d9SAndrew Turner 		}
3114a8169d9SAndrew Turner 
3124a8169d9SAndrew Turner 		/* Update the link register, we need to use the correct copy */
3134a8169d9SAndrew Turner 		if (data & (1 << BIT_LR)) {
3144a8169d9SAndrew Turner 			frame->tf_svc_lr = *sp;
3154a8169d9SAndrew Turner 			*sp++;
3164a8169d9SAndrew Turner 		}
3174a8169d9SAndrew Turner 		/*
3184a8169d9SAndrew Turner 		 * And the program counter. If it's not in the list skip over
3194a8169d9SAndrew Turner 		 * it when we return so to not hit this again.
3204a8169d9SAndrew Turner 		 */
3214a8169d9SAndrew Turner 		if (data & (1 << BIT_PC)) {
3224a8169d9SAndrew Turner 			frame->tf_pc = *sp;
3234a8169d9SAndrew Turner 			*sp++;
3244a8169d9SAndrew Turner 		} else
3254a8169d9SAndrew Turner 			frame->tf_pc += 4;
3264a8169d9SAndrew Turner 
3274a8169d9SAndrew Turner 		/* Update the stack pointer if we haven't already done so */
3284a8169d9SAndrew Turner 		if (update_sp)
3294a8169d9SAndrew Turner 			frame->tf_svc_sp = (register_t)sp;
330fcb56067SGeorge V. Neville-Neil 		break;
331fcb56067SGeorge V. Neville-Neil 	case DTRACE_INVOP_B:
3324a8169d9SAndrew Turner 		data = DTRACE_INVOP_DATA(invop) & 0x00ffffff;
3334a8169d9SAndrew Turner 		/* Sign extend the data */
3344a8169d9SAndrew Turner 		if ((data & (1 << 23)) != 0)
3354a8169d9SAndrew Turner 			data |= 0xff000000;
3364a8169d9SAndrew Turner 		/* The data is the number of 4-byte words to change the pc */
3374a8169d9SAndrew Turner 		data *= 4;
3384a8169d9SAndrew Turner 		data += 8;
3394a8169d9SAndrew Turner 		frame->tf_pc += data;
340fcb56067SGeorge V. Neville-Neil 		break;
341fcb56067SGeorge V. Neville-Neil 	default:
342fcb56067SGeorge V. Neville-Neil 		return (-1);
343fcb56067SGeorge V. Neville-Neil 		break;
344fcb56067SGeorge V. Neville-Neil 	}
345fcb56067SGeorge V. Neville-Neil 
346fcb56067SGeorge V. Neville-Neil 	return (0);
347fcb56067SGeorge V. Neville-Neil }
348fcb56067SGeorge V. Neville-Neil 
dtrace_invop_init(void)349fcb56067SGeorge V. Neville-Neil void dtrace_invop_init(void)
350fcb56067SGeorge V. Neville-Neil {
351fcb56067SGeorge V. Neville-Neil 	dtrace_invop_jump_addr = dtrace_invop_start;
352fcb56067SGeorge V. Neville-Neil }
353fcb56067SGeorge V. Neville-Neil 
dtrace_invop_uninit(void)354fcb56067SGeorge V. Neville-Neil void dtrace_invop_uninit(void)
355fcb56067SGeorge V. Neville-Neil {
356fcb56067SGeorge V. Neville-Neil 	dtrace_invop_jump_addr = 0;
357fcb56067SGeorge V. Neville-Neil }
358