dtrace_subr.c revision 1.7 1 1.7 chs /* $NetBSD: dtrace_subr.c,v 1.7 2012/06/16 17:31:47 chs Exp $ */
2 1.2 darran
3 1.1 darran /*
4 1.1 darran * CDDL HEADER START
5 1.1 darran *
6 1.1 darran * The contents of this file are subject to the terms of the
7 1.1 darran * Common Development and Distribution License, Version 1.0 only
8 1.1 darran * (the "License"). You may not use this file except in compliance
9 1.1 darran * with the License.
10 1.1 darran *
11 1.1 darran * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
12 1.1 darran * or http://www.opensolaris.org/os/licensing.
13 1.1 darran * See the License for the specific language governing permissions
14 1.1 darran * and limitations under the License.
15 1.1 darran *
16 1.1 darran * When distributing Covered Code, include this CDDL HEADER in each
17 1.1 darran * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
18 1.1 darran * If applicable, add the following below this CDDL HEADER, with the
19 1.1 darran * fields enclosed by brackets "[]" replaced with your own identifying
20 1.1 darran * information: Portions Copyright [yyyy] [name of copyright owner]
21 1.1 darran *
22 1.1 darran * CDDL HEADER END
23 1.1 darran *
24 1.1 darran * $FreeBSD: src/sys/cddl/dev/dtrace/i386/dtrace_subr.c,v 1.3.2.1 2009/08/03 08:13:06 kensmith Exp $
25 1.1 darran *
26 1.1 darran */
27 1.1 darran /*
28 1.1 darran * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
29 1.1 darran * Use is subject to license terms.
30 1.1 darran */
31 1.1 darran
32 1.1 darran #include <sys/param.h>
33 1.1 darran #include <sys/systm.h>
34 1.1 darran #include <sys/types.h>
35 1.1 darran #include <sys/kernel.h>
36 1.1 darran #include <sys/malloc.h>
37 1.1 darran #include <sys/kmem.h>
38 1.2 darran #include <sys/xcall.h>
39 1.2 darran #include <sys/cpu.h>
40 1.2 darran #include <sys/cpuvar.h>
41 1.2 darran //#include <sys/smp.h>
42 1.1 darran #include <sys/dtrace_impl.h>
43 1.1 darran #include <sys/dtrace_bsd.h>
44 1.2 darran #include <machine/cpu.h>
45 1.1 darran #include <machine/clock.h>
46 1.1 darran #include <machine/frame.h>
47 1.2 darran #include <uvm/uvm_pglist.h>
48 1.2 darran #include <uvm/uvm_prot.h>
49 1.2 darran #include <uvm/uvm_pmap.h>
50 1.1 darran
51 1.3 tron #include <x86/include/cpu_counter.h>
52 1.3 tron
53 1.1 darran extern uintptr_t kernelbase;
54 1.1 darran extern uintptr_t dtrace_in_probe_addr;
55 1.1 darran extern int dtrace_in_probe;
56 1.1 darran
57 1.1 darran int dtrace_invop(uintptr_t, uintptr_t *, uintptr_t);
58 1.1 darran
59 1.1 darran typedef struct dtrace_invop_hdlr {
60 1.1 darran int (*dtih_func)(uintptr_t, uintptr_t *, uintptr_t);
61 1.1 darran struct dtrace_invop_hdlr *dtih_next;
62 1.1 darran } dtrace_invop_hdlr_t;
63 1.1 darran
64 1.1 darran dtrace_invop_hdlr_t *dtrace_invop_hdlr;
65 1.1 darran
66 1.3 tron void dtrace_gethrtime_init(void *arg);
67 1.3 tron
68 1.1 darran int
69 1.1 darran dtrace_invop(uintptr_t addr, uintptr_t *stack, uintptr_t eax)
70 1.1 darran {
71 1.1 darran dtrace_invop_hdlr_t *hdlr;
72 1.1 darran int rval;
73 1.1 darran
74 1.1 darran for (hdlr = dtrace_invop_hdlr; hdlr != NULL; hdlr = hdlr->dtih_next)
75 1.1 darran if ((rval = hdlr->dtih_func(addr, stack, eax)) != 0)
76 1.1 darran return (rval);
77 1.1 darran
78 1.1 darran return (0);
79 1.1 darran }
80 1.1 darran
81 1.1 darran void
82 1.1 darran dtrace_invop_add(int (*func)(uintptr_t, uintptr_t *, uintptr_t))
83 1.1 darran {
84 1.1 darran dtrace_invop_hdlr_t *hdlr;
85 1.1 darran
86 1.1 darran hdlr = kmem_alloc(sizeof (dtrace_invop_hdlr_t), KM_SLEEP);
87 1.1 darran hdlr->dtih_func = func;
88 1.1 darran hdlr->dtih_next = dtrace_invop_hdlr;
89 1.1 darran dtrace_invop_hdlr = hdlr;
90 1.1 darran }
91 1.1 darran
92 1.1 darran void
93 1.1 darran dtrace_invop_remove(int (*func)(uintptr_t, uintptr_t *, uintptr_t))
94 1.1 darran {
95 1.1 darran dtrace_invop_hdlr_t *hdlr = dtrace_invop_hdlr, *prev = NULL;
96 1.1 darran
97 1.1 darran for (;;) {
98 1.1 darran if (hdlr == NULL)
99 1.1 darran panic("attempt to remove non-existent invop handler");
100 1.1 darran
101 1.1 darran if (hdlr->dtih_func == func)
102 1.1 darran break;
103 1.1 darran
104 1.1 darran prev = hdlr;
105 1.1 darran hdlr = hdlr->dtih_next;
106 1.1 darran }
107 1.1 darran
108 1.1 darran if (prev == NULL) {
109 1.1 darran ASSERT(dtrace_invop_hdlr == hdlr);
110 1.1 darran dtrace_invop_hdlr = hdlr->dtih_next;
111 1.1 darran } else {
112 1.1 darran ASSERT(dtrace_invop_hdlr != hdlr);
113 1.1 darran prev->dtih_next = hdlr->dtih_next;
114 1.1 darran }
115 1.1 darran
116 1.5 ahoka kmem_free(hdlr, sizeof (dtrace_invop_hdlr_t));
117 1.1 darran }
118 1.1 darran
119 1.1 darran void
120 1.1 darran dtrace_toxic_ranges(void (*func)(uintptr_t base, uintptr_t limit))
121 1.1 darran {
122 1.1 darran (*func)(0, kernelbase);
123 1.1 darran }
124 1.1 darran
125 1.2 darran static void
126 1.2 darran xcall_func(void *arg0, void *arg1)
127 1.2 darran {
128 1.2 darran dtrace_xcall_t func = arg0;
129 1.2 darran
130 1.2 darran (*func)(arg1);
131 1.2 darran }
132 1.2 darran
133 1.1 darran void
134 1.7 chs dtrace_xcall(processorid_t cpu, dtrace_xcall_t func, void *arg)
135 1.1 darran {
136 1.2 darran uint64_t where;
137 1.1 darran
138 1.7 chs if (cpu == DTRACE_CPUALL) {
139 1.2 darran where = xc_broadcast(0, xcall_func, func, arg);
140 1.2 darran } else {
141 1.2 darran struct cpu_info *cinfo = cpu_lookup(cpu);
142 1.1 darran
143 1.2 darran KASSERT(cinfo != NULL);
144 1.2 darran where = xc_unicast(0, xcall_func, func, arg, cinfo);
145 1.1 darran }
146 1.2 darran xc_wait(where);
147 1.1 darran
148 1.2 darran /* XXX Q. Do we really need the other cpus to wait also?
149 1.2 darran * (see solaris:xc_sync())
150 1.2 darran */
151 1.1 darran }
152 1.1 darran
153 1.1 darran static void
154 1.1 darran dtrace_sync_func(void)
155 1.1 darran {
156 1.1 darran }
157 1.1 darran
158 1.1 darran void
159 1.1 darran dtrace_sync(void)
160 1.1 darran {
161 1.1 darran dtrace_xcall(DTRACE_CPUALL, (dtrace_xcall_t)dtrace_sync_func, NULL);
162 1.1 darran }
163 1.1 darran
164 1.1 darran #ifdef notyet
165 1.1 darran int (*dtrace_fasttrap_probe_ptr)(struct regs *);
166 1.1 darran int (*dtrace_pid_probe_ptr)(struct regs *);
167 1.1 darran int (*dtrace_return_probe_ptr)(struct regs *);
168 1.1 darran
169 1.1 darran void
170 1.1 darran dtrace_user_probe(struct regs *rp, caddr_t addr, processorid_t cpuid)
171 1.1 darran {
172 1.1 darran krwlock_t *rwp;
173 1.1 darran proc_t *p = curproc;
174 1.1 darran extern void trap(struct regs *, caddr_t, processorid_t);
175 1.1 darran
176 1.1 darran if (USERMODE(rp->r_cs) || (rp->r_ps & PS_VM)) {
177 1.1 darran if (curthread->t_cred != p->p_cred) {
178 1.1 darran cred_t *oldcred = curthread->t_cred;
179 1.1 darran /*
180 1.1 darran * DTrace accesses t_cred in probe context. t_cred
181 1.1 darran * must always be either NULL, or point to a valid,
182 1.1 darran * allocated cred structure.
183 1.1 darran */
184 1.1 darran curthread->t_cred = crgetcred();
185 1.1 darran crfree(oldcred);
186 1.1 darran }
187 1.1 darran }
188 1.1 darran
189 1.1 darran if (rp->r_trapno == T_DTRACE_RET) {
190 1.1 darran uint8_t step = curthread->t_dtrace_step;
191 1.1 darran uint8_t ret = curthread->t_dtrace_ret;
192 1.1 darran uintptr_t npc = curthread->t_dtrace_npc;
193 1.1 darran
194 1.1 darran if (curthread->t_dtrace_ast) {
195 1.1 darran aston(curthread);
196 1.1 darran curthread->t_sig_check = 1;
197 1.1 darran }
198 1.1 darran
199 1.1 darran /*
200 1.1 darran * Clear all user tracing flags.
201 1.1 darran */
202 1.1 darran curthread->t_dtrace_ft = 0;
203 1.1 darran
204 1.1 darran /*
205 1.1 darran * If we weren't expecting to take a return probe trap, kill
206 1.1 darran * the process as though it had just executed an unassigned
207 1.1 darran * trap instruction.
208 1.1 darran */
209 1.1 darran if (step == 0) {
210 1.1 darran tsignal(curthread, SIGILL);
211 1.1 darran return;
212 1.1 darran }
213 1.1 darran
214 1.1 darran /*
215 1.1 darran * If we hit this trap unrelated to a return probe, we're
216 1.1 darran * just here to reset the AST flag since we deferred a signal
217 1.1 darran * until after we logically single-stepped the instruction we
218 1.1 darran * copied out.
219 1.1 darran */
220 1.1 darran if (ret == 0) {
221 1.1 darran rp->r_pc = npc;
222 1.1 darran return;
223 1.1 darran }
224 1.1 darran
225 1.1 darran /*
226 1.1 darran * We need to wait until after we've called the
227 1.1 darran * dtrace_return_probe_ptr function pointer to set %pc.
228 1.1 darran */
229 1.1 darran rwp = &CPU->cpu_ft_lock;
230 1.1 darran rw_enter(rwp, RW_READER);
231 1.1 darran if (dtrace_return_probe_ptr != NULL)
232 1.1 darran (void) (*dtrace_return_probe_ptr)(rp);
233 1.1 darran rw_exit(rwp);
234 1.1 darran rp->r_pc = npc;
235 1.1 darran
236 1.1 darran } else if (rp->r_trapno == T_DTRACE_PROBE) {
237 1.1 darran rwp = &CPU->cpu_ft_lock;
238 1.1 darran rw_enter(rwp, RW_READER);
239 1.1 darran if (dtrace_fasttrap_probe_ptr != NULL)
240 1.1 darran (void) (*dtrace_fasttrap_probe_ptr)(rp);
241 1.1 darran rw_exit(rwp);
242 1.1 darran
243 1.1 darran } else if (rp->r_trapno == T_BPTFLT) {
244 1.1 darran uint8_t instr;
245 1.1 darran rwp = &CPU->cpu_ft_lock;
246 1.1 darran
247 1.1 darran /*
248 1.1 darran * The DTrace fasttrap provider uses the breakpoint trap
249 1.1 darran * (int 3). We let DTrace take the first crack at handling
250 1.1 darran * this trap; if it's not a probe that DTrace knowns about,
251 1.1 darran * we call into the trap() routine to handle it like a
252 1.1 darran * breakpoint placed by a conventional debugger.
253 1.1 darran */
254 1.1 darran rw_enter(rwp, RW_READER);
255 1.1 darran if (dtrace_pid_probe_ptr != NULL &&
256 1.1 darran (*dtrace_pid_probe_ptr)(rp) == 0) {
257 1.1 darran rw_exit(rwp);
258 1.1 darran return;
259 1.1 darran }
260 1.1 darran rw_exit(rwp);
261 1.1 darran
262 1.1 darran /*
263 1.1 darran * If the instruction that caused the breakpoint trap doesn't
264 1.1 darran * look like an int 3 anymore, it may be that this tracepoint
265 1.1 darran * was removed just after the user thread executed it. In
266 1.1 darran * that case, return to user land to retry the instuction.
267 1.1 darran */
268 1.1 darran if (fuword8((void *)(rp->r_pc - 1), &instr) == 0 &&
269 1.1 darran instr != FASTTRAP_INSTR) {
270 1.1 darran rp->r_pc--;
271 1.1 darran return;
272 1.1 darran }
273 1.1 darran
274 1.1 darran trap(rp, addr, cpuid);
275 1.1 darran
276 1.1 darran } else {
277 1.1 darran trap(rp, addr, cpuid);
278 1.1 darran }
279 1.1 darran }
280 1.1 darran
281 1.1 darran void
282 1.1 darran dtrace_safe_synchronous_signal(void)
283 1.1 darran {
284 1.1 darran kthread_t *t = curthread;
285 1.1 darran struct regs *rp = lwptoregs(ttolwp(t));
286 1.1 darran size_t isz = t->t_dtrace_npc - t->t_dtrace_pc;
287 1.1 darran
288 1.1 darran ASSERT(t->t_dtrace_on);
289 1.1 darran
290 1.1 darran /*
291 1.1 darran * If we're not in the range of scratch addresses, we're not actually
292 1.1 darran * tracing user instructions so turn off the flags. If the instruction
293 1.1 darran * we copied out caused a synchonous trap, reset the pc back to its
294 1.1 darran * original value and turn off the flags.
295 1.1 darran */
296 1.1 darran if (rp->r_pc < t->t_dtrace_scrpc ||
297 1.1 darran rp->r_pc > t->t_dtrace_astpc + isz) {
298 1.1 darran t->t_dtrace_ft = 0;
299 1.1 darran } else if (rp->r_pc == t->t_dtrace_scrpc ||
300 1.1 darran rp->r_pc == t->t_dtrace_astpc) {
301 1.1 darran rp->r_pc = t->t_dtrace_pc;
302 1.1 darran t->t_dtrace_ft = 0;
303 1.1 darran }
304 1.1 darran }
305 1.1 darran
306 1.1 darran int
307 1.1 darran dtrace_safe_defer_signal(void)
308 1.1 darran {
309 1.1 darran kthread_t *t = curthread;
310 1.1 darran struct regs *rp = lwptoregs(ttolwp(t));
311 1.1 darran size_t isz = t->t_dtrace_npc - t->t_dtrace_pc;
312 1.1 darran
313 1.1 darran ASSERT(t->t_dtrace_on);
314 1.1 darran
315 1.1 darran /*
316 1.1 darran * If we're not in the range of scratch addresses, we're not actually
317 1.1 darran * tracing user instructions so turn off the flags.
318 1.1 darran */
319 1.1 darran if (rp->r_pc < t->t_dtrace_scrpc ||
320 1.1 darran rp->r_pc > t->t_dtrace_astpc + isz) {
321 1.1 darran t->t_dtrace_ft = 0;
322 1.1 darran return (0);
323 1.1 darran }
324 1.1 darran
325 1.1 darran /*
326 1.1 darran * If we've executed the original instruction, but haven't performed
327 1.1 darran * the jmp back to t->t_dtrace_npc or the clean up of any registers
328 1.1 darran * used to emulate %rip-relative instructions in 64-bit mode, do that
329 1.1 darran * here and take the signal right away. We detect this condition by
330 1.1 darran * seeing if the program counter is the range [scrpc + isz, astpc).
331 1.1 darran */
332 1.1 darran if (t->t_dtrace_astpc - rp->r_pc <
333 1.1 darran t->t_dtrace_astpc - t->t_dtrace_scrpc - isz) {
334 1.1 darran #ifdef __amd64
335 1.1 darran /*
336 1.1 darran * If there is a scratch register and we're on the
337 1.1 darran * instruction immediately after the modified instruction,
338 1.1 darran * restore the value of that scratch register.
339 1.1 darran */
340 1.1 darran if (t->t_dtrace_reg != 0 &&
341 1.1 darran rp->r_pc == t->t_dtrace_scrpc + isz) {
342 1.1 darran switch (t->t_dtrace_reg) {
343 1.1 darran case REG_RAX:
344 1.1 darran rp->r_rax = t->t_dtrace_regv;
345 1.1 darran break;
346 1.1 darran case REG_RCX:
347 1.1 darran rp->r_rcx = t->t_dtrace_regv;
348 1.1 darran break;
349 1.1 darran case REG_R8:
350 1.1 darran rp->r_r8 = t->t_dtrace_regv;
351 1.1 darran break;
352 1.1 darran case REG_R9:
353 1.1 darran rp->r_r9 = t->t_dtrace_regv;
354 1.1 darran break;
355 1.1 darran }
356 1.1 darran }
357 1.1 darran #endif
358 1.1 darran rp->r_pc = t->t_dtrace_npc;
359 1.1 darran t->t_dtrace_ft = 0;
360 1.1 darran return (0);
361 1.1 darran }
362 1.1 darran
363 1.1 darran /*
364 1.1 darran * Otherwise, make sure we'll return to the kernel after executing
365 1.1 darran * the copied out instruction and defer the signal.
366 1.1 darran */
367 1.1 darran if (!t->t_dtrace_step) {
368 1.1 darran ASSERT(rp->r_pc < t->t_dtrace_astpc);
369 1.1 darran rp->r_pc += t->t_dtrace_astpc - t->t_dtrace_scrpc;
370 1.1 darran t->t_dtrace_step = 1;
371 1.1 darran }
372 1.1 darran
373 1.1 darran t->t_dtrace_ast = 1;
374 1.1 darran
375 1.1 darran return (1);
376 1.1 darran }
377 1.1 darran #endif
378 1.1 darran
379 1.3 tron #if 0
380 1.1 darran static int64_t tgt_cpu_tsc;
381 1.1 darran static int64_t hst_cpu_tsc;
382 1.3 tron #endif
383 1.2 darran static int64_t tsc_skew[MAXCPUS];
384 1.1 darran static uint64_t nsec_scale;
385 1.1 darran
386 1.1 darran /* See below for the explanation of this macro. */
387 1.1 darran #define SCALE_SHIFT 28
388 1.1 darran
389 1.2 darran static __inline uint64_t
390 1.2 darran dtrace_rdtsc(void)
391 1.2 darran {
392 1.2 darran uint64_t rv;
393 1.2 darran
394 1.2 darran __asm __volatile("rdtsc" : "=A" (rv));
395 1.2 darran return (rv);
396 1.2 darran }
397 1.2 darran
398 1.3 tron #if 0
399 1.1 darran static void
400 1.1 darran dtrace_gethrtime_init_sync(void *arg)
401 1.1 darran {
402 1.1 darran #ifdef CHECK_SYNC
403 1.1 darran /*
404 1.1 darran * Delay this function from returning on one
405 1.1 darran * of the CPUs to check that the synchronisation
406 1.1 darran * works.
407 1.1 darran */
408 1.1 darran uintptr_t cpu = (uintptr_t) arg;
409 1.1 darran
410 1.1 darran if (cpu == curcpu) {
411 1.1 darran int i;
412 1.1 darran for (i = 0; i < 1000000000; i++)
413 1.2 darran tgt_cpu_tsc = dtrace_rdtsc();
414 1.1 darran tgt_cpu_tsc = 0;
415 1.1 darran }
416 1.1 darran #endif
417 1.1 darran }
418 1.3 tron #endif
419 1.1 darran
420 1.3 tron #if 0
421 1.1 darran static void
422 1.1 darran dtrace_gethrtime_init_cpu(void *arg)
423 1.1 darran {
424 1.1 darran uintptr_t cpu = (uintptr_t) arg;
425 1.1 darran
426 1.2 darran if (cpu == cpu_number())
427 1.2 darran tgt_cpu_tsc = dtrace_rdtsc();
428 1.1 darran else
429 1.2 darran hst_cpu_tsc = dtrace_rdtsc();
430 1.1 darran }
431 1.3 tron #endif
432 1.1 darran
433 1.2 darran void
434 1.1 darran dtrace_gethrtime_init(void *arg)
435 1.1 darran {
436 1.1 darran uint64_t tsc_f;
437 1.2 darran CPU_INFO_ITERATOR cpuind;
438 1.2 darran struct cpu_info *cinfo = curcpu();
439 1.2 darran cpuid_t cur_cpuid = cpu_number(); /* current cpu id */
440 1.1 darran
441 1.1 darran /*
442 1.1 darran * Get TSC frequency known at this moment.
443 1.1 darran * This should be constant if TSC is invariant.
444 1.1 darran * Otherwise tick->time conversion will be inaccurate, but
445 1.1 darran * will preserve monotonic property of TSC.
446 1.1 darran */
447 1.2 darran tsc_f = cpu_frequency(cinfo);
448 1.1 darran
449 1.1 darran /*
450 1.1 darran * The following line checks that nsec_scale calculated below
451 1.1 darran * doesn't overflow 32-bit unsigned integer, so that it can multiply
452 1.1 darran * another 32-bit integer without overflowing 64-bit.
453 1.1 darran * Thus minimum supported TSC frequency is 62.5MHz.
454 1.1 darran */
455 1.2 darran //KASSERT(tsc_f > (NANOSEC >> (32 - SCALE_SHIFT)), ("TSC frequency is too low"));
456 1.2 darran KASSERT(tsc_f > (NANOSEC >> (32 - SCALE_SHIFT)));
457 1.1 darran
458 1.1 darran /*
459 1.1 darran * We scale up NANOSEC/tsc_f ratio to preserve as much precision
460 1.1 darran * as possible.
461 1.1 darran * 2^28 factor was chosen quite arbitrarily from practical
462 1.1 darran * considerations:
463 1.1 darran * - it supports TSC frequencies as low as 62.5MHz (see above);
464 1.1 darran * - it provides quite good precision (e < 0.01%) up to THz
465 1.1 darran * (terahertz) values;
466 1.1 darran */
467 1.1 darran nsec_scale = ((uint64_t)NANOSEC << SCALE_SHIFT) / tsc_f;
468 1.1 darran
469 1.1 darran /* The current CPU is the reference one. */
470 1.2 darran tsc_skew[cur_cpuid] = 0;
471 1.1 darran
472 1.2 darran for (CPU_INFO_FOREACH(cpuind, cinfo)) {
473 1.2 darran /* use skew relative to cpu 0 */
474 1.2 darran tsc_skew[cpu_index(cinfo)] = cinfo->ci_data.cpu_cc_skew;
475 1.2 darran }
476 1.2 darran
477 1.2 darran /* Already handled in x86/tsc.c for ci_data.cpu_cc_skew */
478 1.2 darran #if 0
479 1.1 darran for (i = 0; i <= mp_maxid; i++) {
480 1.1 darran if (i == curcpu)
481 1.1 darran continue;
482 1.1 darran
483 1.1 darran if (pcpu_find(i) == NULL)
484 1.1 darran continue;
485 1.1 darran
486 1.1 darran map = 0;
487 1.1 darran map |= (1 << curcpu);
488 1.1 darran map |= (1 << i);
489 1.1 darran
490 1.1 darran smp_rendezvous_cpus(map, dtrace_gethrtime_init_sync,
491 1.1 darran dtrace_gethrtime_init_cpu,
492 1.1 darran smp_no_rendevous_barrier, (void *)(uintptr_t) i);
493 1.1 darran
494 1.1 darran tsc_skew[i] = tgt_cpu_tsc - hst_cpu_tsc;
495 1.1 darran }
496 1.2 darran #endif
497 1.1 darran }
498 1.1 darran
499 1.1 darran /*
500 1.1 darran * DTrace needs a high resolution time function which can
501 1.1 darran * be called from a probe context and guaranteed not to have
502 1.1 darran * instrumented with probes itself.
503 1.1 darran *
504 1.1 darran * Returns nanoseconds since boot.
505 1.1 darran */
506 1.1 darran uint64_t
507 1.1 darran dtrace_gethrtime()
508 1.1 darran {
509 1.1 darran uint64_t tsc;
510 1.1 darran uint32_t lo;
511 1.1 darran uint32_t hi;
512 1.1 darran
513 1.1 darran /*
514 1.1 darran * We split TSC value into lower and higher 32-bit halves and separately
515 1.1 darran * scale them with nsec_scale, then we scale them down by 2^28
516 1.1 darran * (see nsec_scale calculations) taking into account 32-bit shift of
517 1.1 darran * the higher half and finally add.
518 1.1 darran */
519 1.2 darran tsc = dtrace_rdtsc() + tsc_skew[cpu_number()];
520 1.1 darran lo = tsc;
521 1.1 darran hi = tsc >> 32;
522 1.1 darran return (((lo * nsec_scale) >> SCALE_SHIFT) +
523 1.1 darran ((hi * nsec_scale) << (32 - SCALE_SHIFT)));
524 1.1 darran }
525 1.1 darran
526 1.1 darran uint64_t
527 1.1 darran dtrace_gethrestime(void)
528 1.1 darran {
529 1.1 darran printf("%s(%d): XXX\n",__func__,__LINE__);
530 1.1 darran return (0);
531 1.1 darran }
532 1.1 darran
533 1.1 darran /* Function to handle DTrace traps during probes. See i386/i386/trap.c */
534 1.1 darran int
535 1.1 darran dtrace_trap(struct trapframe *frame, u_int type)
536 1.1 darran {
537 1.2 darran cpuid_t cpuid = cpu_number(); /* current cpu id */
538 1.2 darran
539 1.1 darran /*
540 1.1 darran * A trap can occur while DTrace executes a probe. Before
541 1.1 darran * executing the probe, DTrace blocks re-scheduling and sets
542 1.1 darran * a flag in it's per-cpu flags to indicate that it doesn't
543 1.1 darran * want to fault. On returning from the the probe, the no-fault
544 1.1 darran * flag is cleared and finally re-scheduling is enabled.
545 1.1 darran *
546 1.1 darran * Check if DTrace has enabled 'no-fault' mode:
547 1.1 darran *
548 1.1 darran */
549 1.2 darran if ((cpu_core[cpuid].cpuc_dtrace_flags & CPU_DTRACE_NOFAULT) != 0) {
550 1.1 darran /*
551 1.1 darran * There are only a couple of trap types that are expected.
552 1.1 darran * All the rest will be handled in the usual way.
553 1.1 darran */
554 1.1 darran switch (type) {
555 1.1 darran /* General protection fault. */
556 1.1 darran case T_PROTFLT:
557 1.1 darran /* Flag an illegal operation. */
558 1.2 darran cpu_core[cpuid].cpuc_dtrace_flags |= CPU_DTRACE_ILLOP;
559 1.1 darran
560 1.1 darran /*
561 1.1 darran * Offset the instruction pointer to the instruction
562 1.1 darran * following the one causing the fault.
563 1.1 darran */
564 1.1 darran frame->tf_eip += dtrace_instr_size((u_char *) frame->tf_eip);
565 1.1 darran return (1);
566 1.1 darran /* Page fault. */
567 1.1 darran case T_PAGEFLT:
568 1.1 darran /* Flag a bad address. */
569 1.2 darran cpu_core[cpuid].cpuc_dtrace_flags |= CPU_DTRACE_BADADDR;
570 1.2 darran cpu_core[cpuid].cpuc_dtrace_illval = rcr2();
571 1.1 darran
572 1.1 darran /*
573 1.1 darran * Offset the instruction pointer to the instruction
574 1.1 darran * following the one causing the fault.
575 1.1 darran */
576 1.1 darran frame->tf_eip += dtrace_instr_size((u_char *) frame->tf_eip);
577 1.1 darran return (1);
578 1.1 darran default:
579 1.1 darran /* Handle all other traps in the usual way. */
580 1.1 darran break;
581 1.1 darran }
582 1.1 darran }
583 1.1 darran
584 1.1 darran /* Handle the trap in the usual way. */
585 1.1 darran return (0);
586 1.1 darran }
587