1*65f88a47Sriastradh /*	$NetBSD: dtrace_subr.c,v 1.14 2022/08/21 18:58:45 riastradh Exp $	*/
201c9547eSdarran 
3bb8023b5Sdarran /*
4bb8023b5Sdarran  * CDDL HEADER START
5bb8023b5Sdarran  *
6bb8023b5Sdarran  * The contents of this file are subject to the terms of the
7bb8023b5Sdarran  * Common Development and Distribution License, Version 1.0 only
8bb8023b5Sdarran  * (the "License").  You may not use this file except in compliance
9bb8023b5Sdarran  * with the License.
10bb8023b5Sdarran  *
11bb8023b5Sdarran  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
12bb8023b5Sdarran  * or http://www.opensolaris.org/os/licensing.
13bb8023b5Sdarran  * See the License for the specific language governing permissions
14bb8023b5Sdarran  * and limitations under the License.
15bb8023b5Sdarran  *
16bb8023b5Sdarran  * When distributing Covered Code, include this CDDL HEADER in each
17bb8023b5Sdarran  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
18bb8023b5Sdarran  * If applicable, add the following below this CDDL HEADER, with the
19bb8023b5Sdarran  * fields enclosed by brackets "[]" replaced with your own identifying
20bb8023b5Sdarran  * information: Portions Copyright [yyyy] [name of copyright owner]
21bb8023b5Sdarran  *
22bb8023b5Sdarran  * CDDL HEADER END
23bb8023b5Sdarran  *
24eada09acSchs  * $FreeBSD: head/sys/cddl/dev/dtrace/i386/dtrace_subr.c 313850 2017-02-17 03:27:20Z markj $
25bb8023b5Sdarran  *
26bb8023b5Sdarran  */
27bb8023b5Sdarran /*
28bb8023b5Sdarran  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
29bb8023b5Sdarran  * Use is subject to license terms.
30bb8023b5Sdarran  */
31bb8023b5Sdarran 
32eada09acSchs /*
33eada09acSchs  * Copyright (c) 2011, Joyent, Inc. All rights reserved.
34eada09acSchs  */
35eada09acSchs 
36bb8023b5Sdarran #include <sys/param.h>
37bb8023b5Sdarran #include <sys/systm.h>
38bb8023b5Sdarran #include <sys/types.h>
39bb8023b5Sdarran #include <sys/kernel.h>
40bb8023b5Sdarran #include <sys/malloc.h>
41bb8023b5Sdarran #include <sys/kmem.h>
4201c9547eSdarran #include <sys/xcall.h>
4301c9547eSdarran #include <sys/cpu.h>
4401c9547eSdarran #include <sys/cpuvar.h>
45bb8023b5Sdarran #include <sys/dtrace_impl.h>
46bb8023b5Sdarran #include <sys/dtrace_bsd.h>
4701c9547eSdarran #include <machine/cpu.h>
48*65f88a47Sriastradh #include <machine/cpufunc.h>
49bb8023b5Sdarran #include <machine/clock.h>
50bb8023b5Sdarran #include <machine/frame.h>
5101c9547eSdarran #include <uvm/uvm_pglist.h>
5201c9547eSdarran #include <uvm/uvm_prot.h>
5301c9547eSdarran #include <uvm/uvm_pmap.h>
54bb8023b5Sdarran 
554a21f050Stron #include <x86/include/cpu_counter.h>
564a21f050Stron 
57bb8023b5Sdarran extern uintptr_t 	kernelbase;
58eada09acSchs 
59eada09acSchs extern void dtrace_getnanotime(struct timespec *tsp);
60bb8023b5Sdarran 
610fa27af2Schs int dtrace_invop(uintptr_t, struct trapframe *, uintptr_t);
62bb8023b5Sdarran 
63bb8023b5Sdarran typedef struct dtrace_invop_hdlr {
640fa27af2Schs 	int (*dtih_func)(uintptr_t, struct trapframe *, uintptr_t);
65bb8023b5Sdarran 	struct dtrace_invop_hdlr *dtih_next;
66bb8023b5Sdarran } dtrace_invop_hdlr_t;
67bb8023b5Sdarran 
68bb8023b5Sdarran dtrace_invop_hdlr_t *dtrace_invop_hdlr;
69bb8023b5Sdarran 
704a21f050Stron void dtrace_gethrtime_init(void *arg);
714a21f050Stron 
72bb8023b5Sdarran int
dtrace_invop(uintptr_t addr,struct trapframe * frame,uintptr_t eax)730fa27af2Schs dtrace_invop(uintptr_t addr, struct trapframe *frame, uintptr_t eax)
74bb8023b5Sdarran {
75bb8023b5Sdarran 	dtrace_invop_hdlr_t *hdlr;
76bb8023b5Sdarran 	int rval;
77bb8023b5Sdarran 
78bb8023b5Sdarran 	for (hdlr = dtrace_invop_hdlr; hdlr != NULL; hdlr = hdlr->dtih_next)
790fa27af2Schs 		if ((rval = hdlr->dtih_func(addr, frame, eax)) != 0)
80bb8023b5Sdarran 			return (rval);
81bb8023b5Sdarran 
82bb8023b5Sdarran 	return (0);
83bb8023b5Sdarran }
84bb8023b5Sdarran 
85bb8023b5Sdarran void
dtrace_invop_add(int (* func)(uintptr_t,struct trapframe *,uintptr_t))860fa27af2Schs dtrace_invop_add(int (*func)(uintptr_t, struct trapframe *, uintptr_t))
87bb8023b5Sdarran {
88bb8023b5Sdarran 	dtrace_invop_hdlr_t *hdlr;
89bb8023b5Sdarran 
90894b3478Ssimonb 	hdlr = kmem_alloc(sizeof(*hdlr), KM_SLEEP);
91bb8023b5Sdarran 	hdlr->dtih_func = func;
92bb8023b5Sdarran 	hdlr->dtih_next = dtrace_invop_hdlr;
93bb8023b5Sdarran 	dtrace_invop_hdlr = hdlr;
94bb8023b5Sdarran }
95bb8023b5Sdarran 
96bb8023b5Sdarran void
dtrace_invop_remove(int (* func)(uintptr_t,struct trapframe *,uintptr_t))970fa27af2Schs dtrace_invop_remove(int (*func)(uintptr_t, struct trapframe *, uintptr_t))
98bb8023b5Sdarran {
99bb8023b5Sdarran 	dtrace_invop_hdlr_t *hdlr = dtrace_invop_hdlr, *prev = NULL;
100bb8023b5Sdarran 
101bb8023b5Sdarran 	for (;;) {
102bb8023b5Sdarran 		if (hdlr == NULL)
103bb8023b5Sdarran 			panic("attempt to remove non-existent invop handler");
104bb8023b5Sdarran 
105bb8023b5Sdarran 		if (hdlr->dtih_func == func)
106bb8023b5Sdarran 			break;
107bb8023b5Sdarran 
108bb8023b5Sdarran 		prev = hdlr;
109bb8023b5Sdarran 		hdlr = hdlr->dtih_next;
110bb8023b5Sdarran 	}
111bb8023b5Sdarran 
112bb8023b5Sdarran 	if (prev == NULL) {
113bb8023b5Sdarran 		ASSERT(dtrace_invop_hdlr == hdlr);
114bb8023b5Sdarran 		dtrace_invop_hdlr = hdlr->dtih_next;
115bb8023b5Sdarran 	} else {
116bb8023b5Sdarran 		ASSERT(dtrace_invop_hdlr != hdlr);
117bb8023b5Sdarran 		prev->dtih_next = hdlr->dtih_next;
118bb8023b5Sdarran 	}
119bb8023b5Sdarran 
120894b3478Ssimonb 	kmem_free(hdlr, sizeof(*hdlr));
121bb8023b5Sdarran }
122bb8023b5Sdarran 
123bb8023b5Sdarran void
dtrace_toxic_ranges(void (* func)(uintptr_t base,uintptr_t limit))124bb8023b5Sdarran dtrace_toxic_ranges(void (*func)(uintptr_t base, uintptr_t limit))
125bb8023b5Sdarran {
126bb8023b5Sdarran 	(*func)(0, kernelbase);
127bb8023b5Sdarran }
128bb8023b5Sdarran 
12901c9547eSdarran static void
xcall_func(void * arg0,void * arg1)13001c9547eSdarran xcall_func(void *arg0, void *arg1)
13101c9547eSdarran {
13201c9547eSdarran     	dtrace_xcall_t func = arg0;
13301c9547eSdarran 
13401c9547eSdarran     	(*func)(arg1);
13501c9547eSdarran }
13601c9547eSdarran 
137bb8023b5Sdarran void
dtrace_xcall(processorid_t cpu,dtrace_xcall_t func,void * arg)138ebd379eeSchs dtrace_xcall(processorid_t cpu, dtrace_xcall_t func, void *arg)
139bb8023b5Sdarran {
14001c9547eSdarran 	uint64_t where;
141bb8023b5Sdarran 
142ebd379eeSchs 	if (cpu == DTRACE_CPUALL) {
14301c9547eSdarran 		where = xc_broadcast(0, xcall_func, func, arg);
14401c9547eSdarran 	} else {
14501c9547eSdarran 		struct cpu_info *cinfo = cpu_lookup(cpu);
146bb8023b5Sdarran 
14701c9547eSdarran 		KASSERT(cinfo != NULL);
14801c9547eSdarran 		where = xc_unicast(0, xcall_func, func, arg, cinfo);
149bb8023b5Sdarran 	}
15001c9547eSdarran 	xc_wait(where);
151bb8023b5Sdarran 
15201c9547eSdarran 	/* XXX Q. Do we really need the other cpus to wait also?
15301c9547eSdarran 	 * (see solaris:xc_sync())
15401c9547eSdarran 	 */
155bb8023b5Sdarran }
156bb8023b5Sdarran 
157bb8023b5Sdarran static void
dtrace_sync_func(void)158bb8023b5Sdarran dtrace_sync_func(void)
159bb8023b5Sdarran {
160bb8023b5Sdarran }
161bb8023b5Sdarran 
162bb8023b5Sdarran void
dtrace_sync(void)163bb8023b5Sdarran dtrace_sync(void)
164bb8023b5Sdarran {
165bb8023b5Sdarran         dtrace_xcall(DTRACE_CPUALL, (dtrace_xcall_t)dtrace_sync_func, NULL);
166bb8023b5Sdarran }
167bb8023b5Sdarran 
168bb8023b5Sdarran #ifdef notyet
169bb8023b5Sdarran void
dtrace_safe_synchronous_signal(void)170bb8023b5Sdarran dtrace_safe_synchronous_signal(void)
171bb8023b5Sdarran {
172bb8023b5Sdarran 	kthread_t *t = curthread;
173bb8023b5Sdarran 	struct regs *rp = lwptoregs(ttolwp(t));
174bb8023b5Sdarran 	size_t isz = t->t_dtrace_npc - t->t_dtrace_pc;
175bb8023b5Sdarran 
176bb8023b5Sdarran 	ASSERT(t->t_dtrace_on);
177bb8023b5Sdarran 
178bb8023b5Sdarran 	/*
179bb8023b5Sdarran 	 * If we're not in the range of scratch addresses, we're not actually
180bb8023b5Sdarran 	 * tracing user instructions so turn off the flags. If the instruction
181bb8023b5Sdarran 	 * we copied out caused a synchonous trap, reset the pc back to its
182bb8023b5Sdarran 	 * original value and turn off the flags.
183bb8023b5Sdarran 	 */
184bb8023b5Sdarran 	if (rp->r_pc < t->t_dtrace_scrpc ||
185bb8023b5Sdarran 	    rp->r_pc > t->t_dtrace_astpc + isz) {
186bb8023b5Sdarran 		t->t_dtrace_ft = 0;
187bb8023b5Sdarran 	} else if (rp->r_pc == t->t_dtrace_scrpc ||
188bb8023b5Sdarran 	    rp->r_pc == t->t_dtrace_astpc) {
189bb8023b5Sdarran 		rp->r_pc = t->t_dtrace_pc;
190bb8023b5Sdarran 		t->t_dtrace_ft = 0;
191bb8023b5Sdarran 	}
192bb8023b5Sdarran }
193bb8023b5Sdarran 
194bb8023b5Sdarran int
dtrace_safe_defer_signal(void)195bb8023b5Sdarran dtrace_safe_defer_signal(void)
196bb8023b5Sdarran {
197bb8023b5Sdarran 	kthread_t *t = curthread;
198bb8023b5Sdarran 	struct regs *rp = lwptoregs(ttolwp(t));
199bb8023b5Sdarran 	size_t isz = t->t_dtrace_npc - t->t_dtrace_pc;
200bb8023b5Sdarran 
201bb8023b5Sdarran 	ASSERT(t->t_dtrace_on);
202bb8023b5Sdarran 
203bb8023b5Sdarran 	/*
204bb8023b5Sdarran 	 * If we're not in the range of scratch addresses, we're not actually
205bb8023b5Sdarran 	 * tracing user instructions so turn off the flags.
206bb8023b5Sdarran 	 */
207bb8023b5Sdarran 	if (rp->r_pc < t->t_dtrace_scrpc ||
208bb8023b5Sdarran 	    rp->r_pc > t->t_dtrace_astpc + isz) {
209bb8023b5Sdarran 		t->t_dtrace_ft = 0;
210bb8023b5Sdarran 		return (0);
211bb8023b5Sdarran 	}
212bb8023b5Sdarran 
213bb8023b5Sdarran 	/*
214eada09acSchs 	 * If we have executed the original instruction, but we have performed
215eada09acSchs 	 * neither the jmp back to t->t_dtrace_npc nor the clean up of any
216eada09acSchs 	 * registers used to emulate %rip-relative instructions in 64-bit mode,
217eada09acSchs 	 * we'll save ourselves some effort by doing that here and taking the
218eada09acSchs 	 * signal right away.  We detect this condition by seeing if the program
219eada09acSchs 	 * counter is the range [scrpc + isz, astpc).
220bb8023b5Sdarran 	 */
221eada09acSchs 	if (rp->r_pc >= t->t_dtrace_scrpc + isz &&
222eada09acSchs 	    rp->r_pc < t->t_dtrace_astpc) {
223bb8023b5Sdarran #ifdef __amd64
224bb8023b5Sdarran 		/*
225bb8023b5Sdarran 		 * If there is a scratch register and we're on the
226bb8023b5Sdarran 		 * instruction immediately after the modified instruction,
227bb8023b5Sdarran 		 * restore the value of that scratch register.
228bb8023b5Sdarran 		 */
229bb8023b5Sdarran 		if (t->t_dtrace_reg != 0 &&
230bb8023b5Sdarran 		    rp->r_pc == t->t_dtrace_scrpc + isz) {
231bb8023b5Sdarran 			switch (t->t_dtrace_reg) {
232bb8023b5Sdarran 			case REG_RAX:
233bb8023b5Sdarran 				rp->r_rax = t->t_dtrace_regv;
234bb8023b5Sdarran 				break;
235bb8023b5Sdarran 			case REG_RCX:
236bb8023b5Sdarran 				rp->r_rcx = t->t_dtrace_regv;
237bb8023b5Sdarran 				break;
238bb8023b5Sdarran 			case REG_R8:
239bb8023b5Sdarran 				rp->r_r8 = t->t_dtrace_regv;
240bb8023b5Sdarran 				break;
241bb8023b5Sdarran 			case REG_R9:
242bb8023b5Sdarran 				rp->r_r9 = t->t_dtrace_regv;
243bb8023b5Sdarran 				break;
244bb8023b5Sdarran 			}
245bb8023b5Sdarran 		}
246bb8023b5Sdarran #endif
247bb8023b5Sdarran 		rp->r_pc = t->t_dtrace_npc;
248bb8023b5Sdarran 		t->t_dtrace_ft = 0;
249bb8023b5Sdarran 		return (0);
250bb8023b5Sdarran 	}
251bb8023b5Sdarran 
252bb8023b5Sdarran 	/*
253bb8023b5Sdarran 	 * Otherwise, make sure we'll return to the kernel after executing
254bb8023b5Sdarran 	 * the copied out instruction and defer the signal.
255bb8023b5Sdarran 	 */
256bb8023b5Sdarran 	if (!t->t_dtrace_step) {
257bb8023b5Sdarran 		ASSERT(rp->r_pc < t->t_dtrace_astpc);
258bb8023b5Sdarran 		rp->r_pc += t->t_dtrace_astpc - t->t_dtrace_scrpc;
259bb8023b5Sdarran 		t->t_dtrace_step = 1;
260bb8023b5Sdarran 	}
261bb8023b5Sdarran 
262bb8023b5Sdarran 	t->t_dtrace_ast = 1;
263bb8023b5Sdarran 
264bb8023b5Sdarran 	return (1);
265bb8023b5Sdarran }
266bb8023b5Sdarran #endif
267bb8023b5Sdarran 
268bb8023b5Sdarran static int64_t	tgt_cpu_tsc;
269bb8023b5Sdarran static int64_t	hst_cpu_tsc;
27001c9547eSdarran static int64_t	tsc_skew[MAXCPUS];
271bb8023b5Sdarran static uint64_t	nsec_scale;
272bb8023b5Sdarran 
273bb8023b5Sdarran /* See below for the explanation of this macro. */
274bb8023b5Sdarran #define SCALE_SHIFT	28
275bb8023b5Sdarran 
27601c9547eSdarran static __inline uint64_t
dtrace_rdtsc(void)27701c9547eSdarran dtrace_rdtsc(void)
27801c9547eSdarran {
27901c9547eSdarran 	uint64_t rv;
28001c9547eSdarran 
28101c9547eSdarran 	__asm __volatile("rdtsc" : "=A" (rv));
28201c9547eSdarran 	return (rv);
28301c9547eSdarran }
28401c9547eSdarran 
285bb8023b5Sdarran static void
dtrace_gethrtime_init_cpu(void * arg)286bb8023b5Sdarran dtrace_gethrtime_init_cpu(void *arg)
287bb8023b5Sdarran {
288bb8023b5Sdarran 	uintptr_t cpu = (uintptr_t) arg;
289bb8023b5Sdarran 
29001c9547eSdarran 	if (cpu == cpu_number())
29101c9547eSdarran 		tgt_cpu_tsc = dtrace_rdtsc();
292bb8023b5Sdarran 	else
29301c9547eSdarran 		hst_cpu_tsc = dtrace_rdtsc();
294bb8023b5Sdarran }
295bb8023b5Sdarran 
29601c9547eSdarran void
dtrace_gethrtime_init(void * arg)297bb8023b5Sdarran dtrace_gethrtime_init(void *arg)
298bb8023b5Sdarran {
299bb8023b5Sdarran 	uint64_t tsc_f;
30001c9547eSdarran 	CPU_INFO_ITERATOR cpuind;
30101c9547eSdarran 	struct cpu_info *cinfo = curcpu();
30201c9547eSdarran 	cpuid_t cur_cpuid = cpu_number();	/* current cpu id */
303bb8023b5Sdarran 
304bb8023b5Sdarran 	/*
305bb8023b5Sdarran 	 * Get TSC frequency known at this moment.
306bb8023b5Sdarran 	 * This should be constant if TSC is invariant.
307bb8023b5Sdarran 	 * Otherwise tick->time conversion will be inaccurate, but
308bb8023b5Sdarran 	 * will preserve monotonic property of TSC.
309bb8023b5Sdarran 	 */
31001c9547eSdarran 	tsc_f = cpu_frequency(cinfo);
311bb8023b5Sdarran 
312bb8023b5Sdarran 	/*
313bb8023b5Sdarran 	 * The following line checks that nsec_scale calculated below
314bb8023b5Sdarran 	 * doesn't overflow 32-bit unsigned integer, so that it can multiply
315bb8023b5Sdarran 	 * another 32-bit integer without overflowing 64-bit.
316bb8023b5Sdarran 	 * Thus minimum supported TSC frequency is 62.5MHz.
317bb8023b5Sdarran 	 */
318eada09acSchs 	KASSERTMSG(tsc_f > (NANOSEC >> (32 - SCALE_SHIFT)),
319eada09acSchs 	    "TSC frequency is too low");
320bb8023b5Sdarran 
321bb8023b5Sdarran 	/*
322bb8023b5Sdarran 	 * We scale up NANOSEC/tsc_f ratio to preserve as much precision
323bb8023b5Sdarran 	 * as possible.
324bb8023b5Sdarran 	 * 2^28 factor was chosen quite arbitrarily from practical
325bb8023b5Sdarran 	 * considerations:
326bb8023b5Sdarran 	 * - it supports TSC frequencies as low as 62.5MHz (see above);
327bb8023b5Sdarran 	 * - it provides quite good precision (e < 0.01%) up to THz
328bb8023b5Sdarran 	 *   (terahertz) values;
329bb8023b5Sdarran 	 */
330bb8023b5Sdarran 	nsec_scale = ((uint64_t)NANOSEC << SCALE_SHIFT) / tsc_f;
331bb8023b5Sdarran 
332bb8023b5Sdarran 	/* The current CPU is the reference one. */
33301c9547eSdarran 	tsc_skew[cur_cpuid] = 0;
334bb8023b5Sdarran 
33501c9547eSdarran 	for (CPU_INFO_FOREACH(cpuind, cinfo)) {
33601c9547eSdarran 		/* use skew relative to cpu 0 */
33701c9547eSdarran 		tsc_skew[cpu_index(cinfo)] = cinfo->ci_data.cpu_cc_skew;
33801c9547eSdarran 	}
33901c9547eSdarran 
34001c9547eSdarran 	/* Already handled in x86/tsc.c for ci_data.cpu_cc_skew */
34101c9547eSdarran #if 0
342eada09acSchs 	/* The current CPU is the reference one. */
343eada09acSchs 	sched_pin();
344eada09acSchs 	tsc_skew[curcpu] = 0;
345eada09acSchs 	CPU_FOREACH(i) {
346bb8023b5Sdarran 		if (i == curcpu)
347bb8023b5Sdarran 			continue;
348bb8023b5Sdarran 
349eada09acSchs 		pc = pcpu_find(i);
350eada09acSchs 		CPU_SETOF(PCPU_GET(cpuid), &map);
351eada09acSchs 		CPU_SET(pc->pc_cpuid, &map);
352bb8023b5Sdarran 
353eada09acSchs 		smp_rendezvous_cpus(map, NULL,
354bb8023b5Sdarran 		    dtrace_gethrtime_init_cpu,
355bb8023b5Sdarran 		    smp_no_rendevous_barrier, (void *)(uintptr_t) i);
356bb8023b5Sdarran 
357bb8023b5Sdarran 		tsc_skew[i] = tgt_cpu_tsc - hst_cpu_tsc;
358bb8023b5Sdarran 	}
359eada09acSchs 	sched_unpin();
36001c9547eSdarran #endif
361bb8023b5Sdarran }
362bb8023b5Sdarran 
363eada09acSchs #ifdef __FreeBSD__
364eada09acSchs #ifdef EARLY_AP_STARTUP
365eada09acSchs SYSINIT(dtrace_gethrtime_init, SI_SUB_DTRACE, SI_ORDER_ANY,
366eada09acSchs     dtrace_gethrtime_init, NULL);
367eada09acSchs #else
368eada09acSchs SYSINIT(dtrace_gethrtime_init, SI_SUB_SMP, SI_ORDER_ANY, dtrace_gethrtime_init,
369eada09acSchs     NULL);
370eada09acSchs #endif
371eada09acSchs #endif
372eada09acSchs 
373bb8023b5Sdarran /*
374bb8023b5Sdarran  * DTrace needs a high resolution time function which can
375bb8023b5Sdarran  * be called from a probe context and guaranteed not to have
376bb8023b5Sdarran  * instrumented with probes itself.
377bb8023b5Sdarran  *
378bb8023b5Sdarran  * Returns nanoseconds since boot.
379bb8023b5Sdarran  */
380bb8023b5Sdarran uint64_t
dtrace_gethrtime()381bb8023b5Sdarran dtrace_gethrtime()
382bb8023b5Sdarran {
383bb8023b5Sdarran 	uint64_t tsc;
384bb8023b5Sdarran 	uint32_t lo;
385bb8023b5Sdarran 	uint32_t hi;
386bb8023b5Sdarran 
387bb8023b5Sdarran 	/*
388bb8023b5Sdarran 	 * We split TSC value into lower and higher 32-bit halves and separately
389bb8023b5Sdarran 	 * scale them with nsec_scale, then we scale them down by 2^28
390bb8023b5Sdarran 	 * (see nsec_scale calculations) taking into account 32-bit shift of
391bb8023b5Sdarran 	 * the higher half and finally add.
392bb8023b5Sdarran 	 */
39301c9547eSdarran 	tsc = dtrace_rdtsc() + tsc_skew[cpu_number()];
394bb8023b5Sdarran 	lo = tsc;
395bb8023b5Sdarran 	hi = tsc >> 32;
396bb8023b5Sdarran 	return (((lo * nsec_scale) >> SCALE_SHIFT) +
397bb8023b5Sdarran 	    ((hi * nsec_scale) << (32 - SCALE_SHIFT)));
398bb8023b5Sdarran }
399bb8023b5Sdarran 
400bb8023b5Sdarran uint64_t
dtrace_gethrestime(void)401bb8023b5Sdarran dtrace_gethrestime(void)
402bb8023b5Sdarran {
403eada09acSchs 	struct timespec current_time;
404eada09acSchs 
405eada09acSchs 	dtrace_getnanotime(&current_time);
406eada09acSchs 
407eada09acSchs 	return (current_time.tv_sec * 1000000000ULL + current_time.tv_nsec);
408bb8023b5Sdarran }
409bb8023b5Sdarran 
410bb8023b5Sdarran /* Function to handle DTrace traps during probes. See i386/i386/trap.c */
411bb8023b5Sdarran int
dtrace_trap(struct trapframe * frame,u_int type)412bb8023b5Sdarran dtrace_trap(struct trapframe *frame, u_int type)
413bb8023b5Sdarran {
414eada09acSchs 	bool nofault;
41501c9547eSdarran 	cpuid_t cpuid = cpu_number();	/* current cpu id */
41601c9547eSdarran 
417bb8023b5Sdarran 	/*
418bb8023b5Sdarran 	 * A trap can occur while DTrace executes a probe. Before
419bb8023b5Sdarran 	 * executing the probe, DTrace blocks re-scheduling and sets
420eada09acSchs 	 * a flag in its per-cpu flags to indicate that it doesn't
421eada09acSchs 	 * want to fault. On returning from the probe, the no-fault
422bb8023b5Sdarran 	 * flag is cleared and finally re-scheduling is enabled.
423bb8023b5Sdarran 	 *
424bb8023b5Sdarran 	 * Check if DTrace has enabled 'no-fault' mode:
425bb8023b5Sdarran 	 */
426eada09acSchs 	nofault = (cpu_core[cpuid].cpuc_dtrace_flags & CPU_DTRACE_NOFAULT) != 0;
427eada09acSchs 	if (nofault) {
42849f82716Srin 		KASSERTMSG((x86_read_flags() & PSL_I) == 0,
42949f82716Srin 		    "interrupts enabled");
430eada09acSchs 
431bb8023b5Sdarran 		/*
432bb8023b5Sdarran 		 * There are only a couple of trap types that are expected.
433bb8023b5Sdarran 		 * All the rest will be handled in the usual way.
434bb8023b5Sdarran 		 */
435bb8023b5Sdarran 		switch (type) {
436bb8023b5Sdarran 		/* General protection fault. */
437bb8023b5Sdarran 		case T_PROTFLT:
438bb8023b5Sdarran 			/* Flag an illegal operation. */
43901c9547eSdarran 			cpu_core[cpuid].cpuc_dtrace_flags |= CPU_DTRACE_ILLOP;
440bb8023b5Sdarran 
441bb8023b5Sdarran 			/*
442bb8023b5Sdarran 			 * Offset the instruction pointer to the instruction
443bb8023b5Sdarran 			 * following the one causing the fault.
444bb8023b5Sdarran 			 */
445bb8023b5Sdarran 			frame->tf_eip += dtrace_instr_size((u_char *) frame->tf_eip);
446bb8023b5Sdarran 			return (1);
447bb8023b5Sdarran 		/* Page fault. */
448bb8023b5Sdarran 		case T_PAGEFLT:
449bb8023b5Sdarran 			/* Flag a bad address. */
45001c9547eSdarran 			cpu_core[cpuid].cpuc_dtrace_flags |= CPU_DTRACE_BADADDR;
45101c9547eSdarran 			cpu_core[cpuid].cpuc_dtrace_illval = rcr2();
452bb8023b5Sdarran 
453bb8023b5Sdarran 			/*
454bb8023b5Sdarran 			 * Offset the instruction pointer to the instruction
455bb8023b5Sdarran 			 * following the one causing the fault.
456bb8023b5Sdarran 			 */
457bb8023b5Sdarran 			frame->tf_eip += dtrace_instr_size((u_char *) frame->tf_eip);
458bb8023b5Sdarran 			return (1);
459bb8023b5Sdarran 		default:
460bb8023b5Sdarran 			/* Handle all other traps in the usual way. */
461bb8023b5Sdarran 			break;
462bb8023b5Sdarran 		}
463bb8023b5Sdarran 	}
464bb8023b5Sdarran 
465bb8023b5Sdarran 	/* Handle the trap in the usual way. */
466bb8023b5Sdarran 	return (0);
467bb8023b5Sdarran }
468