Home | History | Annotate | Line # | Download | only in i386
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