xref: /freebsd/sys/cddl/dev/dtrace/powerpc/dtrace_subr.c (revision 95ee2897e98f5d444f26ed2334cc7c439f9c16c6)
1c7570492SJustin Hibbits /*
2c7570492SJustin Hibbits  * CDDL HEADER START
3c7570492SJustin Hibbits  *
4c7570492SJustin Hibbits  * The contents of this file are subject to the terms of the
5c7570492SJustin Hibbits  * Common Development and Distribution License, Version 1.0 only
6c7570492SJustin Hibbits  * (the "License").  You may not use this file except in compliance
7c7570492SJustin Hibbits  * with the License.
8c7570492SJustin Hibbits  *
9c7570492SJustin Hibbits  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10c7570492SJustin Hibbits  * or http://www.opensolaris.org/os/licensing.
11c7570492SJustin Hibbits  * See the License for the specific language governing permissions
12c7570492SJustin Hibbits  * and limitations under the License.
13c7570492SJustin Hibbits  *
14c7570492SJustin Hibbits  * When distributing Covered Code, include this CDDL HEADER in each
15c7570492SJustin Hibbits  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16c7570492SJustin Hibbits  * If applicable, add the following below this CDDL HEADER, with the
17c7570492SJustin Hibbits  * fields enclosed by brackets "[]" replaced with your own identifying
18c7570492SJustin Hibbits  * information: Portions Copyright [yyyy] [name of copyright owner]
19c7570492SJustin Hibbits  *
20c7570492SJustin Hibbits  * CDDL HEADER END
21c7570492SJustin Hibbits  *
22c7570492SJustin Hibbits  */
23c7570492SJustin Hibbits /*
24c7570492SJustin Hibbits  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
25c7570492SJustin Hibbits  * Use is subject to license terms.
26c7570492SJustin Hibbits  */
27c7570492SJustin Hibbits 
28c7570492SJustin Hibbits #include <sys/param.h>
29c7570492SJustin Hibbits #include <sys/systm.h>
30c7570492SJustin Hibbits #include <sys/kernel.h>
31c7570492SJustin Hibbits #include <sys/malloc.h>
32c7570492SJustin Hibbits #include <sys/kmem.h>
33*bdd101c4SMark Johnston #include <sys/proc.h>
34c7570492SJustin Hibbits #include <sys/smp.h>
35c7570492SJustin Hibbits #include <sys/dtrace_impl.h>
36c7570492SJustin Hibbits #include <sys/dtrace_bsd.h>
37*bdd101c4SMark Johnston #include <cddl/dev/dtrace/dtrace_cddl.h>
38c7570492SJustin Hibbits #include <machine/clock.h>
39c7570492SJustin Hibbits #include <machine/frame.h>
40c7570492SJustin Hibbits #include <machine/trap.h>
41c7570492SJustin Hibbits #include <vm/pmap.h>
42c7570492SJustin Hibbits 
43c7570492SJustin Hibbits #define	DELAYBRANCH(x)	((int)(x) < 0)
44c7570492SJustin Hibbits 
45c7570492SJustin Hibbits extern dtrace_id_t	dtrace_probeid_error;
4680a5635cSJustin Hibbits extern int (*dtrace_invop_jump_addr)(struct trapframe *);
47c7570492SJustin Hibbits 
48f0bd82a1SJustin Hibbits extern void dtrace_getnanotime(struct timespec *tsp);
49f0bd82a1SJustin Hibbits 
506c280659SMark Johnston int dtrace_invop(uintptr_t, struct trapframe *, uintptr_t);
5180a5635cSJustin Hibbits void dtrace_invop_init(void);
5280a5635cSJustin Hibbits void dtrace_invop_uninit(void);
53c7570492SJustin Hibbits 
54c7570492SJustin Hibbits typedef struct dtrace_invop_hdlr {
556c280659SMark Johnston 	int (*dtih_func)(uintptr_t, struct trapframe *, uintptr_t);
56c7570492SJustin Hibbits 	struct dtrace_invop_hdlr *dtih_next;
57c7570492SJustin Hibbits } dtrace_invop_hdlr_t;
58c7570492SJustin Hibbits 
59c7570492SJustin Hibbits dtrace_invop_hdlr_t *dtrace_invop_hdlr;
60c7570492SJustin Hibbits 
61c7570492SJustin Hibbits int
dtrace_invop(uintptr_t addr,struct trapframe * frame,uintptr_t arg0)626c280659SMark Johnston dtrace_invop(uintptr_t addr, struct trapframe *frame, uintptr_t arg0)
63c7570492SJustin Hibbits {
64*bdd101c4SMark Johnston 	struct thread *td;
65c7570492SJustin Hibbits 	dtrace_invop_hdlr_t *hdlr;
66c7570492SJustin Hibbits 	int rval;
67c7570492SJustin Hibbits 
68*bdd101c4SMark Johnston 	rval = 0;
69*bdd101c4SMark Johnston 	td = curthread;
70*bdd101c4SMark Johnston 	td->t_dtrace_trapframe = frame;
71c7570492SJustin Hibbits 	for (hdlr = dtrace_invop_hdlr; hdlr != NULL; hdlr = hdlr->dtih_next)
726c280659SMark Johnston 		if ((rval = hdlr->dtih_func(addr, frame, arg0)) != 0)
73*bdd101c4SMark Johnston 			break;
74*bdd101c4SMark Johnston 	td->t_dtrace_trapframe = NULL;
75c7570492SJustin Hibbits 	return (rval);
76c7570492SJustin Hibbits }
77c7570492SJustin Hibbits 
7880a5635cSJustin Hibbits void
dtrace_invop_add(int (* func)(uintptr_t,struct trapframe *,uintptr_t))796c280659SMark Johnston dtrace_invop_add(int (*func)(uintptr_t, struct trapframe *, uintptr_t))
8080a5635cSJustin Hibbits {
8180a5635cSJustin Hibbits 	dtrace_invop_hdlr_t *hdlr;
8280a5635cSJustin Hibbits 
8380a5635cSJustin Hibbits 	hdlr = kmem_alloc(sizeof (dtrace_invop_hdlr_t), KM_SLEEP);
8480a5635cSJustin Hibbits 	hdlr->dtih_func = func;
8580a5635cSJustin Hibbits 	hdlr->dtih_next = dtrace_invop_hdlr;
8680a5635cSJustin Hibbits 	dtrace_invop_hdlr = hdlr;
8780a5635cSJustin Hibbits }
8880a5635cSJustin Hibbits 
8980a5635cSJustin Hibbits void
dtrace_invop_remove(int (* func)(uintptr_t,struct trapframe *,uintptr_t))906c280659SMark Johnston dtrace_invop_remove(int (*func)(uintptr_t, struct trapframe *, uintptr_t))
9180a5635cSJustin Hibbits {
9280a5635cSJustin Hibbits 	dtrace_invop_hdlr_t *hdlr = dtrace_invop_hdlr, *prev = NULL;
9380a5635cSJustin Hibbits 
9480a5635cSJustin Hibbits 	for (;;) {
9580a5635cSJustin Hibbits 		if (hdlr == NULL)
9680a5635cSJustin Hibbits 			panic("attempt to remove non-existent invop handler");
9780a5635cSJustin Hibbits 
9880a5635cSJustin Hibbits 		if (hdlr->dtih_func == func)
9980a5635cSJustin Hibbits 			break;
10080a5635cSJustin Hibbits 
10180a5635cSJustin Hibbits 		prev = hdlr;
10280a5635cSJustin Hibbits 		hdlr = hdlr->dtih_next;
10380a5635cSJustin Hibbits 	}
10480a5635cSJustin Hibbits 
10580a5635cSJustin Hibbits 	if (prev == NULL) {
10680a5635cSJustin Hibbits 		ASSERT(dtrace_invop_hdlr == hdlr);
10780a5635cSJustin Hibbits 		dtrace_invop_hdlr = hdlr->dtih_next;
10880a5635cSJustin Hibbits 	} else {
10980a5635cSJustin Hibbits 		ASSERT(dtrace_invop_hdlr != hdlr);
11080a5635cSJustin Hibbits 		prev->dtih_next = hdlr->dtih_next;
11180a5635cSJustin Hibbits 	}
11280a5635cSJustin Hibbits 
11380a5635cSJustin Hibbits 	kmem_free(hdlr, 0);
11480a5635cSJustin Hibbits }
11580a5635cSJustin Hibbits 
116c7570492SJustin Hibbits 
117c7570492SJustin Hibbits /*ARGSUSED*/
118c7570492SJustin Hibbits void
dtrace_toxic_ranges(void (* func)(uintptr_t base,uintptr_t limit))119c7570492SJustin Hibbits dtrace_toxic_ranges(void (*func)(uintptr_t base, uintptr_t limit))
120c7570492SJustin Hibbits {
121c7570492SJustin Hibbits 	/*
122c7570492SJustin Hibbits 	 * No toxic regions?
123c7570492SJustin Hibbits 	 */
124c7570492SJustin Hibbits }
125c7570492SJustin Hibbits 
126c7570492SJustin Hibbits void
dtrace_xcall(processorid_t cpu,dtrace_xcall_t func,void * arg)127c7570492SJustin Hibbits dtrace_xcall(processorid_t cpu, dtrace_xcall_t func, void *arg)
128c7570492SJustin Hibbits {
129c7570492SJustin Hibbits 	cpuset_t cpus;
130c7570492SJustin Hibbits 
131c7570492SJustin Hibbits 	if (cpu == DTRACE_CPUALL)
132c7570492SJustin Hibbits 		cpus = all_cpus;
133c7570492SJustin Hibbits 	else
134c7570492SJustin Hibbits 		CPU_SETOF(cpu, &cpus);
135c7570492SJustin Hibbits 
13667d955aaSPatrick Kelsey 	smp_rendezvous_cpus(cpus, smp_no_rendezvous_barrier, func,
13767d955aaSPatrick Kelsey 			smp_no_rendezvous_barrier, arg);
138c7570492SJustin Hibbits }
139c7570492SJustin Hibbits 
140c7570492SJustin Hibbits static void
dtrace_sync_func(void)141c7570492SJustin Hibbits dtrace_sync_func(void)
142c7570492SJustin Hibbits {
143c7570492SJustin Hibbits }
144c7570492SJustin Hibbits 
145c7570492SJustin Hibbits void
dtrace_sync(void)146c7570492SJustin Hibbits dtrace_sync(void)
147c7570492SJustin Hibbits {
148c7570492SJustin Hibbits 	dtrace_xcall(DTRACE_CPUALL, (dtrace_xcall_t)dtrace_sync_func, NULL);
149c7570492SJustin Hibbits }
150c7570492SJustin Hibbits 
151f0bd82a1SJustin Hibbits static int64_t	tgt_cpu_tsc;
152f0bd82a1SJustin Hibbits static int64_t	hst_cpu_tsc;
153f0bd82a1SJustin Hibbits static int64_t	timebase_skew[MAXCPU];
154f0bd82a1SJustin Hibbits static uint64_t	nsec_scale;
155f0bd82a1SJustin Hibbits 
156f0bd82a1SJustin Hibbits /* See below for the explanation of this macro. */
157f0bd82a1SJustin Hibbits /* This is taken from the amd64 dtrace_subr, to provide a synchronized timer
158f0bd82a1SJustin Hibbits  * between multiple processors in dtrace.  Since PowerPC Timebases can be much
159f0bd82a1SJustin Hibbits  * lower than x86, the scale shift is 26 instead of 28, allowing for a 15.63MHz
160f0bd82a1SJustin Hibbits  * timebase.
161f0bd82a1SJustin Hibbits  */
162f0bd82a1SJustin Hibbits #define SCALE_SHIFT	26
163f0bd82a1SJustin Hibbits 
164f0bd82a1SJustin Hibbits static void
dtrace_gethrtime_init_cpu(void * arg)165f0bd82a1SJustin Hibbits dtrace_gethrtime_init_cpu(void *arg)
166f0bd82a1SJustin Hibbits {
167f0bd82a1SJustin Hibbits 	uintptr_t cpu = (uintptr_t) arg;
168f0bd82a1SJustin Hibbits 
169f0bd82a1SJustin Hibbits 	if (cpu == curcpu)
170f0bd82a1SJustin Hibbits 		tgt_cpu_tsc = mftb();
171f0bd82a1SJustin Hibbits 	else
172f0bd82a1SJustin Hibbits 		hst_cpu_tsc = mftb();
173f0bd82a1SJustin Hibbits }
174f0bd82a1SJustin Hibbits 
175f0bd82a1SJustin Hibbits static void
dtrace_gethrtime_init(void * arg)176f0bd82a1SJustin Hibbits dtrace_gethrtime_init(void *arg)
177f0bd82a1SJustin Hibbits {
178f0bd82a1SJustin Hibbits 	struct pcpu *pc;
179f0bd82a1SJustin Hibbits 	uint64_t tb_f;
180f0bd82a1SJustin Hibbits 	cpuset_t map;
181f0bd82a1SJustin Hibbits 	int i;
182f0bd82a1SJustin Hibbits 
183f0bd82a1SJustin Hibbits 	tb_f = cpu_tickrate();
184f0bd82a1SJustin Hibbits 
185f0bd82a1SJustin Hibbits 	/*
186f0bd82a1SJustin Hibbits 	 * The following line checks that nsec_scale calculated below
187f0bd82a1SJustin Hibbits 	 * doesn't overflow 32-bit unsigned integer, so that it can multiply
188f0bd82a1SJustin Hibbits 	 * another 32-bit integer without overflowing 64-bit.
189f0bd82a1SJustin Hibbits 	 * Thus minimum supported Timebase frequency is 15.63MHz.
190f0bd82a1SJustin Hibbits 	 */
191f0bd82a1SJustin Hibbits 	KASSERT(tb_f > (NANOSEC >> (32 - SCALE_SHIFT)), ("Timebase frequency is too low"));
192f0bd82a1SJustin Hibbits 
193f0bd82a1SJustin Hibbits 	/*
194f0bd82a1SJustin Hibbits 	 * We scale up NANOSEC/tb_f ratio to preserve as much precision
195f0bd82a1SJustin Hibbits 	 * as possible.
196f0bd82a1SJustin Hibbits 	 * 2^26 factor was chosen quite arbitrarily from practical
197f0bd82a1SJustin Hibbits 	 * considerations:
198f0bd82a1SJustin Hibbits 	 * - it supports TSC frequencies as low as 15.63MHz (see above);
199f0bd82a1SJustin Hibbits 	 */
200f0bd82a1SJustin Hibbits 	nsec_scale = ((uint64_t)NANOSEC << SCALE_SHIFT) / tb_f;
201f0bd82a1SJustin Hibbits 
202f0bd82a1SJustin Hibbits 	/* The current CPU is the reference one. */
203f0bd82a1SJustin Hibbits 	sched_pin();
204f0bd82a1SJustin Hibbits 	timebase_skew[curcpu] = 0;
205f0bd82a1SJustin Hibbits 	CPU_FOREACH(i) {
206f0bd82a1SJustin Hibbits 		if (i == curcpu)
207f0bd82a1SJustin Hibbits 			continue;
208f0bd82a1SJustin Hibbits 
209f0bd82a1SJustin Hibbits 		pc = pcpu_find(i);
210f0bd82a1SJustin Hibbits 		CPU_SETOF(PCPU_GET(cpuid), &map);
211f0bd82a1SJustin Hibbits 		CPU_SET(pc->pc_cpuid, &map);
212f0bd82a1SJustin Hibbits 
213f0bd82a1SJustin Hibbits 		smp_rendezvous_cpus(map, NULL,
214f0bd82a1SJustin Hibbits 		    dtrace_gethrtime_init_cpu,
21567d955aaSPatrick Kelsey 		    smp_no_rendezvous_barrier, (void *)(uintptr_t) i);
216f0bd82a1SJustin Hibbits 
217f0bd82a1SJustin Hibbits 		timebase_skew[i] = tgt_cpu_tsc - hst_cpu_tsc;
218f0bd82a1SJustin Hibbits 	}
219f0bd82a1SJustin Hibbits 	sched_unpin();
220f0bd82a1SJustin Hibbits }
221fdce57a0SJohn Baldwin #ifdef EARLY_AP_STARTUP
222fdce57a0SJohn Baldwin SYSINIT(dtrace_gethrtime_init, SI_SUB_DTRACE, SI_ORDER_ANY,
223fdce57a0SJohn Baldwin     dtrace_gethrtime_init, NULL);
224fdce57a0SJohn Baldwin #else
225fdce57a0SJohn Baldwin SYSINIT(dtrace_gethrtime_init, SI_SUB_SMP, SI_ORDER_ANY, dtrace_gethrtime_init,
226fdce57a0SJohn Baldwin     NULL);
227fdce57a0SJohn Baldwin #endif
228f0bd82a1SJustin Hibbits 
229c7570492SJustin Hibbits /*
230c7570492SJustin Hibbits  * DTrace needs a high resolution time function which can
231c7570492SJustin Hibbits  * be called from a probe context and guaranteed not to have
232c7570492SJustin Hibbits  * instrumented with probes itself.
233c7570492SJustin Hibbits  *
234c7570492SJustin Hibbits  * Returns nanoseconds since boot.
235c7570492SJustin Hibbits  */
236c7570492SJustin Hibbits uint64_t
dtrace_gethrtime(void)2377701f301SDimitry Andric dtrace_gethrtime(void)
238c7570492SJustin Hibbits {
239f0bd82a1SJustin Hibbits 	uint64_t timebase;
240f0bd82a1SJustin Hibbits 	uint32_t lo;
241f0bd82a1SJustin Hibbits 	uint32_t hi;
242c7570492SJustin Hibbits 
243f0bd82a1SJustin Hibbits 	/*
244f0bd82a1SJustin Hibbits 	 * We split timebase value into lower and higher 32-bit halves and separately
245f0bd82a1SJustin Hibbits 	 * scale them with nsec_scale, then we scale them down by 2^28
246f0bd82a1SJustin Hibbits 	 * (see nsec_scale calculations) taking into account 32-bit shift of
247f0bd82a1SJustin Hibbits 	 * the higher half and finally add.
248f0bd82a1SJustin Hibbits 	 */
249f0bd82a1SJustin Hibbits 	timebase = mftb() - timebase_skew[curcpu];
250f0bd82a1SJustin Hibbits 	lo = timebase;
251f0bd82a1SJustin Hibbits 	hi = timebase >> 32;
252f0bd82a1SJustin Hibbits 	return (((lo * nsec_scale) >> SCALE_SHIFT) +
253f0bd82a1SJustin Hibbits 	    ((hi * nsec_scale) << (32 - SCALE_SHIFT)));
254c7570492SJustin Hibbits }
255c7570492SJustin Hibbits 
256c7570492SJustin Hibbits uint64_t
dtrace_gethrestime(void)257c7570492SJustin Hibbits dtrace_gethrestime(void)
258c7570492SJustin Hibbits {
259c7570492SJustin Hibbits 	struct      timespec curtime;
260c7570492SJustin Hibbits 
261f0bd82a1SJustin Hibbits 	dtrace_getnanotime(&curtime);
262c7570492SJustin Hibbits 
263c7570492SJustin Hibbits 	return (curtime.tv_sec * 1000000000UL + curtime.tv_nsec);
264c7570492SJustin Hibbits }
265c7570492SJustin Hibbits 
266f0bd82a1SJustin Hibbits /* Function to handle DTrace traps during probes. See powerpc/powerpc/trap.c */
267c7570492SJustin Hibbits int
dtrace_trap(struct trapframe * frame,u_int type)268cafe8744SMark Johnston dtrace_trap(struct trapframe *frame, u_int type)
269c7570492SJustin Hibbits {
270880870b4SJustin Hibbits 	uint16_t nofault;
271cafe8744SMark Johnston 
272c7570492SJustin Hibbits 	/*
273c7570492SJustin Hibbits 	 * A trap can occur while DTrace executes a probe. Before
274c7570492SJustin Hibbits 	 * executing the probe, DTrace blocks re-scheduling and sets
275291624fdSMark Johnston 	 * a flag in its per-cpu flags to indicate that it doesn't
276c7570492SJustin Hibbits 	 * want to fault. On returning from the probe, the no-fault
277c7570492SJustin Hibbits 	 * flag is cleared and finally re-scheduling is enabled.
278c7570492SJustin Hibbits 	 *
279c7570492SJustin Hibbits 	 * Check if DTrace has enabled 'no-fault' mode:
280c7570492SJustin Hibbits 	 */
281880870b4SJustin Hibbits 	sched_pin();
282880870b4SJustin Hibbits 	nofault = cpu_core[curcpu].cpuc_dtrace_flags & CPU_DTRACE_NOFAULT;
283880870b4SJustin Hibbits 	sched_unpin();
284880870b4SJustin Hibbits 	if (nofault) {
285880870b4SJustin Hibbits 		KASSERT((frame->srr1 & PSL_EE) == 0, ("interrupts enabled"));
286c7570492SJustin Hibbits 		/*
287c7570492SJustin Hibbits 		 * There are only a couple of trap types that are expected.
288c7570492SJustin Hibbits 		 * All the rest will be handled in the usual way.
289c7570492SJustin Hibbits 		 */
290cafe8744SMark Johnston 		switch (type) {
291c7570492SJustin Hibbits 		/* Page fault. */
292c7570492SJustin Hibbits 		case EXC_DSI:
293c7570492SJustin Hibbits 		case EXC_DSE:
294c7570492SJustin Hibbits 			/* Flag a bad address. */
295c7570492SJustin Hibbits 			cpu_core[curcpu].cpuc_dtrace_flags |= CPU_DTRACE_BADADDR;
2964c790d26SNathan Whitehorn 			cpu_core[curcpu].cpuc_dtrace_illval = frame->dar;
297c7570492SJustin Hibbits 
298c7570492SJustin Hibbits 			/*
299c7570492SJustin Hibbits 			 * Offset the instruction pointer to the instruction
300c7570492SJustin Hibbits 			 * following the one causing the fault.
301c7570492SJustin Hibbits 			 */
302c7570492SJustin Hibbits 			frame->srr0 += sizeof(int);
303c7570492SJustin Hibbits 			return (1);
304c7570492SJustin Hibbits 		case EXC_ISI:
305c7570492SJustin Hibbits 		case EXC_ISE:
306c7570492SJustin Hibbits 			/* Flag a bad address. */
307c7570492SJustin Hibbits 			cpu_core[curcpu].cpuc_dtrace_flags |= CPU_DTRACE_BADADDR;
308c7570492SJustin Hibbits 			cpu_core[curcpu].cpuc_dtrace_illval = frame->srr0;
309c7570492SJustin Hibbits 
310c7570492SJustin Hibbits 			/*
311c7570492SJustin Hibbits 			 * Offset the instruction pointer to the instruction
312c7570492SJustin Hibbits 			 * following the one causing the fault.
313c7570492SJustin Hibbits 			 */
314c7570492SJustin Hibbits 			frame->srr0 += sizeof(int);
315c7570492SJustin Hibbits 			return (1);
316c7570492SJustin Hibbits 		default:
317c7570492SJustin Hibbits 			/* Handle all other traps in the usual way. */
318c7570492SJustin Hibbits 			break;
319c7570492SJustin Hibbits 		}
320c7570492SJustin Hibbits 	}
321c7570492SJustin Hibbits 
322c7570492SJustin Hibbits 	/* Handle the trap in the usual way. */
323c7570492SJustin Hibbits 	return (0);
324c7570492SJustin Hibbits }
325c7570492SJustin Hibbits 
326c7570492SJustin Hibbits void
dtrace_probe_error(dtrace_state_t * state,dtrace_epid_t epid,int which,int fault,int fltoffs,uintptr_t illval)327c7570492SJustin Hibbits dtrace_probe_error(dtrace_state_t *state, dtrace_epid_t epid, int which,
328c7570492SJustin Hibbits     int fault, int fltoffs, uintptr_t illval)
329c7570492SJustin Hibbits {
330c7570492SJustin Hibbits 
331c7570492SJustin Hibbits 	dtrace_probe(dtrace_probeid_error, (uint64_t)(uintptr_t)state,
332c7570492SJustin Hibbits 	    (uintptr_t)epid,
333c7570492SJustin Hibbits 	    (uintptr_t)which, (uintptr_t)fault, (uintptr_t)fltoffs);
334c7570492SJustin Hibbits }
33580a5635cSJustin Hibbits 
33680a5635cSJustin Hibbits static int
dtrace_invop_start(struct trapframe * frame)33780a5635cSJustin Hibbits dtrace_invop_start(struct trapframe *frame)
33880a5635cSJustin Hibbits {
3396c280659SMark Johnston 
3406c280659SMark Johnston 	switch (dtrace_invop(frame->srr0, frame, frame->fixreg[3])) {
34180a5635cSJustin Hibbits 	case DTRACE_INVOP_JUMP:
34280a5635cSJustin Hibbits 		break;
34380a5635cSJustin Hibbits 	case DTRACE_INVOP_BCTR:
34480a5635cSJustin Hibbits 		frame->srr0 = frame->ctr;
34580a5635cSJustin Hibbits 		break;
34680a5635cSJustin Hibbits 	case DTRACE_INVOP_BLR:
34780a5635cSJustin Hibbits 		frame->srr0 = frame->lr;
34880a5635cSJustin Hibbits 		break;
34980a5635cSJustin Hibbits 	case DTRACE_INVOP_MFLR_R0:
35080a5635cSJustin Hibbits 		frame->fixreg[0] = frame->lr;
351f0bd82a1SJustin Hibbits 		frame->srr0 = frame->srr0 + 4;
35280a5635cSJustin Hibbits 		break;
35380a5635cSJustin Hibbits 	default:
35480a5635cSJustin Hibbits 		return (-1);
35580a5635cSJustin Hibbits 	}
35680a5635cSJustin Hibbits 	return (0);
35780a5635cSJustin Hibbits }
35880a5635cSJustin Hibbits 
dtrace_invop_init(void)35980a5635cSJustin Hibbits void dtrace_invop_init(void)
36080a5635cSJustin Hibbits {
36180a5635cSJustin Hibbits 	dtrace_invop_jump_addr = dtrace_invop_start;
36280a5635cSJustin Hibbits }
36380a5635cSJustin Hibbits 
dtrace_invop_uninit(void)36480a5635cSJustin Hibbits void dtrace_invop_uninit(void)
36580a5635cSJustin Hibbits {
36680a5635cSJustin Hibbits 	dtrace_invop_jump_addr = 0;
36780a5635cSJustin Hibbits }
368